GRINS-0.8.0
integrated_function_test.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------bl-
2 //--------------------------------------------------------------------------
3 //
4 // GRINS - General Reacting Incompressible Navier-Stokes
5 //
6 // Copyright (C) 2014-2017 Paul T. Bauman, Roy H. Stogner
7 // Copyright (C) 2010-2013 The PECOS Development Team
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the Version 2.1 GNU Lesser General
11 // Public License as published by the Free Software Foundation.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc. 51 Franklin Street, Fifth Floor,
21 // Boston, MA 02110-1301 USA
22 //
23 //-----------------------------------------------------------------------el-
24 
25 #include "grins_config.h"
26 
27 #ifdef GRINS_HAVE_CPPUNIT
28 
29 #include <libmesh/ignore_warnings.h>
30 #include <cppunit/extensions/HelperMacros.h>
31 #include <cppunit/TestCase.h>
32 #include <libmesh/restore_warnings.h>
33 
34 #include "test_comm.h"
35 #include "grins_test_paths.h"
36 #include "regression_helper.h"
37 
38 // GRINS
39 #include "grins/math_constants.h"
40 #include "grins/grins_enums.h"
42 #include "grins/composite_qoi.h"
44 #include "grins/simulation.h"
46 
47 // libMesh
48 #include "libmesh/parsed_function.h"
49 #include "libmesh/qoi_set.h"
50 #include "libmesh/steady_solver.h"
51 #include "libmesh/mesh_refinement.h"
52 #include "libmesh/elem.h"
53 
54 // Ignore warnings from auto_ptr in CPPUNIT_TEST_SUITE_END()
55 #include <libmesh/ignore_warnings.h>
56 
57 namespace GRINSTesting
58 {
59  class IntegratedFunctionTest : public CppUnit::TestCase,
60  public RegressionHelper
61  {
62  public:
64 
69 
71 
72  public:
73 
74  void tearDown()
75  {
76  // Clear out the VariableWarehouse so it doesn't interfere with other tests.
78  }
79 
82  {
83  const std::string filename = std::string(GRINS_TEST_UNIT_INPUT_SRCDIR)+"/integrated_function_quad9.in";
84  this->init_sim(filename);
85 
86  libMesh::Point origin(0.0,0.0);
87 
88  // angles for rayfire
89  std::vector<libMesh::Real> theta;
90  theta.push_back(0.0);
91  theta.push_back(0.25);
92 
93  for (unsigned int t=0; t<theta.size(); t++)
94  {
95  libMesh::Real L = 3.0/std::cos(theta[t]);
96  libMesh::Real sintheta = std::sin(theta[t]);
97  libMesh::Real costheta = std::cos(theta[t]);
98 
99  std::vector<std::string> functions;
100  std::vector<libMesh::Real> calc_answers;
101 
102  // constant
103  functions.push_back("1");
104  calc_answers.push_back(L);
105 
106  // linear
107  functions.push_back("x");
108  calc_answers.push_back(0.5/costheta*3.0*3.0);
109  functions.push_back("y");
110  calc_answers.push_back( sintheta/2.0*L*L );
111 
112  // polynomial
113  functions.push_back("x*(y^2)");
114  calc_answers.push_back(0.25*std::pow(L,4)*std::pow(sintheta,2)*costheta);
115  functions.push_back("(4/3)*(x^3)+10");
116  calc_answers.push_back( (4.0/12.0)*pow(costheta,3)*std::pow(L,4)+10*L );
117 
118  GRINS::MultiphysicsSystem* system = _sim->get_multiphysics_system();
119 
120  CPPUNIT_ASSERT_EQUAL(functions.size(), calc_answers.size());
121 
122  // and now the CompositeQoI to do the evalutaion
123  GRINS::CompositeQoI comp_qoi;
124 
125  for (unsigned int i=0; i<functions.size(); i++)
126  {
127  GRINS::RayfireMesh * rayfire = new GRINS::RayfireMesh(origin,theta[t]);
128  GRINS::IntegratedFunction<libMesh::FunctionBase<libMesh::Real> > integ_func((unsigned int)2,new libMesh::ParsedFunction<libMesh::Real>(functions[i]),rayfire,"integrated_function");
129  comp_qoi.add_qoi(integ_func);
130  }
131 
132  comp_qoi.init(*_input,*system);
133  system->attach_qoi(&comp_qoi);
134  system->assemble_qoi();
135 
136  for (unsigned int i=0; i<calc_answers.size(); i++)
137  CPPUNIT_ASSERT_DOUBLES_EQUAL( calc_answers[i], _sim->get_qoi_value(i),libMesh::TOLERANCE );
138 
139  } // for t
140  }
141 
144 
153  {
154  const std::string filename = std::string(GRINS_TEST_UNIT_INPUT_SRCDIR)+"/integrated_function_quad9.in";
155  this->init_sim(filename);
156 
157  libMesh::Point origin(0.0,0.0);
158 
159  // angles for rayfire
160  std::vector<libMesh::Real> theta;
161  theta.push_back(0.0);
162  theta.push_back(0.25);
163 
164  for (unsigned int t=0; t<theta.size(); t++)
165  {
166  libMesh::Real costheta = std::cos(theta[t]);
167  libMesh::Real sintheta = std::sin(theta[t]);
168  libMesh::Real L = 3.0/costheta;
169 
170  std::vector<std::string> functions; // parsed functions
171  std::vector<libMesh::Real> calc_answers; // analytical solutions
172  std::vector<libMesh::Real> tolerance; // absolute error tolerance
173  std::vector<bool> converged;
174 
175  // trig
176  functions.push_back("sin(x)+cos(y)");
177 
178  if (theta[t] == 0.0)
179  calc_answers.push_back( L-std::cos(L)+1.0 );
180  else
181  calc_answers.push_back( ( (std::sin(L*sintheta))/sintheta ) - ( (std::cos(L*costheta)-1.0)/costheta ) );
182 
183  tolerance.push_back(1e-9);
184  converged.push_back(false);
185 
186  // exponential
187  functions.push_back("exp(x)");
188  calc_answers.push_back( (std::exp(3.0) - 1.0) / costheta);
189  tolerance.push_back(1e-8);
190  converged.push_back(false);
191 
192  std::vector<std::vector<libMesh::Real> > errors(functions.size());
193  std::vector<std::vector<libMesh::Real> > h_vals(functions.size());
194 
195  GRINS::MultiphysicsSystem* system = _sim->get_multiphysics_system();
196  GRINS::SharedPtr<libMesh::EquationSystems> es = _sim->get_equation_system();
197 
198  CPPUNIT_ASSERT_EQUAL(functions.size(), calc_answers.size());
199 
200  // and now the CompositeQoI to do the evalutaion
201  GRINS::CompositeQoI comp_qoi;
202 
203  // all functions use the same mesh, so they have identical rayfires.
204  // instead of trying to access each of them directly, we create a reference rayfire that
205  // can be used for checking the number of rayfire elements and
206  // finding the longest rayfire element for calculating convergence
207  GRINS::SharedPtr<GRINS::RayfireMesh> ref_rayfire(new GRINS::RayfireMesh(origin,theta[t]));
208  ref_rayfire->init( system->get_mesh() );
209 
210  for (unsigned int i=0; i<functions.size(); i++)
211  {
212  GRINS::RayfireMesh * rayfire = new GRINS::RayfireMesh(origin,theta[t]);
213  GRINS::IntegratedFunction<libMesh::FunctionBase<libMesh::Real> > integ_func((unsigned int)3,new libMesh::ParsedFunction<libMesh::Real>(functions[i]),rayfire,"integrated_function");
214  comp_qoi.add_qoi(integ_func);
215  }
216 
217  comp_qoi.init(*_input,*system);
218  system->attach_qoi(&comp_qoi);
219 
220  libMesh::MeshRefinement mr(system->get_mesh());
221 
222  unsigned int num_converged = 0;
223  unsigned int iter = 0;
224 
225  // limit iterations to prevent excessive runtime
226  unsigned int max_iter = 7;
227 
228  // calculate qoi's, check error
229  // refine until all qoi's converge within their tolerance
230  do
231  {
232  std::vector<libMesh::dof_id_type> elems_in_rayfire;
233  ref_rayfire->elem_ids_in_rayfire(elems_in_rayfire);
234 
235  system->assemble_qoi();
236 
237  // get the length of the longest rayfire elem
238  libMesh::Real h = -1.0;
239  for (unsigned int i=0; i<elems_in_rayfire.size(); i++)
240  {
241  libMesh::Real l = (ref_rayfire->map_to_rayfire_elem(elems_in_rayfire[i]))->length(0,1);
242  if (l>h)
243  h=l;
244  }
245 
246  CPPUNIT_ASSERT(h > 0.0);
247 
248  // check for convergence
249  for (unsigned int i=0; i<calc_answers.size(); i++)
250  {
251  if (!converged[i])
252  {
253  libMesh::Real err = std::abs( _sim->get_qoi_value(i) - calc_answers[i] );
254  if (err < tolerance[i])
255  {
256  num_converged++;
257  converged[i] = true;
258  h_vals[i].push_back(std::log10(h));
259  errors[i].push_back(std::log10(err));
260  }
261  else
262  {
263  h_vals[i].push_back(std::log10(h));
264  errors[i].push_back(std::log10(err));
265  }
266  }
267  }
268 
269  // if all functions have not yet converged, refine along the rayfire
270  if (num_converged < calc_answers.size())
271  {
272  if (iter++ > max_iter+1 )
273  libmesh_error_msg("Exceeded maximum iterations");
274 
275  for (unsigned int i=0; i<elems_in_rayfire.size(); i++)
276  system->get_mesh().elem_ref(elems_in_rayfire[i]).set_refinement_flag(libMesh::Elem::RefinementState::REFINE);
277 
278  mr.refine_elements();
279 
280  // ensure all elems marked for refinement were actually refined
281  for (unsigned int i=0; i<elems_in_rayfire.size(); i++)
282  CPPUNIT_ASSERT( !( system->get_mesh().elem_ref(elems_in_rayfire[i]).active() ) );
283 
284  // need to manually reinit the reference rayfire
285  ref_rayfire->reinit(system->get_mesh());
286 
287  // and reinit the CompositeQoI (which will reinit all internal rayfires)
288  libMesh::DifferentiableQoI* diff_qoi = system->get_qoi();
289  GRINS::CompositeQoI* qoi = libMesh::cast_ptr<GRINS::CompositeQoI*>(diff_qoi);
290  qoi->reinit(*system);
291 
292  es->reinit();
293  }
294 
295  } while(num_converged < calc_answers.size());
296 
297  // verify that all functions had quartic convergence within 2%
298  for (unsigned int i=0; i<functions.size(); i++)
299  this->check_convergence_rate(h_vals[i],errors[i],0,errors[i].size()-1,4.0,0.08);
300 
301  } //for t
302  }
303 
307  {
308  const std::string filename = std::string(GRINS_TEST_UNIT_INPUT_SRCDIR)+"/integrated_function_qoi_quad9.in";
309  this->init_sim(filename);
310 
311  libMesh::Real theta = 0.25;
312  libMesh::Real L = 10.0/std::cos(theta);
313  libMesh::Real costheta = std::cos(theta);
314 
315  // function: "(4/3)*(x^3)+10"
316 
317  libMesh::Real calc_answer = (4.0/12.0)*pow(costheta,3)*std::pow(L,4)+10*L;
318 
319  _sim->run();
320 
321  CPPUNIT_ASSERT_DOUBLES_EQUAL( calc_answer, _sim->get_qoi_value(0),libMesh::TOLERANCE );
322  }
323 
326  {
327  const std::string filename = std::string(GRINS_TEST_UNIT_INPUT_SRCDIR)+"/integrated_function_quad9.in";
328  this->init_sim(filename);
329 
330  libMesh::Point origin(0.0,0.0);
331  libMesh::Real theta = 0.0;
332 
333  GRINS::MultiphysicsSystem* system = _sim->get_multiphysics_system();
334  GRINS::SharedPtr<libMesh::EquationSystems> es = _sim->get_equation_system();
335 
336  libMesh::MeshRefinement mr(system->get_mesh());
337 
338  // build rayfire
339  GRINS::RayfireMesh * rayfire = new GRINS::RayfireMesh(origin,theta);
340 
341  // and now the CompositeQoI to do the evalutaion
342  GRINS::CompositeQoI comp_qoi;
343 
344  libMesh::Real costheta = std::cos(theta);
345 
346  // simple function
347  std::string function = "x";
348  libMesh::Real calc_answer = 0.5/costheta*3.0*3.0;
349 
350  GRINS::IntegratedFunction<libMesh::FunctionBase<libMesh::Real> > integ_func((unsigned int)3,new libMesh::ParsedFunction<libMesh::Real>(function),rayfire,"integrated_function");
351  comp_qoi.add_qoi(integ_func);
352 
353  comp_qoi.init(*_input,*system);
354  system->attach_qoi(&comp_qoi);
355 
356  // evaluate qoi
357  system->assemble_qoi();
358 
359  // ensure we get the correct answer
360  CPPUNIT_ASSERT_DOUBLES_EQUAL( calc_answer, _sim->get_qoi_value(0),libMesh::TOLERANCE );
361 
362  // get the IntegratedFunction object, since comp_qoi would have already been cloned
363  libMesh::DifferentiableQoI* diff_qoi = system->get_qoi();
364  GRINS::CompositeQoI* qoi = libMesh::cast_ptr<GRINS::CompositeQoI*>(diff_qoi);
365  GRINS::IntegratedFunction<libMesh::FunctionBase<libMesh::Real> > * integrated_func = libMesh::cast_ptr<GRINS::IntegratedFunction<libMesh::FunctionBase<libMesh::Real> > * >( &(qoi->get_qoi(0)) );
366 
367  // make sure we have exactly 3 elements along the rayfire
368  std::vector<libMesh::dof_id_type> elems_in_rayfire;
369  integrated_func->get_rayfire().elem_ids_in_rayfire(elems_in_rayfire);
370  unsigned int num_rayfire_elems = elems_in_rayfire.size();
371  CPPUNIT_ASSERT_EQUAL((unsigned int)3,num_rayfire_elems);
372 
373  for (unsigned int i=0; i<elems_in_rayfire.size(); i++)
374  system->get_mesh().elem_ref(elems_in_rayfire[i]).set_refinement_flag(libMesh::Elem::RefinementState::REFINE);
375 
376  mr.refine_elements();
377 
378  // this should trigger RayfireMesh::reinit()
379  es->reinit();
380 
381  // recalculate the qoi to make sure
382  // we still get the same answer
383  system->assemble_qoi();
384 
385  // after the refinement, we should now have 6 rayfire elements
386  std::vector<libMesh::dof_id_type> refined_elems_in_rayfire;
387  integrated_func->get_rayfire().elem_ids_in_rayfire(refined_elems_in_rayfire);
388  unsigned int num_refined_rayfire_elems = refined_elems_in_rayfire.size();
389  CPPUNIT_ASSERT_EQUAL((unsigned int)6,num_refined_rayfire_elems);
390  CPPUNIT_ASSERT_DOUBLES_EQUAL( calc_answer, _sim->get_qoi_value(0),libMesh::TOLERANCE );
391  }
392 
393 
394  private:
395  GRINS::SharedPtr<GRINS::Simulation> _sim;
396  GRINS::SharedPtr<GetPot> _input;
397 
399  void init_sim(const std::string& filename)
400  {
401  _input.reset(new GetPot(filename));
402 
403  const char* const argv = "unit_driver";
404  GetPot empty_command_line( (const int)1,&argv );
405  GRINS::SimulationBuilder sim_builder;
406 
407  _sim = new GRINS::Simulation(*_input,
408  empty_command_line,
409  sim_builder,
410  *TestCommWorld );
411  }
412 
413  };
414 
415  CPPUNIT_TEST_SUITE_REGISTRATION( IntegratedFunctionTest );
416 
417 } // end namespace GRINSTesting
418 
419 #endif // GRINS_HAVE_CPPUNIT
CPPUNIT_TEST_SUITE_REGISTRATION(AntiochAirNASA9ThermoTest)
CPPUNIT_TEST_SUITE(IntegratedFunctionTest)
RayfireMesh.
Definition: rayfire_mesh.h:65
libMesh::Parallel::Communicator * TestCommWorld
Definition: unit_driver.C:70
const QoIBase & get_qoi(unsigned int qoi_index) const
void test_convergence()
A quartic convergence rate is identified by graphing log(error) vs.
void reinit_through_system()
Here, we use CompositeQoI::reinit() to reinitialize the rayfire post-refinement.
virtual void reinit()
Override FEMSystem::reinit.
void check_convergence_rate(std::vector< libMesh::Real > x, std::vector< libMesh::Real > y, unsigned int start_index, unsigned int end_index, libMesh::Real convergence_rate, libMesh::Real tol)
Check the convergence rate of the supplied data to within the given absolute tolerance.
void test_exact_answer()
Functions that can be integrated exactly using Gauss Quadrature.
Interface with libMesh for solving Multiphysics problems.
virtual void add_qoi(const QoIBase &qoi)
Definition: composite_qoi.C:70
GRINS::SharedPtr< GRINS::Simulation > _sim
virtual void init(const GetPot &input, const MultiphysicsSystem &system)
Method to allow QoI to cache any system information needed for QoI calculation, for example...
Definition: composite_qoi.C:94
static void clear()
Clears the var_map()
void init_sim(const std::string &filename)
Initialize the GetPot and Simulation class objects.
virtual void reinit(MultiphysicsSystem &system)
Reinitialize qoi.

Generated on Tue Dec 19 2017 12:47:29 for GRINS-0.8.0 by  doxygen 1.8.9.1