11 #include "Conversion.h"
13 #include "libmesh/string_to_enum.h"
14 #include "libmesh/mesh_tools.h"
15 #include "libmesh/parallel_sync.h"
21 InputParameters params = validParams<ElementUserObject>();
22 params.addClassDescription(
23 "Base class to compute K_ij (a measure of advective flux from node i to node j) "
24 "and R+ and R- (which quantify amount of antidiffusion to add) in the "
25 "Kuzmin-Turek FEM-TVD multidimensional scheme");
26 MooseEnum flux_limiter_type(
"MinMod VanLeer MC superbee None",
"VanLeer");
27 params.addParam<MooseEnum>(
"flux_limiter_type",
29 "Type of flux limiter to use. 'None' means that no antidiffusion "
30 "will be added in the Kuzmin-Turek scheme");
31 params.addRangeCheckedParam<Real>(
32 "allowable_MB_wastage",
34 "allowable_MB_wastage > 0.0",
35 "This object will issue a memory warning if the internal node-numbering data structure "
36 "wastes more than allowable_MB_wastage megabytes. This data structure uses sequential "
37 "node-numbering which is optimized for speed rather than memory efficiency");
39 params.addRelationshipManager(
"ElementPointNeighborLayers",
40 Moose::RelationshipManagerType::GEOMETRIC |
41 Moose::RelationshipManagerType::ALGEBRAIC |
42 Moose::RelationshipManagerType::COUPLING,
43 [](
const InputParameters &, InputParameters & rm_params) {
44 rm_params.set<
unsigned short>(
"layers") = 2;
47 params.set<ExecFlagEnum>(
"execute_on",
true) = {EXEC_LINEAR};
52 : ElementUserObject(parameters),
53 _resizing_needed(true),
54 _flux_limiter_type(getParam<MooseEnum>(
"flux_limiter_type").getEnum<
FluxLimiterTypeEnum>()),
61 _u_nodal_computed_by_thread(),
64 _my_pid(processor_id()),
69 _allowable_MB_wastage(getParam<Real>(
"allowable_MB_wastage"))
71 if (!_execute_enum.contains(EXEC_LINEAR))
74 "The AdvectiveFluxCalculator UserObject " +
name() +
75 " execute_on parameter must include, at least, 'linear'. This is to ensure that "
76 "this UserObject computes all necessary quantities just before the Kernels evaluate "
97 for (
const auto & elem : _fe_problem.getEvaluableElementRange())
98 if (this->hasBlocks(elem->subdomain_id()))
99 for (
unsigned i = 0; i < elem->n_nodes(); ++i)
102 for (
const auto & elem : _fe_problem.getEvaluableElementRange())
103 if (this->hasBlocks(elem->subdomain_id()))
104 for (
unsigned i = 0; i < elem->n_nodes(); ++i)
105 for (
unsigned j = 0; j < elem->n_nodes(); ++j)
112 gatherMax(mb_wasted);
115 "In at least one processor, the sequential node-numbering internal data structure used "
117 name() +
" is using memory inefficiently.\nThe memory wasted is " +
118 Moose::stringify(mb_wasted) +
119 " megabytes.\n The node-numbering data structure has been optimized for speed at the "
120 "expense of memory, but that may not be an appropriate optimization for your case, "
121 "because the node numbering is not close to sequential in your case.\n");
125 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
126 _kij[sequential_i].assign(
141 for (
const auto & elem : _fe_problem.getEvaluableElementRange())
142 if (this->hasBlocks(elem->subdomain_id()))
143 for (
unsigned i = 0; i < elem->n_nodes(); ++i)
145 const dof_id_type node_i = elem->node_id(i);
154 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
157 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
159 const std::vector<dof_id_type> con_i =
161 const std::size_t num_con_i = con_i.size();
163 for (std::size_t j = 0; j < con_i.size(); ++j)
165 const dof_id_type sequential_j = con_i[j];
166 const std::size_t num_con_j =
172 if (_app.n_processors() > 1)
200 ElementUserObject::meshChanged();
212 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
222 for (
unsigned i = 0; i < _current_elem->n_nodes(); ++i)
224 const dof_id_type node_i = _current_elem->node_id(i);
231 for (
unsigned j = 0; j < _current_elem->n_nodes(); ++j)
233 const dof_id_type node_j = _current_elem->node_id(j);
234 for (
unsigned qp = 0; qp < _qrule->n_points(); ++qp)
242 dof_id_type global_i, dof_id_type global_j,
unsigned local_i,
unsigned local_j,
unsigned qp)
247 _kij[sequential_i][index_i_to_j] += _JxW[qp] * _coord[qp] *
computeVelocity(local_i, local_j, qp);
255 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
257 const std::size_t num_con_i =
259 for (std::size_t j = 0; j < num_con_i; ++j)
260 _kij[sequential_i][j] += afc.
_kij[sequential_i][j];
264 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
276 if (_app.n_processors() > 1)
284 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
286 const std::vector<dof_id_type> & con_i =
288 const std::size_t num_con_i = con_i.size();
289 _dij[sequential_i].assign(num_con_i, 0.0);
290 _dDij_dKij[sequential_i].assign(num_con_i, 0.0);
291 _dDij_dKji[sequential_i].assign(num_con_i, 0.0);
292 _dDii_dKij[sequential_i].assign(num_con_i, 0.0);
293 _dDii_dKji[sequential_i].assign(num_con_i, 0.0);
294 const unsigned index_i_to_i =
296 for (std::size_t j = 0; j < num_con_i; ++j)
298 const dof_id_type sequential_j = con_i[j];
299 if (sequential_i == sequential_j)
301 const unsigned index_j_to_i =
303 const Real kij =
_kij[sequential_i][j];
304 const Real kji =
_kij[sequential_j][index_j_to_i];
305 if ((kij <= kji) && (kij < 0.0))
307 _dij[sequential_i][j] = -kij;
311 else if ((kji <= kij) && (kji < 0.0))
313 _dij[sequential_i][j] = -kji;
318 _dij[sequential_i][j] = 0.0;
319 _dij[sequential_i][index_i_to_i] -=
_dij[sequential_i][j];
325 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
327 const std::vector<dof_id_type> & con_i =
329 const std::size_t num_con_i = con_i.size();
330 _lij[sequential_i].assign(num_con_i, 0.0);
331 for (std::size_t j = 0; j < num_con_i; ++j)
332 _lij[sequential_i][j] =
_kij[sequential_i][j] +
_dij[sequential_i][j];
337 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
346 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
348 const std::vector<dof_id_type> & con_i =
350 const unsigned num_con_i = con_i.size();
351 _fa[sequential_i].assign(num_con_i, 0.0);
352 _dfa[sequential_i].resize(num_con_i);
355 for (std::size_t j = 0; j < num_con_i; ++j)
357 for (
const auto & global_k : con_i)
358 _dfa[sequential_i][j][global_k] = 0;
359 const dof_id_type global_j = con_i[j];
361 const unsigned num_con_j = con_j.size();
362 for (
const auto & global_k : con_j)
363 _dfa[sequential_i][j][global_k] = 0;
364 _dFij_dKik[sequential_i][j].assign(num_con_i, 0.0);
365 _dFij_dKjk[sequential_i][j].assign(num_con_j, 0.0);
369 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
372 const Real u_i =
_u_nodal[sequential_i];
373 const std::vector<dof_id_type> & con_i =
375 const std::size_t num_con_i = con_i.size();
376 for (std::size_t j = 0; j < num_con_i; ++j)
378 const dof_id_type sequential_j = con_i[j];
379 if (sequential_i == sequential_j)
381 const unsigned index_j_to_i =
383 const Real Lij =
_lij[sequential_i][j];
384 const Real Lji =
_lij[sequential_j][index_j_to_i];
387 const Real Dij =
_dij[sequential_i][j];
389 const Real u_j =
_u_nodal[sequential_j];
390 Real prefactor = 0.0;
391 std::vector<Real> dprefactor_du(num_con_i,
393 std::vector<Real> dprefactor_dKij(
395 Real dprefactor_dKji = 0;
398 if (Lji <=
_rP[sequential_i] * Dij)
401 dprefactor_dKij[j] +=
_dDij_dKji[sequential_j][index_j_to_i];
402 dprefactor_dKji += 1.0 +
_dDij_dKij[sequential_j][index_j_to_i];
406 prefactor =
_rP[sequential_i] * Dij;
407 for (std::size_t ind_j = 0; ind_j < num_con_i; ++ind_j)
408 dprefactor_du[ind_j] =
_drP[sequential_i][ind_j] * Dij;
409 dprefactor_dKij[j] +=
_rP[sequential_i] *
_dDij_dKij[sequential_i][j];
410 dprefactor_dKji +=
_rP[sequential_i] *
_dDij_dKji[sequential_i][j];
411 for (std::size_t ind_j = 0; ind_j < num_con_i; ++ind_j)
412 dprefactor_dKij[ind_j] +=
_drP_dk[sequential_i][ind_j] * Dij;
417 if (Lji <=
_rM[sequential_i] * Dij)
420 dprefactor_dKij[j] +=
_dDij_dKji[sequential_j][index_j_to_i];
421 dprefactor_dKji += 1.0 +
_dDij_dKij[sequential_j][index_j_to_i];
425 prefactor =
_rM[sequential_i] * Dij;
426 for (std::size_t ind_j = 0; ind_j < num_con_i; ++ind_j)
427 dprefactor_du[ind_j] =
_drM[sequential_i][ind_j] * Dij;
428 dprefactor_dKij[j] +=
_rM[sequential_i] *
_dDij_dKij[sequential_i][j];
429 dprefactor_dKji +=
_rM[sequential_i] *
_dDij_dKji[sequential_i][j];
430 for (std::size_t ind_j = 0; ind_j < num_con_i; ++ind_j)
431 dprefactor_dKij[ind_j] +=
_drM_dk[sequential_i][ind_j] * Dij;
434 _fa[sequential_i][j] = prefactor * (u_i - u_j);
435 _dfa[sequential_i][j][global_i] = prefactor;
436 _dfa[sequential_i][j][global_j] = -prefactor;
437 for (std::size_t ind_j = 0; ind_j < num_con_i; ++ind_j)
440 dprefactor_du[ind_j] * (u_i - u_j);
441 _dFij_dKik[sequential_i][j][ind_j] += dprefactor_dKij[ind_j] * (u_i - u_j);
443 _dFij_dKjk[sequential_i][j][index_j_to_i] += dprefactor_dKji * (u_i - u_j);
448 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
450 const std::vector<dof_id_type> & con_i =
452 const std::size_t num_con_i = con_i.size();
453 for (std::size_t j = 0; j < num_con_i; ++j)
455 const dof_id_type sequential_j = con_i[j];
456 if (sequential_i == sequential_j)
458 const unsigned index_j_to_i =
460 if (
_lij[sequential_j][index_j_to_i] <
_lij[sequential_i][j])
462 _fa[sequential_i][j] = -
_fa[sequential_j][index_j_to_i];
463 for (
const auto & dof_deriv :
_dfa[sequential_j][index_j_to_i])
464 _dfa[sequential_i][j][dof_deriv.first] = -dof_deriv.second;
465 for (std::size_t k = 0; k < num_con_i; ++k)
467 const std::size_t num_con_j =
469 for (std::size_t k = 0; k < num_con_j; ++k)
482 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
490 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
492 const std::vector<dof_id_type> & con_i =
494 const std::size_t num_con_i = con_i.size();
496 for (std::size_t j = 0; j < num_con_i; ++j)
498 const dof_id_type sequential_j = con_i[j];
499 const std::vector<dof_id_type> & con_j =
507 for (dof_id_type sequential_i = 0; sequential_i <
_number_of_nodes; ++sequential_i)
509 const std::vector<dof_id_type> & con_i =
511 const size_t num_con_i = con_i.size();
512 const dof_id_type index_i_to_i =
514 for (std::size_t j = 0; j < num_con_i; ++j)
516 const dof_id_type sequential_j = con_i[j];
518 const Real u_j =
_u_nodal[sequential_j];
521 _flux_out[sequential_i] -=
_lij[sequential_i][j] * u_j +
_fa[sequential_i][j];
524 for (
const auto & dof_deriv :
_dfa[sequential_i][j])
525 _dflux_out_du[sequential_i][dof_deriv.first] -= dof_deriv.second;
529 if (sequential_j == sequential_i)
530 for (dof_id_type k = 0; k < num_con_i; ++k)
534 for (dof_id_type k = 0; k < num_con_i; ++k)
537 if (sequential_j == sequential_i)
538 for (
unsigned k = 0; k < con_i.size(); ++k)
540 const unsigned index_k_to_i =
546 const unsigned index_j_to_i =
560 std::vector<Real> & dlimited_du,
561 std::vector<Real> & dlimited_dk)
const
564 dlimited_du.assign(num_con, 0.0);
565 dlimited_dk.assign(num_con, 0.0);
568 std::vector<Real> dp_du;
569 std::vector<Real> dp_dk;
574 std::vector<Real> dq_du;
575 std::vector<Real> dq_dk;
578 const Real r = q / p;
584 for (std::size_t j = 0; j < num_con; ++j)
586 const Real dr_du = dq_du[j] / p - q * dp_du[j] / p2;
587 const Real dr_dk = dq_dk[j] / p - q * dp_dk[j] / p2;
588 dlimited_du[j] = dlimited_dr * dr_du;
589 dlimited_dk[j] = dlimited_dr * dr_dk;
596 std::vector<Real> & dlimited_du,
597 std::vector<Real> & dlimited_dk)
const
600 dlimited_du.assign(num_con, 0.0);
601 dlimited_dk.assign(num_con, 0.0);
604 std::vector<Real> dp_du;
605 std::vector<Real> dp_dk;
610 std::vector<Real> dq_du;
611 std::vector<Real> dq_dk;
614 const Real r = q / p;
620 for (std::size_t j = 0; j < num_con; ++j)
622 const Real dr_du = dq_du[j] / p - q * dp_du[j] / p2;
623 const Real dr_dk = dq_dk[j] / p - q * dp_dk[j] / p2;
624 dlimited_du[j] = dlimited_dr * dr_du;
625 dlimited_dk[j] = dlimited_dr * dr_dk;
638 if ((a >= 0.0 && b <= 0.0) || (a <= 0.0 && b >= 0.0))
640 const Real s = (a > 0.0 ? 1.0 : -1.0);
642 const Real lal = std::abs(a);
643 const Real lbl = std::abs(b);
644 const Real dlbl = (b >= 0.0 ? 1.0 : -1.0);
657 dlimited_db = s * dlbl;
663 limited = s * 2 * lal * lbl / (lal + lbl);
664 dlimited_db = s * 2 * lal * (dlbl / (lal + lbl) - lbl * dlbl /
std::pow(lal + lbl, 2));
669 const Real av = 0.5 * std::abs(a + b);
670 if (2 * lal <= av && lal <= lbl)
673 limited = s * 2.0 * lal;
676 else if (2 * lbl <= av && lbl <= lal)
679 limited = s * 2.0 * lbl;
680 dlimited_db = s * 2.0 * dlbl;
689 dlimited_db = s * 0.5 * dlbl;
695 const Real term1 = std::min(2.0 * lal, lbl);
696 const Real term2 = std::min(lal, 2.0 * lbl);
699 if (2.0 * lal <= lbl)
701 limited = s * 2 * lal;
707 dlimited_db = s * dlbl;
712 if (lal <= 2.0 * lbl)
719 limited = s * 2.0 * lbl;
720 dlimited_db = s * 2.0 * dlbl;
730 const std::map<dof_id_type, Real> &
736 const std::vector<std::vector<Real>> &
756 dof_id_type node_i)
const
760 the_map[node_j] = 0.0;
766 std::vector<Real> & derivs,
767 std::vector<Real> & dpqdk)
const
770 const Real u_i =
_u_nodal[sequential_i];
773 const std::vector<dof_id_type> con_i =
775 const std::size_t num_con = con_i.size();
781 derivs.assign(num_con, 0.0);
782 dpqdk.assign(num_con, 0.0);
785 for (std::size_t j = 0; j < num_con; ++j)
787 const dof_id_type sequential_j = con_i[j];
788 if (sequential_j == sequential_i)
790 const Real kentry =
_kij[sequential_i][j];
793 const Real u_j =
_u_nodal[sequential_j];
794 const Real ujminusi = u_j - u_i;
797 switch (pq_plus_minus)
801 if (ujminusi < 0.0 && kentry < 0.0)
803 result += kentry * ujminusi;
805 derivs[i_index_i] -= kentry;
806 dpqdk[j] += ujminusi;
812 if (ujminusi > 0.0 && kentry < 0.0)
814 result += kentry * ujminusi;
816 derivs[i_index_i] -= kentry;
817 dpqdk[j] += ujminusi;
823 if (ujminusi > 0.0 && kentry > 0.0)
825 result += kentry * ujminusi;
827 derivs[i_index_i] -= kentry;
828 dpqdk[j] += ujminusi;
834 if (ujminusi < 0.0 && kentry > 0.0)
836 result += kentry * ujminusi;
838 derivs[i_index_i] -= kentry;
839 dpqdk[j] += ujminusi;
866 for (
const auto & elem : _fe_problem.getEvaluableElementRange())
867 if (this->hasBlocks(elem->subdomain_id()))
869 const processor_id_type elem_pid = elem->processor_id();
874 for (
unsigned i = 0; i < elem->n_nodes(); ++i)
884 auto nodes_action_functor = [
this](processor_id_type pid,
const std::vector<dof_id_type> & nts) {
887 Parallel::push_parallel_vector_data(this->comm(),
_nodes_to_receive, nodes_action_functor);
896 const processor_id_type pid = kv.first;
897 const std::size_t num_nodes = kv.second.size();
898 for (
unsigned i = 0; i < num_nodes; ++i)
903 const processor_id_type pid = kv.first;
904 const std::size_t num_nodes = kv.second.size();
905 for (
unsigned i = 0; i < num_nodes; ++i)
911 for (
const auto & elem : _fe_problem.getEvaluableElementRange())
912 if (this->hasBlocks(elem->subdomain_id()))
914 const processor_id_type elem_pid = elem->processor_id();
918 _pairs_to_receive[elem_pid] = std::vector<std::pair<dof_id_type, dof_id_type>>();
919 for (
unsigned i = 0; i < elem->n_nodes(); ++i)
920 for (
unsigned j = 0; j < elem->n_nodes(); ++j)
922 std::pair<dof_id_type, dof_id_type> the_pair(elem->node_id(i), elem->node_id(j));
932 auto pairs_action_functor = [
this](processor_id_type pid,
933 const std::vector<std::pair<dof_id_type, dof_id_type>> & pts) {
936 Parallel::push_parallel_vector_data(this->comm(),
_pairs_to_receive, pairs_action_functor);
945 const processor_id_type pid = kv.first;
946 const std::size_t num_pairs = kv.second.size();
947 for (
unsigned i = 0; i < num_pairs; ++i)
956 const processor_id_type pid = kv.first;
957 const std::size_t num_pairs = kv.second.size();
958 for (
unsigned i = 0; i < num_pairs; ++i)
971 std::map<processor_id_type, std::vector<Real>> unodal_to_send;
974 const processor_id_type pid = kv.first;
975 unodal_to_send[pid] = std::vector<Real>();
976 for (
const auto & nd : kv.second)
977 unodal_to_send[pid].push_back(
_u_nodal[nd]);
980 auto unodal_action_functor = [
this](processor_id_type pid,
981 const std::vector<Real> & unodal_received) {
982 const std::size_t msg_size = unodal_received.size();
984 "Message size, " << msg_size
985 <<
", incompatible with nodes_to_receive, which has size "
987 for (
unsigned i = 0; i < msg_size; ++i)
990 Parallel::push_parallel_vector_data(this->comm(), unodal_to_send, unodal_action_functor);
993 std::map<processor_id_type, std::vector<Real>> kij_to_send;
996 const processor_id_type pid = kv.first;
997 kij_to_send[pid] = std::vector<Real>();
998 for (
const auto & pr : kv.second)
999 kij_to_send[pid].push_back(
_kij[pr.first][pr.second]);
1002 auto kij_action_functor = [
this](processor_id_type pid,
const std::vector<Real> & kij_received) {
1003 const std::size_t msg_size = kij_received.size();
1005 "Message size, " << msg_size
1006 <<
", incompatible with pairs_to_receive, which has size "
1008 for (
unsigned i = 0; i < msg_size; ++i)
1011 Parallel::push_parallel_vector_data(this->comm(), kij_to_send, kij_action_functor);