SpECTRE  v2025.01.30
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
domain::CoordinateMaps::FocallyLiftedMap< InnerMap > Class Template Reference

Map from (x¯,y¯,z¯) to the volume contained between a 2D surface and the surface of a 2-sphere. More...

#include <FocallyLiftedMap.hpp>

Public Member Functions

 FocallyLiftedMap (const std::array< double, 3 > &center, const std::array< double, 3 > &proj_center, double radius, bool source_is_between_focus_and_target, InnerMap inner_map)
 
 FocallyLiftedMap (FocallyLiftedMap &&)=default
 
 FocallyLiftedMap (const FocallyLiftedMap &)=default
 
FocallyLiftedMapoperator= (const FocallyLiftedMap &)=default
 
FocallyLiftedMapoperator= (FocallyLiftedMap &&)=default
 
template<typename T >
std::array< tt::remove_cvref_wrap_t< T >, 3 > operator() (const std::array< T, 3 > &source_coords) const
 
std::optional< std::array< double, 3 > > inverse (const std::array< double, 3 > &target_coords) const
 The inverse function is only callable with doubles because the inverse might fail if called for a point out of range, and it is unclear what should happen if the inverse were to succeed for some points in a DataVector but fail for other points.
 
template<typename T >
tnsr::Ij< tt::remove_cvref_wrap_t< T >, 3, Frame::NoFramejacobian (const std::array< T, 3 > &source_coords) const
 
template<typename T >
tnsr::Ij< tt::remove_cvref_wrap_t< T >, 3, Frame::NoFrameinv_jacobian (const std::array< T, 3 > &source_coords) const
 
void pup (PUP::er &p)
 

Static Public Member Functions

static bool is_identity ()
 

Static Public Attributes

static constexpr size_t dim = 3
 

Friends

bool operator== (const FocallyLiftedMap< InnerMap > &lhs, const FocallyLiftedMap< InnerMap > &rhs)
 

Detailed Description

template<typename InnerMap>
class domain::CoordinateMaps::FocallyLiftedMap< InnerMap >

Map from (x¯,y¯,z¯) to the volume contained between a 2D surface and the surface of a 2-sphere.

2D representation of focally lifted map.

Details

We are given the radius R and center Ci of a sphere, and a projection point Pi. Also, through the class defined by the InnerMap template parameter, we are given the functions fi(x¯,y¯,z¯) and σ(x¯,y¯,z¯) defined below; these functions define the mapping from (x¯,y¯,z¯) to the 2D surface.

The above figure is a 2D representation of the focally lifted map, where the shaded region in x¯i coordinates on the left is mapped to the shaded region in the xi coordinates on the right. Shown is an arbitrary point x¯i that is mapped to xi; for that point, the corresponding x0i and x1i (defined below) are shown on the right, as is the projection point Pi. Also shown are the level surfaces σ=0 and σ=1.

The input coordinates are labeled (x¯,y¯,z¯). Let x0i=fi(x¯,y¯,z¯) be the three coordinates of the 2D surface in 3D space.

Now let x1i be a point on the surface of the sphere, constructed so that Pi, x0i, and x1i are co-linear. In particular, x1i is determined by the equation

(1)x1i=Pi+(x0iPi)λ,

where λ is a scalar factor that depends on x0i and that can be computed by solving a quadratic equation. This quadratic equation is derived by demanding that x1i lies on the sphere:

(2)|Pi+(x0iPi)λCi|2R2=0,

where |Ai|2 means δijAiAj.

The quadratic equation, Eq. (2), takes the usual form aλ2+bλ+c=0, with

a=|x0iPi|2,b=2(x0iPi)(PjCj)δij,c=|PiCi|2R2.

Now assume that x0i lies on a level surface defined by some scalar function σ(x¯i)=0, where σ is normalized so that σ=1 on the sphere. Then, once λ has been computed and x1i has been determined, the map is given by

(3)xi=x0i+(x1ix0i)σ(x¯i).

Note that classes using FocallyLiftedMap will place restrictions on Pi, Ci, x0i, and R. For example, we demand that Pi does not lie on either the σ=0 or σ=1 surfaces depicted in the right panel of the figure, and we demand that the σ=0 and σ=1 surfaces do not intersect; otherwise the map is singular.

Also note that the quadratic Eq. (2) typically has more than one root, corresponding to two intersections of the sphere. The boolean parameter source_is_between_focus_and_target that is passed into the constructor of FocallyLiftedMap is used to choose the appropriate root, or to error if a suitable root is not found. source_is_between_focus_and_target should be true if the source point lies between the projection point Pi and the sphere. source_is_between_focus_and_target is known only by each particular CoordinateMap that uses FocallyLiftedMap.

Jacobian

Differentiating Eq. (1) above yields

(4)x1ix0j=λδji+(x0iPi)λx0j.

and differentiating Eq. (2) and then inserting Eq. (1) yields

(5)λx0j=λ2Cjx1j|x1iPi|2+(x1iPi)(PiCi).

The Jacobian can be found by differentiating Eq. (3) above and using the chain rule, recognizing that x1i depends on x¯i only through its dependence on x0i; this is because there is no explicit dependence on x¯i in Eq. (1) (which determines x1i) or Eq. (2) (which determines λ).

xix¯j=σx1ix0kx0kx¯j+(1σ)x0ix¯j+σx¯j(x1ix0i),(6)=(1σ+λσ)x0ix¯j+σ(x0iPi)λx0kx0kx¯j+σx¯j(x1ix0i),

where in the last line we have substituted Eq. (4).

The class defined by the InnerMap template parameter provides the function deriv_sigma, which returns σ/x¯j, and the function jacobian, which returns x0k/x¯j.

Inverse map.

Given xi, we wish to compute x¯i.

We first find the coordinates x0i that lie on the 2-surface and are defined such that Pi, x0i, and xi are co-linear. See the right panel of the above figure. x0i is determined by the equation

(7)x0i=Pi+(xiPi)λ~,

where λ~ is a scalar factor that depends on xi and is determined by the class defined by the InnerMap template parameter. InnerMap provides a function lambda_tilde that takes xi and Pi as arguments and returns λ~ (or a default-constructed std::optional if the appropriate λ~ cannot be found; this default-constructed value indicates that the point xi is outside the range of the map).

Now consider the coordinates x1i that lie on the sphere and are defined such that Pi, x1i, and xi are co-linear. See the right panel of the figure. x1i is determined by the equation

(8)x1i=Pi+(xiPi)λ¯,

where λ¯ is a scalar factor that depends on xi and is the solution of a quadratic that is derived by demanding that x1i lies on the sphere:

(9)|Pi+(xiPi)λ¯Ci|2R2=0.

Eq. (9) is a quadratic equation that takes the usual form aλ¯2+bλ¯+c=0, with

a=|xiPi|2,b=2(xiPi)(PjCj)δij,c=|PiCi|2R2.

Note that we don't actually need to compute x1i. Instead, we can determine σ by the relation (obtained by solving Eq. (3) for σ and then inserting Eqs. (7) and (8) to eliminate x1i and x0i)

(10)σ=λ~1λ~λ¯.

The denominator of Eq. (10) is nonzero for nonsingular maps: From Eqs. (7) and (8), λ¯=λ~ means that x1i=x0i, which means that the σ=0 and σ=1 surfaces intersect, i.e. the map is singular.

Once we have x0i and σ, the point (x¯,y¯,z¯) is uniquely determined by InnerMap. The inverse function of InnerMap takes x0i and σ as arguments, and returns (x¯,y¯,z¯), or a default-constructed std::optional if x0i or σ are outside the range of the map.

Root polishing

The inverse function described above will sometimes have errors that are noticeably larger than roundoff. Therefore we apply a single Newton-Raphson iteration to refine the result of the inverse map: Suppose we are given xi, and we have computed x¯i by the above procedure. We then correct x¯i by adding

(11)δx¯i=(xjxj(x¯))x¯ixj,

where xj(x¯) is the result of applying the forward map to x¯i and x¯i/xj is the inverse jacobian.

Inverse jacobian

We write the inverse Jacobian as

(12)x¯ixj=x¯ix0kx0kxj+x¯iσσxj,

where we have recognized that x¯i depends both on x0k (the corresponding point on the 2-surface) and on σ (encoding the distance away from the 2-surface).

We now evaluate Eq. (12). The InnerMap class provides a function inv_jacobian that returns x¯i/x0k (where σ is held fixed), and a function dxbar_dsigma that returns x¯i/σ (where x0i is held fixed). The factor x0j/xi can be computed by differentiating Eq. (7), which yields

(13)x0jxi=λ~δij+x0jPjλ~λ~xi,

where λ~/xi is provided by the deriv_lambda_tilde function of InnerMap. Note that for nonsingular maps there is no worry that λ~ is zero in the denominator of the second term of Eq. (13); if λ~=0 then x0i=Pi by Eq. (7), and therefore the map is singular.

To evaluate the remaining unknown factor in Eq. (12), σ/xj, note that [combining Eqs. (1), (7), and (8)] λ¯=λ~λ. Therefore Eq. (10) is equivalent to

(14)σ=λ~1λ~(1λ).

Differentiating this expression yields

(15)σxi=σλλx0jx0jxi+σλ~λ~xi(16)=σ1λλx0jx0jxi+1λ~2(1λ)λ~xi,

where the second factor in the first term can be evaluated using Eq. (5), the third factor in the first term can be evaluated using Eq. (13), and the second factor in the second term is provided by InnerMaps function deriv_lambda_tilde.


The documentation for this class was generated from the following file: