VertexCFD  0.0-dev
VertexCFD_EvaluatorTestHarness.hpp
1 #ifndef VERTEXCFD_EVALUATORTESTHARNESS_HPP
2 #define VERTEXCFD_EVALUATORTESTHARNESS_HPP
3 
4 #include <Panzer_BasisIRLayout.hpp>
5 #include <Panzer_BasisValues2.hpp>
6 #include <Panzer_CellData.hpp>
7 #include <Panzer_CommonArrayFactories.hpp>
8 #include <Panzer_Dimension.hpp>
9 #include <Panzer_IntegrationRule.hpp>
10 #include <Panzer_IntegrationValues2.hpp>
11 #include <Panzer_Traits.hpp>
12 #include <Panzer_Workset.hpp>
13 
14 #include <Phalanx_Evaluator.hpp>
15 #include <Phalanx_FieldManager.hpp>
16 #include <Phalanx_KokkosDeviceTypes.hpp>
17 
18 #include <Shards_BasicTopologies.hpp>
19 #include <Shards_CellTopology.hpp>
20 #include <Shards_CellTopologyData.h>
21 #include <Shards_CellTopologyTraits.hpp>
22 
23 #include <Teuchos_RCP.hpp>
24 
25 #include <gtest/gtest.h>
26 
27 #include <Kokkos_Core.hpp>
28 
29 #include <Trilinos_version.h>
30 
31 #include <exception>
32 #include <sstream>
33 #include <string>
34 #include <vector>
35 
36 namespace VertexCFD
37 {
38 namespace Test
39 {
40 //---------------------------------------------------------------------------//
41 // Evaluator cell test fixture.
43 {
44  Teuchos::RCP<PHX::FieldManager<panzer::Traits>> fm;
45  Teuchos::RCP<shards::CellTopology> cell_topo;
46  Teuchos::RCP<panzer::Workset> workset;
47  Teuchos::RCP<panzer::CellData> cell_data;
48  Teuchos::RCP<panzer::IntegrationRule> ir;
49  Teuchos::RCP<panzer::IntegrationValues2<double>> int_values;
50  Teuchos::RCP<panzer::BasisIRLayout> basis_ir_layout;
51  Teuchos::RCP<panzer::BasisValues2<double>> basis_values;
52  Teuchos::RCP<std::vector<panzer::Workset>> worksets;
53  Teuchos::RCP<panzer::Traits::SD> setup_data;
54 
55  using host_coords_view = Kokkos::View<double***,
56  typename PHX::DevLayout<double>::type,
57  PHX::Device>::HostMirror;
58 
59  // Create an evaluator test fixture object. If a side id is not specified
60  // then integration rules will be setup over the volume of the cell
61  // instead of the side.
62  EvaluatorTestFixture(const CellTopologyData* cell_topo_data,
63  const host_coords_view host_coords,
64  const int integration_order,
65  const int basis_order,
66  const int side_id = -1)
67  {
68  initialize(cell_topo_data,
69  host_coords,
70  integration_order,
71  basis_order,
72  side_id);
73  }
74 
75  // Use a default cell topology.
76  EvaluatorTestFixture(const int num_space_dim,
77  const int integration_order,
78  const int basis_order,
79  const int side_id = -1)
80  {
81  // Single cell.
82  const int num_cell = 1;
83 
84  const CellTopologyData* cell_topo_data = nullptr;
85  host_coords_view host_coords;
86 
87  // Build a line, quad, or hex as the test cell.
88  if (1 == num_space_dim)
89  {
90  cell_topo_data = shards::getCellTopologyData<shards::Line<2>>();
91 
92  host_coords = host_coords_view("coords", num_cell, 2, 1);
93 
94  host_coords(0, 0, 0) = 0.0;
95  host_coords(0, 1, 0) = 1.0;
96  }
97  else if (2 == num_space_dim)
98  {
99  cell_topo_data
100  = shards::getCellTopologyData<shards::Quadrilateral<4>>();
101 
102  host_coords = host_coords_view("coords", num_cell, 4, 2);
103 
104  host_coords(0, 0, 0) = 0.0;
105  host_coords(0, 0, 1) = 0.0;
106 
107  host_coords(0, 1, 0) = 1.0;
108  host_coords(0, 1, 1) = 0.0;
109 
110  host_coords(0, 2, 0) = 1.0;
111  host_coords(0, 2, 1) = 1.0;
112 
113  host_coords(0, 3, 0) = 0.0;
114  host_coords(0, 3, 1) = 1.0;
115  }
116  else if (3 == num_space_dim)
117  {
118  cell_topo_data
119  = shards::getCellTopologyData<shards::Hexahedron<8>>();
120 
121  host_coords = host_coords_view("coords", num_cell, 8, 3);
122 
123  host_coords(0, 0, 0) = 0.0;
124  host_coords(0, 0, 1) = 0.0;
125  host_coords(0, 0, 2) = 0.0;
126 
127  host_coords(0, 1, 0) = 1.0;
128  host_coords(0, 1, 1) = 0.0;
129  host_coords(0, 1, 2) = 0.0;
130 
131  host_coords(0, 2, 0) = 1.0;
132  host_coords(0, 2, 1) = 1.0;
133  host_coords(0, 2, 2) = 0.0;
134 
135  host_coords(0, 3, 0) = 0.0;
136  host_coords(0, 3, 1) = 1.0;
137  host_coords(0, 3, 2) = 0.0;
138 
139  host_coords(0, 4, 0) = 0.0;
140  host_coords(0, 4, 1) = 0.0;
141  host_coords(0, 4, 2) = 1.0;
142 
143  host_coords(0, 5, 0) = 1.0;
144  host_coords(0, 5, 1) = 0.0;
145  host_coords(0, 5, 2) = 1.0;
146 
147  host_coords(0, 6, 0) = 1.0;
148  host_coords(0, 6, 1) = 1.0;
149  host_coords(0, 6, 2) = 1.0;
150 
151  host_coords(0, 7, 0) = 0.0;
152  host_coords(0, 7, 1) = 1.0;
153  host_coords(0, 7, 2) = 1.0;
154  }
155  else
156  {
157  std::ostringstream msg;
158  msg << "Invalid spatial dimensions (" << num_space_dim
159  << "): must be 1, 2, or 3.";
160  throw std::logic_error(msg.str());
161  }
162 
163  initialize(cell_topo_data,
164  host_coords,
165  integration_order,
166  basis_order,
167  side_id);
168  }
169 
170  // Add an evaluator to the manager.
171  template<class EvalType>
172  void
173  registerEvaluator(const Teuchos::RCP<PHX::Evaluator<panzer::Traits>>& eval)
174  {
175  fm->registerEvaluator<EvalType>(eval);
176  }
177 
178  // Register fields that will be checked in the test.
179  template<class EvalType, class Field>
180  void registerTestField(const Field& field)
181  {
182  fm->requireField<EvalType>(field.fieldTag());
183  }
184 
185  // Set time.
186  void setTime(const double& time) { workset->time = time; }
187 
188  // Set stage number
189  void setStageNumber(const int& stage) { workset->stage_number = stage; }
190 
191  // Set time step size.
192  void setStepSize(const double& step_size)
193  {
194  workset->step_size = step_size;
195  }
196 
197  void postRegSetup()
198  {
199  // Moved from evaluate()
200  setup_data = Teuchos::rcp(new panzer::Traits::SD);
201  worksets = Teuchos::rcp(new std::vector<panzer::Workset>);
202  worksets->push_back(*workset);
203  setup_data->worksets_ = worksets;
204  std::vector<PHX::index_size_type> derivative_dimensions;
205  derivative_dimensions.push_back(4);
206  fm->setKokkosExtendedDataTypeDimensions<panzer::Traits::Jacobian>(
207  derivative_dimensions);
208  fm->postRegistrationSetup(*setup_data);
209  }
210 
211  // Evaluate.
212  template<class EvalType>
213  void evaluate(const bool& doPostRegSetup = true)
214  {
215  if (doPostRegSetup)
216  this->postRegSetup();
217 
218  const panzer::Traits::PED ped;
219  fm->preEvaluate<EvalType>(ped);
220  fm->evaluateFields<EvalType>(*workset);
221  fm->postEvaluate<EvalType>(0);
222  }
223 
224  // Get a test field on the host to test after evaluation.
225  template<class EvalType, class Field>
226  auto getTestFieldData(const Field& field) const
227  {
228  auto field_view = field.get_static_view();
229  auto field_mirror = Kokkos::create_mirror(field_view);
230  Kokkos::deep_copy(field_mirror, field_view);
231  return field_mirror;
232  }
233 
234  // Get the number of quadrature points.
235  int numPoint() const { return ir->num_points; }
236 
237  // Get the number of basis points.
238  int cardinality() const { return basis_ir_layout->cardinality(); }
239 
240  private:
241  void initialize(const CellTopologyData* cell_topo_data,
242  const host_coords_view host_coords,
243  const int integration_order,
244  const int basis_order,
245  const int side_id)
246  {
247  cell_topo = Teuchos::rcp(new shards::CellTopology(cell_topo_data));
248 
249  const int num_space_dim = cell_topo->getDimension();
250 
251  if (num_space_dim != host_coords.extent_int(2))
252  {
253  std::ostringstream msg;
254  msg << "Unexpected spatial dimensions in provided coordinates: "
255  << cell_topo->getName() << " expects " << num_space_dim
256  << " dimensions, but " << host_coords.extent(2)
257  << " were provided.";
258  throw std::logic_error(msg.str());
259  }
260 
261  const int nodes_per_cell = cell_topo->getNodeCount();
262 
263  if (nodes_per_cell != host_coords.extent_int(1))
264  {
265  std::ostringstream msg;
266  msg << "Unexpected node count in provided coordinates: "
267  << cell_topo->getName() << " expects " << nodes_per_cell
268  << " nodes, but " << host_coords.extent(1)
269  << " were provided.";
270  throw std::logic_error(msg.str());
271  }
272 
273  const int num_cell = host_coords.extent(0);
274 
275  // Create field manager.
276  fm = Teuchos::rcp(new PHX::FieldManager<panzer::Traits>);
277 
278  // Create the workset.
279  workset = Teuchos::rcp(new panzer::Workset);
280  workset->num_cells = num_cell;
281 
282  // Fill cell local IDs
283  {
284  const Kokkos::View<int*, PHX::Device> cell_local_ids_k(
285  "cell_local_ids_k", num_cell);
286  auto cell_local_ids_k_host
287  = Kokkos::create_mirror_view(cell_local_ids_k);
288 
289  workset->cell_local_ids.resize(num_cell);
290 
291  for (int i = 0; i < num_cell; ++i)
292  {
293  cell_local_ids_k_host(i) = i;
294  workset->cell_local_ids[i] = i;
295  }
296 
297  Kokkos::deep_copy(cell_local_ids_k, cell_local_ids_k_host);
298  workset->cell_local_ids_k = cell_local_ids_k;
299  }
300 
301  workset->block_id = "block_0";
302  workset->ir_degrees = Teuchos::rcp(new std::vector<int>);
303  workset->basis_names = Teuchos::rcp(new std::vector<std::string>);
304  workset->time = 0.0;
305  workset->step_size = 0.0;
306 
307  const panzer::MDFieldArrayFactory array_factory("", true);
308  auto& node_coords = workset->cell_node_coordinates;
309  node_coords
310  = array_factory
311  .buildStaticArray<double, panzer::Cell, panzer::NODE, panzer::Dim>(
312  "coords", num_cell, nodes_per_cell, num_space_dim);
313 
314  Kokkos::deep_copy(node_coords.get_static_view(), host_coords);
315 
316  // Setup a cell.
317  cell_data
318  = Teuchos::rcp(new panzer::CellData(num_cell, side_id, cell_topo));
319 
320  // Create integration rule and populate integration values.
321  ir = Teuchos::rcp(
322  new panzer::IntegrationRule(integration_order, *cell_data));
323  int_values
324  = Teuchos::rcp(new panzer::IntegrationValues2<double>("", true));
325  int_values->setupArrays(ir);
326  int_values->evaluateValues(node_coords);
327  workset->ir_degrees->push_back(ir->cubature_degree);
328  workset->int_rules.push_back(int_values);
329 
330  // Create basis and populate basis values.
331  basis_ir_layout = panzer::basisIRLayout("HGrad", basis_order, *ir);
332  basis_values
333  = Teuchos::rcp(new panzer::BasisValues2<double>("", true, true));
334  basis_values->setupArrays(basis_ir_layout);
335  basis_values->evaluateValues(int_values->cub_points,
336  int_values->jac,
337  int_values->jac_det,
338  int_values->jac_inv,
339  int_values->weighted_measure,
340  int_values->node_coordinates);
341  workset->bases.push_back(basis_values);
342  workset->basis_names->push_back(basis_ir_layout->getBasis()->name());
343  }
344 };
345 
346 //---------------------------------------------------------------------------//
347 // For a residual evaluation, the field value is a double and returned as-is.
348 double accessValue(double v)
349 {
350  return v;
351 }
352 
353 //---------------------------------------------------------------------------//
354 // For a Jacobian evaluation, the field value is Sacado FAD type, so return its
355 // value.
356 template<class Value>
357 double accessValue(Value&& v)
358 {
359  return accessValue(v.val());
360 }
361 
362 //---------------------------------------------------------------------------//
363 // Access a field value at the given indices.
364 template<class Field, class... Indices>
365 double fieldValue(Field f, const Indices... i)
366 {
367  return accessValue(f(i...));
368 }
369 
370 //---------------------------------------------------------------------------//
371 
372 } // end namespace Test
373 } // end namespace VertexCFD
374 
375 #endif // end VERTEXCFD_EVALUATORTESTHARNESS_HPP
VertexCFD
Definition: tstMethodManufacturedSolutionBC.cpp:23
VertexCFD::Test::EvaluatorTestFixture
Definition: VertexCFD_EvaluatorTestHarness.hpp:43