Files
mfem/tests/unit/linalg/test_particlevector.cpp
T

227 lines
5.8 KiB
C++

// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "mfem.hpp"
#include "unit_tests.hpp"
using namespace mfem;
using namespace std;
static constexpr int VDIM = 7;
static_assert(VDIM > 1);
static constexpr int NV_rm = 12;
static constexpr int NV = 27;
static_assert(NV_rm < NV);
static constexpr int VDIM_INC = 3;
void TestSetGetValues(Ordering::Type ordering)
{
ParticleVector mv(VDIM, ordering, NV);
Vector vecs[NV];
for (int i = 0; i < NV; i++)
{
vecs[i].SetSize(VDIM);
vecs[i].Randomize(i+1);
mv.SetValues(i, vecs[i]);
}
int wrong_vec_count = 0;
Vector aux(VDIM);
for (int i = 0; i < NV; i++)
{
mv.GetValues(i, aux);
if (!(aux.DistanceTo(vecs[i]) == MFEM_Approx(0,0)))
{
wrong_vec_count++;
}
}
REQUIRE(wrong_vec_count == 0);
}
void TestSetGetComponents(Ordering::Type ordering)
{
ParticleVector mv(VDIM, ordering, NV);
Vector vecs[NV];
for (int i = 0; i < NV; i++)
{
vecs[i].SetSize(VDIM);
vecs[i].Randomize(i+1);
}
// Set components individually
Vector comps[VDIM];
for (int vd = 0; vd < VDIM; vd++)
{
comps[vd].SetSize(NV);
for (int i = 0; i < NV; i++)
{
comps[vd][i] = vecs[i][vd];
}
mv.SetComponents(vd, comps[vd]);
}
// Verify get component
int wrong_comp_count = 0;
Vector aux_comp(NV);
for (int vd = 0; vd < VDIM; vd++)
{
mv.GetComponents(vd, aux_comp);
if (!(aux_comp.DistanceTo(comps[vd]) == MFEM_Approx(0,0)))
{
wrong_comp_count++;
}
}
REQUIRE(wrong_comp_count == 0);
// Verify all vectors correct
int wrong_vec_count = 0;
Vector aux(VDIM);
for (int i = 0; i < NV; i++)
{
mv.GetValues(i, aux);
if (!(aux.DistanceTo(vecs[i]) == MFEM_Approx(0,0)))
{
wrong_vec_count++;
}
}
REQUIRE(wrong_vec_count == 0);
}
void TestSetNumParticles(Ordering::Type ordering)
{
SECTION((ordering == Ordering::byNODES ? "byNODES" : "byVDIM"))
{
Vector all_data(NV*VDIM);
all_data.Randomize(1234);
const ParticleVector mv_all(VDIM, ordering, all_data);
// Start with mv_test = mv_all
ParticleVector mv_test(VDIM, ordering, NV);
mv_test = mv_all;
REQUIRE(mv_test.DistanceTo(mv_all) == MFEM_Approx(0.0));
// Remove N_rm vectors from mv_test + save them into vecs_diff
std::vector<Vector> vecs_diff(NV_rm);
for (int i = 0; i < NV_rm; i++)
{
mv_all.GetValues(NV - NV_rm + i, vecs_diff[i]);
}
mv_test.SetNumParticles(NV-NV_rm);
REQUIRE(mv_test.GetNumParticles() == NV - NV_rm);
// Resize mv_test back
mv_test.SetNumParticles(NV);
REQUIRE(mv_test.GetNumParticles() == NV);
// Ensure that vectors post-shrink match those in mv_all
int wrong_shrink_vec_count = 0;
Vector v1, v2;
for (int i = 0; i < NV-NV_rm; i++)
{
mv_all.GetValues(i, v1);
mv_test.GetValues(i, v2);
if (!(v1.DistanceTo(v2) == MFEM_Approx(0,0)))
{
wrong_shrink_vec_count++;
}
}
REQUIRE(wrong_shrink_vec_count == 0);
// Set vectors back to mv_test, and then check equality
mv_test.SetNumParticles(NV);
for (int i = 0; i < NV_rm; i++)
{
mv_test.SetValues(i+(NV-NV_rm), vecs_diff[i]);
}
REQUIRE(mv_test.DistanceTo(mv_all) == MFEM_Approx(0.0));
}
}
void TestSetVDim(Ordering::Type ordering)
{
Vector data_vecs[NV];
Vector data_comps[VDIM_INC]; // last VDIM_INC comps
Vector data_vecs_red[NV]; // Vectors of reduced vdim
ParticleVector mv(VDIM+VDIM_INC, ordering, NV);
for (int i = 0; i < NV; i++)
{
data_vecs[i].SetSize(VDIM+VDIM_INC);
data_vecs[i].Randomize(i+1);
data_vecs_red[i].NewDataAndSize(data_vecs[i].GetData(), VDIM);
mv.SetValues(i, data_vecs[i]);
}
for (int vd = 0; vd < VDIM_INC; vd++)
{
data_comps[vd].SetSize(NV);
mv.GetComponents(vd+VDIM, data_comps[vd]);
}
// Reduce vdim + compare against data_vecs_red
mv.SetVDim(VDIM);
Vector aux(VDIM);
int wrong_vec_red_count = 0;
for (int i = 0; i < NV; i++)
{
mv.GetValues(i, aux);
if (aux.DistanceTo(data_vecs_red[i]) != MFEM_Approx(0.0))
{
wrong_vec_red_count++;
}
}
REQUIRE(wrong_vec_red_count == 0);
// Increase vdim, update components, + compare against data_vecs
mv.SetVDim(VDIM+VDIM_INC);
for (int vd = 0; vd < VDIM_INC; vd++)
{
mv.SetComponents(vd+VDIM, data_comps[vd]);
}
int wrong_vec_count = 0;
aux.SetSize(VDIM+VDIM_INC);
for (int i = 0; i < NV; i++)
{
mv.GetValues(i, aux);
if (aux.DistanceTo(data_vecs[i]) != MFEM_Approx(0.0))
{
wrong_vec_count++;
}
}
REQUIRE(wrong_vec_count == 0);
}
TEST_CASE("ParticleVector set/get values", "[ParticleVector]")
{
TestSetGetValues(Ordering::byNODES);
TestSetGetValues(Ordering::byVDIM);
}
TEST_CASE("ParticleVector set/get components", "[ParticleVector]")
{
TestSetGetComponents(Ordering::byNODES);
TestSetGetComponents(Ordering::byVDIM);
}
TEST_CASE("ParticleVector set num particles", "[ParticleVector]")
{
TestSetNumParticles(Ordering::byNODES);
TestSetNumParticles(Ordering::byVDIM);
}
TEST_CASE("ParticleVector set vdim","[ParticleVector]")
{
TestSetVDim(Ordering::byNODES);
TestSetVDim(Ordering::byVDIM);
}