Panzer  Version of the Day
Panzer_IntegrationRule.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 
43 
45 
46 #include "Teuchos_ArrayRCP.hpp"
47 #include "Teuchos_Assert.hpp"
48 #include "Phalanx_DataLayout_MDALayout.hpp"
49 #include "Intrepid2_DefaultCubatureFactory.hpp"
50 #include "Intrepid2_CubatureControlVolume.hpp"
51 #include "Intrepid2_CubatureControlVolumeSide.hpp"
52 #include "Intrepid2_CubatureControlVolumeBoundary.hpp"
53 #include "Panzer_Dimension.hpp"
54 #include "Panzer_CellData.hpp"
55 
56 
58 IntegrationRule(int in_cubature_degree, const panzer::CellData& cell_data)
60 {
61  if(cell_data.isSide()){
62  IntegrationDescriptor::setup(in_cubature_degree, IntegrationDescriptor::SIDE, cell_data.side());
63  } else {
65  }
66  setup(in_cubature_degree,cell_data);
67 }
68 
70 IntegrationRule(const panzer::CellData& cell_data, const std::string & in_cv_type)
72 {
73  // Cubature orders are only used for indexing so we make them large enough not to interfere with other rules.
74  // TODO: This requirement (on arbitrary cubature order) will be dropped with the new Workset design (using descriptors to find integration rules)
75  // TODO: These isSide conditions shouldn't be required... I'm missing something...
76  if(in_cv_type == "volume"){
77  if(cell_data.isSide()){
79  } else {
81  }
82  } else if(in_cv_type == "side"){
83  if(cell_data.isSide()){
85  } else {
87  }
88  } else if(in_cv_type == "boundary"){
89  if(cell_data.isSide()){
91  } else {
93  }
94  } else {
95  TEUCHOS_ASSERT(false);
96  }
97  setup_cv(cell_data,in_cv_type);
98 }
99 
102  const Teuchos::RCP<const shards::CellTopology> & cell_topology,
103  const int num_cells,
104  const int num_faces)
105  : PointRule(), IntegrationDescriptor(description)
106 {
107 
108  TEUCHOS_ASSERT(description.getType() != panzer::IntegrationDescriptor::NONE);
109 
110  cubature_degree = description.getOrder();
111  cv_type = "none";
112 
113  panzer::CellData cell_data;
114  if(isSide()){
115  cell_data = panzer::CellData(num_cells, getSide(), cell_topology);
116  } else {
117  cell_data = panzer::CellData(num_cells, cell_topology);
118  }
119 
121  setup(getOrder(), cell_data);
122  } else if(description.getType() == panzer::IntegrationDescriptor::SIDE){
123  setup(getOrder(), cell_data);
124  } else if(description.getType() == panzer::IntegrationDescriptor::SURFACE){
125  TEUCHOS_ASSERT(num_faces!=-1);
126  setup_surface(cell_topology, num_cells, num_faces);
127  } else if(description.getType() == panzer::IntegrationDescriptor::CV_VOLUME){
128  setup_cv(cell_data, "volume");
129  } else if(description.getType() == panzer::IntegrationDescriptor::CV_SIDE){
130  setup_cv(cell_data, "side");
131  } else if(description.getType() == panzer::IntegrationDescriptor::CV_BOUNDARY){
132  setup_cv(cell_data, "boundary");
133  } else {
134  TEUCHOS_ASSERT(false);
135  }
136 
137 }
138 
139 void panzer::IntegrationRule::setup(int in_cubature_degree, const panzer::CellData& cell_data)
140 {
141  cubature_degree = in_cubature_degree;
142  cv_type = "none";
143  int spatialDimension = cell_data.baseCellDimension();
144 
145  std::stringstream ss;
146  ss << "CubaturePoints (Degree=" << cubature_degree;
147 
148  // Intrepid2 does not support a quadrature on a 0-dimensional object
149  // (which doesn't make much sense anyway) to work around this we
150  // will adjust the integration rule manually
151  if(cell_data.isSide() && spatialDimension==1) {
152  ss << ",side)";
153  PointRule::setup(ss.str(),1,cell_data);
154 
155  return;
156  }
157 
158  const shards::CellTopology & topo = *cell_data.getCellTopology();
159  Teuchos::RCP<shards::CellTopology> sideTopo = getSideTopology(cell_data);
160 
161  Intrepid2::DefaultCubatureFactory cubature_factory;
162  Teuchos::RCP<Intrepid2::Cubature<PHX::Device::execution_space,double,double>> intrepid_cubature;
163 
164  // get side topology
165  if (Teuchos::is_null(sideTopo)) {
166  ss << ",volume)";
167  intrepid_cubature = cubature_factory.create<PHX::Device::execution_space,double,double>(topo, cubature_degree);
168  }
169  else {
170  ss << ",side)";
171  intrepid_cubature = cubature_factory.create<PHX::Device::execution_space,double,double>(*sideTopo, cubature_degree);
172  }
173 
174  PointRule::setup(ss.str(),intrepid_cubature->getNumPoints(),cell_data);
175 }
176 
177 void panzer::IntegrationRule::setup_surface(const Teuchos::RCP<const shards::CellTopology> & cell_topology, const int num_cells, const int num_faces)
178 {
179 
180  const int cell_dim = cell_topology->getDimension();
181  const int subcell_dim = cell_dim-1;
182  const int num_faces_per_cell = cell_topology->getSubcellCount(subcell_dim);
183 
184  panzer::CellData cell_data(num_cells, cell_topology);
185 
186  std::string point_rule_name;
187  {
188  std::stringstream ss;
189  ss << "CubaturePoints (Degree=" << getOrder() << ",surface)";
190  point_rule_name = ss.str();
191  }
192 
193  // We can skip some steps for 1D
194  if(cell_dim == 1){
195  const int num_points_per_cell = num_faces_per_cell;
196  const int num_points_per_face = 1;
197  PointRule::setup(point_rule_name, num_cells, num_points_per_cell, num_faces, num_points_per_face, cell_topology);
198  _point_offsets.resize(3,0);
199  _point_offsets[0] = 0;
200  _point_offsets[1] = num_points_per_face;
201  _point_offsets[2] = _point_offsets[1]+num_points_per_face;
202  return;
203  }
204 
205  Intrepid2::DefaultCubatureFactory cubature_factory;
206 
207  _point_offsets.resize(num_faces_per_cell+1,0);
208  int test_face_size = -1;
209  for(int subcell_index=0; subcell_index<num_faces_per_cell; ++subcell_index){
210  Teuchos::RCP<shards::CellTopology> face_topology = Teuchos::rcp(new shards::CellTopology(cell_topology->getCellTopologyData(subcell_dim,subcell_index)));
211  const auto & intrepid_cubature = cubature_factory.create<PHX::Device::execution_space,double,double>(*face_topology, getOrder());
212  const int num_face_points = intrepid_cubature->getNumPoints();
213  _point_offsets[subcell_index+1] = _point_offsets[subcell_index] + num_face_points;
214 
215  // Right now we only support each face having the same number of points
216  if(test_face_size==-1){
217  test_face_size = num_face_points;
218  } else {
219  TEUCHOS_ASSERT(num_face_points == test_face_size);
220  }
221  }
222 
223  const int num_points_per_cell = _point_offsets.back();
224  const int num_points_per_face = _point_offsets[1];
225 
226  PointRule::setup(point_rule_name, num_cells, num_points_per_cell, num_faces, num_points_per_face, cell_topology);
227 
228 }
229 
230 void panzer::IntegrationRule::setup_cv(const panzer::CellData& cell_data, std::string in_cv_type)
231 {
232  // set cubature degree to arbitrary constant for indexing
233  cubature_degree = 1;
234  cv_type = in_cv_type;
235  if (cv_type == "volume") {
236  cubature_degree = 75;
237  }
238  if (cv_type == "side") {
239  cubature_degree = 85;
240  }
241  if (cv_type == "boundary") {
242  cubature_degree = 95;
243  }
244 
245  //int spatialDimension = cell_data.baseCellDimension();
246 
247  std::stringstream ss;
248  ss << "CubaturePoints ControlVol (Index=" << cubature_degree;
249 
250  const shards::CellTopology & topo = *cell_data.getCellTopology();
251 
252  Teuchos::RCP<Intrepid2::Cubature<PHX::Device::execution_space,double,double> > intrepid_cubature;
253 
254  int tmp_num_points = 0;
255  if (cv_type == "volume") {
256  ss << ",volume)";
257  intrepid_cubature = Teuchos::rcp(new Intrepid2::CubatureControlVolume<PHX::Device::execution_space,double,double>(topo));
258  tmp_num_points = intrepid_cubature->getNumPoints();
259  }
260  else if (cv_type == "side") {
261  ss << ",side)";
262  intrepid_cubature = Teuchos::rcp(new Intrepid2::CubatureControlVolumeSide<PHX::Device::execution_space,double,double>(topo));
263  tmp_num_points = intrepid_cubature->getNumPoints();
264  }
265  else if (cv_type == "boundary") {
266  ss << ",boundary)";
267  intrepid_cubature = Teuchos::rcp(new Intrepid2::CubatureControlVolumeBoundary<PHX::Device::execution_space,double,double>(topo,cell_data.side()));
268  tmp_num_points = intrepid_cubature->getNumPoints();
269  }
270 
271  PointRule::setup(ss.str(),tmp_num_points,cell_data);
272 }
273 
275 { return cubature_degree; }
276 
277 
278 int panzer::IntegrationRule::getPointOffset(const int subcell_index) const
279 {
280  // Need to make sure this is a surface integrator
281  TEUCHOS_ASSERT(getType() == SURFACE);
282  return _point_offsets[subcell_index];
283 }
284 
285 
286 void panzer::IntegrationRule::print(std::ostream & os)
287 {
288  os << "IntegrationRule ( "
289  << "Name = " << getName()
290  << ", Degree = " << cubature_degree
291  << ", Dimension = " << spatial_dimension
292  << ", Workset Size = " << workset_size
293  << ", Num Points = " << num_points
294  << ", Side = " << side
295  << " )";
296 }
297 
298 void panzer::IntegrationRule::referenceCoordinates(Kokkos::DynRankView<double,PHX::Device> & cub_points)
299 {
300  // build an interpid cubature rule
301  Teuchos::RCP< Intrepid2::Cubature<PHX::Device::execution_space,double,double> > intrepid_cubature;
302  Intrepid2::DefaultCubatureFactory cubature_factory;
303 
304  if (!isSide())
305  intrepid_cubature = cubature_factory.create<PHX::Device::execution_space,double,double>(*(topology),cubature_degree);
306  else
307  intrepid_cubature = cubature_factory.create<PHX::Device::execution_space,double,double>(*(side_topology),cubature_degree);
308 
309  int num_ip = intrepid_cubature->getNumPoints();
310  Kokkos::DynRankView<double,PHX::Device> cub_weights("cub_weights",num_ip);
311 
312  // now compute weights (and throw them out) as well as reference points
313  if (!isSide()) {
314  cub_points = Kokkos::DynRankView<double,PHX::Device>("cub_points", num_ip, topology->getDimension());
315  intrepid_cubature->getCubature(cub_points, cub_weights);
316  }
317  else {
318  cub_points = Kokkos::DynRankView<double,PHX::Device>("cub_points", num_ip, side_topology->getDimension());
319  intrepid_cubature->getCubature(cub_points, cub_weights);
320  }
321 }
Data for determining cell topology and dimensionality.
int baseCellDimension() const
Dimension of the base cell. NOT the dimension of the local side, even if the side() method returns tr...
bool isSide() const
Teuchos::RCP< const shards::CellTopology > getCellTopology() const
Get CellTopology for the base cell.
const int & getType() const
Get type of integrator.
@ VOLUME
No integral specified - default state.
@ CV_VOLUME
Integral over a specific side of cells (side must be set)
@ CV_BOUNDARY
Control volume side integral.
@ SIDE
Integral over all sides of cells (closed surface integral)
const int & getOrder() const
Get order of integrator.
void setup(const int cubature_order, const int integration_type, const int side=-1)
Setup function.
const int & getSide() const
Get side associated with integration - this is for backward compatibility.
IntegrationRule(int cubature_degree, const panzer::CellData &cell_data)
if side = -1 then we use the cell volume integration rule.
void setup_cv(const panzer::CellData &cell_data, std::string cv_type)
int getPointOffset(const int subcell_index) const
Returns the integration point offset for a given subcell_index (i.e. local face index)
void setup_surface(const Teuchos::RCP< const shards::CellTopology > &cell_topology, const int num_cells, const int num_faces)
Setup a surface integration.
virtual void print(std::ostream &os)
print information about the integration rule
void setup(int cubature_degree, const panzer::CellData &cell_data)
void referenceCoordinates(Kokkos::DynRankView< double, PHX::Device > &container)
Construct an array containing the reference coordinates.
int order() const
Returns the order of integration (cubature degree in intrepid lingo)
void setup(const std::string &ptName, int np, const panzer::CellData &cell_data)