LCOV - code coverage report
Current view: top level - src/utils - MooseAppCoordTransform.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 326 356 91.6 %
Date: 2026-05-29 20:35:17 Functions: 24 25 96.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             : #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           8 : MooseAppCoordTransform::processZAxis(const Direction z_axis)
      21             : {
      22           8 :   return _coord_type == Moose::COORD_RZ ? z_axis : INVALID;
      23             : }
      24             : 
      25             : void
      26          12 : MooseAppCoordTransform::setUpDirection(const Direction up_direction)
      27             : {
      28          12 :   Real alpha = 0, beta = 0, gamma = 0;
      29             : 
      30          12 :   const bool must_rotate_axes =
      31          12 :       _coord_type == Moose::COORD_RZ || _coord_type == Moose::COORD_RSPHERICAL;
      32             :   // Don't error immediately for unit testing purposes
      33          12 :   bool negative_radii = false;
      34             : 
      35          12 :   if (up_direction == X)
      36             :   {
      37           4 :     alpha = 90, beta = 0, gamma = 0;
      38           4 :     if (must_rotate_axes)
      39             :     {
      40           4 :       if (_r_axis == X)
      41             :       {
      42           2 :         _r_axis = Y;
      43           2 :         _z_axis = processZAxis(X);
      44             :       }
      45           2 :       else if (_r_axis == Y)
      46             :       {
      47           2 :         negative_radii = true;
      48           2 :         _r_axis = X;
      49           2 :         _z_axis = processZAxis(Y);
      50             :       }
      51             :       else
      52           0 :         mooseError("Bad r-axis value");
      53             :     }
      54             :   }
      55           8 :   else if (up_direction == Y)
      56           4 :     alpha = 0, beta = 0, gamma = 0;
      57           4 :   else if (up_direction == Z)
      58             :   {
      59           4 :     alpha = 0, beta = -90, gamma = 0;
      60           4 :     if (must_rotate_axes)
      61             :     {
      62           4 :       if (_r_axis == X)
      63             :       {
      64           2 :         _r_axis = X;
      65           2 :         _z_axis = processZAxis(Z);
      66             :       }
      67           2 :       else if (_r_axis == Y)
      68             :       {
      69           2 :         negative_radii = true;
      70           2 :         _r_axis = Z;
      71           2 :         _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          12 :   _euler_angles = {{alpha, beta, gamma}};
      81             : 
      82          24 :   _rotate = std::make_unique<RealTensorValue>(
      83          36 :       RealTensorValue::extrinsic_rotation_matrix(alpha, beta, gamma));
      84          12 :   computeRS();
      85             : 
      86          12 :   if (negative_radii)
      87           4 :     mooseError("Rotation yields negative radial values");
      88           8 : }
      89             : 
      90             : void
      91         305 : MooseAppCoordTransform::setRotation(const Real alpha, const Real beta, const Real gamma)
      92             : {
      93         305 :   const bool must_rotate_axes =
      94         305 :       _coord_type == Moose::COORD_RZ || _coord_type == Moose::COORD_RSPHERICAL;
      95         305 :   bool axes_rotated = false;
      96         305 :   if (must_rotate_axes)
      97             :   {
      98          28 :     const auto angles = std::make_tuple(alpha, beta, gamma);
      99          28 :     if (angles == std::make_tuple(0, 90, 0))
     100             :     {
     101          26 :       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           2 :       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           2 :         _r_axis = Z;
     115           2 :         _z_axis = _coord_type == Moose::COORD_RZ ? X : INVALID;
     116             :       }
     117          26 :       axes_rotated = true;
     118             :     }
     119             :   }
     120             : 
     121         305 :   _euler_angles = {{alpha, beta, gamma}};
     122         610 :   _rotate = std::make_unique<RealTensorValue>(
     123         915 :       RealTensorValue::extrinsic_rotation_matrix(alpha, beta, gamma));
     124         305 :   computeRS();
     125             : 
     126         305 :   if (must_rotate_axes && !axes_rotated)
     127           2 :     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         303 : }
     131             : 
     132             : void
     133         178 : MooseAppCoordTransform::setLengthUnit(const MooseUnits & length_unit)
     134             : {
     135         178 :   _length_unit = length_unit;
     136         178 :   const auto scale = Real(_length_unit / MooseUnits("m"));
     137             :   _scale =
     138         178 :       std::make_unique<RealTensorValue>(RealTensorValue(scale, 0, 0, 0, scale, 0, 0, 0, scale));
     139         178 :   computeRS();
     140         178 : }
     141             : 
     142             : void
     143       67327 : MooseAppCoordTransform::setCoordinateSystem(const Moose::CoordinateSystemType coord_type,
     144             :                                             const Direction rz_symmetry_axis)
     145             : {
     146       67327 :   _coord_type = coord_type;
     147             : 
     148       67327 :   if (_coord_type == Moose::COORD_RZ)
     149             :   {
     150         500 :     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         500 :     _z_axis = rz_symmetry_axis;
     155         500 :     _r_axis = _z_axis == X ? Y : X;
     156             :   }
     157       66827 :   else if (_coord_type == Moose::COORD_RSPHERICAL)
     158          68 :     _r_axis = X;
     159       67327 : }
     160             : 
     161             : void
     162       67305 : MooseAppCoordTransform::setCoordinateSystem(const MooseMesh & mesh)
     163             : {
     164       67305 :   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       67305 :   const auto & coord_sys = mesh.getCoordSystem();
     170       67305 :   std::unordered_set<Moose::CoordinateSystemType> coord_types;
     171       67305 :   auto map_it = coord_sys.begin();
     172             :   // It's possible that the mesh is not in a complete state
     173       67305 :   if (map_it == coord_sys.end())
     174        2040 :     setCoordinateSystem(Moose::COORD_XYZ);
     175             :   else
     176      130530 :     setCoordinateSystem(
     177       65265 :         map_it->second,
     178      130530 :         Direction(static_cast<unsigned int>(int(params.get<MooseEnum>("rz_coord_axis")))));
     179      158699 :   for (; map_it != coord_sys.end(); ++map_it)
     180       91394 :     coord_types.insert(map_it->second);
     181             : 
     182       67305 :   _has_different_coord_sys = coord_types.size() > 1;
     183             : 
     184       67305 :   if (mesh.usingGeneralAxisymmetricCoordAxes())
     185          17 :     _using_general_rz_coord_axes = true;
     186       67305 : }
     187             : 
     188             : InputParameters
     189      199641 : MooseAppCoordTransform::validParams()
     190             : {
     191      199641 :   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     1197846 :   params.addDeprecatedParam<std::vector<SubdomainName>>(
     198             :       "block",
     199             :       "Block IDs for the coordinate systems.",
     200             :       "Please use the 'coord_block' parameter instead.");
     201      798564 :   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      399282 :   MultiMooseEnum coord_types("XYZ RZ RSPHERICAL", "XYZ");
     206      798564 :   MooseEnum rz_coord_axis("X=0 Y=1", "Y");
     207      798564 :   params.addParam<MultiMooseEnum>(
     208             :       "coord_type", coord_types, "Type of the coordinate system per block param");
     209      798564 :   params.addParam<MooseEnum>(
     210             :       "rz_coord_axis", rz_coord_axis, "The rotation axis (X | Y) for axisymmetric coordinates");
     211      798564 :   params.addParam<std::vector<SubdomainName>>(
     212             :       "rz_coord_blocks", "Blocks using general axisymmetric coordinate systems");
     213      798564 :   params.addParam<std::vector<Point>>("rz_coord_origins",
     214             :                                       "Axis origin points for each block in 'rz_coord_blocks'");
     215      798564 :   params.addParam<std::vector<RealVectorValue>>(
     216             :       "rz_coord_directions", "Axis directions for each block in 'rz_coord_blocks'");
     217      798564 :   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     1197846 :   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     1197846 :   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     1197846 :   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      798564 :   MooseEnum up_direction("X=0 Y=1 Z=2");
     239      798564 :   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      798564 :   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      598923 :   params.addParamNamesToGroup(
     254             :       "length_unit alpha_rotation beta_rotation gamma_rotation up_direction",
     255             :       "Transformations relative to parent application frame of reference");
     256      399282 :   return params;
     257      199641 : }
     258             : 
     259       67284 : MooseAppCoordTransform::MooseAppCoordTransform(const MooseMesh & mesh)
     260       67284 :   : _coord_type(Moose::COORD_XYZ),
     261       67284 :     _r_axis(INVALID),
     262       67284 :     _z_axis(INVALID),
     263       67284 :     _has_different_coord_sys(false),
     264       67284 :     _using_general_rz_coord_axes(false),
     265      134568 :     _length_unit(std::string("1*m")),
     266      201852 :     _euler_angles(),
     267       67284 :     _mesh_transformed(false)
     268             : {
     269             :   //
     270             :   // Coordinate system transformation
     271             :   //
     272       67284 :   setCoordinateSystem(mesh);
     273             : 
     274       67284 :   const auto & params = mesh.parameters();
     275             : 
     276             :   //
     277             :   // Rotation
     278             :   //
     279      134568 :   const bool has_alpha = params.isParamValid("alpha_rotation");
     280      134568 :   const bool has_beta = params.isParamValid("beta_rotation");
     281       67284 :   const bool has_gamma = params.isParamValid("gamma_rotation");
     282       67284 :   const auto & up_direction = params.get<MooseEnum>("up_direction");
     283             : 
     284       67284 :   if (has_alpha || has_beta || has_gamma)
     285             :   {
     286         301 :     if (up_direction.isValid())
     287           0 :       mooseError("Cannot simultaneously set rotation angles as well as an up direction");
     288             : 
     289         301 :     const auto alpha = (has_alpha ? params.get<Real>("alpha_rotation") : Real(0));
     290         301 :     const auto beta = (has_beta ? params.get<Real>("beta_rotation") : Real(0));
     291         301 :     const auto gamma = (has_gamma ? params.get<Real>("gamma_rotation") : Real(0));
     292             : 
     293         301 :     setRotation(alpha, beta, gamma);
     294         301 :   }
     295       66983 :   else if (up_direction.isValid())
     296           0 :     setUpDirection(Direction(static_cast<unsigned int>(int(up_direction))));
     297             : 
     298             :   //
     299             :   // Scaling
     300             :   //
     301      134568 :   if (params.isParamValid("length_unit"))
     302          81 :     setLengthUnit(MooseUnits(params.get<std::string>("length_unit")));
     303       67284 : }
     304             : 
     305           8 : MooseAppCoordTransform::MooseAppCoordTransform()
     306           8 :   : _coord_type(Moose::COORD_XYZ),
     307           8 :     _r_axis(INVALID),
     308           8 :     _z_axis(INVALID),
     309           8 :     _has_different_coord_sys(false),
     310           8 :     _using_general_rz_coord_axes(false),
     311          16 :     _length_unit(std::string("1*m")),
     312          24 :     _euler_angles(),
     313           8 :     _mesh_transformed(false)
     314             : {
     315           8 : }
     316             : 
     317           2 : MooseAppCoordTransform::MooseAppCoordTransform(const MooseAppCoordTransform & other)
     318           2 :   : _coord_type(other._coord_type),
     319           2 :     _r_axis(other._r_axis),
     320           2 :     _z_axis(other._z_axis),
     321           2 :     _has_different_coord_sys(other._has_different_coord_sys),
     322           2 :     _using_general_rz_coord_axes(other._using_general_rz_coord_axes),
     323           2 :     _length_unit(other._length_unit),
     324           2 :     _euler_angles(other._euler_angles),
     325           2 :     _mesh_transformed(other._mesh_transformed)
     326             : {
     327           2 :   if (other._scale)
     328           0 :     _scale = std::make_unique<RealTensorValue>(*other._scale);
     329           2 :   if (other._rotate)
     330           2 :     _rotate = std::make_unique<RealTensorValue>(*other._rotate);
     331           2 :   computeRS();
     332           2 : }
     333             : 
     334      131246 : MooseAppCoordTransform::MooseAppCoordTransform(const MinimalData & minimal_data)
     335      131246 :   : _coord_type(static_cast<Moose::CoordinateSystemType>(std::get<4>(minimal_data))),
     336      131246 :     _r_axis(static_cast<Direction>(std::get<5>(minimal_data))),
     337      131246 :     _z_axis(static_cast<Direction>(std::get<6>(minimal_data))),
     338      131246 :     _has_different_coord_sys(std::get<7>(minimal_data)),
     339      131246 :     _using_general_rz_coord_axes(std::get<8>(minimal_data)),
     340      262492 :     _length_unit(std::string("1*m")),
     341      131246 :     _euler_angles(std::get<3>(minimal_data)),
     342      262492 :     _mesh_transformed(std::get<9>(minimal_data))
     343             : {
     344      131246 :   if (std::get<0>(minimal_data))
     345          97 :     setLengthUnit(MooseUnits(std::to_string(std::get<1>(minimal_data)) + "*m"));
     346      131246 :   if (std::get<2>(minimal_data))
     347        2502 :     _rotate = std::make_unique<RealTensorValue>(RealTensorValue::extrinsic_rotation_matrix(
     348        2502 :         _euler_angles[0], _euler_angles[1], _euler_angles[2]));
     349      131246 :   computeRS();
     350      131246 : }
     351             : 
     352             : MooseAppCoordTransform::MinimalData
     353       95472 : MooseAppCoordTransform::minimalDataDescription() const
     354             : {
     355       95472 :   const Real scale_factor = _scale ? (*_scale)(0, 0) : 1;
     356       95472 :   return {static_cast<short int>(bool(_scale)),
     357             :           scale_factor,
     358       95472 :           static_cast<short int>(bool(_rotate)),
     359       95472 :           _euler_angles,
     360      190944 :           static_cast<int>(_coord_type),
     361      190944 :           static_cast<unsigned int>(_r_axis),
     362      190944 :           static_cast<unsigned int>(_z_axis),
     363      190944 :           static_cast<short int>(_has_different_coord_sys),
     364      190944 :           static_cast<short int>(_using_general_rz_coord_axes),
     365       95472 :           static_cast<short int>(_mesh_transformed)};
     366             : }
     367             : 
     368             : MooseAppCoordTransform &
     369           2 : MooseAppCoordTransform::operator=(const MooseAppCoordTransform & other)
     370             : {
     371           2 :   _coord_type = other._coord_type;
     372           2 :   _r_axis = other._r_axis;
     373           2 :   _z_axis = other._z_axis;
     374           2 :   _has_different_coord_sys = other._has_different_coord_sys;
     375           2 :   _using_general_rz_coord_axes = other._using_general_rz_coord_axes;
     376           2 :   _length_unit = other._length_unit;
     377           2 :   _euler_angles = other._euler_angles;
     378           2 :   _mesh_transformed = other._mesh_transformed;
     379             : 
     380           2 :   if (other._scale)
     381           0 :     _scale = std::make_unique<RealTensorValue>(*other._scale);
     382             :   else
     383           2 :     _scale.reset();
     384           2 :   if (other._rotate)
     385           2 :     _rotate = std::make_unique<RealTensorValue>(*other._rotate);
     386             :   else
     387           0 :     _rotate.reset();
     388             : 
     389           2 :   computeRS();
     390             : 
     391           2 :   return *this;
     392             : }
     393             : 
     394             : void
     395      131745 : MooseAppCoordTransform::computeRS()
     396             : {
     397      131745 :   if (_scale || _rotate)
     398             :   {
     399        1750 :     _rs = std::make_unique<RealTensorValue>(RealTensorValue(1, 0, 0, 0, 1, 0, 0, 0, 1));
     400             : 
     401        1750 :     if (_scale)
     402         275 :       *_rs = *_scale * *_rs;
     403        1750 :     if (_rotate)
     404        1650 :       *_rs = *_rotate * *_rs;
     405             : 
     406        1750 :     _rs_inverse = std::make_unique<RealTensorValue>(_rs->inverse());
     407             :   }
     408             :   else
     409             :   {
     410      129995 :     _rs.reset();
     411      129995 :     _rs_inverse.reset();
     412             :   }
     413      131745 : }
     414             : 
     415             : void
     416         246 : MooseAppCoordTransform::transformMesh(MooseMesh & mesh, const Point & translation)
     417             : {
     418             :   // Transforming a RZ or R-spherical mesh doesnt always make sense, disallow it
     419         246 :   if (_coord_type != Moose::COORD_XYZ)
     420           3 :     mooseError("Running MultiApps 'in position' is only supported for XYZ coordinate systems");
     421             : 
     422         243 :   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         243 :   if (_mesh_transformed)
     427           0 :     mooseError("App mesh is being transformed twice");
     428             : 
     429             :   // Apply all the transformation to the mesh
     430         243 :   if (_scale)
     431          12 :     MeshTools::Modification::scale(mesh, (*_scale)(0, 0), (*_scale)(1, 1), (*_scale)(2, 2));
     432         243 :   if (_rotate)
     433          12 :     MeshTools::Modification::rotate(mesh, _euler_angles[0], _euler_angles[1], _euler_angles[2]);
     434         243 :   if (translation != Point(0, 0, 0))
     435         243 :     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         243 :   _mesh_transformed = true;
     440         243 : }
     441             : 
     442             : bool
     443      191000 : MooseAppCoordTransform::hasScalingOrRotationTransformation() const
     444             : {
     445      191000 :   if (_rs)
     446        1640 :     for (const auto i : make_range(Moose::dim))
     447        2016 :       for (const auto j : make_range(Moose::dim))
     448             :       {
     449        1922 :         const auto matrix_elem = (*_rs)(i, j);
     450        1922 :         if (i == j)
     451             :         {
     452        1640 :           if (!MooseUtils::absoluteFuzzyEqual(matrix_elem, 1))
     453        1546 :             return true;
     454             :         }
     455         282 :         else if (!MooseUtils::absoluteFuzzyEqual(matrix_elem, 0))
     456           0 :           return true;
     457             :       }
     458             : 
     459      189454 :   return false;
     460             : }
     461             : 
     462      154357 : MultiAppCoordTransform::MultiAppCoordTransform(const MooseAppCoordTransform & our_app_transform)
     463      154357 :   : _our_app_transform(our_app_transform),
     464      154357 :     _destination_app_transform(nullptr),
     465      154357 :     _skip_coordinate_collapsing(false)
     466             : {
     467      154357 : }
     468             : 
     469             : Point
     470    49027250 : MultiAppCoordTransform::operator()(const Point & point) const
     471             : {
     472             :   mooseAssert(_destination_app_transform, "The destination application transform must be set");
     473             : 
     474    49027250 :   Point ret(point);
     475             : 
     476             :   // Translation, rotation and scaling already applied, coordinate system conversion not supported
     477    49027250 :   if (_our_app_transform._mesh_transformed)
     478      854336 :     return ret;
     479             : 
     480             :   // Apply scaling and then rotation
     481    48172914 :   if (_our_app_transform._rs)
     482      919028 :     ret = (*_our_app_transform._rs) * ret;
     483             : 
     484             :   // If this shows up in profiling we can make _translation a pointer
     485    48172914 :   ret += _translation;
     486             : 
     487    48172914 :   if (_skip_coordinate_collapsing)
     488    48117274 :     return ret;
     489             : 
     490             :   // Finally, coordinate system conversions
     491       55640 :   if (_our_app_transform._coord_type == Moose::COORD_XYZ &&
     492       29972 :       _destination_app_transform->_coord_type == Moose::COORD_RZ)
     493             :   {
     494       29970 :     Real r_squared = 0;
     495      119880 :     for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
     496       89910 :       if (i != _destination_app_transform->_z_axis)
     497       59940 :         r_squared += ret(i) * ret(i);
     498             : 
     499       29970 :     const auto r = std::sqrt(r_squared);
     500       29970 :     const auto z = ret(_destination_app_transform->_z_axis);
     501       29970 :     ret = 0;
     502       29970 :     ret(_destination_app_transform->_r_axis) = r;
     503       29970 :     ret(_destination_app_transform->_z_axis) = z;
     504       29970 :   }
     505       25670 :   else if (_our_app_transform._coord_type == Moose::COORD_XYZ &&
     506           2 :            _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL)
     507             :   {
     508           2 :     Real r_squared = 0;
     509           8 :     for (unsigned int i = 0; i < LIBMESH_DIM; ++i)
     510           6 :       r_squared += ret(i) * ret(i);
     511             : 
     512           2 :     const auto r = std::sqrt(r_squared);
     513           2 :     ret = 0;
     514           2 :     ret(_destination_app_transform->_r_axis) = r;
     515           2 :   }
     516       25668 :   else if (_our_app_transform._coord_type == Moose::COORD_RZ &&
     517       25668 :            _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL)
     518             :   {
     519           2 :     Real r_squared = 0;
     520           8 :     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           6 :       r_squared += ret(i) * ret(i);
     527             :     }
     528             : 
     529           2 :     const auto r = std::sqrt(r_squared);
     530           2 :     ret = 0;
     531           2 :     ret(_destination_app_transform->_r_axis) = r;
     532             :   }
     533             : 
     534       55640 :   return ret;
     535             : }
     536             : 
     537             : Point
     538     1842497 : MultiAppCoordTransform::mapBack(const Point & point) const
     539             : {
     540     1842497 :   Point ret(point);
     541             : 
     542             :   // Translation, rotation and scaling already applied, coordinate system conversion not supported
     543     1842497 :   if (_our_app_transform._mesh_transformed)
     544           0 :     return ret;
     545             : 
     546             :   // inverse translate
     547     1842497 :   ret -= _translation;
     548             : 
     549             :   // inverse rotate and then inverse scale
     550     1842497 :   if (_our_app_transform._rs_inverse)
     551       30786 :     ret = (*_our_app_transform._rs_inverse) * ret;
     552             : 
     553     1842497 :   if (_skip_coordinate_collapsing)
     554     1842491 :     return ret;
     555             : 
     556             :   // Finally, coordinate system conversions
     557           6 :   if ((_our_app_transform._coord_type == Moose::COORD_XYZ &&
     558           4 :        (_destination_app_transform->_coord_type == Moose::COORD_RZ ||
     559           2 :         _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL)) ||
     560           2 :       (_our_app_transform._coord_type == Moose::COORD_RZ &&
     561           2 :        _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL))
     562           6 :     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      154348 : MultiAppCoordTransform::setDestinationCoordTransform(
     570             :     const MooseAppCoordTransform & destination_app_transform)
     571             : {
     572      154348 :   _destination_app_transform = &destination_app_transform;
     573             : 
     574      154348 :   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      154348 :   if (_skip_coordinate_collapsing)
     582      154200 :     return;
     583             : 
     584         148 :   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         148 :   if ((_destination_app_transform->_coord_type == Moose::COORD_RZ ||
     594          76 :        _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL) &&
     595          76 :       _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         148 :   if (_our_app_transform._using_general_rz_coord_axes ||
     603         148 :       _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      131246 : MultiAppCoordTransform::hasNonTranslationTransformation() const
     610             : {
     611      131246 :   if (_our_app_transform.hasScalingOrRotationTransformation())
     612        1245 :     return true;
     613             : 
     614      130001 :   if (_skip_coordinate_collapsing)
     615      129925 :     return false;
     616             : 
     617          76 :   if (hasCoordinateSystemTypeChange())
     618          76 :     return true;
     619             : 
     620           0 :   return false;
     621             : }
     622             : 
     623             : bool
     624      943560 : MultiAppCoordTransform::hasCoordinateSystemTypeChange() const
     625             : {
     626      943560 :   if (_skip_coordinate_collapsing)
     627      943484 :     return false;
     628             : 
     629          76 :   if ((_our_app_transform._coord_type == Moose::COORD_XYZ &&
     630          74 :        (_destination_app_transform->_coord_type == Moose::COORD_RZ ||
     631           2 :         _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL)) ||
     632           2 :       (_our_app_transform._coord_type == Moose::COORD_RZ &&
     633           2 :        _destination_app_transform->_coord_type == Moose::COORD_RSPHERICAL))
     634          76 :     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      154349 : MultiAppCoordTransform::skipCoordinateCollapsing(const bool skip_coordinate_collapsing)
     654             : {
     655      154349 :   _skip_coordinate_collapsing = skip_coordinate_collapsing;
     656      154349 : }
     657             : 
     658             : void
     659       91369 : MultiAppCoordTransform::setTranslationVector(const Point & translation)
     660             : {
     661       91369 :   _translation = translation;
     662       91369 : }

Generated by: LCOV version 1.14