Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : #include "SCMSolutionTransfer.h"
11 : #include "MultiApp.h"
12 : #include "FEProblemBase.h"
13 : #include "DisplacedProblem.h"
14 : #include "SubChannelMesh.h"
15 :
16 : namespace
17 : {
18 : bool
19 65 : isDeprecatedPinTransferType(const InputParameters & parameters)
20 : {
21 65 : const auto & type = parameters.getObjectType();
22 65 : return type == "SCMPinSolutionTransfer" || type == "PinSolutionTransfer";
23 : }
24 : }
25 :
26 : registerMooseObject("SubChannelApp", SCMSolutionTransfer);
27 : registerMooseObjectRenamed("SubChannelApp",
28 : SolutionTransfer,
29 : "06/30/2027 24:00",
30 : SCMSolutionTransfer);
31 : registerMooseObjectRenamed("SubChannelApp",
32 : SCMPinSolutionTransfer,
33 : "06/30/2027 24:00",
34 : SCMSolutionTransfer);
35 : registerMooseObjectRenamed("SubChannelApp",
36 : PinSolutionTransfer,
37 : "06/30/2027 24:00",
38 : SCMSolutionTransfer);
39 :
40 : InputParameters
41 286 : SCMSolutionTransfer::validParams()
42 : {
43 286 : InputParameters params = MultiAppTransfer::validParams();
44 572 : params.addRequiredParam<std::vector<AuxVariableName>>("variable",
45 : "The auxiliary variables to transfer.");
46 572 : MooseEnum transfer_type("subchannel pin", "subchannel");
47 572 : params.addParam<MooseEnum>("transfer_type",
48 : transfer_type,
49 : "Whether to transfer subchannel-centered or pin-centered fields.");
50 286 : params.addClassDescription(
51 : "Transfers subchannel or pin solutions from a SubChannel mesh onto a visualization mesh.");
52 286 : return params;
53 286 : }
54 :
55 143 : SCMSolutionTransfer::SCMSolutionTransfer(const InputParameters & parameters)
56 : : MultiAppTransfer(parameters),
57 143 : _var_names(getParam<std::vector<AuxVariableName>>("variable")),
58 143 : _pin_transfer(
59 376 : getParam<MooseEnum>("transfer_type") == "pin" ||
60 524 : (!parameters.isParamSetByUser("transfer_type") && isDeprecatedPinTransferType(parameters)))
61 : {
62 143 : if (_directions.contains(Transfer::FROM_MULTIAPP))
63 0 : paramError("from_multiapp", "This transfer works only into multi-app.");
64 143 : }
65 :
66 : void
67 130 : SCMSolutionTransfer::initialSetup()
68 : {
69 130 : MultiAppTransfer::initialSetup();
70 735 : for (std::size_t var_index = 0; var_index < _var_names.size(); ++var_index)
71 : {
72 605 : if (_to_problems.empty())
73 20 : continue;
74 :
75 585 : MooseVariableFieldBase & from_var = _subproblem.getVariable(
76 : 0, _var_names[var_index], Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY);
77 : const auto & fe_type = from_var.feType();
78 :
79 585 : if (fe_type.family != LAGRANGE || fe_type.order != FIRST)
80 0 : paramError("variable",
81 : "This transfer requires a first order Lagrange variable for the source variable");
82 :
83 585 : MooseVariableFieldBase & to_var = _to_problems[0]->getVariable(
84 585 : 0, _var_names[var_index], Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY);
85 : const auto & fe_type_target = to_var.feType();
86 :
87 585 : if (fe_type_target.family != LAGRANGE || fe_type_target.order != FIRST)
88 0 : paramError("variable",
89 : "This transfer requires a first order Lagrange variable for the source variable");
90 : }
91 130 : }
92 :
93 : void
94 254 : SCMSolutionTransfer::execute()
95 : {
96 508 : TIME_SECTION(
97 : "MultiAppDetailedSolutionBaseTransfer::execute()", 5, "Transferring subchannel solutions");
98 254 : getAppInfo();
99 :
100 254 : switch (_current_direction)
101 : {
102 254 : case TO_MULTIAPP:
103 : case BETWEEN_MULTIAPP:
104 254 : transferToMultiApps();
105 : break;
106 :
107 : default:
108 : break;
109 : }
110 252 : }
111 :
112 : void
113 254 : SCMSolutionTransfer::transferToMultiApps()
114 : {
115 : mooseAssert(_from_meshes.size() == 1, "Only one source mesh can be active in this transfer.");
116 254 : auto * from_mesh = dynamic_cast<SubChannelMesh *>(_from_meshes[0]);
117 254 : if (from_mesh == nullptr)
118 0 : mooseError("This transfer works only with SubChannelMesh classes.");
119 254 : if (_pin_transfer && !from_mesh->pinMeshExist())
120 0 : mooseError(
121 : "This transfer was configured for pin variables, but the source mesh has no pin mesh.");
122 :
123 1012 : for (unsigned int i = 0; i < getToMultiApp()->numGlobalApps(); i++)
124 508 : if (getToMultiApp()->hasLocalApp(i))
125 242 : transferVarsToApp(i);
126 252 : }
127 :
128 : void
129 242 : SCMSolutionTransfer::transferVarsToApp(unsigned int app_idx)
130 : {
131 242 : transferNodalVars(app_idx);
132 240 : }
133 :
134 : void
135 242 : SCMSolutionTransfer::transferNodalVars(unsigned int app_idx)
136 : {
137 242 : Moose::ScopedCommSwapper swapper(getToMultiApp()->comm());
138 :
139 242 : FEProblemBase & to_problem = getToMultiApp()->appProblemBase(app_idx);
140 : MooseMesh * mesh = NULL;
141 242 : if (_displaced_target_mesh && to_problem.getDisplacedProblem())
142 0 : mesh = &to_problem.getDisplacedProblem()->mesh();
143 : else
144 242 : mesh = &to_problem.mesh();
145 :
146 242 : const SubChannelMesh & from_mesh = dynamic_cast<SubChannelMesh &>(*_from_meshes[0]);
147 242 : FEProblemBase & from_problem = *_from_problems[0];
148 242 : validateVariableLocations(from_mesh, to_problem);
149 :
150 7775136 : for (auto & node : mesh->getMesh().local_node_ptr_range())
151 : {
152 3887328 : if (processor_id() != 0)
153 881254 : continue;
154 3006074 : Node * from_node = getFromNode(from_mesh, *node);
155 :
156 19042297 : for (auto & var_name : _var_names)
157 : {
158 16036223 : System * to_sys = find_sys(to_problem.es(), var_name);
159 : unsigned int to_sys_num = to_sys->number();
160 16036223 : unsigned int to_var_num = to_sys->variable_number(var_name);
161 :
162 16036223 : if (node->n_dofs(to_sys_num, to_var_num) > 0)
163 : {
164 9526568 : System * from_sys = find_sys(from_problem.es(), var_name);
165 : unsigned int from_sys_num = from_sys->number();
166 9526568 : unsigned int from_var_num = from_sys->variable_number(var_name);
167 :
168 : // Return to parent app MPI communicator to get solution dof
169 : swapper.forceSwap();
170 : NumericVector<Real> * from_solution = from_sys->solution.get();
171 9526568 : dof_id_type from_dof = from_node->dof_number(from_sys_num, from_var_num, 0);
172 9526568 : Real from_value = (*from_solution)(from_dof);
173 : swapper.forceSwap();
174 :
175 19053136 : NumericVector<Real> & to_solution = getToMultiApp()->appTransferVector(app_idx, var_name);
176 9526568 : dof_id_type to_dof = node->dof_number(to_sys_num, to_var_num, 0);
177 9526568 : to_solution.set(to_dof, from_value);
178 : }
179 : }
180 240 : }
181 :
182 1425 : for (auto & var_name : _var_names)
183 : {
184 2370 : getToMultiApp()->appTransferVector(app_idx, var_name).close();
185 1185 : find_sys(to_problem.es(), var_name)->update();
186 : }
187 240 : }
188 :
189 : void
190 242 : SCMSolutionTransfer::validateVariableLocations(const SubChannelMesh & from_mesh,
191 : FEProblemBase & to_problem)
192 : {
193 242 : if (processor_id() != 0)
194 : return;
195 :
196 182 : Node * from_node = _pin_transfer ? from_mesh.getPinNode(0, 0) : from_mesh.getChannelNode(0, 0);
197 : mooseAssert(from_node, "The representative source node must be non-null.");
198 :
199 182 : FEProblemBase & from_problem = *_from_problems[0];
200 182 : const auto transfer_type = _pin_transfer ? "pin" : "subchannel";
201 182 : const auto other_transfer_type = _pin_transfer ? "subchannel" : "pin";
202 182 : const auto expected_block = _pin_transfer ? "fuel_pins" : "subchannel";
203 182 : const auto source_block_id = from_mesh.getSubdomainID(expected_block);
204 364 : const auto target_block_id = to_problem.mesh().getSubdomainID(expected_block);
205 :
206 1055 : for (const auto & var_name : _var_names)
207 : {
208 875 : MooseVariableFieldBase & from_var = from_problem.getVariable(
209 : 0, var_name, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY);
210 875 : MooseVariableFieldBase & to_var = to_problem.getVariable(
211 : 0, var_name, Moose::VarKindType::VAR_ANY, Moose::VarFieldType::VAR_FIELD_ANY);
212 875 : System * from_sys = find_sys(from_problem.es(), var_name);
213 : const auto from_sys_num = from_sys->number();
214 875 : const auto from_var_num = from_sys->variable_number(var_name);
215 :
216 1748 : if (!from_var.activeOnSubdomain(source_block_id) ||
217 1748 : !to_var.activeOnSubdomain(target_block_id) ||
218 873 : from_node->n_dofs(from_sys_num, from_var_num) == 0)
219 2 : paramError("variable",
220 : "The variable '",
221 : var_name,
222 : "' does not have DOFs on ",
223 : transfer_type,
224 : " nodes. Use a separate SCMSolutionTransfer with transfer_type = '",
225 : other_transfer_type,
226 : "' for variables centered on ",
227 : other_transfer_type,
228 : " nodes.");
229 : }
230 : }
231 :
232 : Node *
233 3006074 : SCMSolutionTransfer::getFromNode(const SubChannelMesh & from_mesh, const Point & src_node)
234 : {
235 : unsigned int sch_idx =
236 3006074 : _pin_transfer ? from_mesh.pinIndex(src_node) : from_mesh.channelIndex(src_node);
237 3006074 : unsigned iz = from_mesh.getZIndex(src_node);
238 3006074 : return _pin_transfer ? from_mesh.getPinNode(sch_idx, iz) : from_mesh.getChannelNode(sch_idx, iz);
239 : }
|