16#define DefaultBCDirichlet BoundaryCondition{BCType::DIRICHLET,{0,0,0}}
21 {
"residual_tolerance", 1.0e-2}})
35 const std::string fname =
"dfem_diffusion::Solver::Initialize";
38 << TextName() <<
": Initializing DFEM Diffusion solver ";
42 const auto& grid = *grid_ptr_;
43 if (grid_ptr_ ==
nullptr)
44 throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
47 Chi::log.
Log() <<
"Global num cells: " << grid.GetGlobalNumberOfCells();
50 auto globl_unique_bndry_ids = grid.GetDomainUniqueBoundaryIDs();
52 const auto& grid_boundary_id_map = grid_ptr_->GetBoundaryIDMap();
53 for (uint64_t bndry_id : globl_unique_bndry_ids)
55 if (grid_boundary_id_map.count(bndry_id) == 0)
56 throw std::logic_error(fname +
": Boundary id " +
57 std::to_string(bndry_id) +
" does not have a name-assignment.");
59 const auto& bndry_name = grid_boundary_id_map.at(bndry_id);
60 if (boundary_preferences_.find(bndry_name) != boundary_preferences_.end())
62 BoundaryInfo bndry_info = boundary_preferences_.at(bndry_name);
63 auto& bndry_vals = bndry_info.second;
64 switch (bndry_info.first)
68 boundaries_.insert(std::make_pair(
70 Chi::log.
Log() <<
"Boundary " << bndry_name <<
" set to reflecting.";
75 if (bndry_vals.empty()) bndry_vals.resize(1,0.0);
76 boundaries_.insert(std::make_pair(
78 Chi::log.
Log() <<
"Boundary " << bndry_name <<
" set to dirichlet.";
83 if (bndry_vals.size()!=3)
84 throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
85 " Robin needs 3 values in bndry vals.");
86 boundaries_.insert(std::make_pair(
91 <<
" set to robin." << bndry_vals[0]<<
","
92 << bndry_vals[1]<<
","<<bndry_vals[2];
97 boundaries_.insert(std::make_pair(
99 Chi::log.
Log() <<
"Boundary " << bndry_name <<
" set to vacuum.";
104 if (bndry_vals.size()!=3)
105 throw std::logic_error(std::string(__PRETTY_FUNCTION__) +
106 " Neumann needs 3 values in bndry vals.");
107 boundaries_.insert(std::make_pair(
111 <<
" set to neumann." << bndry_vals[0];
118 boundaries_.insert(std::make_pair(
121 <<
"No boundary preference found for boundary index " << bndry_name
122 <<
"Dirichlet boundary added with zero boundary value.";
128 const auto& sdm = *sdm_ptr_;
130 const auto& OneDofPerNode = sdm.UNITARY_UNKNOWN_MANAGER;
132 num_local_dofs_ = sdm.GetNumLocalDOFs(OneDofPerNode);
133 num_globl_dofs_ = sdm.GetNumGlobalDOFs(OneDofPerNode);
135 Chi::log.
Log() <<
"Num local DOFs: " << num_local_dofs_;
136 Chi::log.
Log() <<
"Num globl DOFs: " << num_globl_dofs_;
139 const auto n =
static_cast<int64_t
>(num_local_dofs_);
140 const auto N =
static_cast<int64_t
>(num_globl_dofs_);
146 std::vector<int64_t> nodal_nnz_in_diag;
147 std::vector<int64_t> nodal_nnz_off_diag;
148 sdm.BuildSparsityPattern(nodal_nnz_in_diag,nodal_nnz_off_diag, OneDofPerNode);
154 if (field_functions_.empty())
156 std::string solver_name;
157 if (not TextName().empty()) solver_name = TextName() +
"-";
159 std::string text_name = solver_name +
"phi";
162 auto initial_field_function =
163 std::make_shared<chi_physics::FieldFunctionGridBased>(
168 field_functions_.push_back(initial_field_function);
177 Chi::log.
Log() <<
"\nExecuting DFEM IP Diffusion solver";
179 const auto& grid = *grid_ptr_;
180 const auto& sdm = *sdm_ptr_;
190 for (
const auto& cell : grid.local_cells)
192 const auto& cell_mapping = sdm.GetCellMapping(cell);
193 const size_t num_nodes = cell_mapping.NumNodes();
194 const auto cc_nodes = cell_mapping.GetNodeLocations();
195 const auto qp_data = cell_mapping.MakeVolumetricQuadraturePointData();
197 const auto imat = cell.material_id_;
199 VecDbl cell_rhs(num_nodes, 0.0);
202 for (
size_t i=0; i<num_nodes; ++i)
204 const int64_t imap = sdm.MapDOF(cell, i);
206 for (
size_t j=0; j<num_nodes; ++j)
208 const int64_t jmap = sdm.MapDOF(cell, j);
209 double entry_aij = 0.0;
210 for (
size_t qp : qp_data.QuadraturePointIndices())
214 CallLua_iXYZFunction(L,
"D_coef",imat,qp_data.QPointXYZ(qp)) *
215 qp_data.ShapeGrad(i, qp).Dot(qp_data.ShapeGrad(j, qp))
217 CallLua_iXYZFunction(L,
"Sigma_a",imat,qp_data.QPointXYZ(qp)) *
218 qp_data.ShapeValue(i, qp) * qp_data.ShapeValue(j, qp)
223 MatSetValue(A_, imap, jmap, entry_aij, ADD_VALUES);
225 double entry_rhs_i = 0.0;
226 for (
size_t qp : qp_data.QuadraturePointIndices())
227 entry_rhs_i += CallLua_iXYZFunction(L,
"Q_ext",imat,qp_data.QPointXYZ(qp))
228 * qp_data.ShapeValue(i, qp) * qp_data.JxW(qp);
229 VecSetValue(b_, imap, entry_rhs_i, ADD_VALUES);
233 const size_t num_faces = cell.faces_.size();
234 for (
size_t f = 0; f < num_faces; ++f) {
235 const auto &face = cell.faces_[f];
236 const auto &n_f = face.normal_;
237 const size_t num_face_nodes = cell_mapping.NumFaceNodes(f);
238 const auto fqp_data = cell_mapping.MakeSurfaceQuadraturePointData(f);
240 const double hm = HPerpendicular(cell, f);
245 if (face.has_neighbor_)
247 const auto &adj_cell = grid.
cells[face.neighbor_id_];
248 const auto &adj_cell_mapping = sdm.GetCellMapping(adj_cell);
249 const auto ac_nodes = adj_cell_mapping.GetNodeLocations();
250 const size_t acf = Grid::MapCellFace(cell, adj_cell, f);
251 const double hp_neigh = HPerpendicular(adj_cell, acf);
253 const auto imat_neigh = adj_cell.material_id_;
265 for (
size_t fi = 0; fi < num_face_nodes; ++fi) {
266 const int i = cell_mapping.MapFaceNode(f, fi);
267 const int64_t imap = sdm.MapDOF(cell, i);
269 for (
size_t fj = 0; fj < num_face_nodes; ++fj) {
270 const int jm = cell_mapping.MapFaceNode(f, fj);
271 const int64_t jmmap = sdm.MapDOF(cell, jm);
273 const int jp = MapFaceNodeDisc(cell, adj_cell, cc_nodes, ac_nodes,
275 const int64_t jpmap = sdm.MapDOF(adj_cell, jp);
278 for (
size_t qp: fqp_data.QuadraturePointIndices())
280 (CallLua_iXYZFunction(L,
"D_coef", imat, fqp_data.QPointXYZ(qp)) / hm +
281 CallLua_iXYZFunction(L,
"D_coef", imat_neigh, fqp_data.QPointXYZ(qp)) / hp_neigh) / 2.
283 fqp_data.ShapeValue(i, qp) * fqp_data.ShapeValue(jm, qp) *
286 MatSetValue(A_, imap, jmmap, aij, ADD_VALUES);
287 MatSetValue(A_, imap, jpmap, -aij, ADD_VALUES);
299 for (
int i = 0; i < num_nodes; ++i) {
300 const int64_t imap = sdm.MapDOF(cell, i);
303 for (
int fj = 0; fj < num_face_nodes; ++fj) {
304 const int jm = cell_mapping.MapFaceNode(f, fj);
305 const int64_t jmmap = sdm.MapDOF(cell, jm);
306 const int jp = MapFaceNodeDisc(cell, adj_cell, cc_nodes, ac_nodes,
308 const int64_t jpmap = sdm.MapDOF(adj_cell, jp);
311 for (
size_t qp: fqp_data.QuadraturePointIndices())
313 CallLua_iXYZFunction(L,
"D_coef", imat, fqp_data.QPointXYZ(qp)) *
314 fqp_data.ShapeValue(jm, qp) * fqp_data.ShapeGrad(i, qp) *
316 const double aij = -0.5 * n_f.
Dot(vec_aij);
318 MatSetValue(A_, imap, jmmap, aij, ADD_VALUES);
319 MatSetValue(A_, imap, jpmap, -aij, ADD_VALUES);
325 for (
int fi = 0; fi < num_face_nodes; ++fi) {
326 const int im = cell_mapping.MapFaceNode(f, fi);
327 const int64_t immap = sdm.MapDOF(cell, im);
329 const int ip = MapFaceNodeDisc(cell, adj_cell, cc_nodes, ac_nodes,
331 const int64_t ipmap = sdm.MapDOF(adj_cell, ip);
333 for (
int j = 0; j < num_nodes; ++j) {
334 const int64_t jmap = sdm.MapDOF(cell, j);
337 for (
size_t qp: fqp_data.QuadraturePointIndices())
339 CallLua_iXYZFunction(L,
"D_coef", imat, fqp_data.QPointXYZ(qp)) *
340 fqp_data.ShapeValue(im, qp) * fqp_data.ShapeGrad(j, qp) *
342 const double aij = -0.5 * n_f.
Dot(vec_aij);
344 MatSetValue(A_, immap, jmap, aij, ADD_VALUES);
345 MatSetValue(A_, ipmap, jmap, -aij, ADD_VALUES);
352 const auto &bndry = boundaries_[face.neighbor_id_];
356 const auto qp_face_data =
357 cell_mapping.MakeSurfaceQuadraturePointData(f);
359 const auto &aval = bndry.values_[0];
360 const auto &bval = bndry.values_[1];
361 const auto &fval = bndry.values_[2];
369 if (std::fabs(bval) < 1e-8)
370 throw std::logic_error(
"if b=0, this is a Dirichlet BC, not a Robin BC");
372 for (
size_t fi = 0; fi < num_face_nodes; fi++) {
373 const uint i = cell_mapping.MapFaceNode(f, fi);
374 const int64_t ir = sdm.MapDOF(cell, i);
376 if (std::fabs(aval) >= 1.0e-12) {
377 for (
size_t fj = 0; fj < num_face_nodes; fj++) {
378 const uint j = cell_mapping.MapFaceNode(f, fj);
379 const int64_t jr = sdm.MapDOF(cell, j);
382 for (
size_t qp: fqp_data.QuadraturePointIndices())
383 aij += fqp_data.ShapeValue(i, qp) * fqp_data.ShapeValue(j, qp) *
385 aij *= (aval / bval);
387 MatSetValue(A_, ir, jr, aij, ADD_VALUES);
391 if (std::fabs(fval) >= 1.0e-12) {
392 double rhs_val = 0.0;
393 for (
size_t qp: fqp_data.QuadraturePointIndices())
394 rhs_val += fqp_data.ShapeValue(i, qp) * fqp_data.JxW(qp);
395 rhs_val *= (fval / bval);
397 VecSetValue(b_, ir, rhs_val, ADD_VALUES);
402 const double bc_value = bndry.values_[0];
413 for (
size_t fi = 0; fi < num_face_nodes; ++fi) {
414 const uint i = cell_mapping.MapFaceNode(f, fi);
415 const int64_t imap = sdm.MapDOF(cell, i);
417 for (
size_t fj = 0; fj < num_face_nodes; ++fj) {
418 const uint jm = cell_mapping.MapFaceNode(f, fj);
419 const int64_t jmmap = sdm.MapDOF(cell, jm);
422 for (
size_t qp: fqp_data.QuadraturePointIndices())
424 CallLua_iXYZFunction(L,
"D_coef", imat, fqp_data.QPointXYZ(qp)) / hm *
425 fqp_data.ShapeValue(i, qp) * fqp_data.ShapeValue(jm, qp) *
427 double aij_bc_value = aij * bc_value;
429 MatSetValue(A_, imap, jmmap, aij, ADD_VALUES);
430 VecSetValue(b_, imap, aij_bc_value, ADD_VALUES);
439 for (
size_t i = 0; i < num_nodes; i++) {
440 const int64_t imap = sdm.MapDOF(cell, i);
442 for (
size_t j = 0; j < num_nodes; j++) {
443 const int64_t jmap = sdm.MapDOF(cell, j);
446 for (
size_t qp: fqp_data.QuadraturePointIndices())
448 (fqp_data.ShapeValue(j, qp) * fqp_data.ShapeGrad(i, qp) +
449 fqp_data.ShapeValue(i, qp) * fqp_data.ShapeGrad(j, qp)) *
451 CallLua_iXYZFunction(L,
"D_coef", imat, fqp_data.QPointXYZ(qp));
453 const double aij = -n_f.Dot(vec_aij);
454 double aij_bc_value = aij * bc_value;
456 MatSetValue(A_, imap, jmap, aij, ADD_VALUES);
457 VecSetValue(b_, imap, aij_bc_value, ADD_VALUES);
470 MatAssemblyBegin(A_, MAT_FINAL_ASSEMBLY);
471 MatAssemblyEnd(A_, MAT_FINAL_ASSEMBLY);
472 VecAssemblyBegin(b_);
494 basic_options_(
"residual_tolerance").FloatValue(),
495 basic_options_(
"max_iters").IntegerValue()
499 KSPSolve(petsc_solver.ksp, b_, x_);
503 const auto& OneDofPerNode = sdm.UNITARY_UNKNOWN_MANAGER;
504 sdm.LocalizePETScVector(x_, field_, OneDofPerNode);
506 field_functions_.front()->UpdateFieldVector(field_);
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
LogStream Log(LOG_LVL level=LOG_0)
lua_State *& GetConsoleState()
std::string GetTimeString() const
static std::shared_ptr< PieceWiseLinearDiscontinuous > New(const chi_mesh::MeshContinuum &grid, QuadratureOrder q_order=QuadratureOrder::SECOND, CoordinateSystemType cs_type=CoordinateSystemType::CARTESIAN)
chi_mesh::MeshContinuumPtr & GetGrid() const
std::pair< BoundaryType, std::vector< double > > BoundaryInfo
Solver(const std::string &in_solver_name)
void Initialize() override
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()
Vector3 Dot(const chi_mesh::TensorRank2Dim3 &that) const