accumulate.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 #ifndef ACCUMULATE_H_INC_
7 #define ACCUMULATE_H_INC_
8 
9 #include <vector>
10 #include <memory>
11 #include <cassert>
12 
13 // portage includes
15 #include "portage/support/weight.h"
16 #include "portage/support/basis.h"
18 #include "portage/swarm/swarm.h"
19 
20 // wonton includes
21 #include "wonton/support/Matrix.h"
22 
23 namespace Portage { namespace Meshfree {
24 
28 enum EstimateType {
29  KernelDensity,
30  LocalRegression,
31  OperatorRegression
32 };
33 
37 enum WeightCenter {
38  Gather,
39  Scatter
40 };
41 
50 template<int dim,
51  class SourceSwarm,
52  class TargetSwarm>
53 class Accumulate {
54  public:
55 
71  Accumulate(SourceSwarm const& source, TargetSwarm const& target,
72  EstimateType estimate, WeightCenter center,
73  Portage::vector<Weight::Kernel> const& kernels,
74  Portage::vector<Weight::Geometry> const& geometries,
75  Portage::vector<std::vector<std::vector<double>>> const& smoothing,
76  basis::Type basis, oper::Type operator_spec = oper::LastOperator,
77  Portage::vector<oper::Domain> const& operator_domain = {},
78  Portage::vector<std::vector<Wonton::Point<dim>>> const& operator_data = {})
79  : source_(source),
80  target_(target),
81  estimate_(estimate),
82  center_(center),
83  kernels_(kernels),
84  geometries_(geometries),
85  smoothing_(smoothing),
86  basis_(basis),
87  operator_spec_(operator_spec),
88  operator_domain_(operator_domain),
89  operator_data_(operator_data)
90  {
91 #ifdef DEBUG
92  // check sizes of inputs are consistent
93  size_t n_particles = (center == Gather ? target_.num_owned_particles()
94  : source_.num_particles());
95 
96  assert(n_particles == kernels_.size());
97  assert(n_particles == geometries_.size());
98  assert(n_particles == smoothing_.size());
99  if (operator_spec_ != oper::LastOperator) {
100  unsigned const num_target_particles = target_.num_owned_particles();
101  assert(operator_data_.size() == num_target_particles);
102  assert(operator_domain_.size() == num_target_particles);
103  }
104 #endif
105  }
106 
115  double weight(const size_t particleA, const size_t particleB) {
116  double result = 0.0;
117  Wonton::Point<dim> x = target_.get_particle_coordinates(particleA);
118  Wonton::Point<dim> y = source_.get_particle_coordinates(particleB);
119  if (center_ == Gather) {
120  result = Weight::eval<dim>(geometries_[particleA],
121  kernels_[particleA],
122  x,y,
123  smoothing_[particleA]);
124  } else if (center_ == Scatter) {
125  result = Weight::eval<dim>(geometries_[particleB],
126  kernels_[particleB],
127  y,x, // faceted weights are asymmetric
128  smoothing_[particleB]);
129  }
130  return result;
131  }
132 
142  std::vector<Weights_t>
143  operator() (size_t const particleA, std::vector<int> const& source_particles) {
144  std::vector<Weights_t> result;
145  result.reserve(source_particles.size());
146 
147  switch (estimate_) {
148  case KernelDensity: {
149  for (auto const& particleB : source_particles) {
150  double weight_val = weight(particleA, particleB);
151  std::vector<double> pair_result(1, weight_val);
152  result.emplace_back(particleB, pair_result);
153  }
154  break;
155  }
156  case OperatorRegression:
157  case LocalRegression: {
158  size_t nbasis = basis::function_size<dim>(basis_);
159  Wonton::Point<dim> x = target_.get_particle_coordinates(particleA);
160 
161  // If too few particles, set estimate to zero for this target
162  bool zilchit = false;
163  if (source_particles.size() < nbasis) {
164  zilchit = true;
165  }
166 
167  // Calculate weights and moment matrix (P*W*transpose(P))
168  std::vector<double> weight_val(source_particles.size());
169  Wonton::Matrix moment(nbasis,nbasis,0.);
170  size_t iB = 0;
171  if (not zilchit) {
172  for (auto const& particleB : source_particles) {
173  weight_val[iB] = weight(particleA, particleB); // save weights for later
174  Wonton::Point<dim> y = source_.get_particle_coordinates(particleB);
175  auto basis = basis::shift<dim>(basis_, x, y);
176  for (size_t i=0; i<nbasis; i++) {
177  for (size_t j=0; j<nbasis; j++) {
178  moment[i][j] += basis[i]*basis[j]*weight_val[iB];
179  }
180  }
181  iB++;
182  }
183  }
184 
185  // Calculate inverse(P*W*transpose(P))*P*W
186  iB = 0;
187 
188  for (auto const& particleB : source_particles) {
189  std::vector<double> pair_result(nbasis);
190  Wonton::Point<dim> y = source_.get_particle_coordinates(particleB);
191  std::vector<double> basis = basis::shift<dim>(basis_, x, y);
192 
193  // recast as a Portage::Matrix
194  Wonton::Matrix basis_matrix(nbasis,1);
195  for (size_t i=0; i<nbasis; i++) basis_matrix[i][0] = basis[i];
196 
197  // solve the linear system
198  if (not zilchit) {
199  std::string error="check";
200 #ifdef HAVE_LAPACKE
201  Wonton::Matrix pair_result_matrix = moment.solve(basis_matrix, "lapack-sytr", error);
202 #else
203  Wonton::Matrix pair_result_matrix = moment.solve(basis_matrix, "inverse", error);
204 #endif
205  for (size_t i=0; i<nbasis; i++)
206  pair_result[i] = pair_result_matrix[i][0]*weight_val[iB];
207  // NOTE: THIS CODE HAS TO WAIT FOR AN UPDATED WONTON
208  //if (basis_matrix.is_singular() == 2 or error != "none") {
209  // bad_count++;
210  //}
211  } else {
212  for (size_t i=0; i<nbasis; i++)
213  pair_result[i] = 0.;
214  }
215 
216  // If an operator is being applied, adjust final weights.
217  if (estimate_ == OperatorRegression) {
218  auto ijet = basis::inverse_jet<dim>(basis_, x);
219  std::vector<std::vector<double>> basisop;
220  oper::apply<dim>(operator_spec_, basis_,
221  operator_domain_[particleA],
222  operator_data_[particleA], basisop);
223  int const num_basis = nbasis;
224  int const opsize = oper::size_info(operator_spec_, basis_,
225  operator_domain_[particleA])[0];
226  std::vector<double> operator_result(opsize, 0.);
227 
228  for (int j = 0; j < opsize; j++) {
229  for (int k = 0; k < num_basis; k++) {
230  for (int m = 0; m < num_basis; m++) {
231  operator_result[j] += pair_result[k]*ijet[k][m]*basisop[m][j];
232  }
233  }
234  }
235  for (int j = 0; j < num_basis; j++)
236  pair_result[j] = operator_result[j];
237  }
238  result.emplace_back(particleB, pair_result);
239  iB++;
240  }
241  break;
242  }
243  default: // invalid estimate
244  assert(false);
245  }
246  return result;
247  }
248 
249  private:
250  SourceSwarm const& source_;
251  TargetSwarm const& target_;
252  EstimateType estimate_;
253  WeightCenter center_;
254  Portage::vector<Weight::Kernel> const& kernels_;
255  Portage::vector<Weight::Geometry> const& geometries_;
257  basis::Type basis_;
258  oper::Type operator_spec_;
259  Portage::vector<oper::Domain> operator_domain_;
261 };
262 
263 }}
264 
265 #endif // ACCUMULATE_H_INC
std::vector< T > vector
Definition: portage.h:238
Definition: operator.h:30
Type
Definition: basis.h:20
Type
Definition: operator.h:30
Definition: coredriver.h:42
std::array< size_t, 3 > size_info(Type type, basis::Type basis, Domain domain)
Definition: operator.h:513