Files
mfem/tests/unit/fem/test_pgridfunc_save_serial.cpp
T
2025-03-31 18:48:43 -07:00

87 lines
2.9 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;
#ifdef MFEM_USE_MPI
TEST_CASE("ParGridFunction in Serial", "[ParGridFunction][Parallel]")
{
const int num_procs = Mpi::WorldSize();
const int my_rank = Mpi::WorldRank();
const int order = 1;
const int save_rank = 0;
const int n = 2 * num_procs;
Mesh mesh = Mesh::MakeCartesian2D(n, n, Element::QUADRILATERAL);
mesh.SetCurvature(2);
// Define a parallel mesh by a partitioning of the serial mesh.
ParMesh pmesh(MPI_COMM_WORLD, mesh);
H1_FECollection fec(order, mesh.Dimension());
ParFiniteElementSpace pfespace(&pmesh, &fec);
ParGridFunction px(&pfespace);
px.Randomize(1);
// Ensure that the L-DOFs are set consistently on all ranks
px.SetTrueVector();
px.SetFromTrueVector();
ConstantCoefficient zero(0.0);
const double l2_norm = px.ComputeL2Error(zero);
// Get the ParMesh and ParGridFunction on 1 of the mpi ranks. Check the
// L2 error on that rank and save grid function.
Mesh par_to_ser_mesh = pmesh.GetSerialMesh(save_rank);
GridFunction x_par_to_ser = px.GetSerialGridFunction(
save_rank, par_to_ser_mesh);
if (my_rank == save_rank)
{
const double par_to_ser_l2_norm = x_par_to_ser.ComputeL2Error(zero);
REQUIRE(par_to_ser_l2_norm == MFEM_Approx(l2_norm));
// Save to disk
par_to_ser_mesh.Save("parallel_in_serial.mesh");
}
{
FiniteElementSpace &fes = *x_par_to_ser.FESpace();
GridFunction x_par_to_ser_2 = px.GetSerialGridFunction(save_rank, fes);
x_par_to_ser_2 -= x_par_to_ser;
REQUIRE(x_par_to_ser_2.Normlinf() == MFEM_Approx(0.0));
}
// Save the mesh and then load the saved mesh and grid function, and check
// the L2 error on all ranks.
px.SaveAsSerial("parallel_in_serial.gf", 16, save_rank);
if (my_rank == save_rank)
{
Mesh par_to_ser_mesh_read = Mesh("parallel_in_serial.mesh");
named_ifgzstream gfstream("parallel_in_serial.gf");
GridFunction x_par_to_ser_read(&par_to_ser_mesh_read, gfstream);
const double par_to_ser_l2_read_norm = x_par_to_ser_read.ComputeL2Error(zero);
REQUIRE(par_to_ser_l2_read_norm == MFEM_Approx(l2_norm));
}
if (my_rank == save_rank)
{
// Clean up
REQUIRE(std::remove("parallel_in_serial.mesh") == 0);
REQUIRE(std::remove("parallel_in_serial.gf") == 0);
}
}
#endif // MFEM_USE_MPI