Files
mfem/miniapps/tools/compare-dc.cpp
T
2026-01-23 10:24:57 +01:00

167 lines
5.6 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.
//
// -------------------------------------------------------------------
// Compare DC Miniapp: Compare fields saved via DataCollection classes
// -------------------------------------------------------------------
//
// This miniapp loads previously saved data and computes the l2 norm of the
// difference. Currently, only the VisItDataCollection class is supported.
//
// Compile with: make compare-dc
//
// Serial sample runs:
// > compare-dc -r0 ../../examples/Example5 -r1 ../../examples/alt/Example5
// > compare-dc -r0 Example5 -r1 alt/Example5 -tol 1e-6
//
// Parallel sample runs:
// > mpirun -np 4 compare-dc -r0 ../../examples/Example5-Parallel
// -r1 ../../examples/alt/Example5-Parallel
//
// NB: when no tolerance is provided the difference is simple reported.
// If a tolerance is provided this is compared with the symmetric
// relative difference. An error is given if difference exceeds the tolerance.
#include "mfem.hpp"
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
#ifdef MFEM_USE_MPI
Mpi::Init();
if (!Mpi::Root()) { mfem::out.Disable(); mfem::err.Disable(); }
Hypre::Init();
#endif
// Parse command-line options.
const char *coll_name0 = NULL;
const char *coll_name1 = NULL;
int cycle = 0;
int pad_digits_cycle = 6;
int pad_digits_rank = 6;
real_t tol = -1;
OptionsParser args(argc, argv);
args.AddOption(&coll_name0, "-r0", "--root-file_0",
"Set the VisIt data collection root file prefix.", true);
args.AddOption(&coll_name1, "-r1", "--root-file_1",
"Set the VisIt data collection root file prefix.", true);
args.AddOption(&cycle, "-c", "--cycle", "Set the cycle index to read.");
args.AddOption(&pad_digits_cycle, "-pdc", "--pad-digits-cycle",
"Number of digits in cycle.");
args.AddOption(&pad_digits_rank, "-pdr", "--pad-digits-rank",
"Number of digits in MPI rank.");
args.AddOption(&tol, "-tol", "--tolerance",
"Tolerance for checking the results.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(mfem::out);
return 1;
}
args.PrintOptions(mfem::out);
#ifdef MFEM_USE_MPI
VisItDataCollection dc0(MPI_COMM_WORLD, coll_name0);
#else
VisItDataCollection dc0(coll_name0);
#endif
dc0.SetPadDigitsCycle(pad_digits_cycle);
dc0.SetPadDigitsRank(pad_digits_rank);
dc0.Load(cycle);
if (dc0.Error() != DataCollection::No_Error)
{
mfem::out << "Error loading VisIt data collection: " << coll_name0 << endl;
return 1;
}
#ifdef MFEM_USE_MPI
VisItDataCollection dc1(MPI_COMM_WORLD, coll_name1);
#else
VisItDataCollection dc1(coll_name1);
#endif
dc1.SetPadDigitsCycle(pad_digits_cycle);
dc1.SetPadDigitsRank(pad_digits_rank);
dc1.Load(cycle);
if (dc1.Error() != DataCollection::No_Error)
{
mfem::out << "Error loading VisIt data collection: " << coll_name1 << endl;
return 1;
}
typedef DataCollection::FieldMapType fields_t;
const fields_t &fields0 = dc0.GetFieldMap();
// Print the names of all fields.
bool error = false;
for (fields_t::const_iterator it0 = fields0.begin();
it0 != fields0.end() ; ++it0)
{
GridFunction *gf0 = dc0.GetField(it0->first);
if (!gf0)
{
mfem::out << "Error loading:"<<it0->first<< endl;
mfem::out << "From data collection: " << coll_name0 << endl;
return 1;
}
GridFunction *gf1 = dc1.GetField(it0->first);
if (!gf1)
{
mfem::out << "Error loading:"<<it0->first<< endl;
mfem::out << "From data collection: " << coll_name1 << endl;
return 1;
}
if (gf0->Size() != gf1->Size())
{
mfem::out << "Size error for:"<<it0->first<< endl;
mfem::out << "In data collection: " << coll_name0
<<" size is "<<gf0->Size()<< endl;
mfem::out << "In data collection: " << coll_name1
<<" size is "<<gf1->Size()<< endl;
return 1;
}
// Norm of vectors
real_t nrm0 = gf0->Norml2();
real_t nrm1 = gf1->Norml2();
// Difference
(*gf0) -= (*gf1);
real_t nrmd = gf0->Norml2();
real_t rel_sym = 2*nrmd/(nrm0 + nrm1);
if (gf0->Norml2() > rel_sym) { error = true; }
// Report
mfem::out <<"==========================================="<<std::endl;
mfem::out <<"|"<<it0->first<<"_0| = "<<nrm0<<std::endl;
mfem::out <<"|"<<it0->first<<"_1| = "<<nrm1<<std::endl;
mfem::out <<"\n|"<<it0->first<<"_0 - "<<it0->first<<"_1| = "<<nrmd <<std::endl;
mfem::out <<"\n2|"<<it0->first<<"_0 - "<<it0->first<<"_1|"<<std::endl;
mfem::out << std::setfill('-') << std::setw(15 + 2*it0->first.length())
<<" = "<<rel_sym<<std::endl;
mfem::out <<"(|"<<it0->first<<"_0| + |"<<it0->first<<"_1|)\n"<<std::endl;
}
if (error && tol > 0.0)
{
mfem::out << "Data collections: " << coll_name0
<< " & " << coll_name1 << " are outside of the tolerance!\n";
return -1;
}
return 0;
}