19 {
"residual_tolerance", 1.0e-2}})
33 const std::string fname =
"fv_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_;
185 for (
const auto& cell_P : grid.local_cells)
187 const auto& cell_mapping = sdm.GetCellMapping(cell_P);
188 const double volume_P = cell_mapping.CellVolume();
189 const auto& x_cc_P = cell_P.centroid_;
191 const auto imat = cell_P.material_id_;
193 const double sigma_a = CallLua_iXYZFunction(L,
"Sigma_a",imat,x_cc_P);
194 const double q_ext = CallLua_iXYZFunction(L,
"Q_ext" ,imat,x_cc_P);
195 const double D_P = CallLua_iXYZFunction(L,
"D_coef" ,imat,x_cc_P);
197 const int64_t imap = sdm.MapDOF(cell_P, 0);
198 MatSetValue(A_, imap, imap, sigma_a * volume_P, ADD_VALUES);
199 VecSetValue(b_, imap, q_ext * volume_P, ADD_VALUES);
201 for (
size_t f=0; f < cell_P.faces_.size(); ++f)
203 const auto& face = cell_P.faces_[f];
204 const auto& x_fc = face.centroid_;
205 const auto x_PF = x_fc - x_cc_P;
206 const auto A_f = cell_mapping.FaceArea(f);
207 const auto A_f_n = A_f * face.normal_;
209 if (face.has_neighbor_)
211 const auto& cell_N = grid.cells[face.neighbor_id_];
212 const int jmat = cell_N.material_id_;
213 const auto& x_cc_N = cell_N.centroid_;
214 const auto x_PN = x_cc_N - x_cc_P;
216 const double D_N = CallLua_iXYZFunction(L,
"D_coef",jmat,x_cc_N);
218 const double w = x_PF.Norm()/x_PN.Norm();
219 const double D_f = 1.0/(w/D_P + (1.0-w)/D_N);
221 const double entry_ii = A_f_n.Dot(D_f * x_PN/x_PN.NormSquare());
222 const double entry_ij = - entry_ii;
224 const int64_t jmap = sdm.MapDOF(cell_N, 0);
225 MatSetValue(A_, imap, imap, entry_ii, ADD_VALUES);
226 MatSetValue(A_, imap, jmap, entry_ij, ADD_VALUES);
230 const auto& bndry = boundaries_[face.neighbor_id_];
234 const auto& aval = bndry.values_[0];
235 const auto& bval = bndry.values_[1];
236 const auto& fval = bndry.values_[2];
238 if (std::fabs(bval) < 1e-8)
239 throw std::logic_error(
"if b=0, this is a Dirichlet BC, not a Robin BC");
241 if (std::fabs(aval) > 1.0e-8)
242 MatSetValue(A_, imap, imap, A_f * aval / bval, ADD_VALUES);
243 if (std::fabs(fval) > 1.0e-8)
244 VecSetValue(b_, imap, A_f * fval / bval, ADD_VALUES);
249 const auto& boundary_value = bndry.values_[0];
251 const auto& x_cc_N = x_cc_P + 2.0*x_PF;
252 const auto x_PN = x_cc_N - x_cc_P;
254 const double D_f = D_P;
255 const double entry_ii = A_f_n.Dot(D_f * x_PN/x_PN.NormSquare());
257 MatSetValue(A_, imap, imap, entry_ii, ADD_VALUES);
258 VecSetValue(b_, imap, entry_ii * boundary_value, ADD_VALUES);
266 MatAssemblyBegin(A_, MAT_FINAL_ASSEMBLY);
267 MatAssemblyEnd(A_, MAT_FINAL_ASSEMBLY);
268 VecAssemblyBegin(b_);
281 basic_options_(
"residual_tolerance").FloatValue(),
282 basic_options_(
"max_iters").IntegerValue()
286 KSPSolve(petsc_solver.ksp, b_, x_);
288 UpdateFieldFunctions();
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< FiniteVolume > New(const chi_mesh::MeshContinuum &in_grid, CoordinateSystemType in_cs_type=CoordinateSystemType::CARTESIAN)
chi_mesh::MeshContinuumPtr & GetGrid() const
Solver(const std::string &in_solver_name)
void Initialize() override
std::pair< fv_diffusion::BoundaryType, std::vector< double > > BoundaryInfo
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()