19 {
"residual_tolerance", 1.0e-2}})
33 const std::string fname =
"cfem_diffusion::Solver::Initialize";
36 << TextName() <<
": Initializing CFEM Diffusion solver ";
40 const auto& grid = *grid_ptr_;
41 if (grid_ptr_ ==
nullptr)
42 throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
45 Chi::log.
Log() <<
"Global num cells: " << grid.GetGlobalNumberOfCells();
48 auto globl_unique_bndry_ids = grid.GetDomainUniqueBoundaryIDs();
50 const auto& grid_boundary_id_map = grid_ptr_->GetBoundaryIDMap();
51 for (uint64_t bndry_id : globl_unique_bndry_ids)
53 if (grid_boundary_id_map.count(bndry_id) == 0)
54 throw std::logic_error(fname +
": Boundary id " +
55 std::to_string(bndry_id) +
" does not have a name-assignment.");
57 const auto& bndry_name = grid_boundary_id_map.at(bndry_id);
58 if (boundary_preferences_.find(bndry_name) != boundary_preferences_.end())
60 BoundaryInfo bndry_info = boundary_preferences_.at(bndry_name);
61 auto& bndry_vals = bndry_info.second;
62 switch (bndry_info.first)
66 boundaries_.insert(std::make_pair(
68 Chi::log.
Log() <<
"Boundary " << bndry_name <<
" set to reflecting.";
73 if (bndry_vals.empty()) bndry_vals.resize(1,0.0);
74 boundaries_.insert(std::make_pair(
76 Chi::log.
Log() <<
"Boundary " << bndry_name <<
" set to dirichlet.";
81 if (bndry_vals.size()!=3)
82 throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
83 " Robin needs 3 values in bndry vals.");
84 boundaries_.insert(std::make_pair(
89 <<
" set to robin." << bndry_vals[0]<<
","
90 << bndry_vals[1]<<
","<<bndry_vals[2];
95 boundaries_.insert(std::make_pair(
97 Chi::log.
Log() <<
"Boundary " << bndry_name <<
" set to vacuum.";
102 if (bndry_vals.size()!=3)
103 throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
104 " Neumann needs 3 values in bndry vals.");
105 boundaries_.insert(std::make_pair(
109 <<
" set to neumann." << bndry_vals[0];
116 boundaries_.insert(std::make_pair(
119 <<
"No boundary preference found for boundary index " << bndry_name
120 <<
"Dirichlet boundary added with zero boundary value.";
126 const auto& sdm = *sdm_ptr_;
128 const auto& OneDofPerNode = sdm.UNITARY_UNKNOWN_MANAGER;
129 num_local_dofs_ = sdm.GetNumLocalDOFs(OneDofPerNode);
130 num_globl_dofs_ = sdm.GetNumGlobalDOFs(OneDofPerNode);
132 Chi::log.
Log() <<
"Num local DOFs: " << num_local_dofs_;
133 Chi::log.
Log() <<
"Num globl DOFs: " << num_globl_dofs_;
136 const auto n =
static_cast<int64_t
>(num_local_dofs_);
137 const auto N =
static_cast<int64_t
>(num_globl_dofs_);
143 std::vector<int64_t> nodal_nnz_in_diag;
144 std::vector<int64_t> nodal_nnz_off_diag;
145 sdm.BuildSparsityPattern(nodal_nnz_in_diag,nodal_nnz_off_diag, OneDofPerNode);
151 if (field_functions_.empty())
153 std::string solver_name;
154 if (not TextName().empty()) solver_name = TextName() +
"-";
156 std::string text_name = solver_name +
"phi";
159 auto initial_field_function =
160 std::make_shared<chi_physics::FieldFunctionGridBased>(
165 field_functions_.push_back(initial_field_function);
174 Chi::log.
Log() <<
"\nExecuting CFEM Diffusion solver";
176 const auto& grid = *grid_ptr_;
177 const auto& sdm = *sdm_ptr_;
183 for (
const auto& cell : grid.local_cells)
185 const auto& cell_mapping = sdm.GetCellMapping(cell);
186 const auto qp_data = cell_mapping.MakeVolumetricQuadraturePointData();
188 const auto imat = cell.material_id_;
189 const size_t num_nodes = cell_mapping.NumNodes();
191 VecDbl cell_rhs(num_nodes, 0.0);
193 for (
size_t i=0; i<num_nodes; ++i)
195 for (
size_t j=0; j<num_nodes; ++j)
197 double entry_aij = 0.0;
198 for (
size_t qp : qp_data.QuadraturePointIndices())
202 CallLua_iXYZFunction(L,
"D_coef",imat,qp_data.QPointXYZ(qp)) *
203 qp_data.ShapeGrad(i, qp).Dot(qp_data.ShapeGrad(j, qp))
205 CallLua_iXYZFunction(L,
"Sigma_a",imat,qp_data.QPointXYZ(qp)) *
206 qp_data.ShapeValue(i, qp) * qp_data.ShapeValue(j, qp)
211 Acell[i][j] = entry_aij;
213 for (
size_t qp : qp_data.QuadraturePointIndices())
214 cell_rhs[i] += CallLua_iXYZFunction(L,
"Q_ext",imat,qp_data.QPointXYZ(qp)) * qp_data.ShapeValue(i, qp) * qp_data.JxW(qp);
218 std::vector<int> dirichlet_count(num_nodes, 0);
219 std::vector<double> dirichlet_value(num_nodes, 0.0);
221 const size_t num_faces = cell.faces_.size();
222 for (
size_t f=0; f<num_faces; ++f)
224 const auto& face = cell.faces_[f];
226 if (face.has_neighbor_)
continue;
228 const auto& bndry = boundaries_[face.neighbor_id_];
233 const auto qp_face_data =
234 cell_mapping.MakeSurfaceQuadraturePointData(f);
235 const size_t num_face_nodes = face.vertex_ids_.size();
237 const auto& aval = bndry.values_[0];
238 const auto& bval = bndry.values_[1];
239 const auto& fval = bndry.values_[2];
247 if (std::fabs(bval) < 1e-8)
248 throw std::logic_error(
"if b=0, this is a Dirichlet BC, not a Robin BC");
251 for (
size_t fi=0; fi<num_face_nodes; ++fi)
253 const uint i = cell_mapping.MapFaceNode(f,fi);
255 double entry_rhsi = 0.0;
256 for (
size_t qp : qp_face_data.QuadraturePointIndices() )
257 entry_rhsi += qp_face_data.ShapeValue(i, qp) * qp_face_data.JxW(qp);
258 cell_rhs[i] += fval / bval * entry_rhsi;
261 if (std::fabs(aval) > 1.0e-8)
263 for (
size_t fj=0; fj<num_face_nodes; ++fj)
265 const uint j = cell_mapping.MapFaceNode(f,fj);
267 double entry_aij = 0.0;
268 for (
size_t qp : qp_face_data.QuadraturePointIndices())
269 entry_aij += qp_face_data.ShapeValue(i, qp) *qp_face_data.ShapeValue(j, qp)
270 * qp_face_data.JxW(qp);
271 Acell[i][j] += aval / bval * entry_aij;
280 const size_t num_face_nodes = face.vertex_ids_.size();
282 const auto& boundary_value = bndry.values_[0];
285 for (
size_t fi=0; fi<num_face_nodes; ++fi)
287 const uint i = cell_mapping.MapFaceNode(f,fi);
288 dirichlet_count[i] += 1;
289 dirichlet_value[i] += boundary_value;
296 std::vector<int64_t> imap(num_nodes, 0);
297 for (
size_t i=0; i<num_nodes; ++i)
298 imap[i] = sdm.MapDOF(cell, i);
301 for (
size_t i=0; i<num_nodes; ++i)
303 if (dirichlet_count[i]>0)
305 MatSetValue(A_, imap[i], imap[i], 1.0, ADD_VALUES);
307 const double aux = dirichlet_value[i]/dirichlet_count[i];
308 VecSetValue(b_, imap[i], aux, ADD_VALUES);
312 for (
size_t j=0; j<num_nodes; ++j)
314 if (dirichlet_count[j]==0)
315 MatSetValue(A_, imap[i], imap[j], Acell[i][j], ADD_VALUES);
318 const double aux = dirichlet_value[j]/dirichlet_count[j];
319 cell_rhs[i] -= Acell[i][j]*aux;
322 VecSetValue(b_, imap[i], cell_rhs[i], ADD_VALUES);
329 MatAssemblyBegin(A_, MAT_FINAL_ASSEMBLY);
330 MatAssemblyEnd(A_, MAT_FINAL_ASSEMBLY);
331 VecAssemblyBegin(b_);
344 basic_options_(
"residual_tolerance").FloatValue(),
345 basic_options_(
"max_iters").IntegerValue()
349 KSPSolve(petsc_solver.ksp, b_, x_);
351 UpdateFieldFunctions();
std::vector< VecDbl > MatDbl
std::vector< double > VecDbl
static std::vector< chi_physics::FieldFunctionPtr > field_function_stack
static chi::Timer program_timer
static chi::Console & console
void Initialize() override
Solver(const std::string &in_solver_name)
std::pair< BoundaryType, std::vector< double > > BoundaryInfo
LogStream Log(LOG_LVL level=LOG_0)
lua_State *& GetConsoleState()
std::string GetTimeString() const
static std::shared_ptr< PieceWiseLinearContinuous > New(const chi_mesh::MeshContinuum &grid, QuadratureOrder q_order=QuadratureOrder::SECOND, CoordinateSystemType cs_type=CoordinateSystemType::CARTESIAN)
chi_mesh::MeshContinuumPtr & GetGrid() const
void InitMatrixSparsity(Mat &A, const std::vector< int64_t > &nodal_nnz_in_diag, const std::vector< int64_t > &nodal_nnz_off_diag)
PETScSolverSetup CreateCommonKrylovSolverSetup(Mat ref_matrix, const std::string &in_solver_name="KSPSolver", const std::string &in_solver_type=KSPGMRES, const std::string &in_preconditioner_type=PCNONE, double in_relative_residual_tolerance=1.0e-6, int64_t in_maximum_iterations=100)
Mat CreateSquareMatrix(int64_t local_size, int64_t global_size)
Vec CreateVector(int64_t local_size, int64_t global_size)
MeshHandler & GetCurrentHandler()