SpECTRE  v2024.04.12
domain::CoordinateMaps::FocallyLiftedMapHelpers Namespace Reference

Holds helper functions for use with domain::CoordinateMaps::FocallyLiftedMap. More...

Functions

template<typename T >
void scale_factor (const gsl::not_null< tt::remove_cvref_wrap_t< T > * > &result, const std::array< T, 3 > &src_point, const std::array< double, 3 > &proj_center, const std::array< double, 3 > &sphere_center, double radius, bool src_is_between_proj_and_target)
 Finds how long to extend a line segment to have it intersect a point on a 2-sphere. More...
 
std::optional< double > try_scale_factor (const std::array< double, 3 > &src_point, const std::array< double, 3 > &proj_center, const std::array< double, 3 > &sphere_center, double radius, bool pick_larger_root, bool pick_root_greater_than_one, bool solve_for_root_minus_one=true)
 
template<typename T >
void d_scale_factor_d_src_point (const gsl::not_null< std::array< tt::remove_cvref_wrap_t< T >, 3 > * > &result, const std::array< T, 3 > &intersection_point, const std::array< double, 3 > &proj_center, const std::array< double, 3 > &sphere_center, const T &lambda)
 

Detailed Description

Holds helper functions for use with domain::CoordinateMaps::FocallyLiftedMap.

Function Documentation

◆ d_scale_factor_d_src_point()

template<typename T >
void domain::CoordinateMaps::FocallyLiftedMapHelpers::d_scale_factor_d_src_point ( const gsl::not_null< std::array< tt::remove_cvref_wrap_t< T >, 3 > * > &  result,
const std::array< T, 3 > &  intersection_point,
const std::array< double, 3 > &  proj_center,
const std::array< double, 3 > &  sphere_center,
const T &  lambda 
)

Computes \(\partial \lambda/\partial x_0^i\), where \(\lambda\) is the quantity returned by scale_factor and x_0 is src_point in the scale_factor function.

The formula (see FocallyLiftedMap) is

\begin{align*} \frac{\partial\lambda}{\partial x_0^j} &= \lambda^2 \frac{C_j - x_1^j}{|x_1^i - P^i|^2 + (x_1^i - P^i)(P_i - C_i)}. \end{align*}

Note that it takes intersection_point and not src_point as a parameter.

In the arguments to the function below, intersection_point is \(x_1\), proj_center is \(P^i\), sphere_center is \(C^i\), and radius is \(R\).

◆ scale_factor()

template<typename T >
void domain::CoordinateMaps::FocallyLiftedMapHelpers::scale_factor ( const gsl::not_null< tt::remove_cvref_wrap_t< T > * > &  result,
const std::array< T, 3 > &  src_point,
const std::array< double, 3 > &  proj_center,
const std::array< double, 3 > &  sphere_center,
double  radius,
bool  src_is_between_proj_and_target 
)

Finds how long to extend a line segment to have it intersect a point on a 2-sphere.

Details

Consider a 2-sphere with center \(C^i\) and radius \(R\), and and let \(P^i\) and \(x_0^i\) be two arbitrary 3D points.

Consider the line passing through \(P^i\) and \(x_0^i\). If this line intersects the sphere at a point \(x_1^i\), then we can write

\[ x_1^i = P^i + (x_0^i-P^i) \lambda, \]

where \(\lambda\) is a scale factor.

scale_factor computes and returns \(\lambda\).

Even more detail:

To solve for \(\lambda\), we note that \(x_1^i\) is on the surface of the sphere, so

\[ |x_1^i-C^i|^2 = R^2, \]

(where \(|A^i|^2\) means \(\delta_{ij} A^i A^j\)),

or equivalently

\[ | P^i-C^i + (x_0^i-P^i)\lambda |^2 = R^2. \]

This is a quadratic equation for \(\lambda\) and it generally has more than one real root. It takes the usual form \(a\lambda^2+b\lambda+c=0\), with

\begin{align*} a &= |x_0^i-P^i|^2,\\ b &= 2(x_0^i-P^i)(P^j-C^j)\delta_{ij},\\ c &= |P^i-C^i|^2 - R^2, \end{align*}

So how do we choose between multiple roots? Some of the maps that use scale_factor assume that for all points, \(x_0^i\) is between \(P^i\) and \(x_1^i\). Those maps should set the parameter src_is_between_proj_and_target to true. Other maps assume that for all points, \(x^i\) is always between \(x_0^i\) and \(P^i\). Those maps should set the parameter src_is_between_proj_and_target to false.

Warning
If we ever add maps where src_is_between_proj_and_target can change from point to point, the logic of scale_factor needs to be changed.

In the arguments to the function below, src_point is \(x_0^i\), proj_center is \(P^i\), sphere_center is \(C^i\), and radius is \(R\).

◆ try_scale_factor()

std::optional< double > domain::CoordinateMaps::FocallyLiftedMapHelpers::try_scale_factor ( const std::array< double, 3 > &  src_point,
const std::array< double, 3 > &  proj_center,
const std::array< double, 3 > &  sphere_center,
double  radius,
bool  pick_larger_root,
bool  pick_root_greater_than_one,
bool  solve_for_root_minus_one = true 
)

Solves a problem of the same form as scale_factor, but is used only by the inverse function to compute \(\tilde{\lambda}\) and \(\bar{\lambda}\). try_scale_factor is used in two contexts:

try_scale_factor is used to determine \(\bar{\lambda}\) given \(x^i\). \(\bar{\lambda}\) is defined by

\begin{align*} x_1^i = P^i + (x^i - P^i) \bar{\lambda}.\end{align*}

try_scale_factor is used by the lambda_tilde functions of some of the InnerMap classes (namely those InnerMap classes where \(x_0^i\) is a spherical surface) to solve for \(\tilde{\lambda}\) given \(x^i\). \(\tilde{\lambda}\) is defined by

\begin{align*} x_0^i = P^i + (x^i - P^i) \tilde{\lambda}.\end{align*}

In both of these contexts, the input parameter src_point is \(x^i\), a point that is supposed to be in the range of the FocallyLiftedMap. Because the inverse function can be and is called for an arbitrary \(x^i\) that might not be in the range of the FocallyLiftedMap, try_scale_factor returns a std::optional, with a default-constructed std::optional if the roots it finds are not as expected (i.e. if the inverse map was called for a point not in the range of the map).

Because try_scale_factor can be called in different situations, it has additional boolean arguments pick_larger_root and pick_root_greater_than_one that allow the caller to choose which root to return.

Furthermore, to reduce roundoff errors near \(\tilde{\lambda}=1\), the default behavior is to solve the quadratic equation for \(\tilde{\lambda}-1\) (and then add \(1\) to the solution). If instead one wants to solve the quadratic equation directly for \(\tilde{\lambda}\) so as to obtain slightly different roundoff behavior, then one should specify the argument solve_for_root_minus_one to be false.

try_scale_factor is not templated on type because it is used only by the inverse function, which works only on doubles.