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 : #pragma once
11 :
12 : #include "MooseTypes.h"
13 : #include "Units.h"
14 : #include "libmesh/point.h"
15 : #include "libmesh/tensor_value.h"
16 : #include <memory>
17 : #include <string>
18 : #include <array>
19 : #include <tuple>
20 :
21 : class InputParameters;
22 : class MooseMesh;
23 :
24 : class MooseAppCoordTransform
25 : {
26 : public:
27 : /**
28 : * A class scope enumeration for conveniently denoting X, Y, and Z axis directions
29 : */
30 : enum Direction : unsigned int
31 : {
32 : X = 0,
33 : Y,
34 : Z,
35 : INVALID
36 : };
37 :
38 : /**
39 : * A typedef for conveniency that describes the minimal data necessary to broadcast and build a \p
40 : * MooseAppCoordTransform. The data is such:
41 : * 0: whether a scaling matrix exists
42 : * 1: a value describing the scaling
43 : * 2: whether a rotation matrix exists
44 : * 3: the Euler angles describing the rotation
45 : * 4: the coordinate system type
46 : * 5: the r-axis direction
47 : * 6: the z-axis direction
48 : * 7: whether there are multiple coordinate system types on the mesh
49 : * 8: whether general axisymmetric coordinate axes are being used
50 : * 9: whether the mesh has been transformed using the transform
51 : */
52 : typedef std::tuple<short int,
53 : Real,
54 : short int,
55 : std::array<Real, 3>,
56 : int,
57 : unsigned int,
58 : unsigned int,
59 : short int,
60 : short int,
61 : short int>
62 : MinimalData;
63 :
64 : /**
65 : * Default constructor. If no other methods are called to set rotation, translation, or scaling,
66 : * then when \p operator() is called the result will be the passed-in point, e.g. no
67 : * transformation will occur
68 : */
69 : MooseAppCoordTransform();
70 :
71 : MooseAppCoordTransform(const MooseAppCoordTransform & other); // we have unique pointers
72 : MooseAppCoordTransform(MooseAppCoordTransform && other) = default;
73 :
74 : /**
75 : * Construct a coordinate transformation object from the minimal set of data required
76 : */
77 : MooseAppCoordTransform(const MinimalData & minimal_data);
78 :
79 : /**
80 : * Construct this object from the provided mesh and its input parameters. See the \p validParams
81 : * implementation for valid parameters
82 : */
83 : MooseAppCoordTransform(const MooseMesh & mesh);
84 :
85 197959 : ~MooseAppCoordTransform() = default;
86 :
87 : MooseAppCoordTransform &
88 : operator=(const MooseAppCoordTransform & other); // we have unique pointers
89 : MooseAppCoordTransform & operator=(MooseAppCoordTransform && other) = default;
90 :
91 : /**
92 : * Describes the parameters this object can take to setup transformations. These include
93 : * parameters related to coordinate system type, rotation, and scaling
94 : */
95 : static InputParameters validParams();
96 :
97 : /**
98 : * @return the minimal data necessary to describe this coordinate transformation object. This data
99 : * can be broadcast and used to construct identical coordinate transformation objects on other
100 : * processes
101 : */
102 : MinimalData minimalDataDescription() const;
103 :
104 : /**
105 : * @return our coordinate system
106 : */
107 : Moose::CoordinateSystemType coordinateSystem() const { return _coord_type; }
108 :
109 : /**
110 : * Set how much our domain should be translated in order to match a reference frame. In practice
111 : * we choose the parent application to be the reference frame with respect to translation, e.g.
112 : * the parent application origin is the reference frame origin, and we set the translation vectors
113 : * of child applications to the multiapp positions parameter. Similarly to the \p setRotation with
114 : * angles API, this represents a forward transformation from our domain to the reference domain
115 : */
116 : void setTranslationVector(const libMesh::Point & translation);
117 :
118 : /**
119 : * Will setup a rotation transformation. The rotation transformation will be a single 90-degree
120 : * rotation defined such that a point on the axis specified by \p up_direction is rotated onto the
121 : * Y-axis, which is our canonical/reference-frame up-direction
122 : * @param up_direction What direction corresponds to "up" (e.g. the opposite direction of gravity)
123 : * in our moose mesh
124 : */
125 : void setUpDirection(Direction up_direction);
126 :
127 : /**
128 : * Setup an \emph extrinsic rotation defined in the following way:
129 : * 1. rotate by \p alpha degrees about the z-axis
130 : * 2. rotate by \p beta degrees about the x-axis
131 : * 3. rotate by \p gamma degrees about the z-axis
132 : * Definitions of the resulting matrix are found in the last row of the Proper Euler angles column
133 : * of https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix. These rotation angles should
134 : * describe how points in our domain should be rotated in order to arrive back in the reference
135 : * frame. For instance, in 2D your mesh may appear 90 degrees rotated (around the z-axis) with
136 : * respect to the reference frame. In such a case, the angle set you should provide to this
137 : * function is {-90, 0, 0}, e.g. provide forward transformation angles that will map points from
138 : * your domain to the reference domain
139 : *
140 : * If our coordinate system is RZ, then only certain values of alpha, beta, and gamma will be
141 : * accepted such that the radial and axial coordinates are rotated onto Cartesian axes and the
142 : * resulting radial coordinate is non-negative
143 : */
144 : void setRotation(Real alpha, Real beta, Real gamma);
145 :
146 : /**
147 : * Set the scaling transformation
148 : * @param length_unit How much distance one mesh length unit represents, e.g. 1 cm, 1 nm, 1 ft, 5
149 : * inches. We will save off the value provided to this in the \p _length_unit data member as well
150 : * as set the scaling transform
151 : */
152 : void setLengthUnit(const MooseUnits & length_unit);
153 :
154 : /**
155 : * @return How much distance one mesh length unit represents, e.g. 1 cm, 1 nm, 1 ft, 5
156 : * inches
157 : */
158 1 : const MooseUnits & lengthUnit() const { return _length_unit; }
159 :
160 : /**
161 : * Set our coordinate system
162 : * @param system_type the coordinate system type
163 : * @param rz_symmetry_axis the axial coordinate, e.g. the axis of symmetry
164 : */
165 : void setCoordinateSystem(Moose::CoordinateSystemType system_type,
166 : Direction rz_symmetry_axis = INVALID);
167 :
168 : /**
169 : * Set our coordinate system based on the MooseMesh coordinate system data
170 : */
171 : void setCoordinateSystem(const MooseMesh & mesh);
172 :
173 : /**
174 : * Compute the RS and (RS)^{-1} matrices
175 : */
176 : void computeRS();
177 :
178 : /**
179 : * Transforms the entire mesh with the coordinate transform
180 : * This can be done to output in position, or to avoid transforming on every data point
181 : * @param mesh the mesh to modify, usually the child app mesh
182 : * @param translation the translation to apply to the mesh, often the app position
183 : */
184 : void transformMesh(MooseMesh & mesh, const libMesh::Point & translation);
185 :
186 : /**
187 : * Returns true if the app has scaling and/or rotation transformation
188 : */
189 : bool hasScalingOrRotationTransformation() const;
190 :
191 : private:
192 : /**
193 : * If the coordinate system type is RZ, then we return the provided argument. Otherwise we return
194 : * INVALID
195 : */
196 : Direction processZAxis(Direction z_axis);
197 :
198 : /// Represents a forward scaling transformation from our units to reference frame units of meters. This
199 : /// matrix will be diagonal
200 : std::unique_ptr<libMesh::RealTensorValue> _scale;
201 :
202 : /// Represents a forward rotation transformation from our domain to the reference frame domain
203 : std::unique_ptr<libMesh::RealTensorValue> _rotate;
204 :
205 : /// Represents the product of rotation and scaling transformations
206 : std::unique_ptr<libMesh::RealTensorValue> _rs;
207 :
208 : /// Represents the inverse of the product of rotation and scaling transformations
209 : std::unique_ptr<libMesh::RealTensorValue> _rs_inverse;
210 :
211 : /// Our coordinate system
212 : Moose::CoordinateSystemType _coord_type;
213 : /// If we are RZ or RSPHERICAL, the Cartesian axis corresponding to the radial coordinate
214 : Direction _r_axis;
215 : /// If we are RZ, the Cartesian axis corresponding to the axial/axis-of-symmetry coordinate
216 : Direction _z_axis;
217 :
218 : /// Whether we have different coordinate systems within our single domain. If we do, this will be
219 : /// problematic if we need to collapse from our space into an RZ or RSPHERICAL space because we
220 : /// are only ever provided with a point argument and not a subdomain ID argument. Consequently we
221 : /// will not know in what coordinate system our point lies and will not know how to perform the
222 : /// dimension collapse, and so we will error
223 : bool _has_different_coord_sys;
224 :
225 : /// Whether general axisymmetric coordinate axes are being used
226 : bool _using_general_rz_coord_axes;
227 :
228 : /// How much distance one mesh length unit represents, e.g. 1 cm, 1 nm, 1 ft, 5 inches
229 : MooseUnits _length_unit;
230 :
231 : /// The Euler angles describing rotation
232 : std::array<Real, 3> _euler_angles;
233 :
234 : /// Whether the mesh has been translated and rotated. In this case, applying the transform every
235 : /// time is no longer necessary
236 : bool _mesh_transformed;
237 :
238 : friend class MultiAppCoordTransform;
239 : };
240 :
241 : /**
242 : * This class contains transformation information that only exists in a context in which there are
243 : * multiple applications. Such information includes translation and coordinate collapsing
244 : */
245 : class MultiAppCoordTransform
246 : {
247 : public:
248 : explicit MultiAppCoordTransform(const MooseAppCoordTransform & our_app_transform);
249 :
250 : /**
251 : * Transforms a point from our domain into the reference domain. The sequence of transformations
252 : * applied is:
253 : * 1. Scaling
254 : * 2. Rotation
255 : * 3. Translation
256 : * 4. Potential collapse of XYZ coordinates into RZ or RSPHERICAL coordinates depending on the
257 : * destination coordinate system (if there is no destination coordinate system or the
258 : * destination coordinate system is XYZ, then nothing happens in this stage)
259 : * @param point A point in our domain
260 : * @return The corresponding position in the reference domain
261 : */
262 : libMesh::Point operator()(const libMesh::Point & point) const;
263 :
264 : /**
265 : * Inverse transform from the reference space to our space. This will error if coordinate
266 : * collapsing would occur in \p operator(). When doing inversion we invert the order of
267 : * operations, e.g. we will perform
268 : * 1. invert translation
269 : * 2. invert rotation
270 : * 3. invert scaling
271 : */
272 : libMesh::Point mapBack(const libMesh::Point & point) const;
273 :
274 : /**
275 : * Set how much our domain should be translated in order to match a reference frame. In practice
276 : * we choose the parent application to be the reference frame with respect to translation, e.g.
277 : * the parent application origin is the reference frame origin, and we set the translation vectors
278 : * of child applications to the multiapp positions parameter. Similarly to the \p setRotation with
279 : * angles API, this represents a forward transformation from our domain to the reference domain
280 : */
281 : void setTranslationVector(const libMesh::Point & translation);
282 :
283 : /**
284 : * Set the destination coordinate system and destination radial and symmetry axes as appropriate
285 : * for RZ or RSPHERICAL simulations. Depending on the coordinate system type of the provided
286 : * coordinate transform we may perform additional transformations. For instance if the destination
287 : * coordinate system is RZ and we are XYZ, we will translate our xyz points into RZ points, e.g.
288 : * we will collapse from three dimensions into two. The transformation would be non-unique if we
289 : * were to attempt to go from RZ to XYZ, e.g. a single RZ point could correspond to any point in a
290 : * 2pi rotation around the symmetry axis
291 : */
292 : void setDestinationCoordTransform(const MooseAppCoordTransform & destination_coord_transform);
293 :
294 : /**
295 : * @return whether the coordinate transformation object modifies an incoming point, e.g. whether
296 : * the transformation is anything other than the identity matrix
297 : */
298 : bool isIdentity() const;
299 :
300 : /**
301 : * @return whether there are any transformations other than translation in the transform. We have
302 : * this method because translation has always been supported natively by the multiapp transfer
303 : * system through the 'positions' parameter
304 : */
305 : bool hasNonTranslationTransformation() const;
306 :
307 : /**
308 : * @return whether there are any coordinate system type change because the mapping back from RZ
309 : * to XYZ for example is non-unique and would error
310 : */
311 : bool hasCoordinateSystemTypeChange() const;
312 :
313 : /**
314 : * @return our coordinate system
315 : */
316 : Moose::CoordinateSystemType coordinateSystem() const { return _our_app_transform._coord_type; }
317 :
318 : /**
319 : * set whether coordinate collapsing operations should be skipped
320 : */
321 : void skipCoordinateCollapsing(bool skip_coordinate_collapsing);
322 :
323 : /**
324 : * whether coordinate collapsing operations should be skipped
325 : */
326 284525 : bool skipCoordinateCollapsing() const { return _skip_coordinate_collapsing; }
327 :
328 : /**
329 : * @return our moose-app coordinate transformation object
330 : */
331 : const MooseAppCoordTransform & ourAppTransform() const { return _our_app_transform; }
332 :
333 : private:
334 : /// A reference to the \p MooseAppCoordTransform object that describes scaling, rotation, and
335 : /// coordinate system transformations from our domain to the reference domain,
336 : /// e.g. transformations that occur irrespective of the existence of other applications
337 : const MooseAppCoordTransform & _our_app_transform;
338 :
339 : /// A pointer to the \p MooseAppCoordTransform object that describes scaling, rotation, and
340 : /// coordinate system transformations from the destination domain to the reference domain,
341 : /// e.g. transformations that occur irrespective of the existence of other applications
342 : /// This attribute is currently mostly providing only the coordinate system for conversions
343 : /// and sanity checking. The actual transformation of destination app points in transfers is done
344 : /// by the MultiAppCoordTransform for the other direction
345 : const MooseAppCoordTransform * _destination_app_transform;
346 :
347 : /// Describes a forward translation transformation from our domain to the reference frame domain
348 : libMesh::Point _translation;
349 :
350 : /// whether coordinate collapsing operations should be skipped
351 : bool _skip_coordinate_collapsing;
352 : };
|