Skip to content

Commit

Permalink
Add function to create a spacetime tensor from time and spatial ones.
Browse files Browse the repository at this point in the history
  • Loading branch information
ncorsobh committed Jan 16, 2024
1 parent 83244c7 commit f7ea568
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/DataStructures/Tensor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ spectre_target_headers(
${LIBRARY}
INCLUDE_DIRECTORY ${CMAKE_SOURCE_DIR}/src
HEADERS
CombineSpacetimeView.hpp
ContractFirstNIndices.hpp
Identity.hpp
IndexType.hpp
Expand Down
81 changes: 81 additions & 0 deletions src/DataStructures/Tensor/CombineSpacetimeView.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#pragma once

#include <cstddef>
#include <type_traits>

#include "DataStructures/Tensor/IndexType.hpp"
#include "DataStructures/Tensor/Metafunctions.hpp"
#include "DataStructures/Tensor/Tensor.hpp"
#include "DataStructures/VectorImpl.hpp"
#include "Utilities/Array.hpp"
#include "Utilities/Gsl.hpp"
#include "Utilities/StdArrayHelpers.hpp"
#include "Utilities/TMPL.hpp"

/// \ingroup TensorGroup
/// \brief Combines a time component of a tensor with spatial components to
/// produce a spacetime tensor.
///
/// \details Combines a time component of a tensor with spatial components to
/// produce a spacetime tensor. Specifically, the components of the result
/// are views to the inputs. Can do so for a tensor of any rank, but
/// requires that the new index is the first index of the resulting tensor,
/// replacing the position of the spatial index in the input spatial tensor.
/// For instance, it may combine \f$ \phi \f$ with \f$ A^i \f$ into
/// \f$ A^a = \left(\phi, A^i\right) \f$, or it may combine \f$ A^a{}_b{}_c \f$
/// with \f$ B_i{}^a{}_b{}_c \f$ into
/// \f$ C_a{}^b{}_c{}_d = \left(A^b{}_c{}_d, B_i{}^b{}_c{}_d\right)\f$,
/// but it may not combine \f$ A^i{}_a \f$ with \f$ B^i{}_j{}_a \f$ to produce
/// a tensor of the form \f$ C^i{}_a{}_b \f$.
///
/// \tparam SpatialDim the number of spatial dimensions in the input and output
/// tensors
/// \tparam Ul whether the new index is covariant or contravariant (must match
/// that of the spatial index of the input spatial tensor)
/// \tparam Frame the frame of the new spacetime index (must match that of the
/// spatial index of the input spatial tensor)
template <size_t SpatialDim, UpLo Ul, typename Frame, typename DataType,
typename SymmList, typename IndexList>
void combine_spacetime_view(
gsl::not_null<TensorMetafunctions::prepend_spacetime_index<
Tensor<DataType, SymmList, IndexList>, SpatialDim, Ul, Frame>*>
spacetime_tensor,
const Tensor<DataType, SymmList, IndexList>& time_tensor,
const TensorMetafunctions::prepend_spatial_index<
Tensor<DataType, SymmList, IndexList>, SpatialDim, Ul, Frame>&
spatial_tensor) {
for (size_t storage_index = 0;
storage_index < Tensor<DataVector, SymmList, IndexList>::size();
++storage_index) {
const auto u_multi_index =
Tensor<DataVector, SymmList,
IndexList>::structure::get_canonical_tensor_index(storage_index);
if constexpr (std::is_same_v<DataType, DataVector>) {
const auto dtu_multi_index = prepend(u_multi_index, 0_st);
make_const_view(
make_not_null(&std::as_const(spacetime_tensor->get(dtu_multi_index))),
time_tensor.get(u_multi_index), 0,
time_tensor.get(u_multi_index).size());
for (size_t i = 0; i < SpatialDim; i++) {
const auto du_multi_index = prepend(u_multi_index, i + 1);
const auto diu_multi_index = prepend(u_multi_index, i);
make_const_view(make_not_null(&std::as_const(
spacetime_tensor->get(du_multi_index))),
spatial_tensor.get(diu_multi_index), 0,
spatial_tensor.get(diu_multi_index).size());
}
} else {
const auto dtu_multi_index = prepend(u_multi_index, 0_st);
spacetime_tensor->get(dtu_multi_index) = time_tensor.get(u_multi_index);
for (size_t i = 0; i < SpatialDim; ++i) {
const auto du_multi_index = prepend(u_multi_index, i + 1);
const auto diu_multi_index = prepend(u_multi_index, i);
spacetime_tensor->get(du_multi_index) =
spatial_tensor.get(diu_multi_index);
}
}
}
}
1 change: 1 addition & 0 deletions tests/Unit/DataStructures/Tensor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
set(LIBRARY "Test_Tensor")

set(LIBRARY_SOURCES
Test_CombineSpacetimeView.cpp
Test_ContractFirstNIndices.cpp
Test_Identity.cpp
Test_Metafunctions.cpp
Expand Down
66 changes: 66 additions & 0 deletions tests/Unit/DataStructures/Tensor/Test_CombineSpacetimeView.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "Framework/TestingFramework.hpp"

#include <cstddef>

#include "DataStructures/DataVector.hpp"
#include "DataStructures/Tensor/CombineSpacetimeView.hpp"
#include "DataStructures/Tensor/IndexType.hpp"
#include "DataStructures/Tensor/Metafunctions.hpp"
#include "DataStructures/Tensor/Tensor.hpp"
#include "Framework/TestHelpers.hpp"
#include "Helpers/DataStructures/MakeWithRandomValues.hpp"

namespace {

SPECTRE_TEST_CASE("Unit.DataStructures.Tensor.CombineSpacetimeView",
"[DataStructures][Unit]") {
const size_t SpatialDim = 3;
const DataVector used_for_size(5);
MAKE_GENERATOR(generator);
const auto nn_gen = make_not_null(&generator);
std::uniform_real_distribution<> distribution(-1.0, 1.0);
const auto nn_dist = make_not_null(&distribution);

tnsr::a<double, SpatialDim, Frame::Inertial> test_spacetime_vector;
const auto scalar_time_component =
make_with_random_values<Scalar<double>>(nn_gen, nn_dist, used_for_size);
const auto vector_spatial_components =
make_with_random_values<tnsr::i<double, SpatialDim, Frame::Inertial>>(
nn_gen, nn_dist, used_for_size);

combine_spacetime_view<SpatialDim, UpLo::Lo, Frame::Inertial>(
make_not_null(&test_spacetime_vector), scalar_time_component,
vector_spatial_components);

CHECK(test_spacetime_vector.get(0) == get(scalar_time_component));
for (size_t i = 0; i < SpatialDim; ++i) {
CHECK(test_spacetime_vector.get(i + 1) == vector_spatial_components.get(i));
}

tnsr::Abb<DataVector, SpatialDim, Frame::Inertial> test_spacetime_tensor;
const auto tensor_time_component = make_with_random_values<
tnsr::aa<DataVector, SpatialDim, Frame::Inertial>>(nn_gen, nn_dist,
used_for_size);
const auto tensor_spatial_components = make_with_random_values<
tnsr::Iaa<DataVector, SpatialDim, Frame::Inertial>>(nn_gen, nn_dist,
used_for_size);

combine_spacetime_view<SpatialDim, UpLo::Up, Frame::Inertial>(
make_not_null(&test_spacetime_tensor), tensor_time_component,
tensor_spatial_components);

for (size_t i = 0; i <= SpatialDim; ++i) {
for (size_t j = 0; j <= SpatialDim; ++j) {
CHECK(test_spacetime_tensor.get(0, i, j) ==
tensor_time_component.get(i, j));
for (size_t k = 0; k < SpatialDim; ++k) {
CHECK(test_spacetime_tensor.get(k + 1, i, j) ==
tensor_spatial_components.get(k, i, j));
}
}
}
}
} // namespace

0 comments on commit f7ea568

Please sign in to comment.