Panzer Version of the Day
Loading...
Searching...
No Matches
Panzer_IntegrationValues2.cpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// Panzer: A partial differential equation assembly
4// engine for strongly coupled complex multiphysics systems
5//
6// Copyright 2011 NTESS and the Panzer contributors.
7// SPDX-License-Identifier: BSD-3-Clause
8// *****************************************************************************
9// @HEADER
10
13
14#include "Shards_CellTopology.hpp"
15
16#include "Kokkos_DynRankView.hpp"
17#include "Intrepid2_FunctionSpaceTools.hpp"
18#include "Intrepid2_RealSpaceTools.hpp"
19#include "Intrepid2_CellTools.hpp"
20#include "Intrepid2_ArrayTools.hpp"
21#include "Intrepid2_CubatureControlVolume.hpp"
22#include "Intrepid2_CubatureControlVolumeSide.hpp"
23#include "Intrepid2_CubatureControlVolumeBoundary.hpp"
24
26#include "Panzer_Traits.hpp"
29
30// FIXME: There are some calls in Intrepid2 that require non-const arrays when they should be const - search for PHX::getNonConstDynRankViewFromConstMDField
31#include "Phalanx_GetNonConstDynRankViewFromConstMDField.hpp"
32
33namespace panzer {
34
35namespace {
36
37Teuchos::RCP<Intrepid2::Cubature<PHX::Device::execution_space,double,double>>
38getIntrepidCubature(const panzer::IntegrationRule & ir)
39{
41 Teuchos::RCP<Intrepid2::Cubature<PHX::Device::execution_space,double,double> > ic;
42
43 Intrepid2::DefaultCubatureFactory cubature_factory;
44
45 if(ir.getType() == ID::CV_SIDE){
46 ic = Teuchos::rcp(new Intrepid2::CubatureControlVolumeSide<PHX::Device::execution_space,double,double>(*ir.topology));
47 } else if(ir.getType() == ID::CV_VOLUME){
48 ic = Teuchos::rcp(new Intrepid2::CubatureControlVolume<PHX::Device::execution_space,double,double>(*ir.topology));
49 } else if(ir.getType() == ID::CV_BOUNDARY){
50 TEUCHOS_ASSERT(ir.isSide());
51 ic = Teuchos::rcp(new Intrepid2::CubatureControlVolumeBoundary<PHX::Device::execution_space,double,double>(*ir.topology,ir.getSide()));
52 } else if(ir.getType() == ID::VOLUME){
53 ic = cubature_factory.create<PHX::Device::execution_space,double,double>(*(ir.topology),ir.getOrder());
54 } else if(ir.getType() == ID::SIDE){
55 ic = cubature_factory.create<PHX::Device::execution_space,double,double>(*(ir.side_topology),ir.getOrder());
56 } else if(ir.getType() == ID::SURFACE){
57 // closed surface integrals don't exist in intrepid.
58 } else {
59 TEUCHOS_ASSERT(false);
60 }
61
62 return ic;
63}
64
65template<typename Scalar>
66void
67correctVirtualNormals(PHX::MDField<Scalar,Cell,IP,Dim> normals,
68 const int num_real_cells,
69 const int num_virtual_cells,
70 const shards::CellTopology & cell_topology,
71 const SubcellConnectivity & face_connectivity)
72{
73 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::correctVirtualNormals()",corr_virt_norms);
74
75 // What we want is for the adjoining face of the virtual cell to have normals that are the negated real cell's normals.
76 // we correct the normals here:
77 const int space_dim = cell_topology.getDimension();
78 const int faces_per_cell = cell_topology.getSubcellCount(space_dim-1);
79 const int points = normals.extent_int(1);
80 const int points_per_face = points / faces_per_cell;
81
82 Kokkos::parallel_for(num_virtual_cells, KOKKOS_LAMBDA(const int & virtual_cell_ordinal){
83
84 const int virtual_cell = virtual_cell_ordinal+num_real_cells;
85
86 // Find the face and local face ids for the given virtual cell
87 // Note that virtual cells only connect to the owned cells through a single face
88 int face = -1, virtual_lidx = -1;
89 for (int local_face_id=0; local_face_id<faces_per_cell; local_face_id++){
90 // Faces that exist have positive indexes
91 face = face_connectivity.subcellForCell(virtual_cell, local_face_id);
92 if (face >= 0){
93 virtual_lidx = local_face_id;
94 break;
95 }
96 }
97
98 // Indexes for real cell
99 const int real_side = (face_connectivity.cellForSubcell(face, 0) == virtual_cell) ? 1 : 0;
100 const int real_cell = face_connectivity.cellForSubcell(face,real_side);
101 const int real_lidx = face_connectivity.localSubcellForSubcell(face,real_side);
102
103 // Make sure it is a real cell (it should actually be an owned cell)
104 KOKKOS_ASSERT(real_cell < num_real_cells);
105
106 for(int point_ordinal=0; point_ordinal<points_per_face; point_ordinal++){
107
108 // Point indexes for virtual and real point on face
109 const int virtual_cell_point = points_per_face * virtual_lidx + point_ordinal;
110 const int real_cell_point = points_per_face * real_lidx + point_ordinal;
111
112 for (int d=0; d<space_dim; d++)
113 normals(virtual_cell,virtual_cell_point,d) = -normals(real_cell,real_cell_point,d);
114
115 }
116
117 // Clear other normals
118 for (int local_face_id=0; local_face_id<faces_per_cell; local_face_id++){
119
120 if (local_face_id == virtual_lidx) continue;
121
122 for (int point_ordinal=0; point_ordinal<points_per_face; point_ordinal++){
123 const int point = local_face_id * points_per_face + point_ordinal;
124 for (int dim=0; dim<space_dim; dim++)
125 normals(virtual_cell,point,dim) = 0.0;
126 }
127 }
128 });
129 PHX::Device::execution_space().fence();
130}
131
132
133template<typename Scalar>
134void
135correctVirtualRotationMatrices(PHX::MDField<Scalar,Cell,IP,Dim,Dim> rotation_matrices,
136 const int num_real_cells,
137 const int num_virtual_cells,
138 const shards::CellTopology & cell_topology,
139 const SubcellConnectivity & face_connectivity)
140{
141 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::correctVirtualRotationMatrices()",corr_virt_rotmat);
142
143 // What we want is for the adjoining face of the virtual cell to have normals that are the negated real cell's normals.
144 // we correct the normals here:
145 const int space_dim = cell_topology.getDimension();
146 const int faces_per_cell = cell_topology.getSubcellCount(space_dim-1);
147 const int points = rotation_matrices.extent_int(1);
148 const int points_per_face = points / faces_per_cell;
149
150 Kokkos::parallel_for(num_virtual_cells, KOKKOS_LAMBDA(const int & virtual_cell_ordinal){
151
152 const int virtual_cell = virtual_cell_ordinal+num_real_cells;
153
154 // Find the face and local face ids for the given virtual cell
155 // Note that virtual cells only connect to the owned cells through a single face
156 int face = -1, virtual_lidx = -1;
157 for (int local_face_id=0; local_face_id<faces_per_cell; local_face_id++){
158 // Faces that exist have positive indexes
159 face = face_connectivity.subcellForCell(virtual_cell, local_face_id);
160 if (face >= 0){
161 virtual_lidx = local_face_id;
162 break;
163 }
164 }
165
166 // The normals already have the correction applied, so we just need to zero out the rotation matrices on the other faces
167
168 // Clear other rotation matrices
169 for (int local_face_id=0; local_face_id<faces_per_cell; local_face_id++){
170
171 if (local_face_id == virtual_lidx) continue;
172
173 for (int point_ordinal=0; point_ordinal<points_per_face; point_ordinal++){
174 const int point = local_face_id * points_per_face + point_ordinal;
175 for (int dim=0; dim<3; dim++)
176 for (int dim2=0; dim2<3; dim2++)
177 rotation_matrices(virtual_cell,point,dim,dim2) = 0.0;
178 }
179 }
180 });
181 PHX::Device::execution_space().fence();
182}
183
184template<typename Scalar>
185void
186applyBasePermutation(PHX::MDField<Scalar,IP> field,
187 PHX::MDField<const int,Cell,IP> permutations)
188{
189 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::applyBasePermutation(rank 1)",app_base_perm_r1);
190 MDFieldArrayFactory af("",true);
191
192 const int num_ip = field.extent(0);
193
194 auto scratch = af.template buildStaticArray<Scalar,IP>("scratch", num_ip);
195 scratch.deep_copy(field);
196 Kokkos::parallel_for(1, KOKKOS_LAMBDA(const int & ){
197 for(int ip=0; ip<num_ip; ++ip)
198 if (ip != permutations(0,ip))
199 field(ip) = scratch(permutations(0,ip));
200 });
201 PHX::Device::execution_space().fence();
202}
203
204template<typename Scalar>
205void
206applyBasePermutation(PHX::MDField<Scalar,IP,Dim> field,
207 PHX::MDField<const int,Cell,IP> permutations)
208{
209 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::applyBasePermutation(rank 2)",app_base_perm_r2);
210 MDFieldArrayFactory af("",true);
211
212 const int num_ip = field.extent(0);
213 const int num_dim = field.extent(1);
214
215 auto scratch = af.template buildStaticArray<Scalar,IP,Dim>("scratch", num_ip,num_dim);
216 scratch.deep_copy(field);
217 Kokkos::parallel_for(1, KOKKOS_LAMBDA(const int & ){
218 for(int ip=0; ip<num_ip; ++ip)
219 if (ip != permutations(0,ip))
220 for(int dim=0; dim<num_dim; ++dim)
221 field(ip,dim) = scratch(permutations(0,ip),dim);
222 });
223 PHX::Device::execution_space().fence();
224}
225
226template<typename Scalar>
227void
228applyPermutation(PHX::MDField<Scalar,Cell,IP> field,
229 PHX::MDField<const int,Cell,IP> permutations)
230{
231 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::applyPermutation(rank 2)",app_perm_r2);
232 MDFieldArrayFactory af("",true);
233
234 const int num_cells = field.extent(0);
235 const int num_ip = field.extent(1);
236
237 auto scratch = af.template buildStaticArray<Scalar,Cell,IP>("scratch", num_cells, num_ip);
238 scratch.deep_copy(field);
239 Kokkos::parallel_for(num_cells, KOKKOS_LAMBDA(const int & cell){
240 for(int ip=0; ip<num_ip; ++ip)
241 if (ip != permutations(cell,ip))
242 field(cell,ip) = scratch(cell,permutations(cell,ip));
243 });
244 PHX::Device::execution_space().fence();
245}
246
247template<typename Scalar>
248void
249applyPermutation(PHX::MDField<Scalar,Cell,IP,Dim> field,
250 PHX::MDField<const int,Cell,IP> permutations)
251{
252 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::applyPermutation(rank 3)",app_perm_r3);
253 MDFieldArrayFactory af("",true);
254
255 const int num_cells = field.extent(0);
256 const int num_ip = field.extent(1);
257 const int num_dim = field.extent(2);
258
259 auto scratch = af.template buildStaticArray<Scalar,Cell,IP,Dim>("scratch", num_cells, num_ip, num_dim);
260 scratch.deep_copy(field);
261 Kokkos::parallel_for(num_cells, KOKKOS_LAMBDA(const int & cell){
262 for(int ip=0; ip<num_ip; ++ip)
263 if (ip != permutations(cell,ip))
264 for(int dim=0; dim<num_dim; ++dim)
265 field(cell,ip,dim) = scratch(cell,permutations(cell,ip),dim);
266 });
267 PHX::Device::execution_space().fence();
268}
269
270template<typename Scalar>
271void
272applyPermutation(PHX::MDField<Scalar,Cell,IP,Dim,Dim> field,
273 PHX::MDField<const int,Cell,IP> permutations)
274{
275 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::applyPermutation(rank 4)",app_perm_r4);
276 MDFieldArrayFactory af("",true);
277
278 const int num_cells = field.extent(0);
279 const int num_ip = field.extent(1);
280 const int num_dim = field.extent(2);
281 const int num_dim2 = field.extent(3);
282
283 auto scratch = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("scratch", num_cells, num_ip, num_dim, num_dim2);
284 scratch.deep_copy(field);
285 Kokkos::parallel_for(num_cells, KOKKOS_LAMBDA(const int & cell){
286 for(int ip=0; ip<num_ip; ++ip)
287 if (ip != permutations(cell,ip))
288 for(int dim=0; dim<num_dim; ++dim)
289 for(int dim2=0; dim2<num_dim2; ++dim2)
290 field(cell,ip,dim,dim2) = scratch(cell,permutations(cell,ip),dim,dim2);
291 });
292 PHX::Device::execution_space().fence();
293}
294
295
296// Find the permutation that maps the set of points coords to other_coords. To
297// avoid possible finite precision issues, == is not used, but rather
298// min(norm(.)).
299template <typename Scalar>
300PHX::MDField<const int,Cell,IP>
301generatePermutations(const int num_cells,
302 PHX::MDField<const Scalar,Cell,IP,Dim> coords,
303 PHX::MDField<const Scalar,Cell,IP,Dim> other_coords)
304{
305 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::generatePermutations()",gen_perms);
306
307 const int num_ip = coords.extent(1);
308 const int num_dim = coords.extent(2);
309
310 MDFieldArrayFactory af("",true);
311
312 // This will store the permutations to go from coords to other_coords
313 auto permutation = af.template buildStaticArray<int,Cell,IP>("permutation", num_cells, num_ip);
314 permutation.deep_copy(0);
315
316 // This is scratch space - there is likely a better way to do this
317 auto taken = af.template buildStaticArray<int,Cell,IP>("taken", num_cells, num_ip);
318 taken.deep_copy(0);
319
320 Kokkos::parallel_for(num_cells, KOKKOS_LAMBDA(const int & cell){
321
322 for (int ip = 0; ip < num_ip; ++ip) {
323 // Find an other point to associate with ip.
324 int i_min = 0;
325 Scalar d_min = -1;
326 for (int other_ip = 0; other_ip < num_ip; ++other_ip) {
327 // For speed, skip other points that are already associated.
328 if(taken(cell,other_ip)) continue;
329 // Compute the distance between the two points.
330 Scalar d(0);
331 for (int dim = 0; dim < num_dim; ++dim) {
332 const Scalar diff = coords(cell, ip, dim) - other_coords(cell, other_ip, dim);
333 d += diff*diff;
334 }
335 if (d_min < 0 || d < d_min) {
336 d_min = d;
337 i_min = other_ip;
338 }
339 }
340 // Record the match.
341 permutation(cell,ip) = i_min;
342 // This point is now taken.
343 taken(cell,i_min) = 1;
344 }
345 });
346 PHX::Device::execution_space().fence();
347
348 return permutation;
349
350}
351
352template <typename Scalar>
353PHX::MDField<const int,Cell,IP>
354generateSurfacePermutations(const int num_cells,
355 const SubcellConnectivity face_connectivity,
356 PHX::MDField<const Scalar,Cell,IP,Dim> surface_points,
357 PHX::MDField<const Scalar,Cell,IP,Dim,Dim> surface_rotation_matrices)
358
359{
360 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::generateSurfacePermutations()",gen_surf_perms);
361
362 // The challenge for this call is handling wedge-based periodic boundaries
363 // We need to make sure that we can align points along faces that are rotated with respect to one another.
364 // Below we will see an algorithm that rotates two boundaries into a shared frame, then figures out
365 // how to permute the points on one face to line up with the other.
366
367 const int num_points = surface_points.extent_int(1);
368 const int num_faces_per_cell = face_connectivity.numSubcellsOnCellHost(0);
369 const int num_points_per_face = num_points / num_faces_per_cell;
370 const int cell_dim = surface_points.extent(2);
371
372 MDFieldArrayFactory af("",true);
373
374 // This will store the permutations
375 auto permutation = af.template buildStaticArray<int,Cell,IP>("permutation", num_cells, num_points);
376 permutation.deep_copy(0);
377
378 // Fill permutations with trivial values (i.e. no permutation - this will get overwritten for some cells)
379 Kokkos::parallel_for(num_cells,KOKKOS_LAMBDA (const int & cell) {
380 for(int point=0; point<num_points; ++point)
381 permutation(cell,point) = point;
382 });
383
384 // Now we need to align the cubature points for each face
385 // If there is only one point there is no need to align things
386 if(num_points_per_face != 1) {
387 // To enforce that quadrature points on faces are aligned properly we will iterate through faces,
388 // map points to a plane shared by the faces, then re-order quadrature points on the "1" face to
389 // line up with the "0" face
390
391 // Utility calls
392#define PANZER_DOT(a,b) (a[0]*b[0] + a[1]*b[1] + a[2]*b[2])
393#define PANZER_CROSS(a,b,c) {c[0] = a[1]*b[2] - a[2]*b[1]; c[1] = a[2]*b[0] - a[0]*b[2]; c[2] = a[0]*b[1] - a[1]*b[0];}
394
395 // Iterate through faces
396 Kokkos::parallel_for("face iteration",face_connectivity.numSubcells(),KOKKOS_LAMBDA (const int face) {
397 // Cells for sides 0 and 1
398 const int cell_0 = face_connectivity.cellForSubcell(face,0);
399 const int cell_1 = face_connectivity.cellForSubcell(face,1);
400
401 // If this face doesn't connect to anything we don't need to worry about alignment
402 if(cell_1 < 0)
403 return;
404
405 // Local face index for sides 0 and 1
406 const int lidx_0 = face_connectivity.localSubcellForSubcell(face,0);
407 const int lidx_1 = face_connectivity.localSubcellForSubcell(face,1);
408
409 // If the cell exists, then the local face index needs to exist
410 KOKKOS_ASSERT(lidx_1 >= 0);
411
412 // To compare points on planes, it is good to center the planes around the origin
413 // Find the face center for the left and right cell (may not be the same point - e.g. periodic conditions)
414 // We also define a length scale r2 which gives an order of magnitude approximation to the cell size squared
415 Scalar xc0[3] = {0}, xc1[3] = {0}, r2 = 0;
416 for(int face_point=0; face_point<num_points_per_face; ++face_point){
417 Scalar dx2 = 0.;
418 for(int dim=0; dim<cell_dim; ++dim){
419 xc0[dim] += surface_points(cell_0,lidx_0*num_points_per_face + face_point,dim);
420 xc1[dim] += surface_points(cell_1,lidx_1*num_points_per_face + face_point,dim);
421 const Scalar dx = surface_points(cell_0,lidx_0*num_points_per_face + face_point,dim) - surface_points(cell_0,lidx_0*num_points_per_face,dim);
422 dx2 += dx*dx;
423 }
424
425 // Check if the distance squared between these two points is larger than the others (doesn't need to be perfect)
426 r2 = (r2 < dx2) ? dx2 : r2;
427 }
428 for(int dim=0; dim<cell_dim; ++dim){
429 xc0[dim] /= double(num_points_per_face);
430 xc1[dim] /= double(num_points_per_face);
431 }
432
433 // TODO: This needs to be adaptable to having curved faces - for now this will work
434
435 // We need to define a plane with two vectors (transverse and binormal)
436 // These will be used with the face centers to construct a local reference frame for aligning points
437
438 // We use the first point on the face to define the normal (may break for curved faces)
439 const int example_point_0 = lidx_0*num_points_per_face;
440 const int example_point_1 = lidx_1*num_points_per_face;
441
442 // Load the transverse and binormal for the 0 cell (default)
443 Scalar t[3] = {surface_rotation_matrices(cell_0,example_point_0,1,0), surface_rotation_matrices(cell_0,example_point_0,1,1), surface_rotation_matrices(cell_0,example_point_0,1,2)};
444 Scalar b[3] = {surface_rotation_matrices(cell_0,example_point_0,2,0), surface_rotation_matrices(cell_0,example_point_0,2,1), surface_rotation_matrices(cell_0,example_point_0,2,2)};
445
446 // In case the faces are not antiparallel (e.g. periodic wedge), we may need to change the transverse and binormal
447 {
448
449 // Get the normals for each face for constructing one of the plane vectors (transverse)
450 const Scalar n0[3] = {surface_rotation_matrices(cell_0,example_point_0,0,0), surface_rotation_matrices(cell_0,example_point_0,0,1), surface_rotation_matrices(cell_0,example_point_0,0,2)};
451 const Scalar n1[3] = {surface_rotation_matrices(cell_1,example_point_1,0,0), surface_rotation_matrices(cell_1,example_point_1,0,1), surface_rotation_matrices(cell_1,example_point_1,0,2)};
452
453 // n_0*n_1 == -1 (antiparallel), n_0*n_1 == 1 (parallel - bad), |n_0*n_1| < 1 (other)
454 const Scalar n0_dot_n1 = PANZER_DOT(n0,n1);
455
456 // FIXME: Currently virtual cells will set their surface normal along the same direction as the cell they "reflect"
457 // This causes a host of issues (e.g. identifying 180 degree periodic wedges), but we have to support virtual cells as a priority
458 // Therefore, we will just assume that the ordering is fine (not valid for 180 degree periodic wedges)
459 if(Kokkos::fabs(n0_dot_n1 - 1.) < 1.e-8)
460 return;
461
462 // Rotated faces case (e.g. periodic wedge) we need to check for non-antiparallel face normals
463 if(Kokkos::fabs(n0_dot_n1 + 1.) > 1.e-2){
464
465 // Now we need to define an arbitrary transverse and binormal in the plane across which the faces are anti-symmetric
466 // We can do this by setting t = n_0 \times n_1
467 PANZER_CROSS(n0,n1,t);
468
469 // Normalize the transverse vector
470 const Scalar mag_t = Kokkos::sqrt(PANZER_DOT(t,t));
471 t[0] /= mag_t;
472 t[1] /= mag_t;
473 t[2] /= mag_t;
474
475 // The binormal will be the sum of the normals (does not need to be a right handed system)
476 b[0] = n0[0] + n1[0];
477 b[1] = n0[1] + n1[1];
478 b[2] = n0[2] + n1[2];
479
480 // Normalize the binormal vector
481 const Scalar mag_b = Kokkos::sqrt(PANZER_DOT(b,b));
482 b[0] /= mag_b;
483 b[1] /= mag_b;
484 b[2] /= mag_b;
485
486 }
487 }
488
489 // Now that we have a reference coordinate plane in which to align our points
490 // Point on the transverse/binormal plane
491 Scalar p0[2] = {0};
492 Scalar p1[2] = {0};
493
494 // Differential position in mesh
495 Scalar x0[3] = {0};
496 Scalar x1[3] = {0};
497
498 // Iterate through points in cell 1 and find which point they align with in cell 0
499 for(int face_point_1=0; face_point_1<num_points_per_face; ++face_point_1){
500
501 // Get the point index in the 1 cell
502 const int point_1 = lidx_1*num_points_per_face + face_point_1;
503
504 // Load position shifted by face center
505 for(int dim=0; dim<cell_dim; ++dim)
506 x1[dim] = surface_points(cell_1,point_1,dim) - xc1[dim];
507
508 // Convert position to transverse/binormal plane
509 p1[0] = PANZER_DOT(x1,t);
510 p1[1] = PANZER_DOT(x1,b);
511
512 // Compare to points on the other surface
513 for(int face_point_0=0; face_point_0<num_points_per_face; ++face_point_0){
514
515 // Get the point index in the 0 cell
516 const int point_0 = lidx_0*num_points_per_face + face_point_0;
517
518 // Load position shifted by face center
519 for(int dim=0; dim<cell_dim; ++dim)
520 x0[dim] = surface_points(cell_0,point_0,dim) - xc0[dim];
521
522 // Convert position to transverse/binormal plane
523 p0[0] = PANZER_DOT(x0,t);
524 p0[1] = PANZER_DOT(x0,b);
525
526 // Find the distance squared between p0 and p1
527 const Scalar p012 = (p0[0]-p1[0])*(p0[0]-p1[0]) + (p0[1]-p1[1])*(p0[1]-p1[1]);
528
529 // TODO: Should this be a constant value, or should we just find the minimum point?
530 // If the distance, compared to the size of the cell, is small, we assume these are the same points
531 if(p012 / r2 < 1.e-12){
532 permutation(cell_1,lidx_1*num_points_per_face+face_point_0) = point_1;
533 break;
534 }
535
536 }
537 }
538 });
539 PHX::Device::execution_space().fence();
540 }
541
542#undef PANZER_DOT
543#undef PANZER_CROSS
544
545 return permutation;
546}
547
548} // end anonymous namespace
549
550//template<typename DataType>
551//using UnmanagedDynRankView = Kokkos::DynRankView<DataType,typename PHX::DevLayout<DataType>::type,PHX::Device,Kokkos::MemoryTraits<Kokkos::Unmanaged>>;
552
553template <typename Scalar>
555IntegrationValues2(const std::string & pre,
556 const bool allocArrays):
557 num_cells_(0),
558 num_evaluate_cells_(0),
559 num_virtual_cells_(-1),
560 requires_permutation_(false),
561 alloc_arrays_(allocArrays),
562 prefix_(pre),
563 ddims_(1,0)
564{
565 resetArrays();
566}
567
568template <typename Scalar>
569void
572{
573 cub_points_evaluated_ = false;
574 side_cub_points_evaluated_ = false;
575 cub_weights_evaluated_ = false;
576 node_coordinates_evaluated_ = false;
577 jac_evaluated_ = false;
578 jac_inv_evaluated_ = false;
579 jac_det_evaluated_ = false;
580 weighted_measure_evaluated_ = false;
581 weighted_normals_evaluated_ = false;
582 surface_normals_evaluated_ = false;
583 surface_rotation_matrices_evaluated_ = false;
584 covarient_evaluated_ = false;
585 contravarient_evaluated_ = false;
586 norm_contravarient_evaluated_ = false;
587 ip_coordinates_evaluated_ = false;
588 ref_ip_coordinates_evaluated_ = false;
589
590 // TODO: We need to clear the views
591}
592
593template <typename Scalar>
595setupArrays(const Teuchos::RCP<const panzer::IntegrationRule>& ir)
596{
597 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::setupArrays()",setup_arrays);
598
599 MDFieldArrayFactory af(prefix_,alloc_arrays_);
600
602
603 int_rule = ir;
604
605 const int num_nodes = ir->topology->getNodeCount();
606 const int num_cells = ir->workset_size;
607 const int num_space_dim = ir->topology->getDimension();
608
609 // Specialize content if this is quadrature at a node
610 const bool is_node_rule = (num_space_dim==1) and ir->isSide();
611 if(not is_node_rule) {
612 TEUCHOS_ASSERT(ir->getType() != ID::NONE);
613 intrepid_cubature = getIntrepidCubature(*ir);
614 }
615
616 const int num_ip = is_node_rule ? 1 : ir->num_points;
617
618 cub_points = af.template buildStaticArray<Scalar,IP,Dim>("cub_points",num_ip, num_space_dim);
619
620 if (ir->isSide() && ir->cv_type == "none")
621 side_cub_points = af.template buildStaticArray<Scalar,IP,Dim>("side_cub_points",num_ip,ir->side_topology->getDimension());
622
623 cub_weights = af.template buildStaticArray<Scalar,IP>("cub_weights",num_ip);
624
625 node_coordinates = af.template buildStaticArray<Scalar,Cell,BASIS,Dim>("node_coordinates",num_cells, num_nodes, num_space_dim);
626
627 jac = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("jac",num_cells, num_ip, num_space_dim,num_space_dim);
628
629 jac_inv = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("jac_inv",num_cells, num_ip, num_space_dim,num_space_dim);
630
631 jac_det = af.template buildStaticArray<Scalar,Cell,IP>("jac_det",num_cells, num_ip);
632
633 weighted_measure = af.template buildStaticArray<Scalar,Cell,IP>("weighted_measure",num_cells, num_ip);
634
635 covarient = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("covarient",num_cells, num_ip, num_space_dim,num_space_dim);
636
637 contravarient = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("contravarient",num_cells, num_ip, num_space_dim,num_space_dim);
638
639 norm_contravarient = af.template buildStaticArray<Scalar,Cell,IP>("norm_contravarient",num_cells, num_ip);
640
641 ip_coordinates = af.template buildStaticArray<Scalar,Cell,IP,Dim>("ip_coordiantes",num_cells, num_ip,num_space_dim);
642
643 ref_ip_coordinates = af.template buildStaticArray<Scalar,Cell,IP,Dim>("ref_ip_coordinates",num_cells, num_ip,num_space_dim);
644
645 weighted_normals = af.template buildStaticArray<Scalar,Cell,IP,Dim>("weighted_normal",num_cells,num_ip,num_space_dim);
646
647 surface_normals = af.template buildStaticArray<Scalar,Cell,IP,Dim>("surface_normals",num_cells, num_ip,num_space_dim);
648
649 surface_rotation_matrices = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("surface_rotation_matrices",num_cells, num_ip,3,3);
650}
651
652
653// ***********************************************************
654// * Evaluation of values - NOT specialized
655// ***********************************************************
656template <typename Scalar>
658evaluateValues(const PHX::MDField<Scalar,Cell,NODE,Dim> & in_node_coordinates,
659 const int in_num_cells,
660 const Teuchos::RCP<const SubcellConnectivity> & face_connectivity,
661 const int num_virtual_cells)
662{
663 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::evaluateValues(with virtual cells)",eval_vals_with_virts);
664
665 setup(int_rule, in_node_coordinates, in_num_cells);
666
667 // Setup permutations (only required for surface integrators)
669 if((int_rule->getType() == ID::SURFACE) and (face_connectivity != Teuchos::null))
670 setupPermutations(face_connectivity, num_virtual_cells);
671
672 // Evaluate everything once permutations are generated
673 evaluateEverything();
674}
675
676template <typename Scalar>
677void
679evaluateValues(const PHX::MDField<Scalar,Cell,NODE,Dim>& in_node_coordinates,
680 const PHX::MDField<Scalar,Cell,IP,Dim>& other_ip_coordinates,
681 const int in_num_cells)
682{
683 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::evaluateValues(no virtual cells)",eval_vals_no_virts);
684
685 setup(int_rule, in_node_coordinates, in_num_cells);
686
687 // Setup permutations
688 setupPermutations(other_ip_coordinates);
689
690 // Evaluate everything once permutations are generated
691 evaluateEverything();
692}
693
694template <typename Scalar>
695void
697setupPermutations(const Teuchos::RCP<const SubcellConnectivity> & face_connectivity,
698 const int num_virtual_cells)
699{
700 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::setupPermutations(connectivity)",setup_perms_conn);
701
702 TEUCHOS_ASSERT(not int_rule->isSide());
703 TEUCHOS_ASSERT(face_connectivity != Teuchos::null);
704 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->getType() != panzer::IntegrationDescriptor::SURFACE,
705 "IntegrationValues2::setupPermutations : Face connectivity based permutations are only required for surface integration schemes");
706 TEUCHOS_TEST_FOR_EXCEPT_MSG(num_virtual_cells_ >= 0,
707 "IntegrationValues2::setupPermutations : Number of virtual cells for surface permuations must be >= 0");
708 resetArrays();
709 side_connectivity_ = face_connectivity;
710 num_virtual_cells_ = num_virtual_cells;
711 requires_permutation_ = false;
712 permutations_ = generateSurfacePermutations<Scalar>(num_evaluate_cells_,*face_connectivity, getCubaturePoints(false,true), getSurfaceRotationMatrices(false,true));
713 requires_permutation_ = true;
714}
715
716template <typename Scalar>
717void
719setupPermutations(const PHX::MDField<Scalar,Cell,IP,Dim> & other_ip_coordinates)
720{
721 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::setupPermutations(other_coords)",setup_perms_coords);
722 resetArrays();
723 requires_permutation_ = false;
724 permutations_ = generatePermutations<Scalar>(num_evaluate_cells_, getCubaturePoints(false,true), other_ip_coordinates);
725 requires_permutation_ = true;
726}
727
728
729template <typename Scalar>
730void
732setup(const Teuchos::RCP<const panzer::IntegrationRule>& ir,
733 const PHX::MDField<Scalar,Cell,NODE,Dim> & cell_node_coordinates,
734 const int num_cells)
735{
736 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::setup()",setup);
737
738 // Clear arrays just in case we are rebuilding this object
739 resetArrays();
740
741 num_cells_ = cell_node_coordinates.extent(0);
742 num_evaluate_cells_ = num_cells < 0 ? cell_node_coordinates.extent(0) : num_cells;
743 int_rule = ir;
744
745 TEUCHOS_ASSERT(ir->getType() != IntegrationDescriptor::NONE);
746 intrepid_cubature = getIntrepidCubature(*ir);
747
748 // Copy node coordinates into owned allocation
749 {
750 MDFieldArrayFactory af(prefix_,true);
751
752 const int num_space_dim = int_rule->topology->getDimension();
753 const int num_nodes = int_rule->topology->getNodeCount();
754 TEUCHOS_ASSERT(static_cast<int>(cell_node_coordinates.extent(1)) == num_nodes);
755
756 auto aux = af.template buildStaticArray<Scalar,Cell,NODE,Dim>("node_coordinates",num_cells_,num_nodes, num_space_dim);
757 Kokkos::MDRangePolicy<PHX::Device,Kokkos::Rank<3>> policy({0,0,0},{num_evaluate_cells_,num_nodes,num_space_dim});
758 Kokkos::parallel_for(policy,KOKKOS_LAMBDA(const int & cell, const int & point, const int & dim){
759 aux(cell,point,dim) = cell_node_coordinates(cell,point,dim);
760 });
761 PHX::Device::execution_space().fence();
762 node_coordinates = aux;
763 }
764
765}
766
767template <typename Scalar>
770getUniformCubaturePointsRef(const bool cache,
771 const bool force,
772 const bool apply_permutation) const
773{
774 if(cub_points_evaluated_ and (apply_permutation == requires_permutation_) and not force)
775 return cub_points;
776
777 // Only log time if values computed (i.e. don't log if values are already cached)
778 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getUniformCubaturePointsRef()",get_uniform_cub_pts_ref);
779
780 Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
781 MDFieldArrayFactory af(prefix_,true);
782
783 int num_space_dim = int_rule->topology->getDimension();
784 int num_ip = int_rule->num_points;
785
786 auto aux = af.template buildStaticArray<Scalar,IP,Dim>("cub_points",num_ip, num_space_dim);
787
788 if (int_rule->isSide() && num_space_dim==1) {
789 std::cout << "WARNING: 0-D quadrature rule infrastructure does not exist!!! Will not be able to do "
790 << "non-natural integration rules.";
791 return aux;
792 }
793
794 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->cv_type != "none",
795 "IntegrationValues2::getUniformCubaturePointsRef : Cannot build reference cubature points for control volume integration scheme.");
796
797 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->getType() == IntegrationDescriptor::SURFACE,
798 "IntegrationValues2::getUniformCubaturePointsRef : Cannot build reference cubature points for surface integration scheme.");
799
800 auto weights = af.template buildStaticArray<Scalar,IP>("cub_weights",num_ip);
801
802 if (!int_rule->isSide())
803 intrepid_cubature->getCubature(aux.get_view(), weights.get_view());
804 else {
805 auto s_cub_points = af.template buildStaticArray<Scalar,IP,Dim>("side_cub_points",num_ip, num_space_dim-1);
806
807 intrepid_cubature->getCubature(s_cub_points.get_view(), weights.get_view());
808 cell_tools.mapToReferenceSubcell(aux.get_view(), s_cub_points.get_view(), num_space_dim-1, int_rule->getSide(), *(int_rule->topology));
809 }
810
811 PHX::Device::execution_space().fence();
812
813 if(apply_permutation and requires_permutation_)
814 applyBasePermutation(aux, permutations_);
815
816 if(cache and (apply_permutation == requires_permutation_)){
817 cub_points = aux;
818 cub_points_evaluated_ = true;
819 }
820
821 return aux;
822
823}
824
825template <typename Scalar>
828getUniformSideCubaturePointsRef(const bool cache,
829 const bool force,
830 const bool apply_permutation) const
831{
832 if(side_cub_points_evaluated_ and (apply_permutation == requires_permutation_) and not force)
833 return side_cub_points;
834
835 // Only log time if values computed (i.e. don't log if values are already cached)
836 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getUniformSideCubaturePointsRef()",get_uniform_side_cub_pts_ref);
837
838 MDFieldArrayFactory af(prefix_,true);
839
840 int num_space_dim = int_rule->topology->getDimension();
841 int num_ip = int_rule->num_points;
842
843 auto aux = af.template buildStaticArray<Scalar,IP,Dim>("side_cub_points",num_ip, num_space_dim-1);
844
845 if (int_rule->isSide() && num_space_dim==1) {
846 std::cout << "WARNING: 0-D quadrature rule infrastructure does not exist!!! Will not be able to do "
847 << "non-natural integration rules.";
848 return aux;
849 }
850
851 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->cv_type != "none",
852 "IntegrationValues2::getUniformSideCubaturePointsRef : Cannot build reference cubature points for control volume integration scheme.");
853
854 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->getType() == IntegrationDescriptor::SURFACE,
855 "IntegrationValues2::getUniformSideCubaturePointsRef : Cannot build reference cubature points for surface integration scheme.");
856
857 TEUCHOS_TEST_FOR_EXCEPT_MSG(!int_rule->isSide(),
858 "IntegrationValues2::getUniformSideCubaturePointsRef : Requested side points, which is not supported by integration rule.");
859
860 auto weights = af.template buildStaticArray<Scalar,IP>("cub_weights",num_ip);
861
862 intrepid_cubature->getCubature(aux.get_view(), weights.get_view());
863
864 PHX::Device::execution_space().fence();
865
866 if(apply_permutation and requires_permutation_)
867 applyBasePermutation(aux, permutations_);
868
869 if(cache and (apply_permutation == requires_permutation_)){
870 side_cub_points = aux;
871 side_cub_points_evaluated_ = true;
872 }
873
874 return aux;
875}
876
877template <typename Scalar>
880getUniformCubatureWeightsRef(const bool cache,
881 const bool force,
882 const bool apply_permutation) const
883{
884 if(cub_weights_evaluated_ and (apply_permutation == requires_permutation_) and not force)
885 return cub_weights;
886
887 // Only log time if values computed (i.e. don't log if values are already cached)
888 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getUniformCubatureWeightRef()",get_uniform_cub_weights_ref);
889
890 MDFieldArrayFactory af(prefix_,true);
891
892 int num_space_dim = int_rule->topology->getDimension();
893 int num_ip = int_rule->num_points;
894
895 auto aux = af.template buildStaticArray<Scalar,IP>("cub_weights",num_ip);
896
897 if (int_rule->isSide() && num_space_dim==1) {
898 std::cout << "WARNING: 0-D quadrature rule infrastructure does not exist!!! Will not be able to do "
899 << "non-natural integration rules.";
900 return aux;
901 }
902
903 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->cv_type != "none",
904 "IntegrationValues2::getUniformCubatureWeightsRef : Cannot build reference cubature weights for control volume integration scheme.");
905
906 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->getType() == IntegrationDescriptor::SURFACE,
907 "IntegrationValues2::getUniformCubatureWeightsRef : Cannot build reference cubature weights for surface integration scheme.");
908
909 auto points = af.template buildStaticArray<Scalar,IP,Dim>("cub_points",num_ip,num_space_dim);
910
911 intrepid_cubature->getCubature(points.get_view(), aux.get_view());
912
913 PHX::Device::execution_space().fence();
914
915 if(apply_permutation and requires_permutation_)
916 applyBasePermutation(aux, permutations_);
917
918 if(cache and (apply_permutation == requires_permutation_)){
919 cub_weights = aux;
920 cub_weights_evaluated_ = true;
921 }
922
923 return aux;
924
925}
926
927template <typename Scalar>
930getNodeCoordinates() const
931{
932 return node_coordinates;
933}
934
935template <typename Scalar>
938getJacobian(const bool cache,
939 const bool force) const
940{
941 if(jac_evaluated_ and not force)
942 return jac;
943
944 // Only log time if values computed (i.e. don't log if values are already cached)
945 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getJacobian()",get_jacobian);
946
947 Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
948 MDFieldArrayFactory af(prefix_,true);
949
950 int num_space_dim = int_rule->topology->getDimension();
951 int num_ip = int_rule->num_points;
952
954 const bool is_cv = (int_rule->getType() == ID::CV_VOLUME) or (int_rule->getType() == ID::CV_SIDE) or (int_rule->getType() == ID::CV_BOUNDARY);
955 const bool is_surface = int_rule->getType() == ID::SURFACE;
956
957 auto aux = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("jac",num_cells_, num_ip, num_space_dim,num_space_dim);
958
959 if(is_cv or is_surface){
960
961 // Don't forget that since we are not caching this, we have to make sure the managed view remains alive while we use the non-const wrapper
962 auto const_ref_coord = getCubaturePointsRef(false,force);
963 auto ref_coord = PHX::getNonConstDynRankViewFromConstMDField(const_ref_coord);
964 auto node_coord = PHX::getNonConstDynRankViewFromConstMDField(getNodeCoordinates());
965
966 const auto cell_range = std::make_pair(0,num_evaluate_cells_);
967 auto s_ref_coord = Kokkos::subview(ref_coord, cell_range,Kokkos::ALL(),Kokkos::ALL());
968 auto s_node_coord = Kokkos::subview(node_coord, cell_range,Kokkos::ALL(),Kokkos::ALL());
969 auto s_jac = Kokkos::subview(aux.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
970
971 cell_tools.setJacobian(s_jac, s_ref_coord, s_node_coord,*(int_rule->topology));
972
973 } else {
974
975 // Don't forget that since we are not caching this, we have to make sure the managed view remains alive while we use the non-const wrapper
976 auto const_ref_coord = getUniformCubaturePointsRef(false,force,false);
977 auto ref_coord = PHX::getNonConstDynRankViewFromConstMDField(const_ref_coord);
978 auto node_coord = PHX::getNonConstDynRankViewFromConstMDField(getNodeCoordinates());
979
980 const auto cell_range = std::make_pair(0,num_evaluate_cells_);
981 auto s_node_coord = Kokkos::subview(node_coord, cell_range,Kokkos::ALL(),Kokkos::ALL());
982 auto s_jac = Kokkos::subview(aux.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
983
984 cell_tools.setJacobian(s_jac, ref_coord, s_node_coord,*(int_rule->topology));
985
986 if(requires_permutation_)
987 applyPermutation(aux, permutations_);
988
989 }
990
991 PHX::Device::execution_space().fence();
992
993 if(cache){
994 jac = aux;
995 jac_evaluated_ = true;
996 }
997
998 return aux;
999}
1000
1001template <typename Scalar>
1004getJacobianInverse(const bool cache,
1005 const bool force) const
1006{
1007 if(jac_inv_evaluated_ and not force)
1008 return jac_inv;
1009
1010 // Only log time if values computed (i.e. don't log if values are already cached)
1011 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getJacobianInverse()",get_jacobian_inv);
1012
1013 Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
1014 MDFieldArrayFactory af(prefix_,true);
1015
1016 const int num_space_dim = int_rule->topology->getDimension();
1017 const int num_ip = int_rule->num_points;
1018
1019 auto jacobian = getJacobian(false,force);
1020 auto aux = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("jac_inv",num_cells_, num_ip, num_space_dim,num_space_dim);
1021
1022 const auto cell_range = std::make_pair(0,num_evaluate_cells_);
1023 auto s_jac = Kokkos::subview(jacobian.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
1024 auto s_jac_inv = Kokkos::subview(aux.get_view(), cell_range,Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
1025
1026 cell_tools.setJacobianInv(s_jac_inv, s_jac);
1027
1028 PHX::Device::execution_space().fence();
1029
1030 if(cache){
1031 jac_inv = aux;
1032 jac_inv_evaluated_ = true;
1033 }
1034
1035 return aux;
1036}
1037
1038template <typename Scalar>
1041getJacobianDeterminant(const bool cache,
1042 const bool force) const
1043{
1044 if(jac_det_evaluated_ and not force)
1045 return jac_det;
1046
1047 // Only log time if values computed (i.e. don't log if values are already cached)
1048 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getJacobianDeterminant()",get_jacobian_det);
1049
1050 Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
1051 MDFieldArrayFactory af(prefix_,true);
1052
1053 const int num_ip = int_rule->num_points;
1054
1055 auto jacobian = getJacobian(false,force);
1056 auto aux = af.template buildStaticArray<Scalar,Cell,IP>("jac_det",num_cells_, num_ip);
1057
1058 const auto cell_range = std::make_pair(0,num_evaluate_cells_);
1059 auto s_jac = Kokkos::subview(jacobian.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
1060 auto s_jac_det = Kokkos::subview(aux.get_view(), cell_range,Kokkos::ALL());
1061
1062 cell_tools.setJacobianDet(s_jac_det, s_jac);
1063
1064 PHX::Device::execution_space().fence();
1065
1066 if(cache){
1067 jac_det = aux;
1068 jac_det_evaluated_ = true;
1069 }
1070
1071 return aux;
1072}
1073
1074template <typename Scalar>
1077getWeightedMeasure(const bool cache,
1078 const bool force) const
1079{
1080 if(weighted_measure_evaluated_ and not force)
1081 return weighted_measure;
1082
1083 // Only log time if values computed (i.e. don't log if values are already cached)
1084 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getWeightedMeasure()",get_wt_meas);
1085
1086 MDFieldArrayFactory af(prefix_,true);
1087
1088 const int num_space_dim = int_rule->topology->getDimension();
1089 const int num_ip = int_rule->num_points;
1090
1091 auto aux = af.template buildStaticArray<Scalar,Cell,IP>("weighted_measure",num_cells_, num_ip);
1092
1093 if(int_rule->cv_type != "none"){
1094
1095 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->cv_type == "side",
1096 "IntegrationValues2::getWeightedMeasure : Weighted measure not available for side control volume integrators. Use getWeightedNormals instead.");
1097
1098 // CV integration uses a single call to map from physical space to the weighted measure - I assume this is slower than what we do with non-cv integration methods
1099
1100 auto s_cub_points = af.template buildStaticArray<Scalar, Cell, IP, Dim>("cub_points",num_evaluate_cells_,num_ip,num_space_dim);
1101
1102 auto node_coord = PHX::getNonConstDynRankViewFromConstMDField(getNodeCoordinates());
1103
1104 const auto cell_range = std::make_pair(0,num_evaluate_cells_);
1105 auto s_node_coord = Kokkos::subview(node_coord, cell_range,Kokkos::ALL(),Kokkos::ALL());
1106 auto s_weighted_measure = Kokkos::subview(aux.get_view(),cell_range,Kokkos::ALL());
1107
1108 intrepid_cubature->getCubature(s_cub_points.get_view(),s_weighted_measure,s_node_coord);
1109
1110 } else if(int_rule->getType() == IntegrationDescriptor::SURFACE){
1111
1112 const auto & cell_topology = *int_rule->topology;
1113 const int cell_dim = cell_topology.getDimension();
1114 const int num_sides = (cell_dim==1) ? 2 : cell_topology.getSideCount();
1115 const int cubature_order = int_rule->order();
1116 const int num_points_on_side = num_ip / num_sides;
1117
1118 Intrepid2::DefaultCubatureFactory cubature_factory;
1119 auto jacobian = getJacobian(false,force);
1120
1121 for(int side=0; side<num_sides; ++side) {
1122
1123 const int point_offset=side*num_points_on_side;
1124
1125 // Get the cubature for the side
1126 Kokkos::DynRankView<double,PHX::Device> side_cub_weights;
1127 if(cell_dim==1){
1128 side_cub_weights = Kokkos::DynRankView<double,PHX::Device>("side_cub_weights",num_points_on_side);
1129 auto tmp_side_cub_weights_host = Kokkos::create_mirror_view(side_cub_weights);
1130 tmp_side_cub_weights_host(0)=1.;
1131 Kokkos::deep_copy(side_cub_weights,tmp_side_cub_weights_host);
1132 } else {
1133
1134 // Get the face topology from the cell topology
1135 const shards::CellTopology face_topology(cell_topology.getCellTopologyData(cell_dim-1,side));
1136
1137 auto ic = cubature_factory.create<PHX::Device::execution_space,double,double>(face_topology,cubature_order);
1138
1139 side_cub_weights = Kokkos::DynRankView<double,PHX::Device>("side_cub_weights",num_points_on_side);
1140 auto subcell_cub_points = Kokkos::DynRankView<double,PHX::Device>("subcell_cub_points",num_points_on_side,cell_dim-1);
1141
1142 // Get the reference face points
1143 ic->getCubature(subcell_cub_points, side_cub_weights);
1144 }
1145
1146 PHX::Device::execution_space().fence();
1147
1148 // Iterating over face points
1149 Kokkos::MDRangePolicy<PHX::Device::execution_space,Kokkos::Rank<2>> policy({0,0},{num_evaluate_cells_,num_points_on_side});
1150
1151 // Calculate measures (quadrature weights in physical space) for this side
1152 auto side_weighted_measure = Kokkos::DynRankView<Scalar,PHX::Device>("side_weighted_measure",num_evaluate_cells_,num_points_on_side);
1153 if(cell_dim == 1){
1154 auto side_cub_weights_host = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(),side_cub_weights);
1155 Kokkos::deep_copy(side_weighted_measure, side_cub_weights_host(0));
1156 } else {
1157
1158 // Copy from complete jacobian to side jacobian
1159 auto side_jacobian = Kokkos::DynRankView<Scalar,PHX::Device>("side_jac",num_evaluate_cells_,num_points_on_side,cell_dim,cell_dim);
1160
1161 Kokkos::parallel_for("Copy jacobian to side jacobian",policy,KOKKOS_LAMBDA (const int cell,const int point) {
1162 for(int dim=0;dim<cell_dim;++dim)
1163 for(int dim1=0;dim1<cell_dim;++dim1)
1164 side_jacobian(cell,point,dim,dim1) = jacobian(cell,point_offset+point,dim,dim1);
1165 });
1166
1167 auto scratch = af.template buildStaticArray<Scalar,Point>("scratch_for_compute_measure", num_evaluate_cells_*num_points_on_side*num_space_dim*num_space_dim);
1168
1169 if(cell_dim == 2){
1170 Intrepid2::FunctionSpaceTools<PHX::Device::execution_space>::
1171 computeEdgeMeasure(side_weighted_measure, side_jacobian, side_cub_weights,
1172 side,cell_topology,
1173 scratch.get_view());
1174 PHX::Device::execution_space().fence();
1175 } else if(cell_dim == 3){
1176 Intrepid2::FunctionSpaceTools<PHX::Device::execution_space>::
1177 computeFaceMeasure(side_weighted_measure, side_jacobian, side_cub_weights,
1178 side,cell_topology,
1179 scratch.get_view());
1180 PHX::Device::execution_space().fence();
1181 }
1182 }
1183
1184
1185 // Copy to the main array
1186 Kokkos::parallel_for("copy surface weighted measure values",policy,KOKKOS_LAMBDA (const int cell,const int point) {
1187 aux(cell,point_offset + point) = side_weighted_measure(cell,point);
1188 });
1189 PHX::Device::execution_space().fence();
1190 }
1191
1192 } else {
1193
1194 auto cell_range = std::make_pair(0,num_evaluate_cells_);
1195 auto s_weighted_measure = Kokkos::subview(aux.get_view(),cell_range,Kokkos::ALL());
1196 auto cubature_weights = getUniformCubatureWeightsRef(false,force,false);
1197
1198 if (!int_rule->isSide()) {
1199
1200 auto s_jac_det = Kokkos::subview(getJacobianDeterminant(false,force).get_view(),cell_range,Kokkos::ALL());
1201 Intrepid2::FunctionSpaceTools<PHX::Device::execution_space>::
1202 computeCellMeasure(s_weighted_measure, s_jac_det, cubature_weights.get_view());
1203
1204 } else if(int_rule->spatial_dimension==3) {
1205
1206 auto s_jac = Kokkos::subview(getJacobian(false,force).get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
1207 auto scratch = af.template buildStaticArray<Scalar,Point>("scratch_for_compute_measure", num_evaluate_cells_*num_ip*num_space_dim*num_space_dim);
1208 Intrepid2::FunctionSpaceTools<PHX::Device::execution_space>::
1209 computeFaceMeasure(s_weighted_measure, s_jac, cubature_weights.get_view(),
1210 int_rule->side, *int_rule->topology,
1211 scratch.get_view());
1212
1213 } else if(int_rule->spatial_dimension==2) {
1214
1215 auto s_jac = Kokkos::subview(getJacobian(false,force).get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL(),Kokkos::ALL());
1216 auto scratch = af.template buildStaticArray<Scalar,Point>("scratch_for_compute_measure", num_evaluate_cells_*num_ip*num_space_dim*num_space_dim);
1217 Intrepid2::FunctionSpaceTools<PHX::Device::execution_space>::
1218 computeEdgeMeasure(s_weighted_measure, s_jac, cubature_weights.get_view(),
1219 int_rule->side,*int_rule->topology,
1220 scratch.get_view());
1221
1222 } else {
1223 TEUCHOS_ASSERT(false);
1224 }
1225
1226 }
1227
1228 PHX::Device::execution_space().fence();
1229
1230 // Apply permutations if necessary
1231 if(requires_permutation_)
1232 applyPermutation(aux, permutations_);
1233
1234 if(cache){
1235 weighted_measure = aux;
1236 weighted_measure_evaluated_ = true;
1237 }
1238
1239 return aux;
1240}
1241
1242template <typename Scalar>
1245getWeightedNormals(const bool cache,
1246 const bool force) const
1247{
1248 if(weighted_normals_evaluated_ and not force)
1249 return weighted_normals;
1250
1251 // Only log time if values computed (i.e. don't log if values are already cached)
1252 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getWeightedNormals()",get_wt_normals);
1253
1254 MDFieldArrayFactory af(prefix_,true);
1255
1256 const int num_space_dim = int_rule->topology->getDimension();
1257 const int num_ip = int_rule->num_points;
1258
1259 auto aux = af.template buildStaticArray<Scalar,Cell,IP,Dim>("weighted_normals",num_cells_,num_ip,num_space_dim);
1260
1261 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->getType() == IntegrationDescriptor::SURFACE,
1262 "IntegrationValues2::getWeightedNormals : Cannot build reference weighted normals for surface integration scheme.");
1263
1264 auto points = af.template buildStaticArray<Scalar,Cell,IP,Dim>("cub_points",num_cells_,num_ip,num_space_dim);
1265
1266 auto node_coord = PHX::getNonConstDynRankViewFromConstMDField(getNodeCoordinates());
1267
1268 const auto cell_range = std::make_pair(0,num_evaluate_cells_);
1269 auto s_cub_points = Kokkos::subview(points.get_view(),cell_range, Kokkos::ALL(), Kokkos::ALL());
1270 auto s_weighted_normals = Kokkos::subview(aux.get_view(), cell_range, Kokkos::ALL(), Kokkos::ALL());
1271 auto s_node_coord = Kokkos::subview(node_coord, cell_range, Kokkos::ALL(), Kokkos::ALL());
1272
1273 intrepid_cubature->getCubature(s_cub_points,s_weighted_normals,s_node_coord);
1274
1275 PHX::Device::execution_space().fence();
1276
1277 // Apply permutations if necessary
1278 if(requires_permutation_)
1279 applyPermutation(aux, permutations_);
1280
1281 if(cache){
1282 weighted_normals = aux;
1283 weighted_normals_evaluated_ = true;
1284 }
1285
1286 return aux;
1287}
1288
1289template <typename Scalar>
1292getSurfaceNormals(const bool cache,
1293 const bool force) const
1294{
1295 if(surface_normals_evaluated_ and not force)
1296 return surface_normals;
1297
1298 // Only log time if values computed (i.e. don't log if values are already cached)
1299 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getSurfaceNormals()",get_surf_normals);
1300
1301 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->isSide(),
1302 "IntegrationValues2::getSurfaceNormals : This call doesn't work with sides (only surfaces).");
1303
1304 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->cv_type != "none",
1305 "IntegrationValues2::getSurfaceNormals : This call does not support control volume integration schemes.");
1306
1307 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->getType() != IntegrationDescriptor::SURFACE,
1308 "IntegrationValues2::getSurfaceNormals : Can only build for surface integrators.");
1309
1310 Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
1311 MDFieldArrayFactory af(prefix_,true);
1312
1313 const shards::CellTopology & cell_topology = *(int_rule->topology);
1314 const int cell_dim = cell_topology.getDimension();
1315 const int subcell_dim = cell_topology.getDimension()-1;
1316 const int num_subcells = cell_topology.getSubcellCount(subcell_dim);
1317 const int num_space_dim = int_rule->topology->getDimension();
1318 const int num_ip = int_rule->num_points;
1319 const int num_points_on_face = num_ip / num_subcells;
1320
1321 auto aux = af.template buildStaticArray<Scalar,Cell,IP,Dim>("surface_normals",num_cells_,num_ip,num_space_dim);
1322
1323 // We only need the jacobian if we're not in 1D
1324 ConstArray_CellIPDimDim jacobian;
1325 if(cell_dim != 1)
1326 jacobian = getJacobian(false,force);
1327
1328 // We get to build up our surface normals one 'side' at a time
1329 for(int subcell_index=0; subcell_index<num_subcells; ++subcell_index) {
1330
1331 const int point_offset = subcell_index * num_points_on_face;;
1332
1333 // Calculate normals
1334 auto side_normals = Kokkos::DynRankView<Scalar,PHX::Device>("side_normals",num_evaluate_cells_,num_points_on_face,cell_dim);
1335 if(cell_dim == 1){
1336
1337 const int other_subcell_index = (subcell_index==0) ? 1 : 0;
1338 auto in_node_coordinates_k = getNodeCoordinates().get_view();
1339 const auto min = std::numeric_limits<typename Sacado::ScalarType<Scalar>::type>::min();
1340
1341 Kokkos::parallel_for("compute normals 1D",num_evaluate_cells_,KOKKOS_LAMBDA (const int cell) {
1342 Scalar norm = (in_node_coordinates_k(cell,subcell_index,0) - in_node_coordinates_k(cell,other_subcell_index,0));
1343 side_normals(cell,0,0) = norm / fabs(norm + min);
1344 });
1345
1346 } else {
1347
1348 // Iterating over side points
1349 Kokkos::MDRangePolicy<PHX::Device::execution_space,Kokkos::Rank<2>> policy({0,0},{num_evaluate_cells_,num_points_on_face});
1350
1351 auto side_jacobian = Kokkos::DynRankView<Scalar,PHX::Device>("side_jac",num_evaluate_cells_,num_points_on_face,cell_dim,cell_dim);
1352 Kokkos::parallel_for("Copy jacobian to side jacobian",policy,KOKKOS_LAMBDA (const int cell,const int point) {
1353 for(int dim=0;dim<cell_dim;++dim)
1354 for(int dim1=0;dim1<cell_dim;++dim1)
1355 side_jacobian(cell,point,dim,dim1) = jacobian(cell,point_offset+point,dim,dim1);
1356 });
1357
1358 // Get the "physical side normals"
1359 cell_tools.getPhysicalSideNormals(side_normals,side_jacobian,subcell_index,cell_topology);
1360
1361 // Normalize each normal
1362 Kokkos::parallel_for("Normalize the normals",policy,KOKKOS_LAMBDA (const int cell,const int point) {
1363 Scalar n = 0.;
1364 for(int dim=0;dim<cell_dim;++dim){
1365 n += side_normals(cell,point,dim)*side_normals(cell,point,dim);
1366 }
1367 // If n is zero then this is - hopefully - a virtual cell
1368 if(n > 0.){
1369 n = Kokkos::sqrt(n);
1370 for(int dim=0;dim<cell_dim;++dim)
1371 side_normals(cell,point,dim) /= n;
1372 }
1373 });
1374 }
1375
1376 PHX::Device::execution_space().fence();
1377
1378 Kokkos::MDRangePolicy<PHX::Device::execution_space,Kokkos::Rank<2>> policy({0,0},{num_evaluate_cells_,num_points_on_face});
1379 Kokkos::parallel_for("copy surface normals", policy,KOKKOS_LAMBDA (const int cell,const int point) {
1380 for(int dim=0;dim<cell_dim;++dim)
1381 aux(cell,point_offset + point,dim) = side_normals(cell,point,dim);
1382 });
1383 PHX::Device::execution_space().fence();
1384 }
1385
1386 // Need to correct the virtual cells
1387 {
1388 TEUCHOS_TEST_FOR_EXCEPT_MSG(side_connectivity_ == Teuchos::null,
1389 "IntegrationValues2::getSurfaceNormals : Surface normals require a SubcellConnectivity object pass in through the setupPermutations call");
1390 TEUCHOS_TEST_FOR_EXCEPT_MSG(num_virtual_cells_ < 0,
1391 "IntegrationValues2::getSurfaceNormals : Number of virtual cells (see setupPermutations or evaluateValues) must be greater or equal to zero");
1392
1393 // Virtual cell normals need to be reversed
1394 if(num_virtual_cells_ > 0)
1395 correctVirtualNormals(aux, num_evaluate_cells_ - num_virtual_cells_, num_virtual_cells_, *int_rule->topology, *side_connectivity_);
1396 }
1397
1398 if(cache){
1399 surface_normals = aux;
1400 surface_normals_evaluated_ = true;
1401 }
1402
1403 return aux;
1404
1405}
1406
1407template <typename Scalar>
1410getSurfaceRotationMatrices(const bool cache,
1411 const bool force) const
1412{
1413 if(surface_rotation_matrices_evaluated_ and not force)
1414 return surface_rotation_matrices;
1415
1416 // Only log time if values computed (i.e. don't log if values are already cached)
1417 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getSurfaceRotationMatrices()",get_surf_rot_mat);
1418
1419 MDFieldArrayFactory af(prefix_,true);
1420
1421 const int num_ip = int_rule->num_points;
1422 const int cell_dim = int_rule->topology->getDimension();
1423
1424 // This call will handle all the error checking
1425 auto normals = getSurfaceNormals(false,force).get_static_view();
1426 auto aux = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("surface_rotation_matrices",num_cells_, num_ip, 3, 3);
1427
1428 Kokkos::MDRangePolicy<PHX::Device::execution_space,Kokkos::Rank<2>> policy({0,0},{num_evaluate_cells_,num_ip});
1429 Kokkos::parallel_for("create surface rotation matrices",policy,KOKKOS_LAMBDA (const int cell,const int point) {
1430 Scalar normal[3];
1431 for(int i=0;i<3;i++)
1432 normal[i]=0.;
1433 for(int dim=0; dim<cell_dim; ++dim)
1434 normal[dim] = normals(cell,point,dim);
1435
1436 Scalar transverse[3];
1437 Scalar binormal[3];
1438 panzer::convertNormalToRotationMatrix(normal,transverse,binormal);
1439
1440 for(int dim=0; dim<3; ++dim){
1441 aux(cell,point,0,dim) = normal[dim];
1442 aux(cell,point,1,dim) = transverse[dim];
1443 aux(cell,point,2,dim) = binormal[dim];
1444 }
1445 });
1446 PHX::Device::execution_space().fence();
1447
1448 // Need to correct the virtual cells
1449 {
1450 TEUCHOS_TEST_FOR_EXCEPT_MSG(side_connectivity_ == Teuchos::null,
1451 "IntegrationValues2::getSurfaceRotationMatrices : Surface normals require a SubcellConnectivity object pass in through the setupPermutations call");
1452 TEUCHOS_TEST_FOR_EXCEPT_MSG(num_virtual_cells_ < 0,
1453 "IntegrationValues2::getSurfaceRotationMatrices : Number of virtual cells (see setupPermutations or evaluateValues) must be greater or equal to zero");
1454
1455 // Virtual cell normals need to be reversed
1456 if(num_virtual_cells_ > 0)
1457 correctVirtualRotationMatrices(aux, num_evaluate_cells_ - num_virtual_cells_, num_virtual_cells_, *int_rule->topology, *side_connectivity_);
1458 }
1459
1460 if(cache){
1461 surface_rotation_matrices = aux;
1462 surface_rotation_matrices_evaluated_ = true;
1463 }
1464
1465 return aux;
1466}
1467
1468template <typename Scalar>
1471getCovarientMatrix(const bool cache,
1472 const bool force) const
1473{
1474 if(covarient_evaluated_ and not force)
1475 return covarient;
1476
1477 // Only log time if values computed (i.e. don't log if values are already cached)
1478 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getCovariantMatrix()",get_cov_mat);
1479
1480 MDFieldArrayFactory af(prefix_,true);
1481
1482 const int num_space_dim = int_rule->topology->getDimension();
1483 const int num_ip = int_rule->num_points;
1484
1485 auto jacobian = getJacobian(false,force).get_static_view();
1486 auto aux = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("covarient",num_cells_, num_ip, num_space_dim,num_space_dim);
1487
1488 Kokkos::MDRangePolicy<PHX::Device,Kokkos::Rank<2>> policy({0,0},{num_evaluate_cells_,num_ip});
1489 Kokkos::parallel_for("evalaute covarient metric tensor",policy,KOKKOS_LAMBDA (const int cell,const int ip) {
1490 // g^{ij} = \frac{\parital x_i}{\partial \chi_\alpha}\frac{\parital x_j}{\partial \chi_\alpha}
1491 for (int i = 0; i < num_space_dim; ++i) {
1492 for (int j = 0; j < num_space_dim; ++j) {
1493 Scalar value(0.0);
1494 for (int alpha = 0; alpha < num_space_dim; ++alpha)
1495 value += jacobian(cell,ip,i,alpha) * jacobian(cell,ip,j,alpha);
1496 aux(cell,ip,i,j) = value;
1497 }
1498 }
1499 });
1500 PHX::Device::execution_space().fence();
1501
1502 if(cache){
1503 covarient = aux;
1504 covarient_evaluated_ = true;
1505 }
1506
1507 return aux;
1508}
1509
1510template <typename Scalar>
1513getContravarientMatrix(const bool cache,
1514 const bool force) const
1515{
1516 if(contravarient_evaluated_ and not force)
1517 return contravarient;
1518
1519 // Only log time if values computed (i.e. don't log if values are already cached)
1520 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getContravarientMatrix()",get_contra_mat);
1521
1522 MDFieldArrayFactory af(prefix_,true);
1523
1524 const int num_space_dim = int_rule->topology->getDimension();
1525 const int num_ip = int_rule->num_points;
1526
1527 auto cov = getCovarientMatrix(false,force);
1528 auto aux = af.template buildStaticArray<Scalar,Cell,IP,Dim,Dim>("contravarient",num_cells_, num_ip, num_space_dim,num_space_dim);
1529
1530 const auto cell_range = std::make_pair(0,num_evaluate_cells_);
1531 auto s_contravarient = Kokkos::subview(aux.get_view(), cell_range,Kokkos::ALL,Kokkos::ALL,Kokkos::ALL);
1532 auto s_covarient = Kokkos::subview(cov.get_view(), cell_range,Kokkos::ALL,Kokkos::ALL,Kokkos::ALL);
1533
1534 Intrepid2::RealSpaceTools<PHX::Device::execution_space>::inverse(s_contravarient, s_covarient);
1535 PHX::Device::execution_space().fence();
1536
1537 if(cache){
1538 contravarient = aux;
1539 contravarient_evaluated_ = true;
1540 }
1541
1542 return aux;
1543}
1544
1545template <typename Scalar>
1548getNormContravarientMatrix(const bool cache,
1549 const bool force) const
1550{
1551 if(norm_contravarient_evaluated_ and not force)
1552 return norm_contravarient;
1553
1554 // Only log time if values computed (i.e. don't log if values are already cached)
1555 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getNormContravarientMatrix()",get_norm_contr_mat);
1556
1557 MDFieldArrayFactory af(prefix_,true);
1558
1559 const int num_space_dim = int_rule->topology->getDimension();
1560 const int num_ip = int_rule->num_points;
1561
1562 auto con = getContravarientMatrix(false,force).get_static_view();
1563 auto aux = af.template buildStaticArray<Scalar,Cell,IP>("norm_contravarient",num_cells_, num_ip);
1564
1565 // norm of g_ij
1566 Kokkos::MDRangePolicy<PHX::Device,Kokkos::Rank<2>> policy({0,0},{num_evaluate_cells_,num_ip});
1567 Kokkos::parallel_for("evaluate norm_contravarient",policy,KOKKOS_LAMBDA (const int cell,const int ip) {
1568 aux(cell,ip) = 0.0;
1569 for (int i = 0; i < num_space_dim; ++i) {
1570 for (int j = 0; j < num_space_dim; ++j) {
1571 aux(cell,ip) += con(cell,ip,i,j) * con(cell,ip,i,j);
1572 }
1573 }
1574 aux(cell,ip) = Kokkos::sqrt(aux(cell,ip));
1575 });
1576 PHX::Device::execution_space().fence();
1577
1578 if(cache){
1579 norm_contravarient = aux;
1580 norm_contravarient_evaluated_ = true;
1581 }
1582
1583 return aux;
1584}
1585
1586template <typename Scalar>
1589getCubaturePoints(const bool cache,
1590 const bool force) const
1591{
1592 if(ip_coordinates_evaluated_ and not force)
1593 return ip_coordinates;
1594
1595 // Only log time if values computed (i.e. don't log if values are already cached)
1596 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getCubaturePoints()",get_cub_pts);
1597
1598 MDFieldArrayFactory af(prefix_,true);
1599
1600 const int num_space_dim = int_rule->topology->getDimension();
1601 const int num_ip = int_rule->num_points;
1602
1603 auto aux = af.template buildStaticArray<Scalar,Cell,IP,Dim>("ip_coordinates",num_cells_, num_ip, num_space_dim);
1604
1606 const bool is_cv = (int_rule->getType() == ID::CV_VOLUME) or (int_rule->getType() == ID::CV_SIDE) or (int_rule->getType() == ID::CV_BOUNDARY);
1607 const bool is_surface = int_rule->getType() == ID::SURFACE;
1608
1609 auto node_coord = PHX::getNonConstDynRankViewFromConstMDField(getNodeCoordinates());
1610
1611 if(is_cv){
1612
1613 // CV integration uses a single call to map from physical space to the weighted measure - I assume this is slower than what we do with non-cv integration methods
1614 const auto cell_range = std::make_pair(0,num_evaluate_cells_);
1615 auto s_node_coord = Kokkos::subview(node_coord, cell_range,Kokkos::ALL(),Kokkos::ALL());
1616 auto s_cub_points = Kokkos::subview(aux.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL());
1617
1618 // TODO: We need to pull this apart for control volumes. Right now we calculate both weighted measures/norms and cubature points at the same time
1619 if(int_rule->cv_type == "side"){
1620 auto scratch = af.template buildStaticArray<Scalar,Cell,IP,Dim>("scratch",num_evaluate_cells_,num_ip,num_space_dim);
1621 intrepid_cubature->getCubature(s_cub_points,scratch.get_view(),s_node_coord);
1622 } else {
1623 // I think boundary is included as a weighted measure because it has a side embedded in intrepid_cubature
1624 TEUCHOS_ASSERT((int_rule->getType() == ID::CV_VOLUME) or (int_rule->getType() == ID::CV_BOUNDARY));
1625 auto scratch = af.template buildStaticArray<Scalar,Cell,IP>("scratch",num_evaluate_cells_,num_ip);
1626 intrepid_cubature->getCubature(s_cub_points,scratch.get_view(),s_node_coord);
1627 }
1628
1629 } else if(is_surface){
1630
1631 // Don't forget that since we are not caching this, we have to make sure the managed view remains alive while we use the non-const wrapper
1632 auto const_ref_coord = getCubaturePointsRef(false,force);
1633 auto ref_coord = PHX::getNonConstDynRankViewFromConstMDField(const_ref_coord);
1634
1635 const auto cell_range = std::make_pair(0,num_evaluate_cells_);
1636 auto s_ref_coord = Kokkos::subview(ref_coord, cell_range,Kokkos::ALL(),Kokkos::ALL());
1637 auto s_coord = Kokkos::subview(aux.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL());
1638 auto s_node_coord = Kokkos::subview(node_coord, cell_range,Kokkos::ALL(),Kokkos::ALL());
1639
1640 Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
1641 cell_tools.mapToPhysicalFrame(s_coord, s_ref_coord, s_node_coord, *(int_rule->topology));
1642
1643 } else {
1644
1645 // Don't forget that since we are not caching this, we have to make sure the managed view remains alive while we use the non-const wrapper
1646 auto const_ref_coord = getUniformCubaturePointsRef(false,force,false);
1647 auto ref_coord = PHX::getNonConstDynRankViewFromConstMDField(const_ref_coord);
1648
1649 const auto cell_range = std::make_pair(0,num_evaluate_cells_);
1650 auto s_coord = Kokkos::subview(aux.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL());
1651 auto s_node_coord = Kokkos::subview(node_coord, cell_range,Kokkos::ALL(),Kokkos::ALL());
1652
1653 Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
1654 cell_tools.mapToPhysicalFrame(s_coord, ref_coord, s_node_coord, *(int_rule->topology));
1655
1656 if(requires_permutation_)
1657 applyPermutation(aux, permutations_);
1658
1659 }
1660
1661 PHX::Device::execution_space().fence();
1662
1663 if(cache){
1664 ip_coordinates = aux;
1665 ip_coordinates_evaluated_ = true;
1666 }
1667
1668 return aux;
1669}
1670
1671
1672template <typename Scalar>
1675getCubaturePointsRef(const bool cache,
1676 const bool force) const
1677{
1678 if(ref_ip_coordinates_evaluated_ and not force)
1679 return ref_ip_coordinates;
1680
1681 // Only log time if values computed (i.e. don't log if values are already cached)
1682 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::getCubaturePointsRef()",get_cub_pts_ref);
1683
1685 const bool is_surface = int_rule->getType() == ID::SURFACE;
1686 const bool is_cv = (int_rule->getType() == ID::CV_VOLUME) or (int_rule->getType() == ID::CV_SIDE) or (int_rule->getType() == ID::CV_BOUNDARY);
1687
1688 const int num_space_dim = int_rule->topology->getDimension();
1689 const int num_ip = int_rule->num_points;
1690
1691 MDFieldArrayFactory af(prefix_,true);
1692
1693 Intrepid2::CellTools<PHX::Device::execution_space> cell_tools;
1694
1695 auto aux = af.template buildStaticArray<Scalar,Cell,IP,Dim>("ref_ip_coordinates",num_cells_, num_ip, num_space_dim);
1696
1697 if(is_cv){
1698
1699 // Control volume reference points are actually generated from the physical points (i.e. reverse to everything else)
1700
1701 auto node_coord = PHX::getNonConstDynRankViewFromConstMDField(getNodeCoordinates());
1702
1703 // Don't forget that since we are not caching this, we have to make sure the managed view remains alive while we use the non-const wrapper
1704 auto const_coord = getCubaturePoints(false,force);
1705 auto coord = PHX::getNonConstDynRankViewFromConstMDField(const_coord);
1706
1707 const auto cell_range = std::make_pair(0,num_evaluate_cells_);
1708 auto s_ref_coord = Kokkos::subview(aux.get_view(),cell_range,Kokkos::ALL(),Kokkos::ALL());
1709 auto s_coord = Kokkos::subview(coord, cell_range,Kokkos::ALL(),Kokkos::ALL());
1710 auto s_node_coord = Kokkos::subview(node_coord, cell_range,Kokkos::ALL(),Kokkos::ALL());
1711
1712 cell_tools.mapToReferenceFrame(s_ref_coord, s_coord, s_node_coord, *(int_rule->topology));
1713
1714 } else if(is_surface){
1715
1716 const auto & cell_topology = *int_rule->topology;
1717 const int cell_dim = cell_topology.getDimension();
1718 const int num_sides = (cell_dim==1) ? 2 : cell_topology.getSideCount();
1719 const int subcell_dim = cell_dim-1;
1720 const int num_points_on_face = num_ip / num_sides;
1721 const int order = int_rule->getOrder();
1722
1723 // Scratch space for storing the points for each side of the cell
1724 auto side_cub_points2 = af.template buildStaticArray<Scalar,IP,Dim>("side_cub_points",num_points_on_face,cell_dim);
1725
1726 Intrepid2::DefaultCubatureFactory cubature_factory;
1727
1728 // We get to build up our cubature one side at a time
1729 for(int side=0; side<num_sides; ++side) {
1730
1731 const int point_offset = side*num_points_on_face;
1732
1733 // Get the cubature for the side
1734 if(cell_dim==1){
1735 // In 1D the surface point is either on the left side of the cell, or the right side
1736 auto side_cub_points_host = Kokkos::create_mirror_view(side_cub_points2.get_view());
1737 side_cub_points_host(0,0) = (side==0)? -1. : 1.;
1738 Kokkos::deep_copy(side_cub_points2.get_view(),side_cub_points_host);
1739 } else {
1740
1741 // Get the face topology from the cell topology
1742 const shards::CellTopology face_topology(cell_topology.getCellTopologyData(subcell_dim,side));
1743
1744 // Create a cubature for the face of the cell
1745 auto ic = cubature_factory.create<PHX::Device::execution_space,double,double>(face_topology,order);
1746 auto tmp_side_cub_weights = Kokkos::DynRankView<double,PHX::Device>("tmp_side_cub_weights",num_points_on_face);
1747 auto tmp_side_cub_points = Kokkos::DynRankView<double,PHX::Device>("tmp_side_cub_points",num_points_on_face,subcell_dim);
1748
1749 // Get the reference face points
1750 ic->getCubature(tmp_side_cub_points, tmp_side_cub_weights);
1751
1752 // Convert from reference face points to reference cell points
1753 cell_tools.mapToReferenceSubcell(side_cub_points2.get_view(), tmp_side_cub_points, subcell_dim, side, cell_topology);
1754 }
1755
1756 PHX::Device::execution_space().fence();
1757
1758 // Copy from the side allocation to the surface allocation
1759 Kokkos::MDRangePolicy<PHX::Device::execution_space,Kokkos::Rank<3>> policy({0,0,0},{num_evaluate_cells_,num_points_on_face, num_space_dim});
1760 Kokkos::parallel_for("copy values",policy,KOKKOS_LAMBDA (const int cell,const int point, const int dim) {
1761 aux(cell,point_offset + point,dim) = side_cub_points2(point,dim);
1762 });
1763 PHX::Device::execution_space().fence();
1764 }
1765
1766 } else {
1767
1768 // Haven't set this up yet
1769 TEUCHOS_TEST_FOR_EXCEPT_MSG(int_rule->isSide() && num_space_dim==1,
1770 "ERROR: 0-D quadrature rule infrastructure does not exist!!! Will not be able to do "
1771 << "non-natural integration rules.");
1772
1773 auto cub_points2 = getUniformCubaturePointsRef(false,force,false);
1774
1775 Kokkos::MDRangePolicy<PHX::Device,Kokkos::Rank<3>> policy({0,0,0},{num_evaluate_cells_,num_ip,num_space_dim});
1776 Kokkos::parallel_for(policy, KOKKOS_LAMBDA(const int & cell, const int & ip, const int & dim){
1777 aux(cell,ip,dim) = cub_points2(ip,dim);
1778 });
1779 }
1780
1781 PHX::Device::execution_space().fence();
1782
1783 if(requires_permutation_)
1784 applyPermutation(aux, permutations_);
1785
1786 if(cache){
1787 ref_ip_coordinates = aux;
1788 ref_ip_coordinates_evaluated_ = true;
1789 }
1790
1791 return aux;
1792}
1793
1794template <typename Scalar>
1795void
1798{
1799 PANZER_FUNC_TIME_MONITOR_DIFF("panzer::integrationValues2::evaluateEverything()",eval_everything);
1800
1802 const bool is_surface = int_rule->getType() == ID::SURFACE;
1803 const bool is_cv = (int_rule->getType() == ID::CV_VOLUME) or (int_rule->getType() == ID::CV_SIDE) or (int_rule->getType() == ID::CV_BOUNDARY);
1804 const bool is_side = int_rule->isSide();
1805
1806 // This will force all values to be re-evaluated
1807 resetArrays();
1808
1809 // Base cubature stuff
1810 if(is_cv){
1811 getCubaturePoints(true);
1812 getCubaturePointsRef(true);
1813 } else {
1814 if(not is_surface){
1815 getUniformCubaturePointsRef(true,true,requires_permutation_);
1816 getUniformCubatureWeightsRef(true,true,requires_permutation_);
1817 if(is_side)
1818 getUniformSideCubaturePointsRef(true,true,requires_permutation_);
1819 }
1820 getCubaturePointsRef(true);
1821 getCubaturePoints(true);
1822 }
1823
1824 // Measure stuff
1825 getJacobian(true);
1826 getJacobianDeterminant(true);
1827 getJacobianInverse(true);
1828 if(int_rule->cv_type == "side")
1829 getWeightedNormals(true);
1830 else
1831 getWeightedMeasure(true);
1832
1833 // Surface stuff
1834 if(is_surface){
1835 getSurfaceNormals(true);
1836 getSurfaceRotationMatrices(true);
1837 }
1838
1839 // Stabilization stuff
1840 if(not (is_surface or is_cv)){
1841 getContravarientMatrix(true);
1842 getCovarientMatrix(true);
1843 getNormContravarientMatrix(true);
1844 }
1845}
1846
1847#define INTEGRATION_VALUES2_INSTANTIATION(SCALAR) \
1848 template class IntegrationValues2<SCALAR>;
1849
1851
1852// Disabled FAD support due to long build times on cuda (in debug mode
1853// it takes multiple hours on some platforms). If we need
1854// sensitivities wrt coordinates, we can reenable.
1855
1856// INTEGRATION_VALUES2_INSTANTIATION(panzer::Traits::FadType)
1857
1858}
#define PANZER_CROSS(a, b, c)
#define PANZER_DOT(a, b)
#define INTEGRATION_VALUES2_INSTANTIATION(SCALAR)
PHX::MDField< ScalarT, panzer::Cell, panzer::BASIS > field
A field to which we'll contribute, or in which we'll store, the result of computing this integral.
const int & getOrder() const
Get order of integrator.
const int & getSide() const
Get side associated with integration - this is for backward compatibility.
const int & getType() const
Get type of integrator.
ConstArray_IPDim getUniformCubaturePointsRef(const bool cache=true, const bool force=false, const bool apply_permutation=true) const
Get the uniform cubature points.
void setupPermutations(const Teuchos::RCP< const SubcellConnectivity > &face_connectivity, const int num_virtual_cells)
Initialize the permutation arrays given a face connectivity.
ConstArray_CellIP getWeightedMeasure(const bool cache=true, const bool force=false) const
Get the weighted measure (integration weights)
ConstArray_CellIPDimDim getJacobian(const bool cache=true, const bool force=false) const
Get the Jacobian matrix evaluated at the cubature points.
void evaluateValues(const PHX::MDField< Scalar, Cell, NODE, Dim > &cell_node_coordinates, const int num_cells=-1, const Teuchos::RCP< const SubcellConnectivity > &face_connectivity=Teuchos::null, const int num_virtual_cells=-1)
Evaluate basis values.
PHX::MDField< const Scalar, Cell, IP > ConstArray_CellIP
ConstArray_CellIPDim getCubaturePointsRef(const bool cache=true, const bool force=false) const
Get the cubature points in the reference space.
ConstArray_CellIPDimDim getSurfaceRotationMatrices(const bool cache=true, const bool force=false) const
Get the surface rotation matrices.
PHX::MDField< const Scalar, IP, Dim > ConstArray_IPDim
void setupArrays(const Teuchos::RCP< const panzer::IntegrationRule > &ir)
Sizes/allocates memory for arrays.
PHX::MDField< const Scalar, Cell, IP, Dim, Dim > ConstArray_CellIPDimDim
PHX::MDField< const Scalar, IP > ConstArray_IP
IntegrationValues2(const std::string &pre="", const bool allocArrays=false)
Base constructor.
ConstArray_CellIPDim getWeightedNormals(const bool cache=true, const bool force=false) const
Get the weighted normals.
ConstArray_CellIP getNormContravarientMatrix(const bool cache=true, const bool force=false) const
Get the contravarient matrix.
ConstArray_CellIPDimDim getContravarientMatrix(const bool cache=true, const bool force=false) const
Get the contravarient matrix.
ConstArray_CellIPDim getCubaturePoints(const bool cache=true, const bool force=false) const
Get the cubature points in physical space.
PHX::MDField< const Scalar, Cell, IP, Dim > ConstArray_CellIPDim
void setup(const Teuchos::RCP< const panzer::IntegrationRule > &ir, const PHX::MDField< Scalar, Cell, NODE, Dim > &cell_node_coordinates, const int num_cells=-1)
Main setup call for the lazy evaluation interface.
ConstArray_CellIPDimDim getCovarientMatrix(const bool cache=true, const bool force=false) const
Get the covarient matrix.
ConstArray_CellBASISDim getNodeCoordinates() const
Get the node coordinates describing the geometry of the mesh.
ConstArray_IPDim getUniformSideCubaturePointsRef(const bool cache=true, const bool force=false, const bool apply_permutation=true) const
Get the uniform cubature points for a side.
ConstArray_CellIPDim getSurfaceNormals(const bool cache=true, const bool force=false) const
Get the surface normals.
PHX::MDField< const Scalar, Cell, BASIS, Dim > ConstArray_CellBASISDim
ConstArray_IP getUniformCubatureWeightsRef(const bool cache=true, const bool force=false, const bool apply_permutation=true) const
Get the uniform cubature weights.
ConstArray_CellIPDimDim getJacobianInverse(const bool cache=true, const bool force=false) const
Get the inverse of the Jacobian matrix evaluated at the cubature points.
ConstArray_CellIP getJacobianDeterminant(const bool cache=true, const bool force=false) const
Get the determinant of the Jacobian matrix evaluated at the cubature points.
Teuchos::RCP< shards::CellTopology > side_topology
Teuchos::RCP< const shards::CellTopology > topology
KOKKOS_INLINE_FUNCTION void convertNormalToRotationMatrix(const Scalar normal[3], Scalar transverse[3], Scalar binormal[3])