mmdriver.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_DRIVER_MMDRIVER_H_
8 #define PORTAGE_DRIVER_MMDRIVER_H_
9 
10 #include <algorithm>
11 #include <vector>
12 #include <iterator>
13 #include <string>
14 #include <utility>
15 #include <iostream>
16 #include <type_traits>
17 #include <memory>
18 #include <limits>
19 #include <cmath>
20 
21 #ifdef HAVE_TANGRAM
22  #include "tangram/driver/driver.h"
23 #endif
24 
27 #include "portage/support/timer.h"
33 #include "wonton/mesh/flat/flat_mesh_wrapper.h"
34 #include "wonton/state/flat/flat_state_mm_wrapper.h"
35 #include "wonton/support/Point.h"
36 #include "wonton/state/state_vector_multi.h"
39 
40 #ifdef PORTAGE_ENABLE_MPI
42 #endif
43 
52 namespace Portage {
53 
54 using namespace Wonton;
55 
87 template <template <int, Entity_kind, class, class> class Search,
88  template <Entity_kind, class, class, class,
89  template <class, int, class, class> class,
90  class, class> class Intersect,
91  template<int, Entity_kind, class, class, class, class, class,
92  template<class, int, class, class> class,
93  class, class, class=Wonton::DefaultCoordSys
94  > class Interpolate,
95  int D,
96  class SourceMesh_Wrapper,
97  class SourceState_Wrapper,
98  class TargetMesh_Wrapper = SourceMesh_Wrapper,
99  class TargetState_Wrapper = SourceState_Wrapper,
100  template <class, int, class, class> class InterfaceReconstructorType = DummyInterfaceReconstructor,
101  class Matpoly_Splitter = void,
102  class Matpoly_Clipper = void>
103 class MMDriver {
104 
105 #ifdef HAVE_TANGRAM
106  // alias for interface reconstructor parameterized on the mesh type.
107  // it will be used for gradient field computation.
108  template<typename SourceMesh>
109  using InterfaceReconstructor = Tangram::Driver<InterfaceReconstructorType, D,
110  SourceMesh, Matpoly_Splitter,
111  Matpoly_Clipper>;
112 #endif
113 
114  public:
124  MMDriver(SourceMesh_Wrapper const& sourceMesh,
125  SourceState_Wrapper const& sourceState,
126  TargetMesh_Wrapper const& targetMesh,
127  TargetState_Wrapper& targetState)
128  : source_mesh_(sourceMesh),
129  target_mesh_(targetMesh),
130  source_state_(sourceState),
131  target_state_(targetState),
132  dim_(sourceMesh.space_dimension()) {
133  assert(sourceMesh.space_dimension() == targetMesh.space_dimension());
134  }
135 
137  MMDriver(const MMDriver &) = delete;
138 
140  MMDriver & operator = (const MMDriver &) = delete;
141 
143  ~MMDriver() = default;
144 
146  MMDriver(MMDriver &&) noexcept = default;
147 
154  void set_remap_var_names(std::vector<std::string> const &remap_var_names) {
155  // remap variable names same in source and target mesh
156  set_remap_var_names(remap_var_names, remap_var_names);
157  }
158 
168  std::vector<std::string> const & source_remap_var_names,
169  std::vector<std::string> const & target_remap_var_names) {
170 
171  assert(source_remap_var_names.size() == target_remap_var_names.size());
172 
173  // No appending allowed
174  source_target_varname_map_.clear();
175 
176  int nvars = source_remap_var_names.size();
177 #ifdef DEBUG
178  for (int i = 0; i < nvars; ++i) {
179  Entity_kind srckind = source_state_.get_entity(source_remap_var_names[i]);
180  Entity_kind trgkind = target_state_.get_entity(target_remap_var_names[i]);
181  if (trgkind == Entity_kind::UNKNOWN_KIND)
182  continue; // Presumably field does not exist on target - will get added
183 
184  assert(srckind == trgkind); // if target field exists, entity kinds must match
185  }
186 #endif
187 
188  for (int i = 0; i < nvars; i++) {
189  source_target_varname_map_[source_remap_var_names[i]] = target_remap_var_names[i];
190 
191  // Set options so that defaults will produce something reasonable
192  limiters_[source_remap_var_names[i]] = Limiter_type::BARTH_JESPERSEN;
193  bnd_limiters_[source_remap_var_names[i]] = Boundary_Limiter_type::BND_NOLIMITER;
194  partial_fixup_types_[target_remap_var_names[i]] =
196  empty_fixup_types_[target_remap_var_names[i]] =
198  }
199  }
200 
205  void set_limiter(Limiter_type limiter) {
206  for (auto const& stpair : source_target_varname_map_) {
207  std::string const& source_var_name = stpair.first;
208  limiters_[source_var_name] = limiter;
209  }
210  }
211 
218  for (auto const& stpair : source_target_varname_map_) {
219  std::string const& source_var_name = stpair.first;
220  bnd_limiters_[source_var_name] = bnd_limiter;
221  }
222  }
223 
230  void set_limiter(std::string const& source_var_name, Limiter_type limiter) {
231  limiters_[source_var_name] = limiter;
232  }
233 
241  void set_bnd_limiter(std::string const& source_var_name, Boundary_Limiter_type bnd_limiter) {
242  bnd_limiters_[source_var_name] = bnd_limiter;
243  }
244 
252  for (auto const& stpair : source_target_varname_map_) {
253  std::string const& target_var_name = stpair.second;
254  partial_fixup_types_[target_var_name] = fixup_type;
255  }
256  }
257 
265  void set_partial_fixup_type(std::string const& target_var_name,
266  Partial_fixup_type fixup_type) {
267  partial_fixup_types_[target_var_name] = fixup_type;
268  }
269 
276  for (auto const& stpair : source_target_varname_map_) {
277  std::string const& target_var_name = stpair.second;
278  empty_fixup_types_[target_var_name] = fixup_type;
279  }
280  }
281 
288  void set_empty_fixup_type(std::string const& target_var_name,
289  Empty_fixup_type fixup_type) {
290  empty_fixup_types_[target_var_name] = fixup_type;
291  }
292 
293 
294  void set_max_fixup_iter(int maxiter) {
295  max_fixup_iter_ = maxiter;
296  }
297 
299  void set_num_tols(const double min_absolute_distance,
300  const double min_absolute_volume) {
301  num_tols_.min_absolute_distance = min_absolute_distance;
302  num_tols_.min_absolute_volume = min_absolute_volume;
303  num_tols_.user_tolerances = true;
304  }
305 
307  void set_num_tols(const NumericTolerances_t& num_tols) {
308  num_tols_ = num_tols;
309  }
310 
315  template<typename T>
316  void set_remap_var_bounds(std::string target_var_name,
317  T lower_bound, T upper_bound) {
318  if (typeid(T) == typeid(double)) {
319  double_lower_bounds_[target_var_name] = lower_bound;
320  double_upper_bounds_[target_var_name] = upper_bound;
321  } else
322  std::cerr << "Type not supported \n";
323  }
324 
329  template<typename T>
330  void set_conservation_tolerance(std::string target_var_name,
331  T conservation_tol) {
332  if (typeid(T) == typeid(double))
333  conservation_tol_[target_var_name] = conservation_tol;
334  else
335  std::cerr << "Type not supported \n";
336  }
337 
338 #ifdef HAVE_TANGRAM
339 
351  void set_reconstructor_options(bool all_convex,
352  const std::vector<Tangram::IterativeMethodTolerances_t> &tols =
353  std::vector<Tangram::IterativeMethodTolerances_t>()){
354  reconstructor_tols_ = tols;
355  reconstructor_all_convex_ = all_convex;
356  }
357 
358 #endif
359 
365  std::vector<std::string> source_remap_var_names() const {
366  std::vector<std::string> source_var_names;
367  source_var_names.reserve(source_target_varname_map_.size());
368  for (auto const& stname_pair : source_target_varname_map_)
369  source_var_names.push_back(stname_pair.first);
370  return source_var_names;
371  }
372 
378  std::vector<std::string> target_remap_var_names() const {
379  std::vector<std::string> target_var_names;
380  target_var_names.reserve(source_target_varname_map_.size());
381  for (auto const& stname_pair : source_target_varname_map_)
382  target_var_names.push_back(stname_pair.second);
383  return target_var_names;
384  }
385 
390  unsigned int dim() const {
391  return dim_;
392  }
393 
394 
409  template<class SourceMesh_Wrapper2, class SourceState_Wrapper2>
410  int cell_remap(SourceMesh_Wrapper2 const & source_mesh2,
411  SourceState_Wrapper2 const & source_state2,
412  std::vector<std::string> const &src_meshvar_names,
413  std::vector<std::string> const &trg_meshvar_names,
414  std::vector<std::string> const &src_matvar_names,
415  std::vector<std::string> const &trg_matvar_names,
416  Wonton::Executor_type const *executor = nullptr);
417 
418 
431  template<class SourceMesh_Wrapper2, class SourceState_Wrapper2>
432  int node_remap(SourceMesh_Wrapper2 const & source_mesh2,
433  SourceState_Wrapper2 const & source_state2,
434  std::vector<std::string> const &src_meshvar_names,
435  std::vector<std::string> const &trg_meshvar_names,
436  Wonton::Executor_type const *executor = nullptr);
437 
438 
439 
454  template<class SourceState_Wrapper2,Entity_kind onwhat>
455  void compute_bounds(SourceState_Wrapper2 const& source_state2,
456  std::vector<std::string> const& src_meshvar_names,
457  std::vector<std::string> const& trg_meshvar_names,
458  Wonton::Executor_type const *executor = nullptr) {
459 
460 #ifdef PORTAGE_ENABLE_MPI
461  MPI_Comm mycomm = MPI_COMM_NULL;
462  auto mpiexecutor = dynamic_cast<Wonton::MPIExecutor_type const *>(executor);
463  if (mpiexecutor && mpiexecutor->mpicomm != MPI_COMM_NULL) {
464  mycomm = mpiexecutor->mpicomm;
465  }
466 #endif
467 
468  int const nvars = src_meshvar_names.size();
469 
470  // loop over mesh variables
471  for (int i = 0; i < nvars; i++) {
472 
473  auto& src_var = src_meshvar_names[i];
474  auto& trg_var = trg_meshvar_names[i];
475 
476  // See if we have caller specified bounds, if so, keep them.
477  // Otherwise, determine sensible values
478  if (not double_lower_bounds_.count(trg_var) or
479  not double_upper_bounds_.count(trg_var)) {
480 
481  // Since caller has not specified bounds for variable, attempt
482  // to derive them from source state. This code should go into
483  // Wonton into each state manager (or better yet, deprecated :-))
484 
485  int nsrcents = source_mesh_.num_entities(onwhat,
486  Entity_type::PARALLEL_OWNED);
487 
488  double const *source_data;
489  source_state_.mesh_get_data(onwhat, src_var, &source_data);
490  double lower_bound = *std::min_element(source_data, source_data + nsrcents);
491  double upper_bound = *std::max_element(source_data, source_data + nsrcents);
492 
493 #ifdef PORTAGE_ENABLE_MPI
494  if (mycomm != MPI_COMM_NULL) {
495  double global_bounds[2] = { 0.0, 0.0 };
496  MPI_Allreduce(&lower_bound, global_bounds+0, 1, MPI_DOUBLE, MPI_MIN, mycomm);
497  MPI_Allreduce(&upper_bound, global_bounds+1, 1, MPI_DOUBLE, MPI_MAX, mycomm);
498  lower_bound = global_bounds[0];
499  upper_bound = global_bounds[1];
500  }
501 #endif
502 
503  double relbounddiff = std::abs((upper_bound-lower_bound)/lower_bound);
504  if (relbounddiff < consttol_) {
505  // The field is constant over the source mesh/part. We HAVE to
506  // relax the bounds to be able to conserve the integral quantity
507  // AND maintain a constant.
508  lower_bound -= 0.5*lower_bound;
509  upper_bound += 0.5*upper_bound;
510  }
511 
512  // set the bounds on the instance variable
513  set_remap_var_bounds(trg_var, lower_bound, upper_bound);
514  }
515 
516  // see if caller has specified a tolerance for conservation
517  if (not conservation_tol_.count(trg_var)) {
518  set_conservation_tolerance(trg_var, DEFAULT_NUMERIC_TOLERANCES<D>.relative_conservation_eps);
519  }
520  }
521  } // compute_bounds
522 
523 
524 
529  int run(Wonton::Executor_type const *executor = nullptr,
530  std::string *errmsg = nullptr) {
531  std::string message;
532 
533  auto tic = timer::now();
534 
535  bool distributed = false;
536  int comm_rank = 0;
537  int nprocs = 1;
538 
539 #ifdef PORTAGE_ENABLE_MPI
540  MPI_Comm mycomm = MPI_COMM_NULL;
541  auto mpiexecutor = dynamic_cast<Wonton::MPIExecutor_type const *>(executor);
542  if (mpiexecutor && mpiexecutor->mpicomm != MPI_COMM_NULL) {
543  mycomm = mpiexecutor->mpicomm;
544  MPI_Comm_rank(mycomm, &comm_rank);
545  MPI_Comm_size(mycomm, &nprocs);
546  if (nprocs > 1)
547  distributed = true;
548  }
549 #endif
550 #ifdef ENABLE_DEBUG
551  if (comm_rank == 0)
552  std::cout << "in MMDriver::run()...\n";
553 
554  int numTargetCells = target_mesh_.num_owned_cells();
555  std::cout << "Number of target cells in target mesh on rank "
556  << comm_rank << ": "
557  << numTargetCells << std::endl;
558 #endif
559 
560  std::vector<std::string> src_meshvar_names, src_matvar_names;
561  std::vector<std::string> trg_meshvar_names, trg_matvar_names;
562 
563 
564  // -------- CELL VARIABLE REMAP ---------
565  // Collect all cell based variables and remap them
566 
567  for (auto const& stpair : source_target_varname_map_) {
568  std::string const& srcvarname = stpair.first;
569  Entity_kind onwhat = source_state_.get_entity(srcvarname);
570  if (onwhat == CELL) {
571  // Separate out mesh fields and multi-material fields - they will be
572  // processed differently
573 
574  std::string const& trgvarname = stpair.second;
575 
576  Field_type ftype = source_state_.field_type(onwhat, srcvarname);
577 
578  if (ftype == Field_type::MESH_FIELD) {
579  src_meshvar_names.push_back(srcvarname);
580  trg_meshvar_names.push_back(trgvarname);
581  } else if (ftype == Field_type::MULTIMATERIAL_FIELD) {
582  src_matvar_names.push_back(srcvarname);
583  trg_matvar_names.push_back(trgvarname);
584  }
585  }
586  }
587 
588  // ALWAYS call because we may have to remap material volume
589  // fractions and centroids which are cell-based fields
590 
591  // Default is serial run (if MPI is not enabled or the
592  // communicator is not defined or the number of processors is 1)
593 #ifdef PORTAGE_ENABLE_MPI
594  // Create a new mesh wrapper that we can use for redistribution
595  // of the source mesh as necessary (so that every target cell
596  // sees any source cell that it overlaps with)
597 
598  Flat_Mesh_Wrapper<> source_mesh_flat;
599  Flat_State_Wrapper<Flat_Mesh_Wrapper<>> source_state_flat(source_mesh_flat);
600 
601  bool redistributed_source = false;
602  if (distributed) {
603  MPI_Bounding_Boxes distributor(mpiexecutor);
604  if (distributor.is_redistribution_needed(source_mesh_, target_mesh_)) {
605  tic = timer::now();
606 
607  source_mesh_flat.initialize(source_mesh_);
608 
609  // Note the flat state should be used for everything including the
610  // centroids and volume fractions for interface reconstruction
611  std::vector<std::string> source_remap_var_names;
612  for (auto & stpair : source_target_varname_map_)
613  source_remap_var_names.push_back(stpair.first);
614  source_state_flat.initialize(source_state_, source_remap_var_names);
615 
616  distributor.distribute(source_mesh_flat, source_state_flat,
617  target_mesh_, target_state_);
618 
619  redistributed_source = true;
620 
621 #ifdef ENABLE_DEBUG
622  float tot_seconds_dist = timer::elapsed(tic);
623  std::cout << "Redistribution Time Rank " << comm_rank << " (s): " <<
624  tot_seconds_dist << std::endl;
625 #endif
626  }
627  }
628 
629  if (redistributed_source) {
630 
631  // Why is it not able to deduce the template arguments, if I don't specify
632  // Flat_Mesh_Wrapper and Flat_State_Wrapper?
633 
634  cell_remap<Flat_Mesh_Wrapper<>, Flat_State_Wrapper<Flat_Mesh_Wrapper<>>>
635  (source_mesh_flat, source_state_flat,
636  src_meshvar_names, trg_meshvar_names,
637  src_matvar_names, trg_matvar_names,
638  executor);
639  }
640  else
641 #endif
642  {
643  // Why is it not able to deduce the template arguments, if I don't specify
644  // Source_Mesh_Wrapper and Source_State_Wrapper?
645 
646  cell_remap<SourceMesh_Wrapper, SourceState_Wrapper>
647  (source_mesh_, source_state_,
648  src_meshvar_names, trg_meshvar_names,
649  src_matvar_names, trg_matvar_names,
650  executor);
651  }
652 
653 
654 
655  // -------- NODE VARIABLE REMAP ---------
656  // Collect all node based variables and remap them
657  // (ignore any multi-material variables on NODES - not well defined)
658 
659  src_meshvar_names.clear(); src_matvar_names.clear();
660  trg_meshvar_names.clear(); trg_matvar_names.clear();
661 
662  for (auto const& stpair : source_target_varname_map_) {
663  std::string const& srcvarname = stpair.first;
664  Entity_kind onwhat = source_state_.get_entity(srcvarname);
665  if (onwhat == NODE) {
666  std::string const& trgvarname = stpair.second;
667 
668  Field_type ftype = source_state_.field_type(onwhat, srcvarname);
669 
670  if (ftype == Field_type::MESH_FIELD) {
671  src_meshvar_names.push_back(srcvarname);
672  trg_meshvar_names.push_back(trgvarname);
673  } else if (ftype == Field_type::MULTIMATERIAL_FIELD)
674  std::cerr << "Cannot handle multi-material fields on nodes\n";
675  }
676  }
677 
678  if (not src_meshvar_names.empty()) {
679 #ifdef PORTAGE_ENABLE_MPI
680  if (redistributed_source)
681  node_remap<Flat_Mesh_Wrapper<>, Flat_State_Wrapper<Flat_Mesh_Wrapper<>>>
682  (source_mesh_flat, source_state_flat,
683  src_meshvar_names, trg_meshvar_names,
684  executor);
685  else
686 #endif
687  node_remap<SourceMesh_Wrapper, SourceState_Wrapper>
688  (source_mesh_, source_state_,
689  src_meshvar_names, trg_meshvar_names,
690  executor);
691  }
692 
693  return 1;
694  } // run
695 
696 
697 
698  private:
699  SourceMesh_Wrapper const& source_mesh_;
700  TargetMesh_Wrapper const& target_mesh_;
701  SourceState_Wrapper const& source_state_;
702  TargetState_Wrapper& target_state_;
703  std::unordered_map<std::string, std::string> source_target_varname_map_;
704  std::unordered_map<std::string, Limiter_type> limiters_;
705  std::unordered_map<std::string, Boundary_Limiter_type> bnd_limiters_;
706  std::unordered_map<std::string, Partial_fixup_type> partial_fixup_types_;
707  std::unordered_map<std::string, Empty_fixup_type> empty_fixup_types_;
708  std::unordered_map<std::string, double> double_lower_bounds_;
709  std::unordered_map<std::string, double> double_upper_bounds_;
710  std::unordered_map<std::string, double> conservation_tol_;
711  unsigned int dim_;
712  double consttol_ = 100*std::numeric_limits<double>::epsilon();
713  int max_fixup_iter_ = 5;
714  NumericTolerances_t num_tols_ = DEFAULT_NUMERIC_TOLERANCES<D>;
715 
716 
717 #ifdef HAVE_TANGRAM
718  // The following tolerances as well as the all-convex flag are
719  // required for the interface reconstructor driver. The size of the
720  // tols vector is currently set to two since MOF requires two
721  // different set of tolerances to match the 0th-order and 1st-order
722  // moments. VOF on the other does not require the second tolerance.
723  // If a new IR method which requires tolerances for higher moment is
724  // added to Tangram, then this vector size should be
725  // generalized. The boolean all_convex flag is to specify if a mesh
726  // contains only convex cells and set to true in that case.
727  //
728  // There is an associated method called set_reconstructor_options
729  // that should be invoked to set user-specific values. Otherwise,
730  // the remapper will use the default values.
731  std::vector<Tangram::IterativeMethodTolerances_t> reconstructor_tols_;
732  bool reconstructor_all_convex_ = true;
733 #endif
734 
735 }; // class MMDriver
736 
737 
738 
739 // remap routine specialization for cells
740 
741 template <template <int, Entity_kind, class, class> class Search,
742  template <Entity_kind, class, class, class,
743  template <class, int, class, class> class,
744  class, class> class Intersect,
745  template<int, Entity_kind, class, class, class, class, class,
746  template<class, int, class, class> class,
747  class, class, class=Wonton::DefaultCoordSys>
748  class Interpolate,
749  int D,
750  class SourceMesh_Wrapper,
751  class SourceState_Wrapper,
752  class TargetMesh_Wrapper,
753  class TargetState_Wrapper,
754  template <class, int, class, class> class InterfaceReconstructorType,
755  class Matpoly_Splitter,
756  class Matpoly_Clipper>
757 template<class SourceMesh_Wrapper2, class SourceState_Wrapper2>
758 int MMDriver<Search, Intersect, Interpolate, D,
759  SourceMesh_Wrapper, SourceState_Wrapper,
760  TargetMesh_Wrapper, TargetState_Wrapper,
761  InterfaceReconstructorType, Matpoly_Splitter,
762  Matpoly_Clipper
763  >::cell_remap(SourceMesh_Wrapper2 const & source_mesh2,
764  SourceState_Wrapper2 const & source_state2,
765  std::vector<std::string> const &src_meshvar_names,
766  std::vector<std::string> const &trg_meshvar_names,
767  std::vector<std::string> const &src_matvar_names,
768  std::vector<std::string> const &trg_matvar_names,
769  Wonton::Executor_type const *executor) {
770 
771  int comm_rank = 0;
772  int nprocs = 1;
773 
774 #ifdef PORTAGE_ENABLE_MPI
775  MPI_Comm mycomm = MPI_COMM_NULL;
776  auto mpiexecutor = dynamic_cast<Wonton::MPIExecutor_type const *>(executor);
777  if (mpiexecutor && mpiexecutor->mpicomm != MPI_COMM_NULL) {
778  mycomm = mpiexecutor->mpicomm;
779  MPI_Comm_rank(mycomm, &comm_rank);
780  MPI_Comm_size(mycomm, &nprocs);
781  }
782 #endif
783 
784 #ifdef ENABLE_DEBUG
785  float tot_seconds = 0.0;
786  float tot_seconds_srch = 0.0;
787  float tot_seconds_xsect = 0.0;
788  float tot_seconds_interp = 0.0;
789  auto tic = timer::now();
790 #endif
791 
792  std::vector<std::string> source_remap_var_names;
793  for (auto & stpair : source_target_varname_map_)
794  source_remap_var_names.push_back(stpair.first);
795 
796 #ifdef HAVE_TANGRAM
797  // If user did NOT set tolerances for Tangram, use Portage tolerances
798  if (reconstructor_tols_.empty()) {
799  reconstructor_tols_ = { {1000, num_tols_.min_absolute_distance,
800  num_tols_.min_absolute_volume},
801  {100, num_tols_.min_absolute_distance,
802  num_tols_.min_absolute_distance} };
803  }
804  // If user set tolerances for Tangram, but not for Portage,
805  // use Tangram tolerances
806  else if (!num_tols_.user_tolerances) {
807  num_tols_.min_absolute_distance = reconstructor_tols_[0].arg_eps;
808  num_tols_.min_absolute_volume = reconstructor_tols_[0].fun_eps;
809  }
810 #endif
811 
812  // Instantiate core driver
813 
814  Portage::CoreDriver<D, CELL,
815  SourceMesh_Wrapper2, SourceState_Wrapper2,
816  TargetMesh_Wrapper, TargetState_Wrapper,
817  InterfaceReconstructorType,
818  Matpoly_Splitter, Matpoly_Clipper>
819  coredriver_cell(source_mesh2, source_state2, target_mesh_, target_state_, executor);
820 
821  coredriver_cell.set_num_tols(num_tols_);
822 #ifdef HAVE_TANGRAM
823  coredriver_cell.set_interface_reconstructor_options(reconstructor_all_convex_,
824  reconstructor_tols_);
825 #endif
826 
827  // SEARCH
828  auto candidates = coredriver_cell.template search<Portage::SearchKDTree>();
829 #ifdef ENABLE_DEBUG
830  tot_seconds_srch = timer::elapsed(tic, true);
831 #endif
832  int nmats = source_state2.num_materials();
833 
834  //--------------------------------------------------------------------
835  // REMAP MESH FIELDS FIRST (this requires just mesh-mesh intersection)
836  //--------------------------------------------------------------------
837 
838  // INTERSECT MESHES
839  auto source_ents_and_weights =
840  coredriver_cell.template intersect_meshes<Intersect>(candidates);
841 #ifdef ENABLE_DEBUG
842  tot_seconds_xsect += timer::elapsed(tic);
843 #endif
844  // check for mesh mismatch
845  coredriver_cell.check_mismatch(source_ents_and_weights);
846 
847  // compute bounds (for all variables) if required for mismatch
848  if (coredriver_cell.has_mismatch())
849  compute_bounds<SourceState_Wrapper2, CELL>
850  (source_state2, src_meshvar_names, trg_meshvar_names, executor);
851 
852  // INTERPOLATE (one variable at a time)
853  int nvars = src_meshvar_names.size();
854 #ifdef ENABLE_DEBUG
855  tic = timer::now();
856 
857  if (comm_rank == 0) {
858  std::cout << "Number of mesh variables on cells to remap is " <<
859  nvars << std::endl;
860  }
861 #endif
862 
863  Portage::vector<Vector<D>> gradients;
864  // to check interpolation order
865  using Interpolator = Interpolate<D, CELL,
866  SourceMesh_Wrapper2, TargetMesh_Wrapper,
867  SourceState_Wrapper2, TargetState_Wrapper,
868  double, InterfaceReconstructorType,
869  Matpoly_Splitter, Matpoly_Clipper>;
870 
871 
872  for (int i = 0; i < nvars; ++i) {
873  std::string const& srcvar = src_meshvar_names[i];
874  std::string const& trgvar = trg_meshvar_names[i];
875 
876  if (Interpolator::order == 2) {
877  // set slope limiters
878  auto limiter = (limiters_.count(srcvar) ? limiters_[srcvar] : DEFAULT_LIMITER);
879  auto bndlimit = (bnd_limiters_.count(srcvar) ? bnd_limiters_[srcvar] : DEFAULT_BND_LIMITER);
880  // compute gradient field
881  gradients = coredriver_cell.compute_source_gradient(srcvar, limiter, bndlimit);
882  // interpolate
883  coredriver_cell.template interpolate_mesh_var<double, Interpolate>
884  (srcvar, trgvar, source_ents_and_weights, &gradients);
885  } else /* order 1 */ {
886  // just interpolate
887  coredriver_cell.template interpolate_mesh_var<double, Interpolate>
888  (srcvar, trgvar, source_ents_and_weights);
889  }
890 
891  // fix mismatch if necessary
892  if (coredriver_cell.has_mismatch()) {
893  coredriver_cell.fix_mismatch(srcvar, trgvar,
894  double_lower_bounds_[trgvar],
895  double_upper_bounds_[trgvar],
896  conservation_tol_[trgvar],
897  max_fixup_iter_,
898  partial_fixup_types_[trgvar],
899  empty_fixup_types_[trgvar]
900  );
901  }
902  }
903 
904 #ifdef ENABLE_DEBUG
905  tot_seconds_interp += timer::elapsed(tic, true);
906 #endif
907 
908  if (nmats > 1) {
909  //--------------------------------------------------------------------
910  // REMAP MULTIMATERIAL FIELDS NEXT, ONE MATERIAL AT A TIME
911  //--------------------------------------------------------------------
912 
913  auto source_ents_and_weights_mat =
914  coredriver_cell.template intersect_materials<Intersect>(candidates);
915 
916  int nmatvars = src_matvar_names.size();
917  std::vector<Portage::vector<Vector<D>>> matgradients(nmats);
918 
919  for (int i = 0; i < nmatvars; ++i) {
920  std::string const& srcvar = src_matvar_names[i];
921  std::string const& trgvar = trg_matvar_names[i];
922 
923  if (Interpolator::order == 2) {
924  // set slope limiters
925  auto limiter = (limiters_.count(srcvar) ? limiters_[srcvar] : DEFAULT_LIMITER);
926  auto bndlimit = (bnd_limiters_.count(srcvar) ? bnd_limiters_[srcvar] : DEFAULT_BND_LIMITER);
927  // compute gradient field for each material
928  for (int m = 0; m < nmats; m++) {
929  matgradients[m] =
930  coredriver_cell.compute_source_gradient(src_matvar_names[i],
931  limiter, bndlimit, m);
932  }
933  // interpolate
934  coredriver_cell.template interpolate_mat_var<double, Interpolate>
935  (srcvar, trgvar, source_ents_and_weights_mat, &matgradients);
936  } else {
937  // interpolate
938  coredriver_cell.template interpolate_mat_var<double, Interpolate>
939  (srcvar, trgvar, source_ents_and_weights_mat);
940  }
941  } // nmatvars
942  }
943 
944 
945 #ifdef ENABLE_DEBUG
946  tot_seconds_interp += timer::elapsed(tic);
947  tot_seconds = tot_seconds_srch + tot_seconds_xsect + tot_seconds_interp;
948 
949  std::cout << "Transform Time for Cell remap on Rank " <<
950  comm_rank << " (s): " << tot_seconds << std::endl;
951  std::cout << " Search Time Rank " << comm_rank << " (s): " <<
952  tot_seconds_srch << std::endl;
953  std::cout << " Intersect Time Rank " << comm_rank << " (s): " <<
954  tot_seconds_xsect << std::endl;
955  std::cout << " Interpolate Time Rank " << comm_rank << " (s): " <<
956  tot_seconds_interp << std::endl;
957 #endif
958  return 1;
959 } // remap specialization for cells
960 
961 
962 
963 
964 // remap routine specialization for nodes
965 
966 template <template <int, Entity_kind, class, class> class Search,
967  template <Entity_kind, class, class, class,
968  template <class, int, class, class> class,
969  class, class> class Intersect,
970  template<int, Entity_kind, class, class, class, class, class,
971  template<class, int, class, class> class,
972  class, class, class=Wonton::DefaultCoordSys>
973  class Interpolate,
974  int D,
975  class SourceMesh_Wrapper,
976  class SourceState_Wrapper,
977  class TargetMesh_Wrapper,
978  class TargetState_Wrapper,
979  template <class, int, class, class> class InterfaceReconstructorType,
980  class Matpoly_Splitter,
981  class Matpoly_Clipper>
982 template<class SourceMesh_Wrapper2, class SourceState_Wrapper2>
983 int MMDriver<Search, Intersect, Interpolate, D,
984  SourceMesh_Wrapper, SourceState_Wrapper,
985  TargetMesh_Wrapper, TargetState_Wrapper,
986  InterfaceReconstructorType, Matpoly_Splitter,
987  Matpoly_Clipper
988  >::node_remap(SourceMesh_Wrapper2 const & source_mesh2,
989  SourceState_Wrapper2 const & source_state2,
990  std::vector<std::string> const &src_meshvar_names,
991  std::vector<std::string> const &trg_meshvar_names,
992  Wonton::Executor_type const *executor) {
993 
994  int comm_rank = 0;
995  int nprocs = 1;
996 
997 #ifdef PORTAGE_ENABLE_MPI
998  MPI_Comm mycomm = MPI_COMM_NULL;
999  auto mpiexecutor = dynamic_cast<Wonton::MPIExecutor_type const *>(executor);
1000  if (mpiexecutor && mpiexecutor->mpicomm != MPI_COMM_NULL) {
1001  mycomm = mpiexecutor->mpicomm;
1002  MPI_Comm_rank(mycomm, &comm_rank);
1003  MPI_Comm_size(mycomm, &nprocs);
1004  }
1005 #endif
1006 
1007 #ifdef ENABLE_DEBUG
1008  float tot_seconds = 0.0;
1009  float tot_seconds_srch = 0.0;
1010  float tot_seconds_xsect = 0.0;
1011  float tot_seconds_interp = 0.0;
1012  auto tic = timer::now();
1013 #endif
1014 
1015  std::vector<std::string> source_remap_var_names;
1016  for (auto & stpair : source_target_varname_map_)
1017  source_remap_var_names.push_back(stpair.first);
1018 
1019 
1020 #ifdef HAVE_TANGRAM
1021  // If user set tolerances for Tangram, but not for Portage,
1022  // use Tangram tolerances
1023  if (!num_tols_.user_tolerances && (!reconstructor_tols_.empty()) ) {
1024  num_tols_.min_absolute_distance = reconstructor_tols_[0].arg_eps;
1025  num_tols_.min_absolute_volume = reconstructor_tols_[0].fun_eps;
1026  }
1027  // If user did NOT set tolerances for Tangram, use Portage tolerances
1028  if (reconstructor_tols_.empty()) {
1029  reconstructor_tols_ = { {1000, num_tols_.min_absolute_distance,
1030  num_tols_.min_absolute_volume},
1031  {100, num_tols_.min_absolute_distance,
1032  num_tols_.min_absolute_distance} };
1033  }
1034 #endif
1035  // Instantiate core driver
1036 
1037  Portage::CoreDriver<D, NODE,
1038  SourceMesh_Wrapper2, SourceState_Wrapper2,
1039  TargetMesh_Wrapper, TargetState_Wrapper>
1040  coredriver_node(source_mesh2, source_state2, target_mesh_, target_state_, executor);
1041 
1042  coredriver_node.set_num_tols(num_tols_);
1043 #ifdef HAVE_TANGRAM
1044  coredriver_node.set_interface_reconstructor_options(reconstructor_all_convex_,
1045  reconstructor_tols_);
1046 #endif
1047 
1048  // SEARCH
1049 
1050  auto candidates = coredriver_node.template search<Portage::SearchKDTree>();
1051 #ifdef ENABLE_DEBUG
1052  tot_seconds_srch = timer::elapsed(tic, true);
1053 #endif
1054  //--------------------------------------------------------------------
1055  // REMAP MESH FIELDS FIRST (this requires just mesh-mesh intersection)
1056  //--------------------------------------------------------------------
1057 
1058  // INTERSECT MESHES
1059  auto source_ents_and_weights =
1060  coredriver_node.template intersect_meshes<Intersect>(candidates);
1061 #ifdef ENABLE_DEBUG
1062  tot_seconds_xsect += timer::elapsed(tic);
1063 #endif
1064  // check for mesh mismatch
1065  coredriver_node.check_mismatch(source_ents_and_weights);
1066 
1067  // compute bounds if required for mismatch
1068  if (coredriver_node.has_mismatch())
1069  compute_bounds<SourceState_Wrapper2, NODE>
1070  (source_state2, src_meshvar_names, trg_meshvar_names, executor);
1071 
1072  // INTERPOLATE (one variable at a time)
1073  int nvars = src_meshvar_names.size();
1074 #ifdef ENABLE_DEBUG
1075  tic = timer::now();
1076 
1077  if (comm_rank == 0) {
1078  std::cout << "Number of mesh variables on nodes to remap is " <<
1079  nvars << std::endl;
1080  }
1081 #endif
1082 
1083  Portage::vector<Vector<D>> gradients;
1084  // to check interpolation order
1085  using Interpolator = Interpolate<D, NODE,
1086  SourceMesh_Wrapper2, TargetMesh_Wrapper,
1087  SourceState_Wrapper2, TargetState_Wrapper,
1088  double, InterfaceReconstructorType,
1089  Matpoly_Splitter, Matpoly_Clipper>;
1090 
1091  for (int i = 0; i < nvars; ++i) {
1092  std::string const& srcvar = src_meshvar_names[i];
1093  std::string const& trgvar = trg_meshvar_names[i];
1094 
1095  if (Interpolator::order == 2) {
1096  // set slope limiters
1097  auto limiter = (limiters_.count(srcvar) ? limiters_[srcvar] : DEFAULT_LIMITER);
1098  auto bndlimit = (bnd_limiters_.count(srcvar) ? bnd_limiters_[srcvar] : DEFAULT_BND_LIMITER);
1099  // compute gradient field
1100  gradients = coredriver_node.compute_source_gradient(srcvar, limiter, bndlimit);
1101  // interpolate
1102  coredriver_node.template interpolate_mesh_var<double, Interpolate>
1103  (srcvar, trgvar, source_ents_and_weights, &gradients);
1104  } else /* order 1 */ {
1105  // just interpolate
1106  coredriver_node.template interpolate_mesh_var<double, Interpolate>
1107  (srcvar, trgvar, source_ents_and_weights);
1108  }
1109 
1110  // fix mismatch if necessary
1111  if (coredriver_node.has_mismatch()) {
1112  coredriver_node.fix_mismatch(srcvar, trgvar,
1113  double_lower_bounds_[trgvar],
1114  double_upper_bounds_[trgvar],
1115  conservation_tol_[trgvar],
1116  max_fixup_iter_,
1117  partial_fixup_types_[trgvar],
1118  empty_fixup_types_[trgvar]
1119  );
1120  }
1121  }
1122 
1123 #ifdef ENABLE_DEBUG
1124  tot_seconds_interp += timer::elapsed(tic);
1125  tot_seconds = tot_seconds_srch + tot_seconds_xsect + tot_seconds_interp;
1126 
1127  std::cout << "Transform Time for Node remap on Rank " <<
1128  comm_rank << " (s): " << tot_seconds << std::endl;
1129  std::cout << " Search Time Rank " << comm_rank << " (s): " <<
1130  tot_seconds_srch << std::endl;
1131  std::cout << " Intersect Time Rank " << comm_rank << " (s): " <<
1132  tot_seconds_xsect << std::endl;
1133  std::cout << " Interpolate Time Rank " << comm_rank << " (s): " <<
1134  tot_seconds_interp << std::endl;
1135 #endif
1136  return 1;
1137 } // remap specialization for nodes
1138 
1139 
1140 } // namespace Portage
1141 
1142 #endif // PORTAGE_DRIVER_MMDRIVER_H_
void set_partial_fixup_type(Partial_fixup_type fixup_type)
set repair method in partially filled cells for all variables
Definition: mmdriver.h:251
void set_remap_var_names(std::vector< std::string > const &source_remap_var_names, std::vector< std::string > const &target_remap_var_names)
Specify the names of the variables to be interpolated.
Definition: mmdriver.h:167
std::vector< std::string > target_remap_var_names() const
Get the names of the variables to be remapped to the target mesh.
Definition: mmdriver.h:378
std::chrono::high_resolution_clock::time_point now()
Get current time.
Definition: timer.h:19
Boundary_Limiter_type
Boundary limiter type.
Definition: portage.h:91
constexpr Boundary_Limiter_type DEFAULT_BND_LIMITER
Definition: portage.h:94
void set_num_tols(const double min_absolute_distance, const double min_absolute_volume)
Set core numerical tolerances.
Definition: mmdriver.h:299
void set_bnd_limiter(Boundary_Limiter_type bnd_limiter)
set boundary limiter for all variables
Definition: mmdriver.h:217
std::vector< T > vector
Definition: portage.h:238
MMDriver provides the API to mapping multi-material data from one mesh to another.
Definition: mmdriver.h:103
void set_bnd_limiter(std::string const &source_var_name, Boundary_Limiter_type bnd_limiter)
set boundary limiter for a variable
Definition: mmdriver.h:241
Intersection and other tolerances to handle tiny values.
Definition: portage.h:152
float elapsed(std::chrono::high_resolution_clock::time_point &tic, bool reset=false)
Get elapsed time in seconds.
Definition: timer.h:27
void set_remap_var_bounds(std::string target_var_name, T lower_bound, T upper_bound)
set the bounds of variable to be remapped on target
Definition: mmdriver.h:316
void set_empty_fixup_type(std::string const &target_var_name, Empty_fixup_type fixup_type)
set repair method in empty cells for all variables
Definition: mmdriver.h:288
MMDriver(SourceMesh_Wrapper const &sourceMesh, SourceState_Wrapper const &sourceState, TargetMesh_Wrapper const &targetMesh, TargetState_Wrapper &targetState)
Constructor for running the interpolation driver.
Definition: mmdriver.h:124
Partial_fixup_type
Fixup options for partially filled cells.
Definition: portage.h:114
void set_empty_fixup_type(Empty_fixup_type fixup_type)
set repair method in empty cells for all variables
Definition: mmdriver.h:275
unsigned int dim() const
Get the dimensionality of the meshes.
Definition: mmdriver.h:390
double const epsilon
Numerical tolerance.
Definition: weight.h:34
Limiter_type
Limiter type.
Definition: portage.h:85
void set_limiter(Limiter_type limiter)
set limiter for all variables
Definition: mmdriver.h:205
void set_limiter(std::string const &source_var_name, Limiter_type limiter)
set limiter for a variable
Definition: mmdriver.h:230
Definition: portage.h:134
Definition: portage.h:114
std::vector< std::string > source_remap_var_names() const
Get the names of the variables to be remapped from the source mesh.
Definition: mmdriver.h:365
Definition: coredriver.h:42
void set_num_tols(const NumericTolerances_t &num_tols)
Set all numerical tolerances.
Definition: mmdriver.h:307
void set_remap_var_names(std::vector< std::string > const &remap_var_names)
Specify the names of the variables to be interpolated.
Definition: mmdriver.h:154
void set_conservation_tolerance(std::string target_var_name, T conservation_tol)
set conservation tolerance of variable to be remapped on target
Definition: mmdriver.h:330
void set_max_fixup_iter(int maxiter)
Definition: mmdriver.h:294
constexpr Limiter_type DEFAULT_LIMITER
Definition: portage.h:88
Core driver for remapping.
void set_partial_fixup_type(std::string const &target_var_name, Partial_fixup_type fixup_type)
set repair method in partially filled cells for all variables
Definition: mmdriver.h:265
Definition: portage.h:91
Portage::vector< Vector< D > > compute_source_gradient(std::string const field_name, Limiter_type limiter_type=NOLIMITER, Boundary_Limiter_type boundary_limiter_type=BND_NOLIMITER, int material_id=0, const Part< SourceMesh, SourceState > *source_part=nullptr) const
Compute the gradient field of the given variable on source mesh.
Definition: coredriver.h:909
void Intersect(const IsotheticBBox< D > &box, const KDTree< D > *kdtree, std::vector< int > &pfound)
Definition: kdtree.h:439
CoreDriver - Core driver that remaps fields on a particular Entity_kind (ONWHAT) like CELL or NODE...
Definition: coredriver.h:64
Empty_fixup_type
Fixup options for empty cells.
Definition: portage.h:134
int run(Wonton::Executor_type const *executor=nullptr, std::string *errmsg=nullptr)
Execute the remapping process.
Definition: mmdriver.h:529
Definition: portage.h:85
void compute_bounds(SourceState_Wrapper2 const &source_state2, std::vector< std::string > const &src_meshvar_names, std::vector< std::string > const &trg_meshvar_names, Wonton::Executor_type const *executor=nullptr)
Compute mismatch fixup bounds dynamically.
Definition: mmdriver.h:455