LCOV - code coverage report
Current view: top level - include/utils - MooseAppCoordTransform.h (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 3 3 100.0 %
Date: 2025-07-17 01:28:37 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          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             : };

Generated by: LCOV version 1.14