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

Generated by: LCOV version 1.14