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 "MooseAppCoordTransform.h"
11 : #include "InputParameters.h"
12 : #include "MultiMooseEnum.h"
13 : #include "MooseEnum.h"
14 : #include "MooseMesh.h"
15 : #include "libmesh/mesh_modification.h"
16 :
17 : using namespace libMesh;
18 :
19 : MooseAppCoordTransform::Direction
20 4 : MooseAppCoordTransform::processZAxis(const Direction z_axis)
21 : {
22 4 : return _coord_type == Moose::COORD_RZ ? z_axis : INVALID;
23 : }
24 :
25 : void
26 6 : MooseAppCoordTransform::setUpDirection(const Direction up_direction)
27 : {
28 6 : Real alpha = 0, beta = 0, gamma = 0;
29 :
30 6 : const bool must_rotate_axes =
31 6 : _coord_type == Moose::COORD_RZ || _coord_type == Moose::COORD_RSPHERICAL;
32 : // Don't error immediately for unit testing purposes
33 6 : bool negative_radii = false;
34 :
35 6 : if (up_direction == X)
36 : {
37 2 : alpha = 90, beta = 0, gamma = 0;
38 2 : if (must_rotate_axes)
39 : {
40 2 : if (_r_axis == X)
41 : {
42 1 : _r_axis = Y;
43 1 : _z_axis = processZAxis(X);
44 : }
45 1 : else if (_r_axis == Y)
46 : {
47 1 : negative_radii = true;
48 1 : _r_axis = X;
49 1 : _z_axis = processZAxis(Y);
50 : }
51 : else
52 0 : mooseError("Bad r-axis value");
53 : }
54 : }
55 4 : else if (up_direction == Y)
56 2 : alpha = 0, beta = 0, gamma = 0;
57 2 : else if (up_direction == Z)
58 : {
59 2 : alpha = 0, beta = -90, gamma = 0;
60 2 : if (must_rotate_axes)
61 : {
62 2 : if (_r_axis == X)
63 : {
64 1 : _r_axis = X;
65 1 : _z_axis = processZAxis(Z);
66 : }
67 1 : else if (_r_axis == Y)
68 : {
69 1 : negative_radii = true;
70 1 : _r_axis = Z;
71 1 : _z_axis = processZAxis(X);
72 : }
73 : else
74 0 : mooseError("Bad r-axis value");
75 : }
76 : }
77 : else
78 0 : mooseError("Bad up direction value");
79 :
80 6 : _euler_angles = {{alpha, beta, gamma}};
81 :
82 12 : _rotate = std::make_unique<RealTensorValue>(
83 18 : RealTensorValue::extrinsic_rotation_matrix(alpha, beta, gamma));
84 6 : computeRS();
85 :
86 6 : if (negative_radii)
87 2 : mooseError("Rotation yields negative radial values");
88 4 : }
89 :
90 : void
91 702 : MooseAppCoordTransform::setRotation(const Real alpha, const Real beta, const Real gamma)
92 : {
93 702 : const bool must_rotate_axes =
94 702 : _coord_type == Moose::COORD_RZ || _coord_type == Moose::COORD_RSPHERICAL;
95 702 : bool axes_rotated = false;
96 702 : if (must_rotate_axes)
97 : {
98 26 : const auto angles = std::make_tuple(alpha, beta, gamma);
99 26 : if (angles == std::make_tuple(0, 90, 0))
100 : {
101 25 : if (_r_axis == X)
102 : {
103 : mooseAssert((_coord_type == Moose::COORD_RZ && _z_axis == Y) ||
104 : (_coord_type == Moose::COORD_RSPHERICAL && _z_axis == INVALID),
105 : "'_z_axis' is not an expected value");
106 24 : _r_axis = X;
107 24 : _z_axis = _coord_type == Moose::COORD_RZ ? Z : INVALID;
108 : }
109 1 : else if (_r_axis == Y)
110 : {
111 : mooseAssert((_coord_type == Moose::COORD_RZ && _z_axis == X) ||
112 : (_coord_type == Moose::COORD_RSPHERICAL && _z_axis == INVALID),
113 : "'_z_axis' is not an expected value");
114 1 : _r_axis = Z;
115 1 : _z_axis = _coord_type == Moose::COORD_RZ ? X : INVALID;
116 : }
117 25 : axes_rotated = true;
118 : }
119 : }
120 :
121 702 : _euler_angles = {{alpha, beta, gamma}};
122 1404 : _rotate = std::make_unique<RealTensorValue>(
123 2106 : RealTensorValue::extrinsic_rotation_matrix(alpha, beta, gamma));
124 702 : computeRS();
125 :
126 702 : if (must_rotate_axes && !axes_rotated)
127 1 : mooseError("Unsupported manual angle prescription in 'MooseAppCoordTransform::setRotation'. "
128 : "For non-Cartesian coordinate systems, the only currently supported rotation is "
129 : "(alpha, beta, gamma) = (0, 90, 0)");
130 701 : }
131 :
132 : void
133 182 : MooseAppCoordTransform::setLengthUnit(const MooseUnits & length_unit)
134 : {
135 182 : _length_unit = length_unit;
136 182 : const auto scale = Real(_length_unit / MooseUnits("m"));
137 : _scale =
138 182 : std::make_unique<RealTensorValue>(RealTensorValue(scale, 0, 0, 0, scale, 0, 0, 0, scale));
139 182 : computeRS();
140 182 : }
141 :
142 : void
143 63437 : MooseAppCoordTransform::setCoordinateSystem(const Moose::CoordinateSystemType coord_type,
144 : const Direction rz_symmetry_axis)
145 : {
146 63437 : _coord_type = coord_type;
147 :
148 63437 : if (_coord_type == Moose::COORD_RZ)
149 : {
150 555 : if (rz_symmetry_axis == INVALID)
151 0 : mooseError("For RZ coordinate systems, the 'rz_symmetry_axis' parameter must be provided to "
152 : "'MooseAppCoordTransform::setCoordinateSystem'");
153 :
154 555 : _z_axis = rz_symmetry_axis;
155 555 : _r_axis = _z_axis == X ? Y : X;
156 : }
157 62882 : else if (_coord_type == Moose::COORD_RSPHERICAL)
158 54 : _r_axis = X;
159 63437 : }
160 :
161 : void
162 63426 : MooseAppCoordTransform::setCoordinateSystem(const MooseMesh & mesh)
163 : {
164 63426 : const auto & params = mesh.parameters();
165 :
166 : // If we have multiple different coordinate system types in our problem, we
167 : // take note of it because that can cause issues if there is a non-Cartesian
168 : // destination coordinate system
169 63426 : const auto & coord_sys = mesh.getCoordSystem();
170 63426 : std::unordered_set<Moose::CoordinateSystemType> coord_types;
171 63426 : auto map_it = coord_sys.begin();
172 : // It's possible that the mesh is not in a complete state
173 63426 : if (map_it == coord_sys.end())
174 2077 : setCoordinateSystem(Moose::COORD_XYZ);
175 : else
176 122698 : setCoordinateSystem(
177 61349 : map_it->second,
178 122698 : Direction(static_cast<unsigned int>(int(params.get<MooseEnum>("rz_coord_axis")))));
179 147920 : for (; map_it != coord_sys.end(); ++map_it)
180 84494 : coord_types.insert(map_it->second);
181 :
182 63426 : _has_different_coord_sys = coord_types.size() > 1;
183 :
184 63426 : if (mesh.usingGeneralAxisymmetricCoordAxes())
185 19 : _using_general_rz_coord_axes = true;
186 63426 : }
187 :
188 : InputParameters
189 330158 : MooseAppCoordTransform::validParams()
190 : {
191 330158 : auto params = emptyInputParameters();
192 : /// One entry of coord system per block, the size of _blocks and _coord_sys has to match, except:
193 : /// 1. _blocks.size() == 0, then there needs to be just one entry in _coord_sys, which will
194 : /// be set for the whole domain
195 : /// 2. _blocks.size() > 0 and no coordinate system was specified, then the whole domain will be XYZ.
196 : /// 3. _blocks.size() > 0 and one coordinate system was specified, then the whole domain will be that system.
197 330158 : params.addDeprecatedParam<std::vector<SubdomainName>>(
198 : "block",
199 : "Block IDs for the coordinate systems.",
200 : "Please use the 'coord_block' parameter instead.");
201 330158 : params.addParam<std::vector<SubdomainName>>(
202 : "coord_block",
203 : "Block IDs for the coordinate systems. If this parameter is specified, then it must "
204 : "encompass all the subdomains on the mesh.");
205 330158 : MultiMooseEnum coord_types("XYZ RZ RSPHERICAL", "XYZ");
206 330158 : MooseEnum rz_coord_axis("X=0 Y=1", "Y");
207 330158 : params.addParam<MultiMooseEnum>(
208 : "coord_type", coord_types, "Type of the coordinate system per block param");
209 330158 : params.addParam<MooseEnum>(
210 : "rz_coord_axis", rz_coord_axis, "The rotation axis (X | Y) for axisymmetric coordinates");
211 330158 : params.addParam<std::vector<SubdomainName>>(
212 : "rz_coord_blocks", "Blocks using general axisymmetric coordinate systems");
213 330158 : params.addParam<std::vector<Point>>("rz_coord_origins",
214 : "Axis origin points for each block in 'rz_coord_blocks'");
215 330158 : params.addParam<std::vector<RealVectorValue>>(
216 : "rz_coord_directions", "Axis directions for each block in 'rz_coord_blocks'");
217 330158 : params.addParam<std::string>(
218 : "length_unit",
219 : "How much distance one mesh length unit represents, e.g. 1 cm, 1 nm, 1 ft, 5inches");
220 330158 : params.addRangeCheckedParam<Real>(
221 : "alpha_rotation",
222 : "-180<alpha_rotation<=180",
223 : "The number of degrees that the domain should be alpha-rotated using the Euler "
224 : "angle ZXZ convention from https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix in "
225 : "order to align with a canonical physical space of your choosing.");
226 330158 : params.addRangeCheckedParam<Real>(
227 : "beta_rotation",
228 : "-180<beta_rotation<=180",
229 : "The number of degrees that the domain should be beta-rotated using the Euler "
230 : "angle ZXZ convention from https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix in "
231 : "order to align with a canonical physical space of your choosing.");
232 330158 : params.addRangeCheckedParam<Real>(
233 : "gamma_rotation",
234 : "-180<gamma_rotation<=180",
235 : "The number of degrees that the domain should be gamma-rotated using the Euler "
236 : "angle ZXZ convention from https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix in "
237 : "order to align with a canonical physical space of your choosing.");
238 330158 : MooseEnum up_direction("X=0 Y=1 Z=2");
239 330158 : params.addParam<MooseEnum>(
240 : "up_direction",
241 : up_direction,
242 : "Specify what axis corresponds to the up direction in physical space (the opposite of the "
243 : "gravity vector if you will). If this parameter is provided, we will perform a single 90 "
244 : "degree rotation of the domain--if the provided axis is 'x' or 'z', we will not rotate if "
245 : "the axis is 'y'--such that a point which was on the provided axis will now lie on the "
246 : "y-axis, e.g. the y-axis is our canonical up direction. If you want finer grained control "
247 : "than this, please use the 'alpha_rotation', 'beta_rotation', and 'gamma_rotation' "
248 : "parameters.");
249 330158 : params.addParamNamesToGroup(
250 : "block coord_type coord_block rz_coord_axis rz_coord_blocks rz_coord_origins "
251 : "rz_coord_directions",
252 : "Coordinate system");
253 330158 : params.addParamNamesToGroup(
254 : "length_unit alpha_rotation beta_rotation gamma_rotation up_direction",
255 : "Transformations relative to parent application frame of reference");
256 660316 : return params;
257 330158 : }
258 :
259 63203 : MooseAppCoordTransform::MooseAppCoordTransform(const MooseMesh & mesh)
260 63203 : : _coord_type(Moose::COORD_XYZ),
261 63203 : _r_axis(INVALID),
262 63203 : _z_axis(INVALID),
263 63203 : _has_different_coord_sys(false),
264 63203 : _using_general_rz_coord_axes(false),
265 63203 : _length_unit(std::string("1*m")),
266 189609 : _euler_angles(),
267 63203 : _mesh_transformed(false)
268 : {
269 : //
270 : // Coordinate system transformation
271 : //
272 63203 : setCoordinateSystem(mesh);
273 :
274 63203 : const auto & params = mesh.parameters();
275 :
276 : //
277 : // Rotation
278 : //
279 63203 : const bool has_alpha = params.isParamValid("alpha_rotation");
280 63203 : const bool has_beta = params.isParamValid("beta_rotation");
281 63203 : const bool has_gamma = params.isParamValid("gamma_rotation");
282 63203 : const auto & up_direction = params.get<MooseEnum>("up_direction");
283 :
284 63203 : if (has_alpha || has_beta || has_gamma)
285 : {
286 700 : if (up_direction.isValid())
287 0 : mooseError("Cannot simultaneously set rotation angles as well as an up direction");
288 :
289 700 : const auto alpha = (has_alpha ? params.get<Real>("alpha_rotation") : Real(0));
290 700 : const auto beta = (has_beta ? params.get<Real>("beta_rotation") : Real(0));
291 700 : const auto gamma = (has_gamma ? params.get<Real>("gamma_rotation") : Real(0));
292 :
293 700 : setRotation(alpha, beta, gamma);
294 700 : }
295 62503 : else if (up_direction.isValid())
296 0 : setUpDirection(Direction(static_cast<unsigned int>(int(up_direction))));
297 :
298 : //
299 : // Scaling
300 : //
301 63203 : if (params.isParamValid("length_unit"))
302 84 : setLengthUnit(MooseUnits(params.get<std::string>("length_unit")));
303 63203 : }
304 :
305 4 : MooseAppCoordTransform::MooseAppCoordTransform()
306 4 : : _coord_type(Moose::COORD_XYZ),
307 4 : _r_axis(INVALID),
308 4 : _z_axis(INVALID),
309 4 : _has_different_coord_sys(false),
310 4 : _using_general_rz_coord_axes(false),
311 4 : _length_unit(std::string("1*m")),
312 12 : _euler_angles(),
313 4 : _mesh_transformed(false)
314 : {
315 4 : }
316 :
317 1 : MooseAppCoordTransform::MooseAppCoordTransform(const MooseAppCoordTransform & other)
318 1 : : _coord_type(other._coord_type),
319 1 : _r_axis(other._r_axis),
320 1 : _z_axis(other._z_axis),
321 1 : _has_different_coord_sys(other._has_different_coord_sys),
322 1 : _using_general_rz_coord_axes(other._using_general_rz_coord_axes),
323 1 : _length_unit(other._length_unit),
324 1 : _euler_angles(other._euler_angles),
325 1 : _mesh_transformed(other._mesh_transformed)
326 : {
327 1 : if (other._scale)
328 0 : _scale = std::make_unique<RealTensorValue>(*other._scale);
329 1 : if (other._rotate)
330 1 : _rotate = std::make_unique<RealTensorValue>(*other._rotate);
331 1 : computeRS();
332 1 : }
333 :
334 139962 : MooseAppCoordTransform::MooseAppCoordTransform(const MinimalData & minimal_data)
335 139962 : : _coord_type(static_cast<Moose::CoordinateSystemType>(std::get<4>(minimal_data))),
336 139962 : _r_axis(static_cast<Direction>(std::get<5>(minimal_data))),
337 139962 : _z_axis(static_cast<Direction>(std::get<6>(minimal_data))),
338 139962 : _has_different_coord_sys(std::get<7>(minimal_data)),
339 139962 : _using_general_rz_coord_axes(std::get<8>(minimal_data)),
340 139962 : _length_unit(std::string("1*m")),
341 139962 : _euler_angles(std::get<3>(minimal_data)),
342 279924 : _mesh_transformed(std::get<9>(minimal_data))
343 : {
344 139962 : if (std::get<0>(minimal_data))
345 98 : setLengthUnit(MooseUnits(std::to_string(std::get<1>(minimal_data)) + "*m"));
346 139962 : if (std::get<2>(minimal_data))
347 2512 : _rotate = std::make_unique<RealTensorValue>(RealTensorValue::extrinsic_rotation_matrix(
348 2512 : _euler_angles[0], _euler_angles[1], _euler_angles[2]));
349 139962 : computeRS();
350 139962 : }
351 :
352 : MooseAppCoordTransform::MinimalData
353 102246 : MooseAppCoordTransform::minimalDataDescription() const
354 : {
355 102246 : const Real scale_factor = _scale ? (*_scale)(0, 0) : 1;
356 102246 : return {static_cast<short int>(bool(_scale)),
357 : scale_factor,
358 102246 : static_cast<short int>(bool(_rotate)),
359 102246 : _euler_angles,
360 204492 : static_cast<int>(_coord_type),
361 204492 : static_cast<unsigned int>(_r_axis),
362 204492 : static_cast<unsigned int>(_z_axis),
363 204492 : static_cast<short int>(_has_different_coord_sys),
364 204492 : static_cast<short int>(_using_general_rz_coord_axes),
365 102246 : static_cast<short int>(_mesh_transformed)};
366 : }
367 :
368 : MooseAppCoordTransform &
369 1 : MooseAppCoordTransform::operator=(const MooseAppCoordTransform & other)
370 : {
371 1 : _coord_type = other._coord_type;
372 1 : _r_axis = other._r_axis;
373 1 : _z_axis = other._z_axis;
374 1 : _has_different_coord_sys = other._has_different_coord_sys;
375 1 : _using_general_rz_coord_axes = other._using_general_rz_coord_axes;
376 1 : _length_unit = other._length_unit;
377 1 : _euler_angles = other._euler_angles;
378 1 : _mesh_transformed = other._mesh_transformed;
379 :
380 1 : if (other._scale)
381 0 : _scale = std::make_unique<RealTensorValue>(*other._scale);
382 : else
383 1 : _scale.reset();
384 1 : if (other._rotate)
385 1 : _rotate = std::make_unique<RealTensorValue>(*other._rotate);
386 : else
387 0 : _rotate.reset();
388 :
389 1 : computeRS();
390 :
391 1 : return *this;
392 : }
393 :
394 : void
395 140854 : MooseAppCoordTransform::computeRS()
396 : {
397 140854 : if (_scale || _rotate)
398 : {
399 2148 : _rs = std::make_unique<RealTensorValue>(RealTensorValue(1, 0, 0, 0, 1, 0, 0, 0, 1));
400 :
401 2148 : if (_scale)
402 280 : *_rs = *_scale * *_rs;
403 2148 : if (_rotate)
404 2046 : *_rs = *_rotate * *_rs;
405 :
406 2148 : _rs_inverse = std::make_unique<RealTensorValue>(_rs->inverse());
407 : }
408 : else
409 : {
410 138706 : _rs.reset();
411 138706 : _rs_inverse.reset();
412 : }
413 140854 : }
414 :
415 : void
416 248 : MooseAppCoordTransform::transformMesh(MooseMesh & mesh, const Point & translation)
417 : {
418 : // Transforming a RZ or R-spherical mesh doesnt always make sense, disallow it
419 248 : if (_coord_type != Moose::COORD_XYZ)
420 4 : mooseError("Running MultiApps 'in position' is only supported for XYZ coordinate systems");
421 :
422 244 : if (_using_general_rz_coord_axes && hasScalingOrRotationTransformation())
423 0 : mooseError("Scaling and rotation are currently not supported for general axisymmetric "
424 : "coordinate systems.");
425 :
426 244 : if (_mesh_transformed)
427 0 : mooseError("App mesh is being transformed twice");
428 :
429 : // Apply all the transformation to the mesh
430 244 : if (_scale)
431 12 : MeshTools::Modification::scale(mesh, (*_scale)(0, 0), (*_scale)(1, 1), (*_scale)(2, 2));
432 244 : if (_rotate)
433 12 : MeshTools::Modification::rotate(mesh, _euler_angles[0], _euler_angles[1], _euler_angles[2]);
434 244 : if (translation != Point(0, 0, 0))
435 244 : MeshTools::Modification::translate(mesh, translation(0), translation(1), translation(2));
436 :
437 : // Translation, scaling and rotation need not be applied anymore when performing coordinate
438 : // transforms
439 244 : _mesh_transformed = true;
440 244 : }
441 :
442 : bool
443 195904 : MooseAppCoordTransform::hasScalingOrRotationTransformation() const
444 : {
445 195904 : if (_rs)
446 2042 : for (const auto i : make_range(Moose::dim))
447 2418 : for (const auto j : make_range(Moose::dim))
448 : {
449 2324 : const auto matrix_elem = (*_rs)(i, j);
450 2324 : if (i == j)
451 : {
452 2042 : if (!MooseUtils::absoluteFuzzyEqual(matrix_elem, 1))
453 1948 : return true;
454 : }
455 282 : else if (!MooseUtils::absoluteFuzzyEqual(matrix_elem, 0))
456 0 : return true;
457 : }
458 :
459 193956 : return false;
460 : }
461 :
462 164292 : MultiAppCoordTransform::MultiAppCoordTransform(const MooseAppCoordTransform & our_app_transform)
463 164292 : : _our_app_transform(our_app_transform),
464 164292 : _destination_app_transform(nullptr),
465 164292 : _skip_coordinate_collapsing(false)
466 : {
467 164292 : }
468 :
469 : Point
470 45705569 : MultiAppCoordTransform::operator()(const Point & point) const
471 : {
472 : mooseAssert(_destination_app_transform, "The destination application transform must be set");
473 :
474 45705569 : Point ret(point);
475 :
476 : // Translation, rotation and scaling already applied, coordinate system conversion not supported
477 45705569 : if (_our_app_transform._mesh_transformed)
478 854336 : return ret;
479 :
480 : // Apply scaling and then rotation
481 44851233 : if (_our_app_transform._rs)
482 919019 : ret = (*_our_app_transform._rs) * ret;
483 :
484 : // If this shows up in profiling we can make _translation a pointer
485 44851233 : ret += _translation;
486 :
487 44851233 : if (_skip_coordinate_collapsing)
488 44795605 : return ret;
489 :
490 : // Finally, coordinate system conversions
491 55628 : if (_our_app_transform._coord_type == Moose::COORD_XYZ &&
492 29970 : _destination_app_transform->_coord_type == Moose::COORD_RZ)
493 : {
494 29969 : Real r_squared = 0;
495 119876 : for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
496 89907 : if (i != _destination_app_transform->_z_axis)
497 59938 : r_squared += ret(i) * ret(i);
498 :
499 29969 : const auto r = std::sqrt(r_squared);
500 29969 : const auto z = ret(_destination_app_transform->_z_axis);
501 29969 : ret = 0;
502 29969 : ret(_destination_app_transform->_r_axis) = r;
503 29969 : ret(_destination_app_transform->_z_axis) = z;
504 29969 : }
505 25659 : else if (_our_app_transform._coord_type == Moose::COORD_XYZ &&
506 1 : _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL)
507 : {
508 1 : Real r_squared = 0;
509 4 : for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
510 3 : r_squared += ret(i) * ret(i);
511 :
512 1 : const auto r = std::sqrt(r_squared);
513 1 : ret = 0;
514 1 : ret(_destination_app_transform->_r_axis) = r;
515 1 : }
516 25658 : else if (_our_app_transform._coord_type == Moose::COORD_RZ &&
517 25658 : _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL)
518 : {
519 1 : Real r_squared = 0;
520 4 : for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
521 : {
522 : mooseAssert(
523 : i == _our_app_transform._r_axis || i == _our_app_transform._z_axis ||
524 : MooseUtils::absoluteFuzzyEqual(ret(i), 0),
525 : "Our point should be 0 if we are evaluating at an index that is neither our r or z-axis");
526 3 : r_squared += ret(i) * ret(i);
527 : }
528 :
529 1 : const auto r = std::sqrt(r_squared);
530 1 : ret = 0;
531 1 : ret(_destination_app_transform->_r_axis) = r;
532 : }
533 :
534 55628 : return ret;
535 : }
536 :
537 : Point
538 1407562 : MultiAppCoordTransform::mapBack(const Point & point) const
539 : {
540 1407562 : Point ret(point);
541 :
542 : // Translation, rotation and scaling already applied, coordinate system conversion not supported
543 1407562 : if (_our_app_transform._mesh_transformed)
544 0 : return ret;
545 :
546 : // inverse translate
547 1407562 : ret -= _translation;
548 :
549 : // inverse rotate and then inverse scale
550 1407562 : if (_our_app_transform._rs_inverse)
551 30786 : ret = (*_our_app_transform._rs_inverse) * ret;
552 :
553 1407562 : if (_skip_coordinate_collapsing)
554 1407559 : return ret;
555 :
556 : // Finally, coordinate system conversions
557 3 : if ((_our_app_transform._coord_type == Moose::COORD_XYZ &&
558 2 : (_destination_app_transform->_coord_type == Moose::COORD_RZ ||
559 1 : _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL)) ||
560 1 : (_our_app_transform._coord_type == Moose::COORD_RZ &&
561 1 : _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL))
562 3 : mooseError("Coordinate collapsing occurred in going to the reference space. There is no unique "
563 : "return mapping");
564 :
565 0 : return ret;
566 : }
567 :
568 : void
569 163888 : MultiAppCoordTransform::setDestinationCoordTransform(
570 : const MooseAppCoordTransform & destination_app_transform)
571 : {
572 163888 : _destination_app_transform = &destination_app_transform;
573 :
574 163888 : if (_our_app_transform._using_general_rz_coord_axes &&
575 0 : _our_app_transform.hasScalingOrRotationTransformation())
576 0 : mooseError("Scaling and rotation are currently not supported for general axisymmetric "
577 : "coordinate systems.");
578 :
579 : // Don't error check mismatching coordinate system types if we've been asked to skip coordinate
580 : // collapsing since in that case the mismatch doesn't matter
581 163888 : if (_skip_coordinate_collapsing)
582 163744 : return;
583 :
584 144 : if (_destination_app_transform->_has_different_coord_sys &&
585 0 : (_our_app_transform._has_different_coord_sys ||
586 0 : _our_app_transform._coord_type != Moose::COORD_RSPHERICAL))
587 0 : mooseError(
588 : "The destination coordinate system has different coordinate systems and we have coordinate "
589 : "system(s) that could require coordinate collapsing when transforming from our coordinate "
590 : "system to the destination coordinate system. Because our transform method only takes a "
591 : "point argument, and not subdomain arguments, the transform is ambiguous");
592 :
593 144 : if ((_destination_app_transform->_coord_type == Moose::COORD_RZ ||
594 73 : _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL) &&
595 73 : _our_app_transform._has_different_coord_sys)
596 0 : mooseError("When the destination coordinate system is RZ or RSPHERICAL, we have to perform "
597 : "coordinate collapsing based on *our* coordinate system. However, we have multiple "
598 : "coordinate systems, and since when evaluating transformations, we are only "
599 : "called with a Point argument, we do not know what subdomain we are on and "
600 : "consequently we do not know what coordinate collapse to apply.");
601 :
602 144 : if (_our_app_transform._using_general_rz_coord_axes ||
603 144 : _destination_app_transform->_using_general_rz_coord_axes)
604 0 : mooseError("If either this app or the destination app uses general axisymmetric axes, "
605 : "coordinate collapsing must be skipped.");
606 : }
607 :
608 : bool
609 139957 : MultiAppCoordTransform::hasNonTranslationTransformation() const
610 : {
611 139957 : if (_our_app_transform.hasScalingOrRotationTransformation())
612 1248 : return true;
613 :
614 138709 : if (_skip_coordinate_collapsing)
615 138636 : return false;
616 :
617 73 : if (hasCoordinateSystemTypeChange())
618 73 : return true;
619 :
620 0 : return false;
621 : }
622 :
623 : bool
624 9971 : MultiAppCoordTransform::hasCoordinateSystemTypeChange() const
625 : {
626 9971 : if (_skip_coordinate_collapsing)
627 9898 : return false;
628 :
629 73 : if ((_our_app_transform._coord_type == Moose::COORD_XYZ &&
630 72 : (_destination_app_transform->_coord_type == Moose::COORD_RZ ||
631 1 : _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL)) ||
632 1 : (_our_app_transform._coord_type == Moose::COORD_RZ &&
633 1 : _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL))
634 73 : return true;
635 :
636 0 : return false;
637 : }
638 :
639 : bool
640 0 : MultiAppCoordTransform::isIdentity() const
641 : {
642 0 : if (hasNonTranslationTransformation())
643 0 : return false;
644 :
645 0 : for (const auto i : make_range(Moose::dim))
646 0 : if (!MooseUtils::absoluteFuzzyEqual(_translation(i), 0))
647 0 : return false;
648 :
649 0 : return true;
650 : }
651 :
652 : void
653 164288 : MultiAppCoordTransform::skipCoordinateCollapsing(const bool skip_coordinate_collapsing)
654 : {
655 164288 : _skip_coordinate_collapsing = skip_coordinate_collapsing;
656 164288 : }
657 :
658 : void
659 100963 : MultiAppCoordTransform::setTranslationVector(const Point & translation)
660 : {
661 100963 : _translation = translation;
662 100963 : }
|