@@ -111,6 +111,79 @@ auto logical_partial_derivative(const Tensor<DataType, SymmList, IndexList>& u,
111111 Frame::ElementLogical>;
112112// / @}
113113
114+ // / @{
115+ /* !
116+ * \ingroup NumericalAlgorithmsGroup
117+ * \brief Compute the partial derivatives of each variable, using the Cartoon
118+ * method for directions not in the computational domain.
119+ *
120+ * For a spacetime with some Killing vector \f$\xi^a\f$, not only does the
121+ * metric respect the isometry via \f$\mathcal{L}_\xi g_{ab} = 0\f$, but the
122+ * fields must as well.
123+ *
124+ * In the case of axial symmetry about the \f$y\f$-axis, the Killing vector is
125+ * \f$\xi^a = (0, -z, 0, x)\f$, so we have that for a vector \f$V^a\f$,
126+ *
127+ * \f{align*}{
128+ * \mathcal{L}_\xi V^a &= \xi^b \partial_b V^a - V^b \partial_b \xi^a
129+ * = -z \partial_x V^a + x \partial_z V^a - V^b \partial_b \xi^a = 0.
130+ * \f}
131+ *
132+ * Choosing the computational domain to be the \f$z=0\f$ plane, get the result:
133+ *
134+ * \f{align*}{
135+ * \partial_z V^a &= \frac{V^b \partial_b \xi^a}{x}.
136+ * \f}
137+ *
138+ * In the case that $x=0$ is in the computational domain, L'Hôpital's
139+ * rule is used. For a general tensor,
140+ * \f$T^{a_0,\ldots,a_n}{}_{b_0,\ldots,b_m}\f$ we have
141+ *
142+ * \f{align*}{
143+ * \partial_z T^{a_0,\ldots,a_n}{}_{b_0,\ldots,b_m} &=
144+ * \left\{
145+ * \begin{array}{ll}
146+ * \partial_x(\sum_k
147+ * T^{a_0,\ldots,c_k,\ldots,a_n}{}_{b_0,\ldots,b_m}\partial_{c_k}
148+ * \xi^{a_k} & \\
149+ * \;\;\;\;\;-\sum_k
150+ * T^{a_0,\ldots,a_n}{}_{b_0,\ldots,c_k,\ldots,b_m}\partial_{b_k}
151+ * \xi^{c_k}
152+ * ) & \mathrm{if} \; x=0 \\
153+ * (\sum_k
154+ * T^{a_0,\ldots,c_k,\ldots,a_n}{}_{b_0,\ldots,b_m}\partial_{c_k}
155+ * \xi^{a_k} & \\
156+ * \;-\sum_k
157+ * T^{a_0,\ldots,a_n}{}_{b_0,\ldots,c_k,\ldots,b_m}\partial_{b_k}
158+ * \xi^{c_k})\frac{1}{x} & \mathrm{otherwise}
159+ * \end{array}\right.
160+ * \f}
161+ *
162+ * In the case of spherical symmetry, another Killing vector
163+ * \f$\xi'^a = (0, -y, x, 0) \f$ is used as well, with the above equation
164+ * easily generalizing. In that case, the computational domain is only the
165+ * \f$x\f$-axis.
166+ *
167+ * This function computes the partial derivatives of _all_ variables in
168+ * `VariableTags`. The additional parameter `inertial_coords` is used for
169+ * division by the \f$x\f$ coordinates. If \f$x=0\f$ is included in the domain,
170+ * it is assumed to be present only at the first index and is handled by
171+ * L'Hôpital's rule.
172+ *
173+ * The mesh is required to have the Cartoon basis in the last and potentially
174+ * second-to-last coordinates and the inverse Jacobian is accordingly used only
175+ * in the first and potentially second dimensions.
176+ */
177+ template <typename ResultTags, typename VariableTags, size_t Dim,
178+ typename DerivativeFrame, Requires<Dim == 3 > = nullptr >
179+ void cartoon_partial_derivatives (
180+ gsl::not_null<Variables<ResultTags>*> du, const Variables<VariableTags>& u,
181+ const Mesh<Dim>& mesh,
182+ const InverseJacobian<DataVector, Dim, Frame::ElementLogical,
183+ DerivativeFrame>& inverse_jacobian_3d,
184+ const tnsr::I<DataVector, Dim, Frame::Inertial>& inertial_coords);
185+ // / @}
186+
114187// / @{
115188// / \ingroup NumericalAlgorithmsGroup
116189// / \brief Compute the partial derivatives of each variable with respect to
0 commit comments