interpolate_2nd_order.h
Go to the documentation of this file.
1 /*
2 This file is part of the Ristra portage project.
3 Please see the license file at the root of this repository, or at:
4  https://github.com/laristra/portage/blob/master/LICENSE
5 */
6 
7 #ifndef PORTAGE_INTERPOLATE_INTERPOLATE_2ND_ORDER_H_
8 #define PORTAGE_INTERPOLATE_INTERPOLATE_2ND_ORDER_H_
9 
10 #include <cassert>
11 #include <stdexcept>
12 #include <algorithm>
13 #include <string>
14 #include <iostream>
15 #include <utility>
16 #include <vector>
17 
22 #include "portage/driver/parts.h"
23 
24 #include "wonton/support/CoordinateSystem.h"
25 
26 #ifdef HAVE_TANGRAM
27  #include "tangram/driver/driver.h"
28  #include "tangram/driver/CellMatPoly.h"
29  #include "tangram/support/MatPoly.h"
30 #endif
31 
32 namespace Portage {
33 
58  template<
59  int D, Entity_kind on_what,
60  typename SourceMeshType,
61  typename TargetMeshType,
62  typename SourceStateType,
63  typename TargetStateType,
64  typename T,
65  template<class, int, class, class>
66  class InterfaceReconstructorType = DummyInterfaceReconstructor,
67  class Matpoly_Splitter = void, class Matpoly_Clipper = void,
68  class CoordSys = Wonton::DefaultCoordSys
69  >
71 
72 #ifdef HAVE_TANGRAM
73  using InterfaceReconstructor =
74  Tangram::Driver<
75  InterfaceReconstructorType, D, SourceMeshType,
76  Matpoly_Splitter, Matpoly_Clipper
77  >;
78 #endif
79 
80  public:
81 
89  Interpolate_2ndOrder(SourceMeshType const& source_mesh,
90  TargetMeshType const& target_mesh,
91  SourceStateType const& source_state,
92  NumericTolerances_t num_tols)
93  : source_mesh_(source_mesh),
94  target_mesh_(target_mesh),
95  source_state_(source_state),
96  variable_name_("VariableNameNotSet"),
97  source_values_(nullptr),
98  num_tols_(num_tols) { CoordSys::template verify_coordinate_system<D>(); }
99 
100 #ifdef HAVE_TANGRAM
101 
110  Interpolate_2ndOrder(SourceMeshType const& source_mesh,
111  TargetMeshType const& target_mesh,
112  SourceStateType const& source_state,
113  NumericTolerances_t num_tols,
114  std::shared_ptr<InterfaceReconstructor> ir)
115  : source_mesh_(source_mesh),
116  target_mesh_(target_mesh),
117  source_state_(source_state),
118  variable_name_("VariableNameNotSet"),
119  source_values_(nullptr),
120  num_tols_(num_tols),
121  interface_reconstructor_(ir) { CoordSys::template verify_coordinate_system<D>(); }
122 #endif
123 
130  Interpolate_2ndOrder& operator = (const Interpolate_2ndOrder& other) = delete;
131 
132 
137  ~Interpolate_2ndOrder() = default;
138 
144  void set_material(int m) { material_id_ = m; }
145 
146 
153  void set_interpolation_variable(std::string const& variable_name,
154  const Portage::vector<Vector<D>>* gradient_field = nullptr) {
155  std::cerr << "Interpolation is available for only cells and nodes";
156  std::cerr << std::endl;
157  }
158 
174  double operator()(int const targetCellID,
175  std::vector<Weights_t> const& sources_and_weights) const {
176 
177  // not implemented for all types - see specialization for cells and nodes
178  std::cerr << "Error: interpolation operator not implemented for this entity type";
179  std::cerr << std::endl;
180  return 0.;
181  }
182 
183  constexpr static int order = 2;
184 
185  private:
186  SourceMeshType const& source_mesh_;
187  TargetMeshType const& target_mesh_;
188  SourceStateType const& source_state_;
189  std::string variable_name_ = "";
190  T const* source_values_;
191  NumericTolerances_t num_tols_;
192  int material_id_ = 0;
193  Portage::vector<Wonton::Vector<D>> const* gradients_;
194  Field_type field_type_ = Field_type::UNKNOWN_TYPE_FIELD;
195 #ifdef HAVE_TANGRAM
196  std::shared_ptr<InterfaceReconstructor> interface_reconstructor_;
197 #endif
198  };
199 
200  /* ------------------------------------------------------------------------ */
201 
215  template<
216  int D,
217  typename SourceMeshType,
218  typename TargetMeshType,
219  typename SourceStateType,
220  typename TargetStateType,
221  template<class, int, class, class>
222  class InterfaceReconstructorType,
223  class Matpoly_Splitter, class Matpoly_Clipper, class CoordSys
224  >
226  D, Entity_kind::CELL,
227  SourceMeshType, TargetMeshType,
228  SourceStateType, TargetStateType,
229  double,
230  InterfaceReconstructorType,
231  Matpoly_Splitter, Matpoly_Clipper, CoordSys> {
232 
233  // useful aliases
234  using Parts = PartPair<
235  D, SourceMeshType, SourceStateType,
236  TargetMeshType, TargetStateType
237  >;
238 
239  using Gradient = Limited_Gradient<
240  D, Entity_kind::CELL,
241  SourceMeshType, SourceStateType,
242  InterfaceReconstructorType,
243  Matpoly_Splitter, Matpoly_Clipper, CoordSys
244  >;
245 
246 #ifdef HAVE_TANGRAM
247  using InterfaceReconstructor = Tangram::Driver<
248  InterfaceReconstructorType, D, SourceMeshType,
249  Matpoly_Splitter, Matpoly_Clipper
250  >;
251 #endif
252 
253  public:
262  Interpolate_2ndOrder(SourceMeshType const& source_mesh,
263  TargetMeshType const& target_mesh,
264  SourceStateType const& source_state,
265  NumericTolerances_t num_tols,
266  const Parts* const parts = nullptr)
267  : source_mesh_(source_mesh),
268  target_mesh_(target_mesh),
269  source_state_(source_state),
270  variable_name_("VariableNameNotSet"),
271  source_values_(nullptr),
272  num_tols_(num_tols),
273  parts_(parts) { CoordSys::template verify_coordinate_system<D>(); }
274 
275 #ifdef HAVE_TANGRAM
276 
285  Interpolate_2ndOrder(SourceMeshType const& source_mesh,
286  TargetMeshType const& target_mesh,
287  SourceStateType const& source_state,
288  NumericTolerances_t num_tols,
289  std::shared_ptr<InterfaceReconstructor> ir,
290  const Parts* const parts = nullptr)
291  : source_mesh_(source_mesh),
292  target_mesh_(target_mesh),
293  source_state_(source_state),
294  variable_name_("VariableNameNotSet"),
295  source_values_(nullptr),
296  num_tols_(num_tols),
297  interface_reconstructor_(ir),
298  parts_(parts) { CoordSys::template verify_coordinate_system<D>(); }
299 #endif
300 
307  Interpolate_2ndOrder &operator=(const Interpolate_2ndOrder &) = delete;
308 
313  ~Interpolate_2ndOrder() = default;
314 
320  void set_material(int m) { material_id_ = m; }
321 
322 
329  void set_interpolation_variable(std::string const& variable_name,
330  const Portage::vector<Vector<D>>* gradient_field = nullptr) {
331 
332  variable_name_ = variable_name;
333  gradients_ = gradient_field;
334  field_type_ = source_state_.field_type(Entity_kind::CELL, variable_name);
335 
336  if (field_type_ == Field_type::MESH_FIELD) {
337  source_state_.mesh_get_data(Entity_kind::CELL, variable_name, &source_values_);
338  } else {
339  source_state_.mat_get_celldata(variable_name, material_id_, &source_values_);
340  }
341  }
342 
343 
359  double operator()(int cell_id,
360  std::vector<Weights_t> const& sources_and_weights) const {
361 
362  if (sources_and_weights.empty())
363  return 0.;
364 
365  auto const& gradient_field = *gradients_;
366  double total_value = 0.;
367  double normalization = 0.;
368 
369  /*
370  * contribution of the source cell is its field value weighted by
371  * its "weight" (in this case, its 0th moment/area/volume).
372  */
373  int nb_summed = 0;
374 
375  // Loop over source cells
376  for (auto&& current : sources_and_weights) {
377  // Get source cell and the intersection weights
378  int src_cell = current.entityID;
379  auto intersect_weights = current.weights;
380  double intersect_volume = intersect_weights[0];
381 
382  if (fabs(intersect_volume) <= num_tols_.min_absolute_volume)
383  continue; // no intersection
384 
385  // Obtain source cell centroid
386  Point<D> source_centroid;
387  if (field_type_ == Field_type::MESH_FIELD) {
388  source_mesh_.cell_centroid(src_cell, &source_centroid);
389  }
390 #ifdef HAVE_TANGRAM
391  else if (field_type_ == Field_type::MULTIMATERIAL_FIELD) {
392  int const nb_mats = source_state_.cell_get_num_mats(src_cell);
393  std::vector<int> cellmats;
394  source_state_.cell_get_mats(src_cell, &cellmats);
395 
396  bool is_pure_cell =
397  (nb_mats == 0 or (nb_mats == 1 and cellmats[0] == material_id_));
398 
399  if (is_pure_cell) {
400  source_mesh_.cell_centroid(src_cell, &source_centroid);
401  } else /* multi-material cell */ {
402  assert(interface_reconstructor_ != nullptr); // must be defined
403 
404  auto pos = std::find(cellmats.begin(), cellmats.end(), material_id_);
405  bool found_material = (pos != cellmats.end());
406 
407  if (found_material) /* mixed cell contains this material */ {
408 
409  // obtain matpoly's for this material
410  auto const& cellmatpoly = interface_reconstructor_->cell_matpoly_data(src_cell);
411  auto matpolys = cellmatpoly.get_matpolys(material_id_);
412 
413  for (int k = 0; k < D; k++)
414  source_centroid[k] = 0;
415 
416  /*
417  * compute centroid of all matpoly's by summing all the
418  * first order moments first, and then dividing by the
419  * total volume of all matpolys.
420  */
421  double mvol = 0.;
422  for (auto&& poly : matpolys) {
423  auto moments = poly.moments();
424  mvol += moments[0];
425  for (int k = 0; k < D; k++)
426  source_centroid[k] += moments[k + 1];
427  }
428 
429  for (int k = 0; k < D; k++)
430  source_centroid[k] /= mvol;
431  }
432  }
433  }
434 #endif
435 
436  // compute intersection centroid
437  Point<D> intersect_centroid;
438  // first-moment / volume
439  for (int k = 0; k < D; ++k)
440  intersect_centroid[k] = intersect_weights[1 + k] / intersect_volume;
441 
442  // retrieve the correct source cell index
443  int const source_index = (field_type_ == Field_type::MULTIMATERIAL_FIELD
444  ? source_state_.cell_index_in_material(src_cell, material_id_)
445  : src_cell);
446 
447  Vector<D> gradient = gradient_field[source_index];
448  Vector<D> dr = intersect_centroid - source_centroid;
449  CoordSys::modify_line_element(dr, source_centroid);
450 
451  double value = source_values_[source_index] + dot(gradient, dr);
452  value *= intersect_volume;
453  total_value += value;
454  normalization += intersect_volume;
455  nb_summed++;
456  }
457 
458  /*
459  * Normalize the value by the volume of the intersection of the target cells
460  * with the source mesh. This will do the right thing for single-material
461  * and multi-material remap (conservative and constant preserving) if there
462  * is NO mismatch between source and target mesh boundaries. IF THERE IS A
463  * MISMATCH, THIS WILL PRESERVE CONSTANT VALUES BUT NOT BE CONSERVATIVE.
464  * THEN WE HAVE TO DO A SEMI-LOCAL OR GLOBAL REPAIR.
465  */
466  return nb_summed ? total_value / normalization : 0.;
467  }
468 
469  constexpr static int order = 2;
470 
471  private:
472  SourceMeshType const& source_mesh_;
473  TargetMeshType const& target_mesh_;
474  SourceStateType const& source_state_;
475  std::string variable_name_;
476  double const* source_values_;
477  NumericTolerances_t num_tols_;
478  int material_id_ = 0;
479  Portage::vector<Wonton::Vector<D>> const* gradients_;
480  Field_type field_type_ = Field_type::UNKNOWN_TYPE_FIELD;
481 #ifdef HAVE_TANGRAM
482  std::shared_ptr<InterfaceReconstructor> interface_reconstructor_;
483 #endif
484  Parts const* parts_;
485  };
486 
487  /* ------------------------------------------------------------------------ */
488 
501  template<
502  int D,
503  typename SourceMeshType,
504  typename TargetMeshType,
505  typename SourceStateType,
506  typename TargetStateType,
507  template<class, int, class, class>
508  class InterfaceReconstructorType,
509  class Matpoly_Splitter, class Matpoly_Clipper, class CoordSys
510  >
512  D, Entity_kind::NODE,
513  SourceMeshType, TargetMeshType,
514  SourceStateType, TargetStateType,
515  double,
516  InterfaceReconstructorType,
517  Matpoly_Splitter, Matpoly_Clipper, CoordSys> {
518 
519  // useful aliases
520  using Gradient = Limited_Gradient<
521  D, Entity_kind::NODE,
522  SourceMeshType, SourceStateType,
523  InterfaceReconstructorType,
524  Matpoly_Splitter, Matpoly_Clipper, CoordSys
525  >;
526 
527 #ifdef HAVE_TANGRAM
528  using InterfaceReconstructor = Tangram::Driver<
529  InterfaceReconstructorType, D, SourceMeshType,
530  Matpoly_Splitter, Matpoly_Clipper
531  >;
532 #endif
533 
534  // get rid of long namespaces
535  static auto const Node = Entity_kind::NODE;
536 
537  public:
538 
547  Interpolate_2ndOrder(SourceMeshType const& source_mesh,
548  TargetMeshType const& target_mesh,
549  SourceStateType const& source_state,
550  NumericTolerances_t num_tols) :
551  source_mesh_(source_mesh),
552  target_mesh_(target_mesh),
553  source_state_(source_state),
554  variable_name_("VariableNameNotSet"),
555  source_values_(nullptr),
556  num_tols_(num_tols) {}
557 
558 #ifdef HAVE_TANGRAM
559 
568  Interpolate_2ndOrder(SourceMeshType const& source_mesh,
569  TargetMeshType const& target_mesh,
570  SourceStateType const& source_state,
571  NumericTolerances_t num_tols,
572  std::shared_ptr<InterfaceReconstructor> ir) :
573  source_mesh_(source_mesh),
574  target_mesh_(target_mesh),
575  source_state_(source_state),
576  variable_name_("VariableNameNotSet"),
577  source_values_(nullptr),
578  num_tols_(num_tols),
579  interface_reconstructor_(ir) {}
580 #endif
581 
589 
594  ~Interpolate_2ndOrder() = default;
595 
601  void set_material(int m) { material_id_ = m; }
602 
609  void set_interpolation_variable(std::string const variable_name,
610  Portage::vector<Vector<D>>* gradient_field = nullptr) {
611 
612  variable_name_ = variable_name;
613  gradients_ = gradient_field;
614 
615  // Extract the field data from the statemanager
616  field_type_ = source_state_.field_type(Entity_kind::NODE, variable_name);
617 
618  if (field_type_ == Field_type::MESH_FIELD) {
619  source_state_.mesh_get_data(Entity_kind::NODE, variable_name, &source_values_);
620  } else {
621  std::cerr << "Sorry: cannot remap node-centered multi-material data.";
622  std::cerr << std::endl;
623  return;
624  }
625  }
626 
627 
643  double operator()(int node_id,
644  std::vector<Weights_t> const& sources_and_weights) const {
645 
646  if (sources_and_weights.empty())
647  return 0.;
648 
649  auto const& gradient_field = *gradients_;
650  double total_value = 0.;
651  double normalization = 0.;
652 
653  // contribution of the source cell is its field value weighted by
654  // its "weight" (in this case, its 0th moment/area/volume)
655  int nb_summed = 0;
656 
657  for (auto&& current : sources_and_weights) {
658  int src_node = current.entityID;
659  auto intersect_weights = current.weights;
660  double intersect_volume = intersect_weights[0];
661 
662  if (fabs(intersect_volume) <= num_tols_.min_absolute_volume)
663  continue; // no intersection
664 
665  // note: here we are getting the node coord, not the centroid of
666  // the dual cell
667  Point<D> source_coord;
668  source_mesh_.node_get_coordinates(src_node, &source_coord);
669 
670  Point<D> intersect_centroid;
671  // first-moment / volume
672  for (int k = 0; k < D; ++k)
673  intersect_centroid[k] = intersect_weights[1 + k] / intersect_volume;
674 
675  Vector<D> gradient = gradient_field[src_node];
676  Vector<D> dr = intersect_centroid - source_coord;
677  CoordSys::modify_line_element(dr, source_coord);
678 
679  double value = source_values_[src_node] + dot(gradient, dr);
680  value *= intersect_volume;
681  total_value += value;
682  normalization += intersect_volume;
683  nb_summed++;
684  }
685 
686  /*
687  * Normalize the value by volume of the target dual cell.
688  *
689  * Normalize the value by the volume of the intersection of the target cells
690  * with the source mesh. This will do the right thing for single-material
691  * and multi-material remap (conservative and constant preserving) if there
692  * is NO mismatch between source and target mesh boundaries. IF THERE IS A
693  * MISMATCH, THIS WILL PRESERVE CONSTANT VALUES BUT NOT BE CONSERVATIVE.
694  * THEN WE HAVE TO DO A SEMI-LOCAL OR GLOBAL REPAIR.
695  */
696  return nb_summed ? total_value / normalization : 0.;
697  }
698 
699  constexpr static int order = 2;
700 
701  private:
702  SourceMeshType const& source_mesh_;
703  TargetMeshType const& target_mesh_;
704  SourceStateType const& source_state_;
705  std::string variable_name_;
706  double const* source_values_;
707  NumericTolerances_t num_tols_;
708  int material_id_ = 0;
709  Portage::vector<Vector<D>>* gradients_ = nullptr;
710  Field_type field_type_ = Field_type::UNKNOWN_TYPE_FIELD;
711 #ifdef HAVE_TANGRAM
712  std::shared_ptr<InterfaceReconstructor> interface_reconstructor_;
713 #endif
714  };
715  /* ------------------------------------------------------------------------ */
716 } // namespace Portage
717 
718 #endif // PORTAGE_INTERPOLATE_INTERPOLATE_2ND_ORDER_H_
void set_material(int m)
Set the material we are operating on.
Definition: interpolate_2nd_order.h:144
void set_interpolation_variable(std::string const variable_name, Portage::vector< Vector< D >> *gradient_field=nullptr)
Set the name of the interpolation variable and the gradient field.
Definition: interpolate_2nd_order.h:609
std::vector< T > vector
Definition: portage.h:238
Intersection and other tolerances to handle tiny values.
Definition: portage.h:152
Interpolate_2ndOrder(SourceMeshType const &source_mesh, TargetMeshType const &target_mesh, SourceStateType const &source_state, NumericTolerances_t num_tols)
Constructor without interface reconstructor.
Definition: interpolate_2nd_order.h:89
Compute limited gradient of a field or components of a field.
Definition: gradient.h:52
Interpolate_2ndOrder & operator=(const Interpolate_2ndOrder &other)=delete
Assignment operator (disabled).
Manages source and target sub-meshes for part-by-part remap.
Manages source and target sub-meshes for part-by-part remap. It detects boundaries mismatch and provi...
Definition: parts.h:234
double operator()(int cell_id, std::vector< Weights_t > const &sources_and_weights) const
Functor to compute the interpolation of cell values.
Definition: interpolate_2nd_order.h:359
double operator()(int const targetCellID, std::vector< Weights_t > const &sources_and_weights) const
Functor to do the actual interpolate calculation.
Definition: interpolate_2nd_order.h:174
Definition: coredriver.h:42
double operator()(int node_id, std::vector< Weights_t > const &sources_and_weights) const
Functor to compute the interpolation of node values.
Definition: interpolate_2nd_order.h:643
~Interpolate_2ndOrder()=default
Destructor.
void set_interpolation_variable(std::string const &variable_name, const Portage::vector< Vector< D >> *gradient_field=nullptr)
Set the name of the interpolation variable and the gradient field.
Definition: interpolate_2nd_order.h:329
static constexpr int order
Definition: interpolate_2nd_order.h:183
Interpolate_2ndOrder does a 2nd order interpolation of scalars.
Definition: interpolate_2nd_order.h:70
Interpolate_2ndOrder(SourceMeshType const &source_mesh, TargetMeshType const &target_mesh, SourceStateType const &source_state, NumericTolerances_t num_tols)
Constructor without interface reconstructor.
Definition: interpolate_2nd_order.h:547
void set_interpolation_variable(std::string const &variable_name, const Portage::vector< Vector< D >> *gradient_field=nullptr)
Set the name of the interpolation variable and the gradient field.
Definition: interpolate_2nd_order.h:153
Interpolate_2ndOrder(SourceMeshType const &source_mesh, TargetMeshType const &target_mesh, SourceStateType const &source_state, NumericTolerances_t num_tols, const Parts *const parts=nullptr)
Constructor without interface reconstructor.
Definition: interpolate_2nd_order.h:262