https://mooseframework.inl.gov
TestReconstruction.C
Go to the documentation of this file.
1 //* This file is part of the MOOSE framework
2 //* https://mooseframework.inl.gov
3 //*
4 //* All rights reserved, see COPYRIGHT for full restrictions
5 //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 //*
7 //* Licensed under LGPL 2.1, please see LICENSE for details
8 //* https://www.gnu.org/licenses/lgpl-2.1.html
9 
10 #include "gtest/gtest.h"
11 
12 #include "Registry.h"
13 #include "MooseMesh.h"
14 #include "NavierStokesApp.h"
15 #include "AppFactory.h"
16 #include "Factory.h"
17 #include "InputParameters.h"
18 #include "MeshGeneratorMesh.h"
19 #include "MooseError.h"
20 #include "CastUniquePointer.h"
21 #include "GeneratedMeshGenerator.h"
22 #include "MooseFunctor.h"
23 #include "PolynomialFit.h"
24 #include "FaceInfo.h"
25 #include "MooseTypes.h"
26 #include "CellCenteredMapFunctor.h"
27 #include "Reconstructions.h"
28 #include "MooseUtils.h"
29 
30 #include "libmesh/elem.h"
31 #include "libmesh/tensor_value.h"
32 #include "libmesh/point.h"
33 #include "libmesh/vector_value.h"
34 #include "libmesh/utility.h"
35 
36 #include <memory>
37 #include <vector>
38 #include <memory>
39 
40 void
42 {
43  const char * argv[2] = {"foo", "\0"};
44 
45  MultiMooseEnum coord_type_enum("XYZ RZ RSPHERICAL", "XYZ");
46  coord_type_enum = (coord_type == Moose::COORD_XYZ) ? "XYZ" : "RZ";
47 
48  std::vector<unsigned int> num_elem = {64, 128, 256};
49  std::vector<Real> weller_errors;
50  std::vector<Real> moukalled_errors;
51  std::vector<Real> tano_errors;
52  std::vector<Real> tano_errors_twice;
53  std::vector<Real> h(num_elem.size());
54  for (const auto i : index_range(num_elem))
55  h[i] = 1. / num_elem[i];
56 
57  for (const auto i : index_range(num_elem))
58  {
59  const auto nx = num_elem[i];
60  auto app = AppFactory::createAppShared("NavierStokesUnitApp", 1, (char **)argv);
61  auto * factory = &app->getFactory();
62  std::string mesh_type = "MeshGeneratorMesh";
63 
64  std::shared_ptr<MeshGeneratorMesh> mesh;
65  {
66  InputParameters params = factory->getValidParams(mesh_type);
67  mesh = factory->create<MeshGeneratorMesh>(mesh_type, "moose_mesh", params);
68  }
69 
70  app->actionWarehouse().mesh() = mesh;
71 
72  {
73  std::unique_ptr<MeshBase> lm_mesh;
74  InputParameters params = factory->getValidParams("GeneratedMeshGenerator");
75  params.set<unsigned int>("nx") = nx;
76  params.set<unsigned int>("ny") = nx;
77  params.set<MooseEnum>("dim") = "2";
78  auto mesh_gen =
79  factory->create<GeneratedMeshGenerator>("GeneratedMeshGenerator", "mesh_gen", params);
80  lm_mesh = mesh_gen->generate();
81  mesh->setMeshBase(std::move(lm_mesh));
82  }
83 
84  mesh->prepare(nullptr);
85  mesh->setCoordSystem({}, coord_type_enum);
86  mooseAssert(mesh->getAxisymmetricRadialCoord() == 0,
87  "This should be 0 because we haven't set anything.");
88  const auto & all_fi = mesh->allFaceInfo();
89  mesh->buildFiniteVolumeInfo();
90  mesh->computeFiniteVolumeCoords();
91  std::vector<const FaceInfo *> faces(all_fi.size());
92  for (const auto i : index_range(all_fi))
93  faces[i] = &all_fi[i];
94 
95  auto & lm_mesh = mesh->getMesh();
96 
98  *mesh, "u", /*extrapoalted_bd=*/true);
99  for (auto * const elem : lm_mesh.active_element_ptr_range())
100  {
101  const auto centroid = elem->vertex_average();
102  const auto value = RealVectorValue(-std::sin(centroid(0)) * std::cos(centroid(1)),
103  std::cos(centroid(0)) * std::sin(centroid(1)));
104  u[elem->id()] = value;
105  }
106 
108  up_weller(*mesh, "up_weller", /*extrapoalted_bd=*/true);
110  up_moukalled(*mesh, "up_moukalled", /*extrapoalted_bd=*/true);
112  up_tano(*mesh, "up_tano", /*extrapoalted_bd=*/true);
113 
114  for (const auto & fi : all_fi)
115  {
116  auto moukalled_reconstruct = [&fi](auto & functor, auto & container)
117  {
118  auto face = Moose::FaceArg(
119  {&fi, Moose::FV::LimiterType::CentralDifference, true, false, nullptr, nullptr});
120  const RealVectorValue uf(functor(face, Moose::currentState()));
121  const Point surface_vector = fi.normal() * fi.faceArea();
122  auto product = (uf * fi.dCN()) * surface_vector;
123 
124  container[fi.elem().id()] += product * fi.gC() / fi.elemVolume();
125  if (fi.neighborPtr())
126  container[fi.neighbor().id()] +=
127  std::move(product) * (1. - fi.gC()) / fi.neighborVolume();
128  };
129 
130  moukalled_reconstruct(u, up_moukalled);
131  }
132 
133  Moose::FV::interpolateReconstruct(up_weller, u, 1, true, faces, Moose::currentState());
134  Moose::FV::interpolateReconstruct(up_tano, u, 1, false, faces, Moose::currentState());
135 
136  Real error = 0;
137  Real weller_error = 0;
138  Real tano_error = 0;
139  Real moukalled_error = 0;
140  const auto current_h = h[i];
141  for (auto * const elem : lm_mesh.active_element_ptr_range())
142  {
143  const auto elem_id = elem->id();
144  auto elem_arg = Moose::ElemArg{elem, false};
145  const RealVectorValue analytic(u(elem_arg, Moose::currentState()));
146 
147  auto compute_elem_error =
148  [elem_id, current_h, elem, &analytic](auto & container, auto & error)
149  {
150  auto & current = libmesh_map_find(container, elem_id);
151  const auto diff = analytic - current;
152  error += diff * diff * current_h * current_h;
153 
154  // Test CellCenteredMapFunctor ElemPointArg overload
155  const auto elem_point_eval = container(
156  Moose::ElemPointArg({elem, elem->vertex_average(), false}), Moose::currentState());
157  for (const auto d : make_range(Moose::dim))
158  EXPECT_TRUE(MooseUtils::absoluteFuzzyEqual(current(d), elem_point_eval(d)));
159  };
160 
161  compute_elem_error(up_weller, weller_error);
162  compute_elem_error(up_moukalled, moukalled_error);
163  compute_elem_error(up_tano, tano_error);
164  }
165  error = std::sqrt(error);
166  weller_error = std::sqrt(weller_error);
167  moukalled_error = std::sqrt(moukalled_error);
168  tano_error = std::sqrt(tano_error);
169  weller_errors.push_back(weller_error);
170  moukalled_errors.push_back(moukalled_error);
171  tano_errors.push_back(tano_error);
172 
173  up_tano.clear();
174  Moose::FV::interpolateReconstruct(up_tano, u, 2, false, faces, Moose::currentState());
175 
176  tano_error = 0;
177  for (auto * const elem : lm_mesh.active_element_ptr_range())
178  {
179  const auto elem_id = elem->id();
180  const auto elem_arg = Moose::ElemArg{elem, false};
181  const RealVectorValue analytic(u(elem_arg, Moose::currentState()));
182 
183  auto compute_elem_error = [elem_id, current_h, &analytic](auto & container, auto & error)
184  {
185  auto & current = libmesh_map_find(container, elem_id);
186  const auto diff = analytic - current;
187  error += diff * diff * current_h * current_h;
188  };
189  compute_elem_error(up_tano, tano_error);
190  }
191  tano_error = std::sqrt(tano_error);
192  tano_errors_twice.push_back(tano_error);
193 
195  *mesh, "not_restricted", /*extrapoalted_bd=*/true);
196  try
197  {
198  unrestricted_error_test(Moose::ElemArg({lm_mesh.elem_ptr(0), false}), Moose::currentState());
199  EXPECT_TRUE(false);
200  }
201  catch (std::runtime_error & e)
202  {
203  EXPECT_TRUE(std::string(e.what()).find("not_restricted") != std::string::npos);
204  EXPECT_TRUE(std::string(e.what()).find("Make sure to fill") != std::string::npos);
205  }
206 
208  *mesh, {1}, "is_restricted", /*extrapoalted_bd=*/true);
209  try
210  {
211  restricted_error_test(Moose::ElemArg({lm_mesh.elem_ptr(0), false}), Moose::currentState());
212  EXPECT_TRUE(false);
213  }
214  catch (std::runtime_error & e)
215  {
216  EXPECT_TRUE(std::string(e.what()).find("is_restricted") != std::string::npos);
217  EXPECT_TRUE(std::string(e.what()).find("0") != std::string::npos);
218  EXPECT_TRUE(
219  std::string(e.what()).find(
220  "that subdomain id is not one of the subdomain ids the functor is restricted to") !=
221  std::string::npos);
222  }
223  }
224 
225  std::for_each(h.begin(), h.end(), [](Real & h_elem) { h_elem = std::log(h_elem); });
226 
227  auto expect_errors = [&h](auto & errors_arg, Real expected_error)
228  {
229  std::for_each(
230  errors_arg.begin(), errors_arg.end(), [](Real & error) { error = std::log(error); });
231  PolynomialFit fit(h, errors_arg, 1);
232  fit.generate();
233 
234  const auto & coeffs = fit.getCoefficients();
235  EXPECT_NEAR(coeffs[1], expected_error, .05);
236  };
237 
238  expect_errors(weller_errors, coord_type == Moose::COORD_RZ ? 1.5 : 2);
239  expect_errors(moukalled_errors, 2);
240  expect_errors(tano_errors, 2);
241  expect_errors(tano_errors_twice, 2);
242 }
243 
245 
246 TEST(TestReconstruction, Cylindrical) { testReconstruction(Moose::COORD_RZ); }
This class constructs a functional expansion using a separate series for each Cartesian dimension...
Definition: Cartesian.h:18
bool absoluteFuzzyEqual(const T &var1, const T2 &var2, const T3 &tol=libMesh::TOLERANCE *libMesh::TOLERANCE)
T & set(const std::string &name, bool quiet_mode=false)
MeshBase & mesh
static constexpr std::size_t dim
void interpolateReconstruct(CellCenteredMapFunctor< T, Map > &output_functor, const Moose::FunctorBase< T > &input_functor, const unsigned int num_int_recs, const bool weight_with_sf, const std::vector< const FaceInfo *> &faces, const Moose::StateArg &time)
Takes an input functor that can be evaluated at faces, typically by linearly interpolating between ad...
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
static MooseAppPtr createAppShared(int argc, char **argv, std::unique_ptr< Parser > parser)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
CoordinateSystemType
IntRange< T > make_range(T beg, T end)
TEST(TestReconstruction, Cartesian)
StateArg currentState()
auto index_range(const T &sizable)
void testReconstruction(const Moose::CoordinateSystemType coord_type)
A functor whose evaluation relies on querying a map where the keys are element ids and the values cor...