Nalu
Nalu: a generalized unstructured massively parallel low Mach flow code designed to support a variety of energy applications of interest (most notably Wind ECP) built on the Sierra Toolkit and Trilinos solver Tpetra/Epetra stack. The open source BSD, clause 3 license model has been chosen for the code base. See LICENSE for more information. http://NaluCFD.org
LinInterp.h
Go to the documentation of this file.
1 /*------------------------------------------------------------------------*/
2 /* Copyright 2014 Sandia Corporation. */
3 /* This software is released under the license detailed */
4 /* in the file, LICENSE, which is located in the top-level Nalu */
5 /* directory structure */
6 /*------------------------------------------------------------------------*/
7 
8 
9 #ifndef LinInterp_h
10 #define LinInterp_h
11 
12 
13 #include <string>
14 #include <vector>
15 #include <utility>
16 
17 #include <stk_mesh/base/Entity.hpp>
18 
19 #include <Realm.h>
21 
22 namespace sierra{
23 namespace nalu{
24 
25 template <class FROM, class TO> class LinInterp {
26 
27 public :
28 
29  typedef FROM MeshA;
30  typedef TO MeshB;
31  typedef typename MeshA::EntityKey EntityKeyA;
32  typedef typename MeshB::EntityKey EntityKeyB;
33  typedef typename MeshA::EntityProc EntityProcA;
34  typedef typename MeshB::EntityProc EntityProcB;
35 
36  typedef std::pair<EntityProcB, EntityProcA> EntityProcRelation;
37  typedef std::vector<EntityProcRelation> EntityProcRelationVec;
38 
39  typedef std::multimap<EntityKeyB, EntityKeyA> EntityKeyMap;
40 
41  enum { Dimension = MeshA::Dimension };
42 
43  static void filter_to_nearest(EntityKeyMap &RangeToDomain,
44  const MeshA &FromElem,
45  MeshB &ToPoints) ;
46 
47  static void apply (MeshB &ToPoints,
48  const MeshA &FromElem,
49  const EntityKeyMap &RangeToDomain) ;
50 };
51 
52 template <class FROM, class TO> void LinInterp<FROM,TO>::filter_to_nearest (
53  EntityKeyMap &RangeToDomain,
54  const MeshA &FromElem,
55  MeshB &ToPoints) {
56 
57  const stk::mesh::BulkData &fromBulkData = FromElem.fromBulkData_;
58  stk::mesh::BulkData &toBulkData = ToPoints.toBulkData_;
59 
60  const VectorFieldType *fromcoordinates = FromElem.fromcoordinates_;
61  const VectorFieldType *tocoordinates = ToPoints.tocoordinates_;
62 
63  // FixMe: Check nDim against Dimension to make sure they are equal
64  const unsigned nDim = FromElem.fromMetaData_.spatial_dimension();
65 
66  typedef typename EntityKeyMap::iterator iterator;
67  typedef typename EntityKeyMap::const_iterator const_iterator;
68 
69  // some simple user diagnostics to let the user know if something bad is happening
70  double maxBestX = -std::numeric_limits<double>::max();
71  size_t maxCandidateBoundingBox = 0;
72 
73  for (const_iterator current_key=RangeToDomain.begin(); current_key!=RangeToDomain.end(); ) {
74 
75  double bestX_ = std::numeric_limits<double>::max();
76 
77  const stk::mesh::EntityKey thePt = current_key->first;
78  stk::mesh::Entity theNode = toBulkData.get_entity(thePt);
79  // load nodal coordinates from node
80  const double * tocoords = stk::mesh::field_data(*tocoordinates, theNode );
81 
82  std::pair<iterator, iterator> keys=RangeToDomain.equal_range(current_key->first);
83  iterator nearest = keys.second;
84 
85  size_t candidateBoundingBoxSize = 0;
86  for (iterator ii=keys.first; ii != keys.second; ++ii) {
87  candidateBoundingBoxSize++;
88 
89  const stk::mesh::EntityKey theBox = ii->second;
90  stk::mesh::Entity theElem = fromBulkData.get_entity(theBox);
91 
92  // extract master element from the bucket in which the element resides
93  const stk::mesh::Bucket &theBucket = fromBulkData.bucket(theElem);
94  const stk::topology &theElemTopo = theBucket.topology();
96 
97  // load nodal coordinates from element
98  stk::mesh::Entity const* elem_node_rels = fromBulkData.begin_nodes(theElem);
99  const int num_nodes = fromBulkData.num_nodes(theElem);
100 
101  const int nodesPerElement = meSCS->nodesPerElement_;
102  std::vector<double> theElementCoords(nDim*nodesPerElement);
103 
104  for ( int ni = 0; ni < num_nodes; ++ni ) {
105  stk::mesh::Entity node = elem_node_rels[ni];
106 
107  // load up vectors
108  const double * fromcoords = stk::mesh::field_data(*fromcoordinates, node );
109  for ( unsigned j = 0; j < nDim; ++j ) {
110  const int offSet = j*nodesPerElement + ni;
111  theElementCoords[offSet] = fromcoords[j];
112  }
113  }
114 
115  std::vector<double> isoParCoords(nDim);
116  const double nearestDistance = meSCS->isInElement(&theElementCoords[0],
117  &(tocoords[0]),
118  &(isoParCoords[0]));
119  if ( nearestDistance < bestX_ ) {
120  bestX_ = nearestDistance;
121  ToPoints.TransferInfo_[thePt] = isoParCoords;
122  nearest = ii;
123  maxBestX = std::max(maxBestX, bestX_);
124  }
125  }
126  maxCandidateBoundingBox = std::max(maxCandidateBoundingBox, candidateBoundingBoxSize);
127 
128  current_key = keys.second;
129  if (nearest != keys.first ) RangeToDomain.erase(keys.first, nearest);
130  if (nearest != keys.second) RangeToDomain.erase(++nearest, keys.second);
131  }
132 
133  // parallel sum and output diagnostics
134  double g_maxBestX = 0.0;
135  size_t g_maxCandidateBoundngBox = 0;
136  stk::all_reduce_max(FromElem.comm(), &maxBestX, &g_maxBestX, 1);
137  stk::all_reduce_max(FromElem.comm(), &maxCandidateBoundingBox, &g_maxCandidateBoundngBox, 1);
138 
139  NaluEnv::self().naluOutputP0() << std::endl;
140  NaluEnv::self().naluOutputP0() << "XFER::LinInterp::fine_search() Overview:" << std::endl;
141  NaluEnv::self().naluOutputP0() << " Maximum normalized distance found is: " << g_maxBestX << " (should be unity or less)" << std::endl;
142  NaluEnv::self().naluOutputP0() << " Maximum number of candidate bounding boxes found for a single point is: " << g_maxCandidateBoundngBox << std::endl;
143  NaluEnv::self().naluOutputP0() << " Should max normalized distance and/or candidate bounding box size be too large, please check setup" << std::endl;
144  }
145 
146 template <class FROM, class TO> void LinInterp<FROM,TO>::apply
147  (MeshB &ToPoints,
148  const MeshA &FromElem,
149  const EntityKeyMap &RangeToDomain) {
150 
151  const stk::mesh::BulkData &fromBulkData = FromElem.fromBulkData_;
152  stk::mesh::BulkData &toBulkData = ToPoints.toBulkData_;
153 
154  typename EntityKeyMap::const_iterator ii;
155  for(ii=RangeToDomain.begin(); ii!=RangeToDomain.end(); ++ii ) {
156 
157  const stk::mesh::EntityKey thePt = ii->first;
158  const stk::mesh::EntityKey theBox = ii->second;
159 
160  if (1 != ToPoints.TransferInfo_.count(thePt)) {
161  if (0 == ToPoints.TransferInfo_.count(thePt))
162  throw std::runtime_error("Key not found in database");
163  else
164  throw std::runtime_error("Too many Keys found in database");
165  }
166  const std::vector<double> &isoParCoords_ = ToPoints.TransferInfo_[thePt];
167  stk::mesh::Entity theNode = toBulkData.get_entity(thePt);
168  stk::mesh::Entity theElem = fromBulkData.get_entity(theBox);
169 
170  const stk::mesh::Bucket &theBucket = fromBulkData.bucket(theElem);
171  const stk::topology &theElemTopo = theBucket.topology();
173 
174  stk::mesh::Entity const* elem_node_rels = fromBulkData.begin_nodes(theElem);
175  const int num_nodes = fromBulkData.num_nodes(theElem);
176  const int nodesPerElement = meSCS->nodesPerElement_;
177 
178  for (unsigned n=0; n!=FromElem.fromFieldVec_.size(); ++n) {
179 
180  // extract field
181  const stk::mesh::FieldBase *toFieldBaseField = ToPoints.toFieldVec_[n];
182 
183  // FixMe: integers are problematic for now...
184  const size_t sizeOfField = field_bytes_per_entity(*toFieldBaseField, theNode) / sizeof(double);
185  std::vector <double > Coeff(nodesPerElement*sizeOfField);
186 
187  // now load the elemental values for future interpolation; fill in connected nodes
188  for ( int ni = 0; ni < num_nodes; ++ni ) {
189  stk::mesh::Entity node = elem_node_rels[ni];
190 
191  const stk::mesh::FieldBase *fromFieldBaseField = FromElem.fromFieldVec_[n];
192  const double *theField = (double*)stk::mesh::field_data(*fromFieldBaseField, node );
193 
194  for ( size_t j = 0; j < sizeOfField; ++j) {
195  const int offSet = j*nodesPerElement + ni;
196  Coeff[offSet] = theField[j];
197  }
198  }
199 
200  double * toField = (double*)stk::mesh::field_data(*toFieldBaseField, theNode);
201  if (!toField) throw std::runtime_error("Receiving field undefined on mesh object.");
202  meSCS->interpolatePoint(sizeOfField,
203  &isoParCoords_[0],
204  &Coeff[0],
205  toField);
206  }
207  }
208 }
209 
210 } // namespace nalu
211 } // namespace Sierra
212 
213 #endif
virtual void interpolatePoint(const int &nComp, const double *isoParCoord, const double *field, double *result)
Definition: MasterElement.h:202
Definition: ABLForcingAlgorithm.C:26
Definition: MasterElement.h:53
FROM MeshA
Definition: LinInterp.h:29
MeshB::EntityProc EntityProcB
Definition: LinInterp.h:34
static MasterElement * get_surface_master_element(const stk::topology &theTopo, int dimension=0, std::string quadType="GaussLegendre")
Definition: MasterElementFactory.C:208
int nodesPerElement_
Definition: MasterElement.h:246
static void apply(MeshB &ToPoints, const MeshA &FromElem, const EntityKeyMap &RangeToDomain)
Definition: LinInterp.h:147
virtual double isInElement(const double *elemNodalCoord, const double *pointCoord, double *isoParCoord)
Definition: MasterElement.h:195
stk::mesh::Field< double, stk::mesh::Cartesian > VectorFieldType
Definition: FieldTypeDef.h:24
TO MeshB
Definition: LinInterp.h:30
std::vector< EntityProcRelation > EntityProcRelationVec
Definition: LinInterp.h:37
MeshB::EntityKey EntityKeyB
Definition: LinInterp.h:32
std::pair< EntityProcB, EntityProcA > EntityProcRelation
Definition: LinInterp.h:36
static NaluEnv & self()
Definition: NaluEnv.C:48
Definition: LinInterp.h:25
MeshA::EntityKey EntityKeyA
Definition: LinInterp.h:31
MeshA::EntityProc EntityProcA
Definition: LinInterp.h:33
Definition: LinInterp.h:41
std::multimap< EntityKeyB, EntityKeyA > EntityKeyMap
Definition: LinInterp.h:39
std::ostream & naluOutputP0()
Definition: NaluEnv.C:58
static void filter_to_nearest(EntityKeyMap &RangeToDomain, const MeshA &FromElem, MeshB &ToPoints)
Definition: LinInterp.h:52