Chi-Tech
diffusion_mip_02a_assembleAand_b.cc
Go to the documentation of this file.
1#include "diffusion_mip.h"
2#include "acceleration.h"
3
5
8
10
11#include "chi_runtime.h"
12#include "chi_log.h"
13#include "utils/chi_timer.h"
14#include "console/chi_console.h"
15
16#define DefaultBCDirichlet BoundaryCondition{BCType::DIRICHLET,{0,0,0}}
17
18//###################################################################
19/**Assembles both the matrix and the RHS using quadrature points. These
20 * routines exist for implementing MMS.*/
22 AssembleAand_b_wQpoints(const std::vector<double>& q_vector)
23{
24 const std::string fname = "lbs::acceleration::DiffusionMIPSolver::"
25 "AssembleAand_b_wQpoints";
26 if (A_ == nullptr or rhs_ == nullptr or ksp_ == nullptr)
27 throw std::logic_error(fname + ": Some or all PETSc elements are null. "
28 "Check that Initialize has been called.");
29 if (options.verbose)
30 Chi::log.Log() << Chi::program_timer.GetTimeString() << " Starting assembly";
31
32 lua_State* L = Chi::console.GetConsoleState();
33 const auto& source_function = options.source_lua_function;
34 const auto& solution_function = options.ref_solution_lua_function;
35
36 const size_t num_groups = uk_man_.unknowns_.front().num_components_;
37
38 VecSet(rhs_, 0.0);
39
40 for (const auto& cell : grid_.local_cells)
41 {
42 const size_t num_faces = cell.faces_.size();
43 const auto& cell_mapping = sdm_.GetCellMapping(cell);
44 const size_t num_nodes = cell_mapping.NumNodes();
45 const auto cc_nodes = cell_mapping.GetNodeLocations();
46 const auto qp_data = cell_mapping.MakeVolumetricQuadraturePointData();
47
48 const auto& xs = mat_id_2_xs_map_.at(cell.material_id_);
49
50 //=========================================== For component/group
51 for (size_t g=0; g<num_groups; ++g)
52 {
53 //==================================== Get coefficient and nodal src
54 const double Dg = xs.Dg[g];
55 const double sigr_g = xs.sigR[g];
56
57 std::vector<double> qg(num_nodes, 0.0);
58 for (size_t j=0; j<num_nodes; j++)
59 qg[j] = q_vector[sdm_.MapDOFLocal(cell, j, uk_man_, 0, g)];
60
61 //==================================== Assemble continuous terms
62 for (size_t i=0; i<num_nodes; i++)
63 {
64 const int64_t imap = sdm_.MapDOF(cell, i, uk_man_, 0, g);
65 double entry_rhs_i = 0.0; //entry may accumulate over j
66 for (size_t j=0; j<num_nodes; j++)
67 {
68 const int64_t jmap = sdm_.MapDOF(cell, j, uk_man_, 0, g);
69 double entry_aij = 0.0;
70 for (size_t qp : qp_data.QuadraturePointIndices())
71 {
72 entry_aij += Dg *
73 qp_data.ShapeGrad(i, qp).Dot(qp_data.ShapeGrad(j, qp)) *
74 qp_data.JxW(qp);
75
76 entry_aij += sigr_g *
77 qp_data.ShapeValue(i, qp) * qp_data.ShapeValue(j, qp) *
78 qp_data.JxW(qp);
79
80 if (source_function.empty())
81 entry_rhs_i +=
82 qg[j] *
83 qp_data.ShapeValue(i, qp) * qp_data.ShapeValue(j, qp) *
84 qp_data.JxW(qp);
85 }//for qp
86 MatSetValue(A_, imap, jmap, entry_aij, ADD_VALUES);
87 }//for j
88
89 if (not source_function.empty())
90 {
91 for (size_t qp : qp_data.QuadraturePointIndices())
92 entry_rhs_i +=
93 CallLuaXYZFunction(L, source_function, qp_data.QPointXYZ(qp)) *
94 qp_data.ShapeValue(i, qp) *
95 qp_data.JxW(qp);
96 }
97
98 VecSetValue(rhs_, imap, entry_rhs_i, ADD_VALUES);
99 }//for i
100
101 //==================================== Assemble face terms
102 for (size_t f=0; f<num_faces; ++f)
103 {
104 const auto& face = cell.faces_[f];
105 const auto& n_f = face.normal_;
106 const size_t num_face_nodes = cell_mapping.NumFaceNodes(f);
107 const auto fqp_data = cell_mapping.MakeSurfaceQuadraturePointData(f);
108
109 const double hm = HPerpendicular(cell, f);
110
111 typedef chi_mesh::MeshContinuum Grid;
112
113 if (face.has_neighbor_)
114 {
115 const auto& adj_cell = grid_.cells[face.neighbor_id_];
116 const auto& adj_cell_mapping = sdm_.GetCellMapping(adj_cell);
117 const auto ac_nodes = adj_cell_mapping.GetNodeLocations();
118 const size_t acf = Grid::MapCellFace(cell, adj_cell, f);
119 const double hp = HPerpendicular(adj_cell, acf);
120
121 const auto& adj_xs = mat_id_2_xs_map_.at(adj_cell.material_id_);
122 const double adj_Dg = adj_xs.Dg[g];
123
124 //========================= Compute kappa
125 double kappa = 1.0;
126 if (cell.Type() == chi_mesh::CellType::SLAB)
127 kappa = fmax(options.penalty_factor*(adj_Dg/hp + Dg/hm)*0.5,0.25);
128 if (cell.Type() == chi_mesh::CellType::POLYGON)
129 kappa = fmax(options.penalty_factor*(adj_Dg/hp + Dg/hm)*0.5,0.25);
130 if (cell.Type() == chi_mesh::CellType::POLYHEDRON)
131 kappa = fmax(options.penalty_factor*2.0*(adj_Dg/hp + Dg/hm)*0.5,0.25);
132
133 //========================= Assembly penalty terms
134 for (size_t fi=0; fi<num_face_nodes; ++fi)
135 {
136 const int i = cell_mapping.MapFaceNode(f,fi);
137 const int64_t imap = sdm_.MapDOF(cell, i, uk_man_, 0, g);
138
139 for (size_t fj=0; fj<num_face_nodes; ++fj)
140 {
141 const int jm = cell_mapping.MapFaceNode(f,fj); //j-minus
142 const int jp = MapFaceNodeDisc(cell, adj_cell, cc_nodes, ac_nodes,
143 f, acf, fj); //j-plus
144 const int64_t jmmap = sdm_.MapDOF(cell, jm, uk_man_, 0, g);
145 const int64_t jpmap = sdm_.MapDOF(adj_cell, jp, uk_man_, 0, g);
146
147 double aij = 0.0;
148 for (size_t qp : fqp_data.QuadraturePointIndices())
149 aij += kappa *
150 fqp_data.ShapeValue(i,qp) * fqp_data.ShapeValue(jm,qp) *
151 fqp_data.JxW(qp);
152
153 MatSetValue(A_, imap, jmmap, aij, ADD_VALUES);
154 MatSetValue(A_, imap, jpmap, -aij, ADD_VALUES);
155 }//for fj
156 }//for fi
157
158 //========================= Assemble gradient terms
159 // For the following comments we use the notation:
160 // Dk = 0.5* n dot nabla bk
161
162 // 0.5*D* n dot (b_j^+ - b_j^-)*nabla b_i^-
163 for (int i=0; i<num_nodes; i++)
164 {
165 const int64_t imap = sdm_.MapDOF(cell, i, uk_man_, 0, g);
166
167 for (int fj=0; fj<num_face_nodes; fj++)
168 {
169 const int jm = cell_mapping.MapFaceNode(f,fj); //j-minus
170 const int jp = MapFaceNodeDisc(cell, adj_cell, cc_nodes, ac_nodes,
171 f, acf, fj); //j-plus
172 const int64_t jmmap = sdm_.MapDOF(cell, jm, uk_man_, 0, g);
173 const int64_t jpmap = sdm_.MapDOF(adj_cell, jp, uk_man_, 0, g);
174
175 chi_mesh::Vector3 vec_aij;
176 for (size_t qp : fqp_data.QuadraturePointIndices())
177 vec_aij +=
178 fqp_data.ShapeValue(jm, qp) * fqp_data.ShapeGrad(i, qp) *
179 fqp_data.JxW(qp);
180 const double aij = -0.5*Dg*n_f.Dot(vec_aij);
181
182 MatSetValue(A_, imap, jmmap, aij, ADD_VALUES);
183 MatSetValue(A_, imap, jpmap, -aij, ADD_VALUES);
184 }//for fj
185 }//for i
186
187 // 0.5*D* n dot (b_i^+ - b_i^-)*nabla b_j^-
188 for (int fi=0; fi<num_face_nodes; fi++)
189 {
190 const int im = cell_mapping.MapFaceNode(f,fi); //i-minus
191 const int ip = MapFaceNodeDisc(cell,adj_cell,cc_nodes,ac_nodes,
192 f,acf,fi); //i-plus
193 const int64_t immap = sdm_.MapDOF(cell, im, uk_man_, 0, g);
194 const int64_t ipmap = sdm_.MapDOF(adj_cell, ip, uk_man_, 0, g);
195
196 for (int j=0; j<num_nodes; j++)
197 {
198 const int64_t jmap = sdm_.MapDOF(cell, j, uk_man_, 0, g);
199
200 chi_mesh::Vector3 vec_aij;
201 for (size_t qp : fqp_data.QuadraturePointIndices())
202 vec_aij +=
203 fqp_data.ShapeValue(im, qp) * fqp_data.ShapeGrad(j, qp) *
204 fqp_data.JxW(qp);
205 const double aij = -0.5*Dg*n_f.Dot(vec_aij);
206
207 MatSetValue(A_, immap, jmap, aij, ADD_VALUES);
208 MatSetValue(A_, ipmap, jmap, -aij, ADD_VALUES);
209 }//for j
210 }//for fi
211
212 }//internal face
213 else
214 {
215 auto bc = DefaultBCDirichlet;
216 if (bcs_.count(face.neighbor_id_) > 0)
217 bc = bcs_.at(face.neighbor_id_);
218
219 if (bc.type == BCType::DIRICHLET)
220 {
221 const double bc_value = bc.values[0];
222
223 //========================= Compute kappa
224 double kappa = 1.0;
225 if (cell.Type() == chi_mesh::CellType::SLAB)
226 kappa = fmax(options.penalty_factor*Dg/hm,0.25);
227 if (cell.Type() == chi_mesh::CellType::POLYGON)
228 kappa = fmax(options.penalty_factor*Dg/hm,0.25);
229 if (cell.Type() == chi_mesh::CellType::POLYHEDRON)
230 kappa = fmax(options.penalty_factor*2.0*Dg/hm,0.25);
231
232 //========================= Assembly penalty terms
233 for (size_t fi=0; fi<num_face_nodes; ++fi)
234 {
235 const int i = cell_mapping.MapFaceNode(f,fi);
236 const int64_t imap = sdm_.MapDOF(cell, i, uk_man_, 0, g);
237
238 for (size_t fj=0; fj<num_face_nodes; ++fj)
239 {
240 const int jm = cell_mapping.MapFaceNode(f,fj);
241 const int64_t jmmap = sdm_.MapDOF(cell, jm, uk_man_, 0, g);
242
243 double aij = 0.0;
244 for (size_t qp : fqp_data.QuadraturePointIndices())
245 aij += kappa *
246 fqp_data.ShapeValue(i, qp) * fqp_data.ShapeValue(jm, qp) *
247 fqp_data.JxW(qp);
248 double aij_bc_value = aij*bc_value;
249
250 if (not solution_function.empty())
251 {
252 aij_bc_value = 0.0;
253 for (size_t qp : fqp_data.QuadraturePointIndices())
254 aij_bc_value +=
255 kappa *CallLuaXYZFunction(L, solution_function,
256 fqp_data.QPointXYZ(qp)) *
257 fqp_data.ShapeValue(i, qp) * fqp_data.ShapeValue(jm, qp) *
258 fqp_data.JxW(qp);
259 }
260
261 MatSetValue(A_ , imap, jmmap, aij, ADD_VALUES);
262 VecSetValue(rhs_, imap, aij_bc_value, ADD_VALUES);
263 }//for fj
264 }//for fi
265
266 //========================= Assemble gradient terms
267 // For the following comments we use the notation:
268 // Dk = n dot nabla bk
269
270 // D* n dot (b_j^+ - b_j^-)*nabla b_i^-
271 for (size_t i=0; i<num_nodes; i++)
272 {
273 const int64_t imap = sdm_.MapDOF(cell, i, uk_man_, 0, g);
274
275 for (size_t j=0; j<num_nodes; j++)
276 {
277 const int64_t jmap = sdm_.MapDOF(cell, j, uk_man_, 0, g);
278
279 chi_mesh::Vector3 vec_aij;
280 for (size_t qp : fqp_data.QuadraturePointIndices())
281 vec_aij +=
282 fqp_data.ShapeValue(j, qp) * fqp_data.ShapeGrad(i, qp) *
283 fqp_data.JxW(qp) +
284 fqp_data.ShapeValue(i, qp) * fqp_data.ShapeGrad(j, qp) *
285 fqp_data.JxW(qp);
286 const double aij = -Dg*n_f.Dot(vec_aij);
287
288 double aij_bc_value = aij*bc_value;
289
290 if (not solution_function.empty())
291 {
292 chi_mesh::Vector3 vec_aij_mms;
293 for (size_t qp : fqp_data.QuadraturePointIndices())
294 vec_aij_mms +=
295 CallLuaXYZFunction(L, solution_function,
296 fqp_data.QPointXYZ(qp)) *
297 (fqp_data.ShapeValue(j, qp) * fqp_data.ShapeGrad(i, qp) *
298 fqp_data.JxW(qp) +
299 fqp_data.ShapeValue(i, qp) * fqp_data.ShapeGrad(j, qp) *
300 fqp_data.JxW(qp));
301 aij_bc_value = -Dg*n_f.Dot(vec_aij_mms);
302 }
303
304 MatSetValue(A_, imap, jmap, aij, ADD_VALUES);
305 VecSetValue(rhs_, imap, aij_bc_value, ADD_VALUES);
306 }//for fj
307 }//for i
308 }//Dirichlet BC
309 else if (bc.type == BCType::ROBIN)
310 {
311 const double aval = bc.values[0];
312 const double bval = bc.values[1];
313 const double fval = bc.values[2];
314
315 if (std::fabs(bval) < 1.0e-12) continue; //a and f assumed zero
316
317 for (size_t fi=0; fi<num_face_nodes; fi++)
318 {
319 const int i = cell_mapping.MapFaceNode(f,fi);
320 const int64_t ir = sdm_.MapDOF(cell, i, uk_man_, 0, g);
321
322 if (std::fabs(aval) >= 1.0e-12)
323 {
324 for (size_t fj=0; fj<num_face_nodes; fj++)
325 {
326 const int j = cell_mapping.MapFaceNode(f,fj);
327 const int64_t jr = sdm_.MapDOF(cell, j, uk_man_, 0, g);
328
329 double aij = 0.0;
330 for (size_t qp : fqp_data.QuadraturePointIndices())
331 aij += fqp_data.ShapeValue(i,qp) * fqp_data.ShapeValue(j,qp) *
332 fqp_data.JxW(qp);
333 aij *= (aval/bval);
334
335 MatSetValue(A_, ir , jr, aij, ADD_VALUES);
336 }//for fj
337 }//if a nonzero
338
339 if (std::fabs(fval) >= 1.0e-12)
340 {
341 double rhs_val = 0.0;
342 for (size_t qp : fqp_data.QuadraturePointIndices())
343 rhs_val += fqp_data.ShapeValue(i,qp) * fqp_data.JxW(qp);
344 rhs_val *= (fval/bval);
345
346 VecSetValue(rhs_, ir, rhs_val, ADD_VALUES);
347 }//if f nonzero
348 }//for fi
349 }//Robin BC
350 }//boundary face
351 }//for face
352 }//for g
353 }//for cell
354
355
356 MatAssemblyBegin(A_, MAT_FINAL_ASSEMBLY);
357 MatAssemblyEnd(A_, MAT_FINAL_ASSEMBLY);
358 VecAssemblyBegin(rhs_);
359 VecAssemblyEnd(rhs_);
360
362 {
363 PetscBool symmetry = PETSC_FALSE;
364 MatIsSymmetric(A_, 1.0e-6, &symmetry);
365 if (symmetry == PETSC_FALSE)
366 throw std::logic_error(fname + ":Symmetry check failed");
367 }
368
369 KSPSetOperators(ksp_, A_, A_);
370
371 if (options.verbose)
372 Chi::log.Log() << Chi::program_timer.GetTimeString() << " Assembly completed";
373
374 PC pc;
375 KSPGetPC(ksp_, &pc);
376 PCSetUp(pc);
377
378 KSPSetUp(ksp_);
379}
static chi::Timer program_timer
Definition: chi_runtime.h:79
static chi::ChiLog & log
Definition: chi_runtime.h:81
static chi::Console & console
Definition: chi_runtime.h:80
LogStream Log(LOG_LVL level=LOG_0)
Definition: chi_log.cc:35
lua_State *& GetConsoleState()
Definition: chi_console.h:130
std::string GetTimeString() const
Definition: chi_timer.cc:38
size_t NumNodes() const
Definition: CellMapping.cc:34
const std::vector< chi_mesh::Vector3 > & GetNodeLocations() const
Definition: CellMapping.cc:156
const CellMapping & GetCellMapping(const chi_mesh::Cell &cell) const
virtual int64_t MapDOF(const chi_mesh::Cell &cell, unsigned int node, const UnknownManager &unknown_manager, unsigned int unknown_id, unsigned int component) const =0
virtual int64_t MapDOFLocal(const chi_mesh::Cell &cell, unsigned int node, const UnknownManager &unknown_manager, unsigned int unknown_id, unsigned int component) const =0
std::vector< Unknown > unknowns_
LocalCellHandler local_cells
GlobalCellHandler cells
void AssembleAand_b_wQpoints(const std::vector< double > &q_vector)
int MapFaceNodeDisc(const chi_mesh::Cell &cur_cell, const chi_mesh::Cell &adj_cell, const std::vector< chi_mesh::Vector3 > &cc_node_locs, const std::vector< chi_mesh::Vector3 > &ac_node_locs, size_t ccf, size_t acf, size_t ccfi, double epsilon=1.0e-12)
double HPerpendicular(const chi_mesh::Cell &cell, unsigned int f)
static double CallLuaXYZFunction(lua_State *L, const std::string &lua_func_name, const chi_mesh::Vector3 &xyz)
struct lbs::acceleration::DiffusionSolver::Options options
const chi_math::SpatialDiscretization & sdm_
Definition: diffusion.h:39
const chi_math::UnknownManager uk_man_
Definition: diffusion.h:40
const chi_mesh::MeshContinuum & grid_
Definition: diffusion.h:38
const std::map< uint64_t, BoundaryCondition > bcs_
Definition: diffusion.h:42
const MatID2XSMap mat_id_2_xs_map_
Definition: diffusion.h:44
#define DefaultBCDirichlet
Vector3 Dot(const chi_mesh::TensorRank2Dim3 &that) const
std::string ref_solution_lua_function
for mms
Definition: diffusion.h:66
bool perform_symmetry_check
For debugging only (very expensive)
Definition: diffusion.h:63