SpECTRE
v2024.08.03
|
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) |
Holds helper functions for use with domain::CoordinateMaps::FocallyLiftedMap.
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\).
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.
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\).
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.
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\).
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.