SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/Tensor/EagerMath - CrossProduct.hpp Hit Total Coverage
Commit: 3c072f0ce967e2e56649d3fa12aa2a0e4fe2a42e Lines: 5 5 100.0 %
Date: 2024-04-23 20:50:18
Legend: Lines: hit not hit

          Line data    Source code
       1           1 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : /// \file
       5             : /// Defines functions `cross_product` for flat and curved-space cross products.
       6             : 
       7             : #pragma once
       8             : 
       9             : #include <cstddef>
      10             : 
      11             : #include "DataStructures/LeviCivitaIterator.hpp"
      12             : #include "DataStructures/Tensor/IndexType.hpp"
      13             : #include "DataStructures/Tensor/Tensor.hpp"
      14             : #include "Utilities/MakeWithValue.hpp"
      15             : 
      16             : /*!
      17             :  * \ingroup TensorGroup
      18             :  * \brief Compute the Euclidean cross product of two vectors or one forms
      19             :  *
      20             :  * \details
      21             :  * Returns \f$A^j B^k \epsilon_{ljk} \delta^{il}\f$ for input vectors \f$A^j\f$
      22             :  * and \f$B^k\f$ or \f$A_j B_k \epsilon^{ljk} \delta_{il}\f$ for input one
      23             :  * forms \f$A_j\f$ and \f$B_k\f$.
      24             :  */
      25             : template <typename DataType, typename Index>
      26           1 : Tensor<DataType, Symmetry<1>, index_list<Index>> cross_product(
      27             :     const Tensor<DataType, Symmetry<1>, index_list<Index>>& vector_a,
      28             :     const Tensor<DataType, Symmetry<1>, index_list<Index>>& vector_b) {
      29             :   static_assert(Index::dim == 3, "cross_product vectors must have dimension 3");
      30             :   static_assert(Index::index_type == IndexType::Spatial,
      31             :                 "cross_product vectors must be spatial");
      32             : 
      33             :   auto cross_product =
      34             :       make_with_value<Tensor<DataType, Symmetry<1>, index_list<Index>>>(
      35             :           vector_a, 0.0);
      36             :   for (LeviCivitaIterator<3> it; it; ++it) {
      37             :     cross_product.get(it[0]) +=
      38             :         it.sign() * vector_a.get(it[1]) * vector_b.get(it[2]);
      39             :   }
      40             :   return cross_product;
      41             : }
      42             : 
      43             : /*!
      44             :  * \ingroup TensorGroup
      45             :  * \brief Compute the Euclidean cross product of a vector and a one form
      46             :  *
      47             :  * \details
      48             :  * Returns \f$A^j B_l \delta^{lk} \epsilon_{ijk}\f$ for input vector \f$A^j\f$
      49             :  * and input one form \f$B_l\f$
      50             :  * or \f$A_j B^l \delta_{lk} \epsilon^{ijk}\f$ for input one form \f$A_j\f$ and
      51             :  * input vector \f$B^l\f$. Note that this function returns a vector if
      52             :  * `vector_b` is a vector and a one form if `vector_b` is a one form.
      53             :  */
      54             : template <typename DataType, typename Index>
      55             : Tensor<DataType, Symmetry<1>, index_list<change_index_up_lo<Index>>>
      56           1 : cross_product(const Tensor<DataType, Symmetry<1>, index_list<Index>>& vector_a,
      57             :               const Tensor<DataType, Symmetry<1>,
      58             :                            index_list<change_index_up_lo<Index>>>& vector_b) {
      59             :   static_assert(Index::dim == 3, "cross_product vectors must have dimension 3");
      60             :   static_assert(Index::index_type == IndexType::Spatial,
      61             :                 "cross_product vectors must be spatial");
      62             : 
      63             :   auto cross_product = make_with_value<
      64             :       Tensor<DataType, Symmetry<1>, index_list<change_index_up_lo<Index>>>>(
      65             :       vector_b, 0.0);
      66             :   for (LeviCivitaIterator<3> it; it; ++it) {
      67             :     cross_product.get(it[0]) +=
      68             :         it.sign() * vector_a.get(it[1]) * vector_b.get(it[2]);
      69             :   }
      70             :   return cross_product;
      71             : }
      72             : 
      73             : /*!
      74             :  * \ingroup TensorGroup
      75             :  * \brief Compute the cross product of two vectors or one forms
      76             :  *
      77             :  * \details
      78             :  * Returns \f$\sqrt{g} g^{li} A^j B^k \epsilon_{ljk}\f$, where
      79             :  * \f$A^j\f$ and \f$B^k\f$ are vectors and \f$g^{li}\f$ and \f$g\f$
      80             :  * are the inverse and determinant, respectively, of
      81             :  * the spatial metric (computed via `determinant_and_inverse`). In this case,
      82             :  * the arguments `vector_a` and `vector_b` should be vectors,
      83             :  * the argument `metric_or_inverse_metric` should be the inverse spatial
      84             :  * metric  \f$g^{ij}\f$, and the argument `metric_determinant` should be the
      85             :  * determinant of the spatial metric \f$\det(g_{ij})\f$.
      86             :  * Or, returns \f$\sqrt{g}^{-1} g_{li} A_j B_k \epsilon^{ljk}\f$, where
      87             :  * \f$A_j\f$ and \f$B_k\f$ are one forms and \f$g_{li}\f$ and \f$g\f$
      88             :  * are the spatial metric and its determinant. In this case,
      89             :  * the arguments `vector_a` and `vector_b` should be one forms,
      90             :  * the argument `metric_or_inverse_metric` should be the spatial metric
      91             :  * \f$g_{ij}\f$, and the argument `metric_determinant` should be the
      92             :  * determinant of the spatial metric \f$\det(g_{ij})\f$.
      93             :  */
      94             : template <typename DataType, typename Index>
      95           1 : Tensor<DataType, Symmetry<1>, index_list<Index>> cross_product(
      96             :     const Tensor<DataType, Symmetry<1>, index_list<Index>>& vector_a,
      97             :     const Tensor<DataType, Symmetry<1>, index_list<Index>>& vector_b,
      98             :     const Tensor<DataType, Symmetry<1, 1>, index_list<Index, Index>>&
      99             :         metric_or_inverse_metric,
     100             :     const Scalar<DataType>& metric_determinant) {
     101             :   static_assert(Index::dim == 3, "cross_product vectors must have dimension 3");
     102             :   static_assert(Index::index_type == IndexType::Spatial,
     103             :                 "cross_product vectors must be spatial");
     104             : 
     105             :   auto cross_product =
     106             :       make_with_value<Tensor<DataType, Symmetry<1>, index_list<Index>>>(
     107             :           vector_a, 0.);
     108             :   for (size_t i = 0; i < Index::dim; ++i) {
     109             :     for (LeviCivitaIterator<3> it; it; ++it) {
     110             :       cross_product.get(i) += it.sign() * vector_a.get(it[1]) *
     111             :                               vector_b.get(it[2]) *
     112             :                               metric_or_inverse_metric.get(it[0], i);
     113             :     }
     114             :     if (Index::ul == UpLo::Up) {
     115             :       cross_product.get(i) *= sqrt(get(metric_determinant));
     116             :     } else {
     117             :       cross_product.get(i) /= sqrt(get(metric_determinant));
     118             :     }
     119             :   }
     120             :   return cross_product;
     121             : }
     122             : 
     123             : /*!
     124             :  * \ingroup TensorGroup
     125             :  * \brief Compute the cross product of a vector and a one form
     126             :  *
     127             :  * \details
     128             :  * Returns \f$\sqrt{g} A^j B_l g^{lk} \epsilon_{ijk}\f$ for input vector
     129             :  * \f$A^j\f$ and input one form \f$B_l\f$. In this case,
     130             :  * the argument `vector_a` should be a vector, `vector_b` should be a one form,
     131             :  * `metric_or_inverse_metric` should be the inverse spatial
     132             :  * metric  \f$g^{ij}\f$, and `metric_determinant` should be the
     133             :  * determinant of the spatial metric \f$\det(g_{ij})\f$.
     134             :  * Or, returns \f$\sqrt{g}^{-1} A_j B^l g_{lk}
     135             :  * \epsilon^{ijk}\f$ for input one form \f$A_j\f$ and input vector \f$B^l\f$.
     136             :  * In this case,
     137             :  * the argument `vector_a` should be a one form, `vector_b` should be a vector,
     138             :  * `metric_or_inverse_metric` should be the spatial metric
     139             :  * \f$g_{ij}\f$, and `metric_determinant` should be the
     140             :  * determinant of the spatial metric \f$\det(g_{ij})\f$.
     141             :  * Note that this function returns a vector if `vector_b` is a vector and a
     142             :  * one form if `vector_b` is a one form.
     143             :  */
     144             : template <typename DataType, typename Index>
     145             : Tensor<DataType, Symmetry<1>, index_list<change_index_up_lo<Index>>>
     146           1 : cross_product(const Tensor<DataType, Symmetry<1>, index_list<Index>>& vector_a,
     147             :               const Tensor<DataType, Symmetry<1>,
     148             :                            index_list<change_index_up_lo<Index>>>& vector_b,
     149             :               const Tensor<DataType, Symmetry<1, 1>, index_list<Index, Index>>&
     150             :                   metric_or_inverse_metric,
     151             :               const Scalar<DataType>& metric_determinant) {
     152             :   static_assert(Index::dim == 3, "cross_product vectors must have dimension 3");
     153             :   static_assert(Index::index_type == IndexType::Spatial,
     154             :                 "cross_product vectors must be spatial");
     155             : 
     156             :   auto cross_product = make_with_value<
     157             :       Tensor<DataType, Symmetry<1>, index_list<change_index_up_lo<Index>>>>(
     158             :       vector_b, 0.0);
     159             :   for (LeviCivitaIterator<3> it; it; ++it) {
     160             :     if (Index::ul == UpLo::Up) {
     161             :       for (size_t l = 0; l < Index::dim; ++l) {
     162             :         cross_product.get(it[0]) += it.sign() * vector_a.get(it[1]) *
     163             :                                     vector_b.get(l) *
     164             :                                     metric_or_inverse_metric.get(it[2], l);
     165             :       }
     166             :     } else {
     167             :       for (size_t l = 0; l < Index::dim; ++l) {
     168             :         cross_product.get(it[0]) += it.sign() * vector_a.get(l) *
     169             :                                     vector_b.get(it[2]) *
     170             :                                     metric_or_inverse_metric.get(it[1], l);
     171             :       }
     172             :     }
     173             :   }
     174             : 
     175             :   for (size_t i = 0; i < Index::dim; ++i) {
     176             :     if (Index::ul == UpLo::Up) {
     177             :       cross_product.get(i) *= sqrt(get(metric_determinant));
     178             :     } else {
     179             :       cross_product.get(i) /= sqrt(get(metric_determinant));
     180             :     }
     181             :   }
     182             :   return cross_product;
     183             : }

Generated by: LCOV version 1.14