Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_IntegrationValues2.cpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Panzer: A partial differential equation assembly
5 // engine for strongly coupled complex multiphysics systems
6 // Copyright (2011) Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact Roger P. Pawlowski (rppawlo@sandia.gov) and
39 // Eric C. Cyr (eccyr@sandia.gov)
40 // ***********************************************************************
41 // @HEADER
42 
44 #include "Panzer_UtilityAlgs.hpp"
45 
46 #include "Shards_CellTopology.hpp"
47 
48 #include "Kokkos_DynRankView.hpp"
49 #include "Intrepid2_FunctionSpaceTools.hpp"
50 #include "Intrepid2_RealSpaceTools.hpp"
51 #include "Intrepid2_CellTools.hpp"
52 #include "Intrepid2_ArrayTools.hpp"
53 #include "Intrepid2_CubatureControlVolume.hpp"
54 #include "Intrepid2_CubatureControlVolumeSide.hpp"
55 #include "Intrepid2_CubatureControlVolumeBoundary.hpp"
56 
58 #include "Panzer_Traits.hpp"
59 
60 // ***********************************************************
61 // * Specializations of setupArrays() for different array types
62 // ***********************************************************
63 
64 namespace panzer {
65 
66 // * Specialization for Kokkos::DynRankView<double,PHX::Device>
67 template <typename Scalar>
70 {
71  MDFieldArrayFactory af(prefix,alloc_arrays);
72 
73  int num_nodes = ir->topology->getNodeCount();
74  int num_cells = ir->workset_size;
75  int num_space_dim = ir->topology->getDimension();
76 
77  int num_ip = 1;
78 
79  dyn_cub_points = af.template buildArray<double,IP,Dim>("cub_points",num_ip, num_space_dim);
80  dyn_cub_weights = af.template buildArray<double,IP>("cub_weights",num_ip);
81 
82  cub_points = af.template buildStaticArray<Scalar,IP,Dim>("cub_points",num_ip, num_space_dim);
83 
84  if (ir->cv_type == "none" && ir->isSide()) {
85  dyn_side_cub_points = af.template buildArray<double,IP,Dim>("side_cub_points",num_ip, ir->side_topology->getDimension());
86  side_cub_points = af.template buildStaticArray<Scalar,IP,Dim>("side_cub_points",num_ip,ir->side_topology->getDimension());
87  }
88 
89  if (ir->cv_type != "none") {
90  dyn_phys_cub_points = af.template buildArray<double,Cell,IP,Dim>("phys_cub_points",num_cells, num_ip, num_space_dim);
91  dyn_phys_cub_weights = af.template buildArray<double,Cell,IP>("phys_cub_weights",num_cells, num_ip);
92  if (ir->cv_type == "side") {
93  dyn_phys_cub_norms = af.template buildArray<double,Cell,IP,Dim>("phys_cub_norms",num_cells, num_ip, num_space_dim);
94  }
95  }
96 
97  dyn_node_coordinates = af.template buildArray<double,Cell,BASIS,Dim>("node_coordinates",num_cells, num_nodes, num_space_dim);
98 
99  cub_weights = af.template buildStaticArray<Scalar,IP>("cub_weights",num_ip);
100 
101  node_coordinates = af.template buildStaticArray<Scalar,Cell,BASIS,Dim>("node_coordinates",num_cells, num_nodes, num_space_dim);
102 
103  jac = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("jac",num_cells, num_ip, num_space_dim,num_space_dim);
104 
105  jac_inv = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("jac_inv",num_cells, num_ip, num_space_dim,num_space_dim);
106 
107  jac_det = af.template buildStaticArray<Scalar,Cell,IP>("jac_det",num_cells, num_ip);
108 
109  weighted_measure = af.template buildStaticArray<Scalar,Cell,IP>("weighted_measure",num_cells, num_ip);
110 
111  covarient = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("covarient",num_cells, num_ip, num_space_dim,num_space_dim);
112 
113  contravarient = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("contravarient",num_cells, num_ip, num_space_dim,num_space_dim);
114 
115  norm_contravarient = af.template buildStaticArray<Scalar,Cell,IP>("norm_contravarient",num_cells, num_ip);
116 
117  ip_coordinates = af.template buildStaticArray<Scalar,Cell,IP,Dim>("ip_coordiantes",num_cells, num_ip,num_space_dim);
118 
119  ref_ip_coordinates = af.template buildStaticArray<Scalar,Cell,IP,Dim>("ref_ip_coordinates",num_cells, num_ip,num_space_dim);
120 
121  weighted_normals = af.template buildStaticArray<Scalar,Cell,IP,Dim>("weighted normal",num_cells, num_ip,num_space_dim);
122 
123  surface_normals = af.template buildStaticArray<Scalar,Cell,IP,Dim>("surface_normals",num_cells, num_ip,num_space_dim);
124 
125  surface_rotation_matrices = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("surface_rotation_matrices",num_cells, num_ip,3,3);
126 
127 }
128 
129 template <typename Scalar>
132 {
133  MDFieldArrayFactory af(prefix,alloc_arrays);
134 
136 
137  int_rule = ir;
138 
139  int num_nodes = ir->topology->getNodeCount();
140  int num_cells = ir->workset_size;
141  int num_space_dim = ir->topology->getDimension();
142 
143  // specialize content if this is quadrature at anode
144  if(num_space_dim==1 && ir->isSide()) {
145  setupArraysForNodeRule(ir);
146  return;
147  }
148 
149  TEUCHOS_ASSERT(ir->getType() != ID::NONE);
150  intrepid_cubature = getIntrepidCubature(*ir);
151 
152  int num_ip = ir->num_points;
153 
154 // Intrepid2::DefaultCubatureFactory cubature_factory;
155 //
156 // if (ir->cv_type == "side")
157 // intrepid_cubature = Teuchos::rcp(new Intrepid2::CubatureControlVolumeSide<PHX::Device::execution_space,double,double>(*ir->topology));
158 //
159 // else if (ir->cv_type == "volume")
160 // intrepid_cubature = Teuchos::rcp(new Intrepid2::CubatureControlVolume<PHX::Device::execution_space,double,double>(*ir->topology));
161 //
162 // else if (ir->cv_type == "boundary" && ir->isSide())
163 // intrepid_cubature = Teuchos::rcp(new Intrepid2::CubatureControlVolumeBoundary<PHX::Device::execution_space,double,double>(*ir->topology,ir->side));
164 //
165 // else if (ir->cv_type == "none" && ir->isSide())
166 // intrepid_cubature = cubature_factory.create<PHX::Device::execution_space,double,double>(*(ir->side_topology),
167 // ir->cubature_degree);
168 // else
169 // intrepid_cubature = cubature_factory.create<PHX::Device::execution_space,double,double>(*(ir->topology),
170 // ir->cubature_degree);
171 // int num_ip = intrepid_cubature->getNumPoints();
172 
173  dyn_cub_points = af.template buildArray<double,IP,Dim>("cub_points",num_ip, num_space_dim);
174  dyn_cub_weights = af.template buildArray<double,IP>("cub_weights",num_ip);
175 
176  cub_points = af.template buildStaticArray<Scalar,IP,Dim>("cub_points",num_ip, num_space_dim);
177 
178  if (ir->isSide() && ir->cv_type == "none") {
179  dyn_side_cub_points = af.template buildArray<double,IP,Dim>("side_cub_points",num_ip, ir->side_topology->getDimension());
180  side_cub_points = af.template buildStaticArray<Scalar,IP,Dim>("side_cub_points",num_ip,ir->side_topology->getDimension());
181  }
182 
183  if (ir->cv_type != "none") {
184  dyn_phys_cub_points = af.template buildArray<double,Cell,IP,Dim>("phys_cub_points",num_cells, num_ip, num_space_dim);
185  dyn_phys_cub_weights = af.template buildArray<double,Cell,IP>("phys_cub_weights",num_cells, num_ip);
186  if (ir->cv_type == "side") {
187  dyn_phys_cub_norms = af.template buildArray<double,Cell,IP,Dim>("phys_cub_norms",num_cells, num_ip, num_space_dim);
188  }
189  }
190 
191  dyn_node_coordinates = af.template buildArray<double,Cell,BASIS,Dim>("node_coordinates",num_cells, num_nodes, num_space_dim);
192 
193  cub_weights = af.template buildStaticArray<Scalar,IP>("cub_weights",num_ip);
194 
195  node_coordinates = af.template buildStaticArray<Scalar,Cell,BASIS,Dim>("node_coordinates",num_cells, num_nodes, num_space_dim);
196 
197  jac = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("jac",num_cells, num_ip, num_space_dim,num_space_dim);
198 
199  jac_inv = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("jac_inv",num_cells, num_ip, num_space_dim,num_space_dim);
200 
201  jac_det = af.template buildStaticArray<Scalar,Cell,IP>("jac_det",num_cells, num_ip);
202 
203  weighted_measure = af.template buildStaticArray<Scalar,Cell,IP>("weighted_measure",num_cells, num_ip);
204 
205  covarient = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("covarient",num_cells, num_ip, num_space_dim,num_space_dim);
206 
207  contravarient = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("contravarient",num_cells, num_ip, num_space_dim,num_space_dim);
208 
209  norm_contravarient = af.template buildStaticArray<Scalar,Cell,IP>("norm_contravarient",num_cells, num_ip);
210 
211  ip_coordinates = af.template buildStaticArray<Scalar,Cell,IP,Dim>("ip_coordiantes",num_cells, num_ip,num_space_dim);
212 
213  ref_ip_coordinates = af.template buildStaticArray<Scalar,Cell,IP,Dim>("ref_ip_coordinates",num_cells, num_ip,num_space_dim);
214 
215  weighted_normals = af.template buildStaticArray<Scalar,Cell,IP,Dim>("weighted_normal",num_cells,num_ip,num_space_dim);
216 
217  surface_normals = af.template buildStaticArray<Scalar,Cell,IP,Dim>("surface_normals",num_cells, num_ip,num_space_dim);
218 
219  surface_rotation_matrices = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("surface_rotation_matrices",num_cells, num_ip,3,3);
220 
221  scratch_for_compute_side_measure =
222  af.template buildStaticArray<Scalar,Point>("scratch_for_compute_side_measure", jac.get_view().span());
223 
224 }
225 
226 template <typename Scalar>
230 {
233 
234  Intrepid2::DefaultCubatureFactory cubature_factory;
235 
236  if(ir.getType() == ID::CV_SIDE){
237  ic = Teuchos::rcp(new Intrepid2::CubatureControlVolumeSide<PHX::Device::execution_space,double,double>(*ir.topology));
238  } else if(ir.getType() == ID::CV_VOLUME){
239  ic = Teuchos::rcp(new Intrepid2::CubatureControlVolume<PHX::Device::execution_space,double,double>(*ir.topology));
240  } else if(ir.getType() == ID::CV_BOUNDARY){
241  ic = Teuchos::rcp(new Intrepid2::CubatureControlVolumeBoundary<PHX::Device::execution_space,double,double>(*ir.topology,ir.getSide()));
242  } else {
243  if(ir.getType() == ID::VOLUME){
244  ic = cubature_factory.create<PHX::Device::execution_space,double,double>(*(ir.topology),ir.getOrder());
245  } else if(ir.getType() == ID::SIDE){
246  ic = cubature_factory.create<PHX::Device::execution_space,double,double>(*(ir.side_topology),ir.getOrder());
247  } else if(ir.getType() == ID::SURFACE){
248  // closed surface integrals don't exist in intrepid.
249  } else {
250  TEUCHOS_ASSERT(false);
251  }
252  }
253 
254  return ic;
255 }
256 
257 
258 // ***********************************************************
259 // * Evaluation of values - NOT specialized
260 // ***********************************************************
261 template <typename Scalar>
263 evaluateValues(const PHX::MDField<Scalar,Cell,NODE,Dim> & in_node_coordinates,
264  const int in_num_cells)
265 {
267  const bool is_surface = int_rule->getType() == ID::SURFACE;
268  const bool is_cv = (int_rule->getType() == ID::CV_VOLUME) or (int_rule->getType() == ID::CV_SIDE) or (int_rule->getType() == ID::CV_BOUNDARY);
269 
270  TEUCHOS_ASSERT(not (is_surface and is_cv));
271 
272  if(is_surface){
273  generateSurfaceCubatureValues(in_node_coordinates,in_num_cells);
274  } else if (is_cv) {
275  getCubatureCV(in_node_coordinates, in_num_cells);
276  evaluateValuesCV(in_node_coordinates, in_num_cells);
277  } else {
278  getCubature(in_node_coordinates, in_num_cells);
279  evaluateRemainingValues(in_node_coordinates, in_num_cells);
280  }
281 }
282 
283 template <typename Scalar>
285 getCubature(const PHX::MDField<Scalar,Cell,NODE,Dim>& in_node_coordinates,
286  const int in_num_cells)
287 {
288 
289  int num_space_dim = int_rule->topology->getDimension();
290  if (int_rule->isSide() && num_space_dim==1) {
291  std::cout << "WARNING: 0-D quadrature rule ifrastructure does not exist!!! Will not be able to do "
292  << "non-natural integration rules.";
293  return;
294  }
295 
296  Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
297 
298  if (!int_rule->isSide())
299  intrepid_cubature->getCubature(dyn_cub_points.get_view(), dyn_cub_weights.get_view());
300  else {
301  intrepid_cubature->getCubature(dyn_side_cub_points.get_view(), dyn_cub_weights.get_view());
302 
303  cell_tools.mapToReferenceSubcell(dyn_cub_points.get_view(),
304  dyn_side_cub_points.get_view(),
305  int_rule->spatial_dimension-1,
306  int_rule->side,
307  *(int_rule->topology));
308  }
309 
310  // IP coordinates
311  const int num_cells = in_num_cells < 0 ? in_node_coordinates.extent(0) : in_num_cells;
312  auto s_ip_coordinates = Kokkos::subview(ip_coordinates.get_view(),std::make_pair(0,num_cells),Kokkos::ALL(),Kokkos::ALL());
313  auto s_in_node_coordinates = Kokkos::subview(in_node_coordinates.get_view(),std::make_pair(0,num_cells),Kokkos::ALL(),Kokkos::ALL());
314  cell_tools.mapToPhysicalFrame(s_ip_coordinates,
315  dyn_cub_points.get_view(),
316  s_in_node_coordinates,
317  *(int_rule->topology));
318 }
319 
320 
321 
322 
323 
324 namespace
325 {
326 
327 template <typename array_t, typename scalar_t>
328 class point_sorter_t
329 {
330 public:
331 
332  point_sorter_t() = delete;
333  point_sorter_t(const array_t & array, const int cell, const int offset):
334  _array(array),
335  _cell(cell),
336  _offset(offset),
337  _rel_tol(1.e-12)
338  {
339  _num_dims=_array.extent(2);
340  }
341 
342 
343  // This needs to be optimized
344  bool operator()(const int & point_a, const int & point_b) const
345  {
346 
347  if(_num_dims==1){
348 
349  const scalar_t & x_a = _array(_cell,_offset+point_a,0);
350  const scalar_t & x_b = _array(_cell,_offset+point_b,0);
351 
352  const scalar_t rel = std::max(std::fabs(x_a),std::fabs(x_b));
353 
354  return test_less(x_a,x_b,rel);
355 
356  } else if(_num_dims==2){
357 
358  const scalar_t & x_a = _array(_cell,_offset+point_a,0);
359  const scalar_t & x_b = _array(_cell,_offset+point_b,0);
360 
361  const scalar_t & y_a = _array(_cell,_offset+point_a,1);
362  const scalar_t & y_b = _array(_cell,_offset+point_b,1);
363 
364  const scalar_t rel_x = std::max(std::fabs(x_a),std::fabs(x_b));
365  const scalar_t rel_y = std::max(std::fabs(y_a),std::fabs(y_b));
366  const scalar_t rel = std::max(rel_x,rel_y);
367 
368  if(test_eq(y_a,y_b,rel)){
369  if(test_less(x_a,x_b,rel)){
370  // Sort by x
371  return true;
372  }
373  } else if(test_less(y_a,y_b,rel)){
374  // Sort by y
375  return true;
376  }
377 
378  // Otherwise b < a
379  return false;
380 
381  } else if(_num_dims==3){
382 
383  const scalar_t & x_a = _array(_cell,_offset+point_a,0);
384  const scalar_t & x_b = _array(_cell,_offset+point_b,0);
385 
386  const scalar_t & y_a = _array(_cell,_offset+point_a,1);
387  const scalar_t & y_b = _array(_cell,_offset+point_b,1);
388 
389  const scalar_t & z_a = _array(_cell,_offset+point_a,2);
390  const scalar_t & z_b = _array(_cell,_offset+point_b,2);
391 
392  const scalar_t rel_x = std::max(std::fabs(x_a),std::fabs(x_b));
393  const scalar_t rel_y = std::max(std::fabs(y_a),std::fabs(y_b));
394  const scalar_t rel_z = std::max(std::fabs(z_a),std::fabs(z_b));
395  const scalar_t rel = std::max(rel_x,std::max(rel_y,rel_z));
396 
397  if(test_less(z_a,z_b,rel)){
398  // Sort by z
399  return true;
400  } else if(test_eq(z_a,z_b,rel)){
401  if(test_eq(y_a,y_b,rel)){
402  if(test_less(x_a,x_b,rel)){
403  // Sort by x
404  return true;
405  }
406  } else if(test_less(y_a,y_b,rel)){
407  // Sort by y
408  return true;
409  }
410  }
411  // Otherwise b < a
412  return false;
413 
414  } else {
415  TEUCHOS_ASSERT(false);
416  }
417  }
418 
419 protected:
420 
421  bool
422  test_eq(const scalar_t & a, const scalar_t & b, const scalar_t & rel) const
423  {
424  if(rel==0){
425  return true;
426  }
427  return std::fabs(a-b) < _rel_tol * rel;
428  }
429 
430  bool
431  test_less(const scalar_t & a, const scalar_t & b, const scalar_t & rel) const
432  {
433  if(rel==0){
434  return false;
435  }
436  return (a-b) < -_rel_tol * rel;
437  }
438 
439  const array_t & _array;
440  int _cell;
441  int _offset;
443  scalar_t _rel_tol;
444 
445 };
446 
447 }
448 
449 template <typename Scalar>
451 convertNormalToRotationMatrix(const Scalar normal[3], Scalar transverse[3], Scalar binormal[3])
452 {
453  using T = Scalar;
454 
455  const T n = sqrt(normal[0]*normal[0]+normal[1]*normal[1]+normal[2]*normal[2]);
456 
457  // If this fails then the geometry for this cell is probably undefined
458  if(n > 0.){
459  // Make sure transverse is not parallel to normal within some margin of error
460  transverse[0]=0.;transverse[1]=1.;transverse[2]=0.;
461  if(std::fabs(normal[0]*transverse[0]+normal[1]*transverse[1])>0.9){
462  transverse[0]=1.;transverse[1]=0.;
463  }
464 
465  const T nt = normal[0]*transverse[0]+normal[1]*transverse[1]+normal[2]*transverse[2];
466 
467  // Note normal has unit length
468  const T mult = nt/(n*n); // = nt
469 
470  // Remove normal projection from transverse
471  for(int dim=0;dim<3;++dim){
472  transverse[dim] = transverse[dim] - mult * normal[dim];
473  }
474 
475  const T t = sqrt(transverse[0]*transverse[0]+transverse[1]*transverse[1]+transverse[2]*transverse[2]);
476  TEUCHOS_ASSERT(t != 0.);
477  for(int dim=0;dim<3;++dim){
478  transverse[dim] /= t;
479  }
480 
481  // We assume a right handed system such that b = n \times t
482  binormal[0] = (normal[1] * transverse[2] - normal[2] * transverse[1]);
483  binormal[1] = (normal[2] * transverse[0] - normal[0] * transverse[2]);
484  binormal[2] = (normal[0] * transverse[1] - normal[1] * transverse[0]);
485 
486  // Normalize binormal
487  const T b = sqrt(binormal[0]*binormal[0]+binormal[1]*binormal[1]+binormal[2]*binormal[2]);
488  for(int dim=0;dim<3;++dim){
489  binormal[dim] /= b;
490  }
491  } else {
492  transverse[0] = 0.;
493  transverse[1] = 0.;
494  transverse[2] = 0.;
495  binormal[0] = 0.;
496  binormal[1] = 0.;
497  binormal[2] = 0.;
498  }
499 }
500 
501 template <typename Scalar>
504  int a,
505  int b)
506 {
507  const int new_cell_point = a;
508  const int old_cell_point = b;
509 
510  const int cell_dim = ref_ip_coordinates.extent(2);
511 
512  Scalar hold;
513 
514  hold = weighted_measure(cell,new_cell_point);
515  weighted_measure(cell,new_cell_point) = weighted_measure(cell,old_cell_point);
516  weighted_measure(cell,old_cell_point) = hold;
517 
518  hold = jac_det(cell,new_cell_point);
519  jac_det(cell,new_cell_point) = jac_det(cell,old_cell_point);
520  jac_det(cell,old_cell_point) = hold;
521 
522  for(int dim=0;dim<cell_dim;++dim){
523 
524  hold = ref_ip_coordinates(cell,new_cell_point,dim);
525  ref_ip_coordinates(cell,new_cell_point,dim) = ref_ip_coordinates(cell,old_cell_point,dim);
526  ref_ip_coordinates(cell,old_cell_point,dim) = hold;
527 
528  hold = ip_coordinates(cell,new_cell_point,dim);
529  ip_coordinates(cell,new_cell_point,dim) = ip_coordinates(cell,old_cell_point,dim);
530  ip_coordinates(cell,old_cell_point,dim) = hold;
531 
532  hold = surface_normals(cell,new_cell_point,dim);
533  surface_normals(cell,new_cell_point,dim) = surface_normals(cell,old_cell_point,dim);
534  surface_normals(cell,old_cell_point,dim) = hold;
535 
536  for(int dim2=0;dim2<cell_dim;++dim2){
537 
538  hold = jac(cell,new_cell_point,dim,dim2);
539  jac(cell,new_cell_point,dim,dim2) = jac(cell,old_cell_point,dim,dim2);
540  jac(cell,old_cell_point,dim,dim2) = hold;
541 
542  hold = jac_inv(cell,new_cell_point,dim,dim2);
543  jac_inv(cell,new_cell_point,dim,dim2) = jac_inv(cell,old_cell_point,dim,dim2);
544  jac_inv(cell,old_cell_point,dim,dim2) = hold;
545  }
546  }
547 }
548 
549 template <typename Scalar>
552  int cell,
553  int offset,
554  std::vector<int> & order)
555 {
556  for(size_t point_index=0;point_index<order.size();++point_index){
557  order[point_index] = point_index;
558  }
559 
560  // We need to sort the indexes in point_indexes by their ip_coordinate's position in space.
561  // We will then use that to sort all of our arrays.
562 
563  point_sorter_t<Array_CellIPDim,Scalar> sorter(coords,cell,offset);
564  std::sort(order.begin(),order.end(),sorter);
565 }
566 
567 template <typename Scalar>
569 generateSurfaceCubatureValues(const PHX::MDField<Scalar,Cell,NODE,Dim>& in_node_coordinates,
570  const int in_num_cells)
571 {
572 
573  TEUCHOS_ASSERT(int_rule->getType() == IntegrationDescriptor::SURFACE);
574 
575  Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
576 
577  const shards::CellTopology & cell_topology = *(int_rule->topology);
578  const panzer::IntegrationRule & ir = *int_rule;
579 
580  const int num_cells = in_num_cells < 0 ? in_node_coordinates.extent(0) : in_num_cells;
581 
582  // Copy over coordinates
583  {
584  const int num_nodes = in_node_coordinates.extent(1);
585  const int num_dims = in_node_coordinates.extent(2);
586 
587  for(int cell=0; cell<num_cells; ++cell){
588  for(int node=0; node<num_nodes; ++node){
589  for(int dim=0; dim<num_dims; ++dim){
590  node_coordinates(cell,node,dim) = in_node_coordinates(cell,node,dim);
591  }
592  }
593  }
594  }
595 
596  // NOTE: We are assuming that each face can have a different number of points.
597  // Not sure if this is necessary, but it requires a lot of additional allocations
598 
599  const int cell_dim = cell_topology.getDimension();
600  const int subcell_dim = cell_topology.getDimension()-1;
601  const int num_subcells = cell_topology.getSubcellCount(subcell_dim);
602 
603  Intrepid2::DefaultCubatureFactory cubature_factory;
604 
605  // We get to build up our cubature one face at a time
606  {
607  int point_offset=0;
608  for(int subcell_index=0; subcell_index<num_subcells; ++subcell_index) {
609 
610  // Default for 1D
611  int num_points_on_face = 1;
612 
613  // Get the cubature for the side
614  Kokkos::DynRankView<double,PHX::Device> tmp_side_cub_weights;
615  Kokkos::DynRankView<double,PHX::Device> tmp_side_cub_points;
616  if(cell_dim==1){
617  tmp_side_cub_weights = Kokkos::DynRankView<double,PHX::Device>("tmp_side_cub_weights",num_points_on_face);
618  tmp_side_cub_points = Kokkos::DynRankView<double,PHX::Device>("cell_tmp_side_cub_points",num_points_on_face,cell_dim);
619  tmp_side_cub_weights(0)=1.;
620  tmp_side_cub_points(0,0) = (subcell_index==0)? -1. : 1.;
621  } else {
622 
623  // Get the face topology from the cell topology
624  const shards::CellTopology face_topology(cell_topology.getCellTopologyData(subcell_dim,subcell_index));
625 
626  auto ic = cubature_factory.create<PHX::Device::execution_space,double,double>(face_topology,ir.getOrder());
627  num_points_on_face = ic->getNumPoints();
628 
629  tmp_side_cub_weights = Kokkos::DynRankView<double,PHX::Device>("tmp_side_cub_weights",num_points_on_face);
630  tmp_side_cub_points = Kokkos::DynRankView<double,PHX::Device>("cell_tmp_side_cub_points",num_points_on_face,cell_dim);
631 
632  auto subcell_cub_points = Kokkos::DynRankView<double,PHX::Device>("subcell_cub_points",num_points_on_face,subcell_dim);
633 
634  // Get the reference face points
635  ic->getCubature(subcell_cub_points, tmp_side_cub_weights);
636 
637  // Convert from reference face points to reference cell points
638  cell_tools.mapToReferenceSubcell(tmp_side_cub_points,
639  subcell_cub_points,
640  subcell_dim,
641  subcell_index,
642  cell_topology);
643  }
644 
645 
646  for(int local_point=0;local_point<num_points_on_face;++local_point){
647  const int point = point_offset + local_point;
648  for(int dim=0;dim<cell_dim;++dim){
649  cub_points(point,dim) = tmp_side_cub_points(local_point,dim);
650  }
651  }
652 
653 
654  // Map from side points to physical points
655  auto side_ip_coordinates = Kokkos::DynRankView<Scalar,PHX::Device>("side_ip_coordinates",num_cells,num_points_on_face,cell_dim);
656  auto s_node_coordinates = Kokkos::subview(node_coordinates.get_view(),std::make_pair(0,num_cells),Kokkos::ALL,Kokkos::ALL);
657  cell_tools.mapToPhysicalFrame(side_ip_coordinates,
658  tmp_side_cub_points,
659  s_node_coordinates,
660  cell_topology);
661 
662  // Create a jacobian and his friends for this side
663  auto side_jacobian = Kokkos::DynRankView<Scalar,PHX::Device>("side_jac",num_cells,num_points_on_face,cell_dim,cell_dim);
664  cell_tools.setJacobian(side_jacobian,
665  tmp_side_cub_points,
666  s_node_coordinates,
667  cell_topology);
668 
669  auto side_inverse_jacobian = Kokkos::DynRankView<Scalar,PHX::Device>("side_inv_jac",num_cells,num_points_on_face,cell_dim,cell_dim);
670  cell_tools.setJacobianInv(side_inverse_jacobian, side_jacobian);
671 
672  auto side_det_jacobian = Kokkos::DynRankView<Scalar,PHX::Device>("side_det_jac",num_cells,num_points_on_face);
673  cell_tools.setJacobianDet(side_det_jacobian, side_jacobian);
674 
675  // Calculate measures (quadrature weights in physical space) for this side
676  auto side_weighted_measure = Kokkos::DynRankView<Scalar,PHX::Device>("side_weighted_measure",num_cells,num_points_on_face);
677  if(cell_dim == 1){
678  Kokkos::deep_copy(side_weighted_measure, tmp_side_cub_weights(0));
679  } else if(cell_dim == 2){
680  Intrepid2::FunctionSpaceTools<PHX::Device::execution_space>::
681  computeEdgeMeasure(side_weighted_measure, side_jacobian, tmp_side_cub_weights,
682  subcell_index,cell_topology,
683  scratch_for_compute_side_measure.get_view());
684  } else if(cell_dim == 3){
685  Intrepid2::FunctionSpaceTools<PHX::Device::execution_space>::
686  computeFaceMeasure(side_weighted_measure, side_jacobian, tmp_side_cub_weights,
687  subcell_index,cell_topology,
688  scratch_for_compute_side_measure.get_view());
689  }
690 
691  // Calculate normals
692  auto side_normals = Kokkos::DynRankView<Scalar,PHX::Device>("side_normals",num_cells,num_points_on_face,cell_dim);
693  if(cell_dim == 1){
694 
695  int other_subcell_index = (subcell_index==0) ? 1 : 0;
696 
697  for(int cell=0;cell<num_cells;++cell){
698  Scalar norm = (in_node_coordinates(cell,subcell_index,0) - in_node_coordinates(cell,other_subcell_index,0));
699  side_normals(cell,0,0) = norm / fabs(norm+std::numeric_limits<typename Sacado::ScalarType<Scalar>::type>::min());
700  }
701 
702  } else {
703 
704  cell_tools.getPhysicalSideNormals(side_normals,side_jacobian,subcell_index,cell_topology);
705 
706  // Normalize each normal
707  for(int cell=0;cell<num_cells;++cell){
708  for(int point=0;point<num_points_on_face;++point){
709  Scalar n = 0.;
710  for(int dim=0;dim<cell_dim;++dim){
711  n += side_normals(cell,point,dim)*side_normals(cell,point,dim);
712  }
713  // If n is zero then this is - hopefully - a virtual cell
714  if(n > 0.){
715  n = std::sqrt(n);
716  for(int dim=0;dim<cell_dim;++dim){
717  side_normals(cell,point,dim) /= n;
718  }
719  }
720  }
721  }
722 
723  }
724 
725 
726  // Now that we have all these wonderful values, lets copy them to the actual arrays
727  for(int cell=0;cell<num_cells;++cell){
728  for(int side_point=0; side_point<num_points_on_face;++side_point){
729  const int cell_point = point_offset + side_point;
730 
731  weighted_measure(cell,cell_point) = side_weighted_measure(cell,side_point);
732  jac_det(cell,cell_point) = side_det_jacobian(cell,side_point);
733  for(int dim=0;dim<cell_dim;++dim){
734  ref_ip_coordinates(cell,cell_point,dim) = cub_points(cell_point,dim);
735  ip_coordinates(cell,cell_point,dim) = side_ip_coordinates(cell,side_point,dim);
736  surface_normals(cell,cell_point,dim) = side_normals(cell,side_point,dim);
737 
738  for(int dim2=0;dim2<cell_dim;++dim2){
739  jac(cell,cell_point,dim,dim2) = side_jacobian(cell,side_point,dim,dim2);
740  jac_inv(cell,cell_point,dim,dim2) = side_inverse_jacobian(cell,side_point,dim,dim2);
741  }
742  }
743  }
744  }
745  point_offset += num_points_on_face;
746  }
747  }
748 
749  // Now we need to sort the cubature points for each face so that they will line up between cells
750  {
751  for(int subcell_index=0; subcell_index<num_subcells;++subcell_index){
752 
753  const int point_offset = ir.getPointOffset(subcell_index);
754  const int num_points_on_face = ir.getPointOffset(subcell_index+1) - point_offset;
755  std::vector<int> point_indexes(num_points_on_face,-1);
756 
757  for(int cell=0; cell<num_cells; ++cell){
758 
759  // build a point index array based on point coordinates
760  uniqueCoordOrdering(ip_coordinates,cell,point_offset,point_indexes);
761 
762  // Indexes are now sorted, now we swap everything around
763  reorder(point_indexes,[=](int a,int b) { swapQuadraturePoints(cell,point_offset+a,point_offset+b); });
764  }
765  }
766  }
767 
768  // We also need surface rotation matrices
769  const int num_points = ir.getPointOffset(num_subcells);
770  Scalar normal[3];
771  Scalar transverse[3];
772  Scalar binormal[3];
773  for(int i=0;i<3;i++){normal[i]=0.;}
774  for(int i=0;i<3;i++){transverse[i]=0.;}
775  for(int i=0;i<3;i++){binormal[i]=0.;}
776  for(int cell=0; cell<num_cells; ++cell){
777  for(int subcell_index=0; subcell_index<num_subcells; ++subcell_index){
778  for(int point=0; point<num_points; ++point){
779 
780  for(int dim=0; dim<3; ++dim)
781  normal[dim] = 0.0;
782 
783  for(int dim=0; dim<cell_dim; ++dim){
784  normal[dim] = surface_normals(cell,point,dim);
785  }
786 
787  convertNormalToRotationMatrix(normal,transverse,binormal);
788 
789  for(int dim=0; dim<3; ++dim){
790  surface_rotation_matrices(cell,point,0,dim) = normal[dim];
791  surface_rotation_matrices(cell,point,1,dim) = transverse[dim];
792  surface_rotation_matrices(cell,point,2,dim) = binormal[dim];
793  }
794  }
795  }
796  }
797 
798 
799  // I'm not sure if these should exist for surface integrals, but here we go!
800 
801  // Shakib contravarient metric tensor
802  for (int cell = 0; cell < num_cells; ++cell) {
803  for (size_type ip = 0; ip < contravarient.extent(1); ++ip) {
804 
805  // zero out matrix
806  for (size_type i = 0; i < contravarient.extent(2); ++i)
807  for (size_type j = 0; j < contravarient.extent(3); ++j)
808  covarient(cell,ip,i,j) = 0.0;
809 
810  // g^{ij} = \frac{\parital x_i}{\partial \chi_\alpha}\frac{\parital x_j}{\partial \chi_\alpha}
811  for (size_type i = 0; i < contravarient.extent(2); ++i) {
812  for (size_type j = 0; j < contravarient.extent(3); ++j) {
813  for (size_type alpha = 0; alpha < contravarient.extent(2); ++alpha) {
814  covarient(cell,ip,i,j) += jac(cell,ip,i,alpha) * jac(cell,ip,j,alpha);
815  }
816  }
817  }
818 
819  }
820  }
821 
822  auto s_contravarient = Kokkos::subview(contravarient.get_view(), std::make_pair(0,num_cells),Kokkos::ALL,Kokkos::ALL,Kokkos::ALL);
823  auto s_covarient = Kokkos::subview(covarient.get_view(), std::make_pair(0,num_cells),Kokkos::ALL,Kokkos::ALL,Kokkos::ALL);
824  Intrepid2::RealSpaceTools<PHX::Device::execution_space>::inverse(s_contravarient, s_covarient);
825 
826  // norm of g_ij
827  for (int cell = 0; cell < num_cells; ++cell) {
828  for (size_type ip = 0; ip < contravarient.extent(1); ++ip) {
829  norm_contravarient(cell,ip) = 0.0;
830  for (size_type i = 0; i < contravarient.extent(2); ++i) {
831  for (size_type j = 0; j < contravarient.extent(3); ++j) {
832  norm_contravarient(cell,ip) += contravarient(cell,ip,i,j) * contravarient(cell,ip,i,j);
833  }
834  }
835  norm_contravarient(cell,ip) = std::sqrt(norm_contravarient(cell,ip));
836  }
837  }
838 
839 }
840 
841 
842 template <typename Scalar>
844 evaluateRemainingValues(const PHX::MDField<Scalar,Cell,NODE,Dim>& in_node_coordinates,
845  const int in_num_cells)
846 {
847  Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
848 
849  // copy the dynamic data structures into the static data structures
850  {
851  size_type num_ip = dyn_cub_points.extent(0);
852  size_type num_dims = dyn_cub_points.extent(1);
853 
854  for (size_type ip = 0; ip < num_ip; ++ip) {
855  cub_weights(ip) = dyn_cub_weights(ip);
856  for (size_type dim = 0; dim < num_dims; ++dim)
857  cub_points(ip,dim) = dyn_cub_points(ip,dim);
858  }
859  }
860 
861  if (int_rule->isSide()) {
862  const size_type num_ip = dyn_cub_points.extent(0), num_side_dims = dyn_side_cub_points.extent(1);
863  for (size_type ip = 0; ip < num_ip; ++ip)
864  for (size_type dim = 0; dim < num_side_dims; ++dim)
865  side_cub_points(ip,dim) = dyn_side_cub_points(ip,dim);
866  }
867 
868  const int num_cells = in_num_cells < 0 ? in_node_coordinates.extent(0) : in_num_cells;
869 
870  {
871  size_type num_nodes = in_node_coordinates.extent(1);
872  size_type num_dims = in_node_coordinates.extent(2);
873 
874  for (int cell = 0; cell < num_cells; ++cell) {
875  for (size_type node = 0; node < num_nodes; ++node) {
876  for (size_type dim = 0; dim < num_dims; ++dim) {
877  node_coordinates(cell,node,dim) =
878  in_node_coordinates(cell,node,dim);
879  }
880  }
881  }
882  }
883 
884  auto s_in_node_coordinates = Kokkos::subview(in_node_coordinates.get_view(),std::make_pair(0,num_cells),Kokkos::ALL(),Kokkos::ALL());
885  auto s_jac = Kokkos::subview(jac.get_view(),std::make_pair(0,num_cells),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
886  cell_tools.setJacobian(jac.get_view(),
887  cub_points.get_view(),
888  node_coordinates.get_view(),
889  *(int_rule->topology));
890 
891  auto s_jac_inv = Kokkos::subview(jac_inv.get_view(),std::make_pair(0,num_cells),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
892  cell_tools.setJacobianInv(s_jac_inv, s_jac);
893 
894  auto s_jac_det = Kokkos::subview(jac_det.get_view(),std::make_pair(0,num_cells),Kokkos::ALL());
895  cell_tools.setJacobianDet(s_jac_det, s_jac);
896 
897  auto s_weighted_measure = Kokkos::subview(weighted_measure.get_view(),std::make_pair(0,num_cells),Kokkos::ALL());
898  if (!int_rule->isSide()) {
899  Intrepid2::FunctionSpaceTools<PHX::Device::execution_space>::
900  computeCellMeasure(s_weighted_measure, s_jac_det, cub_weights.get_view());
901  }
902  else if(int_rule->spatial_dimension==3) {
903  Intrepid2::FunctionSpaceTools<PHX::Device::execution_space>::
904  computeFaceMeasure(s_weighted_measure, s_jac, cub_weights.get_view(),
905  int_rule->side, *int_rule->topology,
906  scratch_for_compute_side_measure.get_view());
907  }
908  else if(int_rule->spatial_dimension==2) {
909  Intrepid2::FunctionSpaceTools<PHX::Device::execution_space>::
910  computeEdgeMeasure(s_weighted_measure, s_jac, cub_weights.get_view(),
911  int_rule->side,*int_rule->topology,
912  scratch_for_compute_side_measure.get_view());
913  }
914  else TEUCHOS_ASSERT(false);
915 
916  // Shakib contravarient metric tensor
917  for (int cell = 0; cell < num_cells; ++cell) {
918  for (size_type ip = 0; ip < contravarient.extent(1); ++ip) {
919 
920  // zero out matrix
921  for (size_type i = 0; i < contravarient.extent(2); ++i)
922  for (size_type j = 0; j < contravarient.extent(3); ++j)
923  covarient(cell,ip,i,j) = 0.0;
924 
925  // g^{ij} = \frac{\parital x_i}{\partial \chi_\alpha}\frac{\parital x_j}{\partial \chi_\alpha}
926  for (size_type i = 0; i < contravarient.extent(2); ++i) {
927  for (size_type j = 0; j < contravarient.extent(3); ++j) {
928  for (size_type alpha = 0; alpha < contravarient.extent(2); ++alpha) {
929  covarient(cell,ip,i,j) += jac(cell,ip,i,alpha) * jac(cell,ip,j,alpha);
930  }
931  }
932  }
933 
934  }
935  }
936 
937  auto s_covarient = Kokkos::subview(covarient.get_view(),std::make_pair(0,num_cells),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
938  auto s_contravarient = Kokkos::subview(contravarient.get_view(),std::make_pair(0,num_cells),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
939  Intrepid2::RealSpaceTools<PHX::Device::execution_space>::inverse(s_contravarient, s_covarient);
940 
941  // norm of g_ij
942  for (int cell = 0; cell < num_cells; ++cell) {
943  for (size_type ip = 0; ip < contravarient.extent(1); ++ip) {
944  norm_contravarient(cell,ip) = 0.0;
945  for (size_type i = 0; i < contravarient.extent(2); ++i) {
946  for (size_type j = 0; j < contravarient.extent(3); ++j) {
947  norm_contravarient(cell,ip) += contravarient(cell,ip,i,j) * contravarient(cell,ip,i,j);
948  }
949  }
950  norm_contravarient(cell,ip) = std::sqrt(norm_contravarient(cell,ip));
951  }
952  }
953 }
954 
955 // Find the permutation that maps the set of points coords to other_coords. To
956 // avoid possible finite precision issues, == is not used, but rather
957 // min(norm(.)).
958 template <typename Scalar>
959 static void
960 permuteToOther(const PHX::MDField<Scalar,Cell,IP,Dim>& coords,
961  const PHX::MDField<Scalar,Cell,IP,Dim>& other_coords,
962  std::vector<typename ArrayTraits<Scalar,PHX::MDField<Scalar> >::size_type>& permutation)
963 {
964  typedef typename ArrayTraits<Scalar,PHX::MDField<Scalar> >::size_type size_type;
965  // We can safely assume: (1) The permutation is the same for every cell in
966  // the workset. (2) The first workset has valid data. Hence we operate only
967  // on cell 0.
968  const size_type cell = 0;
969  const size_type num_ip = coords.extent(1), num_dim = coords.extent(2);
970  permutation.resize(num_ip);
971  std::vector<char> taken(num_ip, 0);
972  for (size_type ip = 0; ip < num_ip; ++ip) {
973  // Find an other point to associate with ip.
974  size_type i_min = 0;
975  Scalar d_min = -1;
976  for (size_type other_ip = 0; other_ip < num_ip; ++other_ip) {
977  // For speed, skip other points that are already associated.
978  if (taken[other_ip]) continue;
979  // Compute the distance between the two points.
980  Scalar d(0);
981  for (size_type dim = 0; dim < num_dim; ++dim) {
982  const Scalar diff = coords(cell, ip, dim) - other_coords(cell, other_ip, dim);
983  d += diff*diff;
984  }
985  if (d_min < 0 || d < d_min) {
986  d_min = d;
987  i_min = other_ip;
988  }
989  }
990  // Record the match.
991  permutation[ip] = i_min;
992  // This point is now taken.
993  taken[i_min] = 1;
994  }
995 }
996 
997 template <typename Scalar>
999 evaluateValues(const PHX::MDField<Scalar,Cell,NODE,Dim>& in_node_coordinates,
1000  const PHX::MDField<Scalar,Cell,IP,Dim>& other_ip_coordinates,
1001  const int in_num_cells)
1002 {
1003  const int num_cells = in_num_cells < 0 ? in_node_coordinates.extent(0) : in_num_cells;
1004 
1005  if (int_rule->cv_type == "none") {
1006 
1007  getCubature(in_node_coordinates, in_num_cells);
1008 
1009  {
1010  // Determine the permutation.
1011  std::vector<size_type> permutation(other_ip_coordinates.extent(1));
1012  permuteToOther(ip_coordinates, other_ip_coordinates, permutation);
1013  // Apply the permutation to the cubature arrays.
1014  MDFieldArrayFactory af(prefix, alloc_arrays);
1015  {
1016  const size_type num_ip = dyn_cub_points.extent(0);
1017  {
1018  const size_type num_dim = dyn_side_cub_points.extent(1);
1019  DblArrayDynamic old_dyn_side_cub_points = af.template buildArray<double,IP,Dim>(
1020  "old_dyn_side_cub_points", num_ip, num_dim);
1021  old_dyn_side_cub_points.deep_copy(dyn_side_cub_points);
1022  for (size_type ip = 0; ip < num_ip; ++ip)
1023  if (ip != permutation[ip])
1024  for (size_type dim = 0; dim < num_dim; ++dim)
1025  dyn_side_cub_points(ip, dim) = old_dyn_side_cub_points(permutation[ip], dim);
1026  }
1027  {
1028  const size_type num_dim = dyn_cub_points.extent(1);
1029  DblArrayDynamic old_dyn_cub_points = af.template buildArray<double,IP,Dim>(
1030  "old_dyn_cub_points", num_ip, num_dim);
1031  old_dyn_cub_points.deep_copy(dyn_cub_points);
1032  for (size_type ip = 0; ip < num_ip; ++ip)
1033  if (ip != permutation[ip])
1034  for (size_type dim = 0; dim < num_dim; ++dim)
1035  dyn_cub_points(ip, dim) = old_dyn_cub_points(permutation[ip], dim);
1036  }
1037  {
1038  DblArrayDynamic old_dyn_cub_weights = af.template buildArray<double,IP>(
1039  "old_dyn_cub_weights", num_ip);
1040  old_dyn_cub_weights.deep_copy(dyn_cub_weights);
1041  for (size_type ip = 0; ip < dyn_cub_weights.extent(0); ++ip)
1042  if (ip != permutation[ip])
1043  dyn_cub_weights(ip) = old_dyn_cub_weights(permutation[ip]);
1044  }
1045  }
1046  {
1047  const size_type num_ip = ip_coordinates.extent(1);
1048  const size_type num_dim = ip_coordinates.extent(2);
1049  Array_CellIPDim old_ip_coordinates = af.template buildStaticArray<Scalar,Cell,IP,Dim>(
1050  "old_ip_coordinates", ip_coordinates.extent(0), num_ip, num_dim);
1051  Kokkos::deep_copy(old_ip_coordinates.get_static_view(), ip_coordinates.get_static_view());
1052  for (int cell = 0; cell < num_cells; ++cell)
1053  for (size_type ip = 0; ip < num_ip; ++ip)
1054  if (ip != permutation[ip])
1055  for (size_type dim = 0; dim < num_dim; ++dim)
1056  ip_coordinates(cell, ip, dim) = old_ip_coordinates(cell, permutation[ip], dim);
1057  }
1058  // All subsequent calculations inherit the permutation.
1059  }
1060 
1061  evaluateRemainingValues(in_node_coordinates, in_num_cells);
1062  }
1063 
1064  else {
1065 
1066  getCubatureCV(in_node_coordinates, in_num_cells);
1067 
1068  // Determine the permutation.
1069  std::vector<size_type> permutation(other_ip_coordinates.extent(1));
1070  permuteToOther(ip_coordinates, other_ip_coordinates, permutation);
1071 
1072  // Apply the permutation to the cubature arrays.
1073  MDFieldArrayFactory af(prefix, alloc_arrays);
1074  {
1075  const size_type workset_size = ip_coordinates.extent(0), num_ip = ip_coordinates.extent(1),
1076  num_dim = ip_coordinates.extent(2);
1077  Array_CellIPDim old_ip_coordinates = af.template buildStaticArray<Scalar,Cell,IP,Dim>(
1078  "old_ip_coordinates", workset_size, num_ip, num_dim);
1079  Kokkos::deep_copy(old_ip_coordinates.get_static_view(), ip_coordinates.get_static_view());
1080  Array_CellIPDim old_weighted_normals = af.template buildStaticArray<Scalar,Cell,IP,Dim>(
1081  "old_weighted_normals", workset_size, num_ip, num_dim);
1082  Array_CellIP old_weighted_measure = af.template buildStaticArray<Scalar,Cell,IP>(
1083  "old_weighted_measure", workset_size, num_ip);
1084  if (int_rule->cv_type == "side")
1085  Kokkos::deep_copy(old_weighted_normals.get_static_view(), weighted_normals.get_static_view());
1086  else
1087  Kokkos::deep_copy(old_weighted_measure.get_static_view(), weighted_measure.get_static_view());
1088  for (int cell = 0; cell < num_cells; ++cell)
1089  {
1090  for (size_type ip = 0; ip < num_ip; ++ip)
1091  {
1092  if (ip != permutation[ip]) {
1093  if (int_rule->cv_type == "boundary" || int_rule->cv_type == "volume")
1094  weighted_measure(cell, ip) = old_weighted_measure(cell, permutation[ip]);
1095  for (size_type dim = 0; dim < num_dim; ++dim)
1096  {
1097  ip_coordinates(cell, ip, dim) = old_ip_coordinates(cell, permutation[ip], dim);
1098  if (int_rule->cv_type == "side")
1099  weighted_normals(cell, ip, dim) = old_weighted_normals(cell, permutation[ip], dim);
1100 
1101  }
1102  }
1103  }
1104  }
1105  }
1106 
1107  evaluateValuesCV(in_node_coordinates, in_num_cells);
1108  }
1109 }
1110 
1111 template <typename Scalar>
1113 getCubatureCV(const PHX::MDField<Scalar,Cell,NODE,Dim>& in_node_coordinates,
1114  const int in_num_cells)
1115 {
1116  int num_space_dim = int_rule->topology->getDimension();
1117  if (int_rule->isSide() && num_space_dim==1) {
1118  std::cout << "WARNING: 0-D quadrature rule infrastructure does not exist!!! Will not be able to do "
1119  << "non-natural integration rules.";
1120  return;
1121  }
1122 
1123  size_type num_cells = in_num_cells < 0 ? in_node_coordinates.extent(0) : (size_type) in_num_cells;
1124  std::pair<int,int> cell_range(0,num_cells);
1125  {
1126  size_type num_nodes = in_node_coordinates.extent(1);
1127  size_type num_dims = in_node_coordinates.extent(2);
1128 
1129  for (size_type cell = 0; cell < num_cells; ++cell) {
1130  for (size_type node = 0; node < num_nodes; ++node) {
1131  for (size_type dim = 0; dim < num_dims; ++dim) {
1132  node_coordinates(cell,node,dim) =
1133  in_node_coordinates(cell,node,dim);
1134  dyn_node_coordinates(cell,node,dim) =
1135  Sacado::ScalarValue<Scalar>::eval(in_node_coordinates(cell,node,dim));
1136  }
1137  }
1138  }
1139  }
1140 
1141  auto s_dyn_phys_cub_points = Kokkos::subdynrankview(dyn_phys_cub_points.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
1142  auto s_dyn_node_coordinates = Kokkos::subdynrankview(dyn_node_coordinates.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
1143  if (int_rule->cv_type == "side") {
1144  auto s_dyn_phys_cub_norms = Kokkos::subdynrankview(dyn_phys_cub_norms.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
1145  intrepid_cubature->getCubature(s_dyn_phys_cub_points,s_dyn_phys_cub_norms,s_dyn_node_coordinates);
1146  }
1147  else {
1148  auto s_dyn_phys_cub_weights = Kokkos::subdynrankview(dyn_phys_cub_weights.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
1149  intrepid_cubature->getCubature(s_dyn_phys_cub_points,s_dyn_phys_cub_weights,s_dyn_node_coordinates);
1150  }
1151 
1152  // size_type num_cells = dyn_phys_cub_points.extent(0);
1153  size_type num_ip =dyn_phys_cub_points.extent(1);
1154  size_type num_dims = dyn_phys_cub_points.extent(2);
1155 
1156  for (size_type cell = 0; cell < num_cells; ++cell) {
1157  for (size_type ip = 0; ip < num_ip; ++ip) {
1158  if (int_rule->cv_type != "side")
1159  weighted_measure(cell,ip) = dyn_phys_cub_weights(cell,ip);
1160  for (size_type dim = 0; dim < num_dims; ++dim) {
1161  ip_coordinates(cell,ip,dim) = dyn_phys_cub_points(cell,ip,dim);
1162  if (int_rule->cv_type == "side")
1163  weighted_normals(cell,ip,dim) = dyn_phys_cub_norms(cell,ip,dim);
1164  }
1165  }
1166  }
1167 
1168 }
1169 
1170 template <typename Scalar>
1172 evaluateValuesCV(const PHX::MDField<Scalar, Cell, NODE, Dim>& in_node_coordinates,
1173  const int in_num_cells)
1174 {
1175 
1176  Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
1177 
1178  size_type num_cells = in_num_cells < 0 ? in_node_coordinates.extent(0) : (size_type) in_num_cells;
1179 
1180  auto s_ref_ip_coordinates = Kokkos::subview(ref_ip_coordinates.get_view(),std::make_pair(0,(int)num_cells),Kokkos::ALL(),Kokkos::ALL());
1181  auto s_ip_coordinates = Kokkos::subview(ip_coordinates.get_view(),std::make_pair<int,int>(0,num_cells),Kokkos::ALL(),Kokkos::ALL());
1182  auto s_node_coordinates = Kokkos::subview(node_coordinates.get_view(),std::make_pair<int,int>(0,num_cells),Kokkos::ALL(),Kokkos::ALL());
1183 
1184  cell_tools.mapToReferenceFrame(s_ref_ip_coordinates,
1185  s_ip_coordinates,
1186  s_node_coordinates,
1187  *(int_rule->topology));
1188 
1189  auto s_jac = Kokkos::subview(jac.get_view(),std::make_pair<int,int>(0,num_cells),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
1190 
1191  cell_tools.setJacobian(s_jac,
1192  s_ref_ip_coordinates,
1193  s_node_coordinates,
1194  *(int_rule->topology));
1195 
1196  auto s_jac_inv = Kokkos::subview(jac_inv.get_view(),std::make_pair<int,int>(0,num_cells),Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
1197 
1198  cell_tools.setJacobianInv(s_jac_inv, s_jac);
1199 
1200  auto s_jac_det = Kokkos::subview(jac_det.get_view(),std::make_pair<int,int>(0,num_cells),Kokkos::ALL());
1201 
1202  cell_tools.setJacobianDet(s_jac_det, s_jac);
1203 }
1204 
1205 #define INTEGRATION_VALUES2_INSTANTIATION(SCALAR) \
1206  template class IntegrationValues2<SCALAR>;
1207 
1209 INTEGRATION_VALUES2_INSTANTIATION(panzer::Traits::FadType)
1210 
1211 }
static void convertNormalToRotationMatrix(const Scalar normal[3], Scalar transverse[3], Scalar binormal[3])
static void uniqueCoordOrdering(Array_CellIPDim &coords, int cell, int offset, std::vector< int > &order)
Using coordinate build an arrray that specifies a unique ordering.
PHX::MDField< Scalar, Cell, IP > Array_CellIP
const array_t & _array
void evaluateValuesCV(const PHX::MDField< Scalar, Cell, NODE, Dim > &vertex_coordinates, const int in_num_cells)
const int & getType() const
Get type of integrator.
void generateSurfaceCubatureValues(const PHX::MDField< Scalar, Cell, NODE, Dim > &in_node_coordinates, const int in_num_cells)
void swapQuadraturePoints(int cell, int a, int b)
Swap the ordering of quadrature points in a specified cell.
void getCubatureCV(const PHX::MDField< Scalar, Cell, NODE, Dim > &in_node_coordinates, const int in_num_cells)
#define INTEGRATION_VALUES2_INSTANTIATION(SCALAR)
int getPointOffset(const int subcell_index) const
Returns the integration point offset for a given subcell_index (i.e. local face index) ...
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
void evaluateValues(const PHX::MDField< Scalar, Cell, NODE, Dim > &vertex_coordinates, const int num_cells=-1)
Evaluate basis values.
Teuchos::RCP< const shards::CellTopology > topology
void evaluateRemainingValues(const PHX::MDField< Scalar, Cell, NODE, Dim > &in_node_coordinates, const int in_num_cells)
ArrayTraits< Scalar, PHX::MDField< Scalar > >::size_type size_type
void setupArrays(const Teuchos::RCP< const panzer::IntegrationRule > &ir)
Sizes/allocates memory for arrays.
const int & getSide() const
Get side associated with integration - this is for backward compatibility.
void getCubature(const PHX::MDField< Scalar, Cell, NODE, Dim > &in_node_coordinates, const int in_num_cells)
PHX::MDField< Scalar, Cell, IP, Dim > Array_CellIPDim
void reorder(std::vector< int > &order, std::function< void(int, int)> swapper)
Using a functor, reorder an array using a order vector.
Teuchos::RCP< Intrepid2::Cubature< PHX::Device::execution_space, double, double > > getIntrepidCubature(const panzer::IntegrationRule &ir) const
PHX::MDField< double > DblArrayDynamic
Teuchos::RCP< shards::CellTopology > side_topology
#define TEUCHOS_ASSERT(assertion_test)
scalar_t _rel_tol
static void permuteToOther(const PHX::MDField< Scalar, Cell, IP, Dim > &coords, const PHX::MDField< Scalar, Cell, IP, Dim > &other_coords, std::vector< typename ArrayTraits< Scalar, PHX::MDField< Scalar > >::size_type > &permutation)
void setupArraysForNodeRule(const Teuchos::RCP< const panzer::IntegrationRule > &ir)
const int & getOrder() const
Get order of integrator.