https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MooseAppCoordTransform.C
Go to the documentation of this file.
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
11#include "InputParameters.h"
12#include "MultiMooseEnum.h"
13#include "MooseEnum.h"
14#include "MooseMesh.h"
15#include "libmesh/mesh_modification.h"
16
22
23void
25{
26 Real alpha = 0, beta = 0, gamma = 0;
27
28 const bool must_rotate_axes =
30 // Don't error immediately for unit testing purposes
31 bool negative_radii = false;
32
33 if (up_direction == X)
34 {
35 alpha = 90, beta = 0, gamma = 0;
36 if (must_rotate_axes)
37 {
38 if (_r_axis == X)
39 {
40 _r_axis = Y;
42 }
43 else if (_r_axis == Y)
44 {
45 negative_radii = true;
46 _r_axis = X;
48 }
49 else
50 mooseError("Bad r-axis value");
51 }
52 }
53 else if (up_direction == Y)
54 alpha = 0, beta = 0, gamma = 0;
55 else if (up_direction == Z)
56 {
57 alpha = 0, beta = -90, gamma = 0;
58 if (must_rotate_axes)
59 {
60 if (_r_axis == X)
61 {
62 _r_axis = X;
64 }
65 else if (_r_axis == Y)
66 {
67 negative_radii = true;
68 _r_axis = Z;
70 }
71 else
72 mooseError("Bad r-axis value");
73 }
74 }
75 else
76 mooseError("Bad up direction value");
77
78 _euler_angles = {{alpha, beta, gamma}};
79
80 _rotate = std::make_unique<RealTensorValue>(
81 RealTensorValue::extrinsic_rotation_matrix(alpha, beta, gamma));
82 computeRS();
83
84 if (negative_radii)
85 mooseError("Rotation yields negative radial values");
86}
87
88void
89MooseAppCoordTransform::setRotation(const Real alpha, const Real beta, const Real gamma)
90{
91 const bool must_rotate_axes =
93 bool axes_rotated = false;
94 if (must_rotate_axes)
95 {
96 const auto angles = std::make_tuple(alpha, beta, gamma);
97 if (angles == std::make_tuple(0, 90, 0))
98 {
99 if (_r_axis == X)
100 {
101 mooseAssert((_coord_type == Moose::COORD_RZ && _z_axis == Y) ||
103 "'_z_axis' is not an expected value");
104 _r_axis = X;
106 }
107 else if (_r_axis == Y)
108 {
109 mooseAssert((_coord_type == Moose::COORD_RZ && _z_axis == X) ||
111 "'_z_axis' is not an expected value");
112 _r_axis = Z;
114 }
115 axes_rotated = true;
116 }
117 }
118
119 _euler_angles = {{alpha, beta, gamma}};
120 _rotate = std::make_unique<RealTensorValue>(
121 RealTensorValue::extrinsic_rotation_matrix(alpha, beta, gamma));
122 computeRS();
123
124 if (must_rotate_axes && !axes_rotated)
125 mooseError("Unsupported manual angle prescription in 'MooseAppCoordTransform::setRotation'. "
126 "For non-Cartesian coordinate systems, the only currently supported rotation is "
127 "(alpha, beta, gamma) = (0, 90, 0)");
128}
129
130void
132{
133 _length_unit = length_unit;
134 const auto scale = Real(_length_unit / MooseUnits("m"));
135 _scale =
136 std::make_unique<RealTensorValue>(RealTensorValue(scale, 0, 0, 0, scale, 0, 0, 0, scale));
137 computeRS();
138}
139
140void
142 const Direction rz_symmetry_axis)
143{
144 _coord_type = coord_type;
145
147 {
148 if (rz_symmetry_axis == INVALID)
149 mooseError("For RZ coordinate systems, the 'rz_symmetry_axis' parameter must be provided to "
150 "'MooseAppCoordTransform::setCoordinateSystem'");
151
152 _z_axis = rz_symmetry_axis;
153 _r_axis = _z_axis == X ? Y : X;
154 }
156 _r_axis = X;
157}
158
159void
161{
162 const auto & params = mesh.parameters();
163
164 // If we have multiple different coordinate system types in our problem, we
165 // take note of it because that can cause issues if there is a non-Cartesian
166 // destination coordinate system
167 const auto & coord_sys = mesh.getCoordSystem();
168 std::unordered_set<Moose::CoordinateSystemType> coord_types;
169 auto map_it = coord_sys.begin();
170 // It's possible that the mesh is not in a complete state
171 if (map_it == coord_sys.end())
173 else
175 map_it->second,
176 Direction(static_cast<unsigned int>(int(params.get<MooseEnum>("rz_coord_axis")))));
177 for (; map_it != coord_sys.end(); ++map_it)
178 coord_types.insert(map_it->second);
179
180 _has_different_coord_sys = coord_types.size() > 1;
181
182 if (mesh.usingGeneralAxisymmetricCoordAxes())
184}
185
188{
189 auto params = emptyInputParameters();
195 params.addDeprecatedParam<std::vector<SubdomainName>>(
196 "block",
197 "Block IDs for the coordinate systems.",
198 "Please use the 'coord_block' parameter instead.");
199 params.addParam<std::vector<SubdomainName>>(
200 "coord_block",
201 "Block IDs for the coordinate systems. If this parameter is specified, then it must "
202 "encompass all the subdomains on the mesh.");
203 MultiMooseEnum coord_types("XYZ RZ RSPHERICAL", "XYZ");
204 MooseEnum rz_coord_axis("X=0 Y=1", "Y");
205 params.addParam<MultiMooseEnum>(
206 "coord_type", coord_types, "Type of the coordinate system per block param");
207 params.addParam<MooseEnum>(
208 "rz_coord_axis", rz_coord_axis, "The rotation axis (X | Y) for axisymmetric coordinates");
209 params.addParam<std::vector<SubdomainName>>(
210 "rz_coord_blocks", "Blocks using general axisymmetric coordinate systems");
211 params.addParam<std::vector<Point>>("rz_coord_origins",
212 "Axis origin points for each block in 'rz_coord_blocks'");
213 params.addParam<std::vector<RealVectorValue>>(
214 "rz_coord_directions", "Axis directions for each block in 'rz_coord_blocks'");
215 params.addParam<std::string>(
216 "length_unit",
217 "How much distance one mesh length unit represents, e.g. 1 cm, 1 nm, 1 ft, 5inches");
218 params.addRangeCheckedParam<Real>(
219 "alpha_rotation",
220 "-180<alpha_rotation<=180",
221 "The number of degrees that the domain should be alpha-rotated using the Euler "
222 "angle ZXZ convention from https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix in "
223 "order to align with a canonical physical space of your choosing.");
224 params.addRangeCheckedParam<Real>(
225 "beta_rotation",
226 "-180<beta_rotation<=180",
227 "The number of degrees that the domain should be beta-rotated using the Euler "
228 "angle ZXZ convention from https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix in "
229 "order to align with a canonical physical space of your choosing.");
230 params.addRangeCheckedParam<Real>(
231 "gamma_rotation",
232 "-180<gamma_rotation<=180",
233 "The number of degrees that the domain should be gamma-rotated using the Euler "
234 "angle ZXZ convention from https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix in "
235 "order to align with a canonical physical space of your choosing.");
236 MooseEnum up_direction("X=0 Y=1 Z=2");
237 params.addParam<MooseEnum>(
238 "up_direction",
239 up_direction,
240 "Specify what axis corresponds to the up direction in physical space (the opposite of the "
241 "gravity vector if you will). If this parameter is provided, we will perform a single 90 "
242 "degree rotation of the domain--if the provided axis is 'x' or 'z', we will not rotate if "
243 "the axis is 'y'--such that a point which was on the provided axis will now lie on the "
244 "y-axis, e.g. the y-axis is our canonical up direction. If you want finer grained control "
245 "than this, please use the 'alpha_rotation', 'beta_rotation', and 'gamma_rotation' "
246 "parameters.");
247 params.addParamNamesToGroup(
248 "block coord_type coord_block rz_coord_axis rz_coord_blocks rz_coord_origins "
249 "rz_coord_directions",
250 "Coordinate system");
251 params.addParamNamesToGroup(
252 "length_unit alpha_rotation beta_rotation gamma_rotation up_direction",
253 "Transformations relative to parent application frame of reference");
254 return params;
255}
256
258 : _coord_type(Moose::COORD_XYZ),
259 _r_axis(INVALID),
260 _z_axis(INVALID),
261 _has_different_coord_sys(false),
262 _using_general_rz_coord_axes(false),
263 _length_unit(std::string("1*m")),
264 _euler_angles(),
265 _mesh_transformed(false)
266{
267 //
268 // Coordinate system transformation
269 //
271
272 const auto & params = mesh.parameters();
273
274 //
275 // Rotation
276 //
277 const bool has_alpha = params.isParamValid("alpha_rotation");
278 const bool has_beta = params.isParamValid("beta_rotation");
279 const bool has_gamma = params.isParamValid("gamma_rotation");
280 const auto & up_direction = params.get<MooseEnum>("up_direction");
281
282 if (has_alpha || has_beta || has_gamma)
283 {
284 if (up_direction.isValid())
285 mooseError("Cannot simultaneously set rotation angles as well as an up direction");
286
287 const auto alpha = (has_alpha ? params.get<Real>("alpha_rotation") : Real(0));
288 const auto beta = (has_beta ? params.get<Real>("beta_rotation") : Real(0));
289 const auto gamma = (has_gamma ? params.get<Real>("gamma_rotation") : Real(0));
290
291 setRotation(alpha, beta, gamma);
292 }
293 else if (up_direction.isValid())
294 setUpDirection(Direction(static_cast<unsigned int>(int(up_direction))));
295
296 //
297 // Scaling
298 //
299 if (params.isParamValid("length_unit"))
300 setLengthUnit(MooseUnits(params.get<std::string>("length_unit")));
301}
302
304 : _coord_type(Moose::COORD_XYZ),
305 _r_axis(INVALID),
306 _z_axis(INVALID),
307 _has_different_coord_sys(false),
308 _using_general_rz_coord_axes(false),
309 _length_unit(std::string("1*m")),
310 _euler_angles(),
311 _mesh_transformed(false)
312{
313}
314
316 : _coord_type(other._coord_type),
317 _r_axis(other._r_axis),
318 _z_axis(other._z_axis),
319 _has_different_coord_sys(other._has_different_coord_sys),
320 _using_general_rz_coord_axes(other._using_general_rz_coord_axes),
321 _length_unit(other._length_unit),
322 _euler_angles(other._euler_angles),
323 _mesh_transformed(other._mesh_transformed)
324{
325 if (other._scale)
326 _scale = std::make_unique<RealTensorValue>(*other._scale);
327 if (other._rotate)
328 _rotate = std::make_unique<RealTensorValue>(*other._rotate);
329 computeRS();
330}
331
333 : _coord_type(static_cast<Moose::CoordinateSystemType>(std::get<4>(minimal_data))),
334 _r_axis(static_cast<Direction>(std::get<5>(minimal_data))),
335 _z_axis(static_cast<Direction>(std::get<6>(minimal_data))),
336 _has_different_coord_sys(std::get<7>(minimal_data)),
337 _using_general_rz_coord_axes(std::get<8>(minimal_data)),
338 _length_unit(std::string("1*m")),
339 _euler_angles(std::get<3>(minimal_data)),
340 _mesh_transformed(std::get<9>(minimal_data))
341{
342 if (std::get<0>(minimal_data))
343 setLengthUnit(MooseUnits(std::to_string(std::get<1>(minimal_data)) + "*m"));
344 if (std::get<2>(minimal_data))
345 _rotate = std::make_unique<RealTensorValue>(RealTensorValue::extrinsic_rotation_matrix(
347 computeRS();
348}
349
352{
353 const Real scale_factor = _scale ? (*_scale)(0, 0) : 1;
354 return {static_cast<short int>(bool(_scale)),
355 scale_factor,
356 static_cast<short int>(bool(_rotate)),
358 static_cast<int>(_coord_type),
359 static_cast<unsigned int>(_r_axis),
360 static_cast<unsigned int>(_z_axis),
361 static_cast<short int>(_has_different_coord_sys),
362 static_cast<short int>(_using_general_rz_coord_axes),
363 static_cast<short int>(_mesh_transformed)};
364}
365
368{
369 _coord_type = other._coord_type;
370 _r_axis = other._r_axis;
371 _z_axis = other._z_axis;
377
378 if (other._scale)
379 _scale = std::make_unique<RealTensorValue>(*other._scale);
380 else
381 _scale.reset();
382 if (other._rotate)
383 _rotate = std::make_unique<RealTensorValue>(*other._rotate);
384 else
385 _rotate.reset();
386
387 computeRS();
388
389 return *this;
390}
391
392void
394{
395 if (_scale || _rotate)
396 {
397 _rs = std::make_unique<RealTensorValue>(RealTensorValue(1, 0, 0, 0, 1, 0, 0, 0, 1));
398
399 if (_scale)
400 *_rs = *_scale * *_rs;
401 if (_rotate)
402 *_rs = *_rotate * *_rs;
403
404 _rs_inverse = std::make_unique<RealTensorValue>(_rs->inverse());
405 }
406 else
407 {
408 _rs.reset();
409 _rs_inverse.reset();
410 }
411}
412
413void
414MooseAppCoordTransform::transformMesh(MooseMesh & mesh, const Point & translation)
415{
416 // Transforming a RZ or R-spherical mesh doesnt always make sense, disallow it
418 mooseError("Running MultiApps 'in position' is only supported for XYZ coordinate systems");
419
421 mooseError("Scaling and rotation are currently not supported for general axisymmetric "
422 "coordinate systems.");
423
425 mooseError("App mesh is being transformed twice");
426
427 // Apply all the transformation to the mesh
428 if (_scale)
429 MeshTools::Modification::scale(mesh, (*_scale)(0, 0), (*_scale)(1, 1), (*_scale)(2, 2));
430 if (_rotate)
431 MeshTools::Modification::rotate(mesh, _euler_angles[0], _euler_angles[1], _euler_angles[2]);
432 if (translation != Point(0, 0, 0))
433 MeshTools::Modification::translate(mesh, translation(0), translation(1), translation(2));
434
435 // Translation, scaling and rotation need not be applied anymore when performing coordinate
436 // transforms
437 _mesh_transformed = true;
438}
439
440bool
442{
443 if (_rs)
444 for (const auto i : make_range(Moose::dim))
445 for (const auto j : make_range(Moose::dim))
446 {
447 const auto matrix_elem = (*_rs)(i, j);
448 if (i == j)
449 {
450 if (!MooseUtils::absoluteFuzzyEqual(matrix_elem, 1))
451 return true;
452 }
453 else if (!MooseUtils::absoluteFuzzyEqual(matrix_elem, 0))
454 return true;
455 }
456
457 return false;
458}
459
461 : _our_app_transform(our_app_transform),
462 _destination_app_transform(nullptr),
463 _skip_coordinate_collapsing(false)
464{
465}
466
467Point
468MultiAppCoordTransform::operator()(const Point & point) const
469{
470 mooseAssert(_destination_app_transform, "The destination application transform must be set");
471
472 Point ret(point);
473
474 // Translation, rotation and scaling already applied, coordinate system conversion not supported
476 return ret;
477
478 // Apply scaling and then rotation
480 ret = (*_our_app_transform._rs) * ret;
481
482 // If this shows up in profiling we can make _translation a pointer
483 ret += _translation;
484
486 return ret;
487
488 // Finally, coordinate system conversions
491 {
492 Real r_squared = 0;
493 for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
495 r_squared += ret(i) * ret(i);
496
497 const auto r = std::sqrt(r_squared);
498 const auto z = ret(_destination_app_transform->_z_axis);
499 ret = 0;
502 }
505 {
506 Real r_squared = 0;
507 for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
508 r_squared += ret(i) * ret(i);
509
510 const auto r = std::sqrt(r_squared);
511 ret = 0;
513 }
516 {
517 Real r_squared = 0;
518 for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
519 {
520 mooseAssert(
522 MooseUtils::absoluteFuzzyEqual(ret(i), 0),
523 "Our point should be 0 if we are evaluating at an index that is neither our r or z-axis");
524 r_squared += ret(i) * ret(i);
525 }
526
527 const auto r = std::sqrt(r_squared);
528 ret = 0;
530 }
531
532 return ret;
533}
534
535Point
536MultiAppCoordTransform::mapBack(const Point & point) const
537{
538 Point ret(point);
539
540 // Translation, rotation and scaling already applied, coordinate system conversion not supported
542 return ret;
543
544 // inverse translate
545 ret -= _translation;
546
547 // inverse rotate and then inverse scale
549 ret = (*_our_app_transform._rs_inverse) * ret;
550
552 return ret;
553
554 // Finally, coordinate system conversions
560 mooseError("Coordinate collapsing occurred in going to the reference space. There is no unique "
561 "return mapping");
562
563 return ret;
564}
565
566void
568 const MooseAppCoordTransform & destination_app_transform)
569{
570 _destination_app_transform = &destination_app_transform;
571
574 mooseError("Scaling and rotation are currently not supported for general axisymmetric "
575 "coordinate systems.");
576
577 // Don't error check mismatching coordinate system types if we've been asked to skip coordinate
578 // collapsing since in that case the mismatch doesn't matter
580 return;
581
586 "The destination coordinate system has different coordinate systems and we have coordinate "
587 "system(s) that could require coordinate collapsing when transforming from our coordinate "
588 "system to the destination coordinate system. Because our transform method only takes a "
589 "point argument, and not subdomain arguments, the transform is ambiguous");
590
594 mooseError("When the destination coordinate system is RZ or RSPHERICAL, we have to perform "
595 "coordinate collapsing based on *our* coordinate system. However, we have multiple "
596 "coordinate systems, and since when evaluating transformations, we are only "
597 "called with a Point argument, we do not know what subdomain we are on and "
598 "consequently we do not know what coordinate collapse to apply.");
599
602 mooseError("If either this app or the destination app uses general axisymmetric axes, "
603 "coordinate collapsing must be skipped.");
604}
605
606bool
608{
610 return true;
611
613 return false;
614
616 return true;
617
618 return false;
619}
620
621bool
636
637bool
639{
641 return false;
642
643 for (const auto i : make_range(Moose::dim))
644 if (!MooseUtils::absoluteFuzzyEqual(_translation(i), 0))
645 return false;
646
647 return true;
648}
649
650void
651MultiAppCoordTransform::skipCoordinateCollapsing(const bool skip_coordinate_collapsing)
652{
653 _skip_coordinate_collapsing = skip_coordinate_collapsing;
654}
655
656void
658{
659 _translation = translation;
660}
InputParameters emptyInputParameters()
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
Real scale
Definition MortarUtils.C:62
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
MooseUnits _length_unit
How much distance one mesh length unit represents, e.g. 1 cm, 1 nm, 1 ft, 5 inches.
std::array< Real, 3 > _euler_angles
The Euler angles describing rotation.
void setCoordinateSystem(Moose::CoordinateSystemType system_type, Direction rz_symmetry_axis=INVALID)
Set our coordinate system.
std::unique_ptr< libMesh::RealTensorValue > _rotate
Represents a forward rotation transformation from our domain to the reference frame domain.
MinimalData minimalDataDescription() const
bool _has_different_coord_sys
Whether we have different coordinate systems within our single domain.
bool hasScalingOrRotationTransformation() const
Returns true if the app has scaling and/or rotation transformation.
Direction processZAxis(Direction z_axis)
If the coordinate system type is RZ, then we return the provided argument.
std::unique_ptr< libMesh::RealTensorValue > _scale
Represents a forward scaling transformation from our units to reference frame units of meters.
Moose::CoordinateSystemType _coord_type
Our coordinate system.
MooseAppCoordTransform()
Default constructor.
void setUpDirection(Direction up_direction)
Will setup a rotation transformation.
Direction _r_axis
If we are RZ or RSPHERICAL, the Cartesian axis corresponding to the radial coordinate.
std::unique_ptr< libMesh::RealTensorValue > _rs_inverse
Represents the inverse of the product of rotation and scaling transformations.
std::unique_ptr< libMesh::RealTensorValue > _rs
Represents the product of rotation and scaling transformations.
void computeRS()
Compute the RS and (RS)^{-1} matrices.
Direction
A class scope enumeration for conveniently denoting X, Y, and Z axis directions.
bool _using_general_rz_coord_axes
Whether general axisymmetric coordinate axes are being used.
Direction _z_axis
If we are RZ, the Cartesian axis corresponding to the axial/axis-of-symmetry coordinate.
static InputParameters validParams()
Describes the parameters this object can take to setup transformations.
MooseAppCoordTransform & operator=(const MooseAppCoordTransform &other)
void setRotation(Real alpha, Real beta, Real gamma)
Setup an \emph extrinsic rotation defined in the following way:
void setLengthUnit(const MooseUnits &length_unit)
Set the scaling transformation.
std::tuple< short int, Real, short int, std::array< Real, 3 >, int, unsigned int, unsigned int, short int, short int, short int > MinimalData
A typedef for conveniency that describes the minimal data necessary to broadcast and build a MooseApp...
bool _mesh_transformed
Whether the mesh has been translated and rotated.
void transformMesh(MooseMesh &mesh, const libMesh::Point &translation)
Transforms the entire mesh with the coordinate transform This can be done to output in position,...
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
MooseMesh wraps a libMesh::Mesh object and enhances its capabilities by caching additional data and s...
Definition MooseMesh.h:95
Physical unit management class with runtime unit string parsing, unit checking, unit conversion,...
Definition Units.h:33
libMesh::Point mapBack(const libMesh::Point &point) const
Inverse transform from the reference space to our space.
MultiAppCoordTransform(const MooseAppCoordTransform &our_app_transform)
libMesh::Point operator()(const libMesh::Point &point) const
Transforms a point from our domain into the reference domain.
libMesh::Point _translation
Describes a forward translation transformation from our domain to the reference frame domain.
void setDestinationCoordTransform(const MooseAppCoordTransform &destination_coord_transform)
Set the destination coordinate system and destination radial and symmetry axes as appropriate for RZ ...
const MooseAppCoordTransform & _our_app_transform
A reference to the MooseAppCoordTransform object that describes scaling, rotation,...
void setTranslationVector(const libMesh::Point &translation)
Set how much our domain should be translated in order to match a reference frame.
bool skipCoordinateCollapsing() const
whether coordinate collapsing operations should be skipped
const MooseAppCoordTransform * _destination_app_transform
A pointer to the MooseAppCoordTransform object that describes scaling, rotation, and coordinate syste...
bool _skip_coordinate_collapsing
whether coordinate collapsing operations should be skipped
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type.
MeshBase & mesh
MOOSE now contains C++17 code, so give a reasonable error message stating what the user can do to add...
static constexpr std::size_t dim
This is the dimension of all vector and tensor datastructures used in MOOSE.
Definition Moose.h:175
CoordinateSystemType
Definition MooseTypes.h:864
@ COORD_RZ
Definition MooseTypes.h:866
@ COORD_RSPHERICAL
Definition MooseTypes.h:867
@ COORD_XYZ
Definition MooseTypes.h:865