diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp
index 4e610f1459b01b2fb643dc45e891446d8c1e3241..3376c89de8da3ae851850aab70ad4db0e7ba00f0 100644
--- a/src/language/modules/SchemeModule.cpp
+++ b/src/language/modules/SchemeModule.cpp
@@ -942,13 +942,15 @@ SchemeModule::SchemeModule()
                                  const std::shared_ptr<const DiscreteFunctionVariant>& F_E,
                                  const std::shared_ptr<const DiscreteFunctionVariant>& rho_ex,
                                  const std::shared_ptr<const DiscreteFunctionVariant>& rho_u_ex,
-                                 const std::shared_ptr<const DiscreteFunctionVariant>& rho_E_ex)
-                                -> std::tuple<std::shared_ptr<const DiscreteFunctionVariant>,
-                                              std::shared_ptr<const DiscreteFunctionVariant>,
-                                              std::shared_ptr<const DiscreteFunctionVariant>,
-                                              std::shared_ptr<const DiscreteFunctionVariant>> {
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& rho_E_ex,
+                                 const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
+                                   bc_descriptor_list) -> std::tuple<std::shared_ptr<const DiscreteFunctionVariant>,
+                                                                     std::shared_ptr<const DiscreteFunctionVariant>,
+                                                                     std::shared_ptr<const DiscreteFunctionVariant>,
+                                                                     std::shared_ptr<const DiscreteFunctionVariant>> {
                                 return eulerKineticSolver2D(dt, gamma, lambda_vector, eps, SpaceOrder, F_rho, F_rho_u1,
-                                                            F_rho_u2, F_E, rho_ex, rho_u_ex, rho_E_ex);
+                                                            F_rho_u2, F_E, rho_ex, rho_u_ex, rho_E_ex,
+                                                            bc_descriptor_list);
                               }
 
                               ));
diff --git a/src/scheme/EulerKineticSolver2D.cpp b/src/scheme/EulerKineticSolver2D.cpp
index eabcc1f3a764fe28b0235ff55f5fdd9d40349af0..0f2513f67ce26de57d583909ba5c1696675c3336 100644
--- a/src/scheme/EulerKineticSolver2D.cpp
+++ b/src/scheme/EulerKineticSolver2D.cpp
@@ -3,11 +3,16 @@
 #include <language/utils/EvaluateAtPoints.hpp>
 #include <mesh/Connectivity.hpp>
 #include <mesh/Mesh.hpp>
+#include <mesh/MeshFlatNodeBoundary.hpp>
+#include <mesh/MeshNodeBoundary.hpp>
 #include <mesh/MeshVariant.hpp>
 #include <scheme/DiscreteFunctionDescriptorP0Vector.hpp>
 #include <scheme/DiscreteFunctionP0Vector.hpp>
 #include <scheme/DiscreteFunctionUtils.hpp>
+#include <scheme/FixedBoundaryConditionDescriptor.hpp>
+#include <scheme/IBoundaryConditionDescriptor.hpp>
 #include <scheme/IDiscreteFunctionDescriptor.hpp>
+#include <scheme/SymmetryBoundaryConditionDescriptor.hpp>
 
 #include <analysis/GaussLegendreQuadratureDescriptor.hpp>
 #include <analysis/QuadratureManager.hpp>
@@ -197,6 +202,12 @@ class EulerKineticSolver2D
   constexpr static size_t Dimension = MeshType::Dimension;
   using Rd                          = TinyVector<Dimension>;
 
+  class FixedBoundaryCondition;
+  class SymmetryBoundaryCondition;
+
+  using BoundaryCondition     = std::variant<FixedBoundaryCondition, SymmetryBoundaryCondition>;
+  using BoundaryConditionList = std::vector<BoundaryCondition>;
+
   const double m_dt;
   const double m_eps;
   const std::vector<TinyVector<Dimension>>& m_lambda_vector;
@@ -221,6 +232,39 @@ class EulerKineticSolver2D
   const CellValue<const TinyVector<Dimension>> m_xj = MeshDataManager::instance().getMeshData(m_mesh).xj();
   const NodeValue<const TinyVector<Dimension>> m_xr = m_mesh.xr();
 
+  BoundaryConditionList
+  _getBCList(const MeshType& mesh,
+             const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const
+  {
+    BoundaryConditionList bc_list;
+
+    for (const auto& bc_descriptor : bc_descriptor_list) {
+      bool is_valid_boundary_condition = true;
+
+      switch (bc_descriptor->type()) {
+      case IBoundaryConditionDescriptor::Type::symmetry: {
+        bc_list.emplace_back(
+          SymmetryBoundaryCondition(getMeshFlatNodeBoundary(mesh, bc_descriptor->boundaryDescriptor())));
+        break;
+      }
+      case IBoundaryConditionDescriptor::Type::fixed: {
+        bc_list.emplace_back(FixedBoundaryCondition(getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor())));
+        break;
+      }
+      default: {
+        is_valid_boundary_condition = false;
+      }
+      }
+      if (not is_valid_boundary_condition) {
+        std::ostringstream error_msg;
+        error_msg << *bc_descriptor << " is an invalid boundary condition for acoustic solver";
+        throw NormalError(error_msg.str());
+      }
+    }
+
+    return bc_list;
+  }
+
  public:
   CellArray<TinyVector<MeshType::Dimension>>
   getA(const DiscreteFunctionP0<const double>& rho,
@@ -473,24 +517,33 @@ class EulerKineticSolver2D
   }
 
   CellValue<bool>
-  getBoundaryCells()
+  getBoundaryCells(const BoundaryConditionList& bc_list)
   {
     CellValue<bool> is_boundary_cell{p_mesh->connectivity()};
-    const auto& cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
-    auto is_boundary_node           = p_mesh->connectivity().isBoundaryNode();
+    auto is_boundary_node = p_mesh->connectivity().isBoundaryNode();
 
     is_boundary_cell.fill(false);
 
-    parallel_for(
-      p_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) {
-        const auto& cell_to_node = cell_to_node_matrix[cell_id];
-        for (size_t i_node = 0; i_node < cell_to_node.size(); ++i_node) {
-          const NodeId node_id = cell_to_node[i_node];
-          if (is_boundary_node[node_id]) {
-            is_boundary_cell[cell_id] = true;
+    auto node_to_cell_matrix = m_mesh.connectivity().nodeToCellMatrix();
+
+    for (auto&& bc_v : bc_list) {
+      std::visit(
+        [=](auto&& bc) {
+          using BCType = std::decay_t<decltype(bc)>;
+          if constexpr (std::is_same_v<BCType, FixedBoundaryCondition>) {
+            auto node_list = bc.nodeList();
+            for (size_t i_node = 0; i_node < node_list.size(); ++i_node) {
+              auto cell_list = node_to_cell_matrix[node_list[i_node]];
+              for (size_t i_cell = 0; i_cell < cell_list.size(); ++i_cell) {
+                const CellId cell_id      = cell_list[i_cell];
+                is_boundary_cell[cell_id] = true;
+              }
+            }
           }
-        }
-      });
+        },
+        bc_v);
+    }
+
     return is_boundary_cell;
   }
 
@@ -498,11 +551,13 @@ class EulerKineticSolver2D
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>>
-  apply()
+  apply(const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list)
   {
+    BoundaryConditionList bc_list = this->_getBCList(m_mesh, bc_descriptor_list);
+
     const size_t nb_waves = m_lambda_vector.size();
 
-    CellValue<bool> is_boundary_cell = getBoundaryCells();
+    CellValue<bool> is_boundary_cell = getBoundaryCells(bc_list);
 
     DiscreteFunctionP0<double> rho_u1_ex{p_mesh};
     DiscreteFunctionP0<double> rho_u2_ex{p_mesh};
@@ -629,14 +684,6 @@ class EulerKineticSolver2D
             Fnp1_rho_E[cell_id][i_wave] =
               c1 * (m_eps * Fn_rho_E[cell_id][i_wave] - c2 * deltaLFn_rho_E[cell_id][i_wave] +
                     m_dt * MPFnp1_rho_E[cell_id][i_wave]);
-            // std::cout << "inside Fnp1_rho[" << cell_id << "][" << i_wave << "] = " << Fnp1_rho[cell_id][i_wave] <<
-            // "\n"; std::cout << "inside Fnp1_rho_u1[" << cell_id << "][" << i_wave << "] = " <<
-            // Fnp1_rho_u1[cell_id][i_wave]
-            //           << "\n";
-            // std::cout << "inside Fnp1_rho_u2[" << cell_id << "][" << i_wave << "] = " << Fnp1_rho_u2[cell_id][i_wave]
-            //           << "\n";
-            // std::cout << "inside Fnp1_rho_E[" << cell_id << "][" << i_wave << "] = " << Fnp1_rho_E[cell_id][i_wave]
-            //           << "\n";
           }
         } else {
           for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
@@ -644,16 +691,6 @@ class EulerKineticSolver2D
             Fnp1_rho_u1[cell_id][i_wave] = Fn_rho_u1_ex[cell_id][i_wave];
             Fnp1_rho_u2[cell_id][i_wave] = Fn_rho_u2_ex[cell_id][i_wave];
             Fnp1_rho_E[cell_id][i_wave]  = Fn_rho_E_ex[cell_id][i_wave];
-            // std::cout << "boundary Fnp1_rho[" << cell_id << "][" << i_wave << "] = " << Fnp1_rho[cell_id][i_wave]
-            //           << "\n";
-            // std::cout << "boundary Fnp1_rho_u1[" << cell_id << "][" << i_wave << "] = " <<
-            // Fnp1_rho_u1[cell_id][i_wave]
-            //           << "\n";
-            // std::cout << "boundary Fnp1_rho_u2[" << cell_id << "][" << i_wave << "] = " <<
-            // Fnp1_rho_u2[cell_id][i_wave]
-            //           << "\n";
-            // std::cout << "boundary Fnp1_rho_E[" << cell_id << "][" << i_wave << "] = " << Fnp1_rho_E[cell_id][i_wave]
-            //           << "\n";
           }
         }
       });
@@ -723,7 +760,8 @@ eulerKineticSolver2D(const double& dt,
                      const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_E,
                      const std::shared_ptr<const DiscreteFunctionVariant>& rho_ex,
                      const std::shared_ptr<const DiscreteFunctionVariant>& rho_u_ex,
-                     const std::shared_ptr<const DiscreteFunctionVariant>& rho_E_ex)
+                     const std::shared_ptr<const DiscreteFunctionVariant>& rho_E_ex,
+                     const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list)
 {
   const std::shared_ptr<const MeshVariant> mesh_v =
     getCommonMesh({F_rho, F_rho_u1, F_rho_u2, F_rho_E, rho_ex, rho_u_ex, rho_E_ex});
@@ -751,10 +789,67 @@ eulerKineticSolver2D(const double& dt,
         EulerKineticSolver2D solver(p_mesh, dt, eps, gamma, lambda_vector, SpaceOrder, Fn_rho, Fn_rho_u1, Fn_rho_u2,
                                     Fn_rho_E, rho_n_ex, rho_u_n_ex, rho_E_n_ex);
 
-        return solver.apply();
+        return solver.apply(bc_descriptor_list);
       } else {
         throw NotImplementedError("Invalid mesh type for 2D Euler Kinetic solver");
       }
     },
     mesh_v->variant());
 }
+
+template <MeshConcept MeshType>
+class EulerKineticSolver2D<MeshType>::FixedBoundaryCondition
+{
+ private:
+  const MeshNodeBoundary m_mesh_node_boundary;
+
+ public:
+  const Array<const NodeId>&
+  nodeList() const
+  {
+    return m_mesh_node_boundary.nodeList();
+  }
+
+  FixedBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary) : m_mesh_node_boundary{mesh_node_boundary} {}
+
+  ~FixedBoundaryCondition() = default;
+};
+
+template <MeshConcept MeshType>
+class EulerKineticSolver2D<MeshType>::SymmetryBoundaryCondition
+{
+ public:
+  static constexpr const size_t Dimension = MeshType::Dimension;
+
+  using Rd = TinyVector<Dimension, double>;
+
+ private:
+  const MeshFlatNodeBoundary<MeshType> m_mesh_flat_node_boundary;
+
+ public:
+  const Rd&
+  outgoingNormal() const
+  {
+    return m_mesh_flat_node_boundary.outgoingNormal();
+  }
+
+  size_t
+  numberOfNodes() const
+  {
+    return m_mesh_flat_node_boundary.nodeList().size();
+  }
+
+  const Array<const NodeId>&
+  nodeList() const
+  {
+    return m_mesh_flat_node_boundary.nodeList();
+  }
+
+  SymmetryBoundaryCondition(const MeshFlatNodeBoundary<MeshType>& mesh_flat_node_boundary)
+    : m_mesh_flat_node_boundary(mesh_flat_node_boundary)
+  {
+    ;
+  }
+
+  ~SymmetryBoundaryCondition() = default;
+};
diff --git a/src/scheme/EulerKineticSolver2D.hpp b/src/scheme/EulerKineticSolver2D.hpp
index 437611c304b6d95e56a514b6bd1cf31cb2002511..76d024c82658527ee2fe895ada184929fabbb6ef 100644
--- a/src/scheme/EulerKineticSolver2D.hpp
+++ b/src/scheme/EulerKineticSolver2D.hpp
@@ -4,6 +4,8 @@
 #include <language/utils/FunctionSymbolId.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
 
+class IBoundaryConditionDescriptor;
+
 std::vector<TinyVector<2>> getLambdaVector(const std::shared_ptr<const MeshVariant>& mesh,
                                            const double& lambda,
                                            const size_t& L,
@@ -38,6 +40,7 @@ eulerKineticSolver2D(const double& dt,
                      const std::shared_ptr<const DiscreteFunctionVariant>& F_rho_E,
                      const std::shared_ptr<const DiscreteFunctionVariant>& rho_ex,
                      const std::shared_ptr<const DiscreteFunctionVariant>& rho_u_ex,
-                     const std::shared_ptr<const DiscreteFunctionVariant>& rho_E_ex);
+                     const std::shared_ptr<const DiscreteFunctionVariant>& rho_E_ex,
+                     const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list);
 
 #endif   // EULER_KINETIC_SOLVER_2D_HPP