SPHinXsys  alpha version
particle_dynamics_dissipation.hpp
Go to the documentation of this file.
1 
7 #ifndef PARTICLE_DYNAMICS_DISSIPATION_HPP
8 #define PARTICLE_DYNAMICS_DISSIPATION_HPP
9 
11 
12 namespace SPH
13 {
14  //=================================================================================================//
15  template <typename VariableType>
16  DampingBySplittingInner<VariableType>::
17  DampingBySplittingInner(BaseBodyRelationInner &inner_relation,
18  const std::string &variable_name, Real eta)
19  : InteractionDynamicsSplitting(*inner_relation.sph_body_),
20  DissipationDataInner(inner_relation), eta_(eta),
21  Vol_(particles_->Vol_), mass_(particles_->mass_),
22  variable_(*particles_->getVariableByName<VariableType>(variable_name)) {}
23  //=================================================================================================//
24  template <typename VariableType>
25  ErrorAndParameters<VariableType>
26  DampingBySplittingInner<VariableType>::computeErrorAndParameters(size_t index_i, Real dt)
27  {
28  Real Vol_i = Vol_[index_i];
29  Real mass_i = mass_[index_i];
30  VariableType &variable_i = variable_[index_i];
31  ErrorAndParameters<VariableType> error_and_parameters(0);
32  Neighborhood &inner_neighborhood = inner_configuration_[index_i];
33  for (size_t n = 0; n != inner_neighborhood.current_size_; ++n)
34  {
35  size_t index_j = inner_neighborhood.j_[n];
36  // linear projection
37  VariableType variable_derivative = (variable_i - variable_[index_j]);
38  Real parameter_b = 2.0 * eta_ * inner_neighborhood.dW_ij_[n] * Vol_i * Vol_[index_j] * dt / inner_neighborhood.r_ij_[n];
39 
40  error_and_parameters.error_ -= variable_derivative * parameter_b;
41  error_and_parameters.a_ += parameter_b;
42  error_and_parameters.c_ += parameter_b * parameter_b;
43  }
44  error_and_parameters.a_ -= mass_i;
45  return error_and_parameters;
46  }
47  //=================================================================================================//
48  template <typename VariableType>
49  void DampingBySplittingInner<VariableType>::
50  updateStates(size_t index_i, Real dt, const ErrorAndParameters<VariableType> &error_and_parameters)
51  {
52  Real parameter_l = error_and_parameters.a_ * error_and_parameters.a_ + error_and_parameters.c_;
53  VariableType parameter_k = error_and_parameters.error_ / (parameter_l + TinyReal);
54  variable_[index_i] += parameter_k * error_and_parameters.a_;
55 
56  Real Vol_i = Vol_[index_i];
57  VariableType &variable_i = variable_[index_i];
58  Neighborhood &inner_neighborhood = inner_configuration_[index_i];
59  for (size_t n = 0; n != inner_neighborhood.current_size_; ++n)
60  {
61  size_t index_j = inner_neighborhood.j_[n];
62 
63  Real parameter_b = 2.0 * eta_ * inner_neighborhood.dW_ij_[n] * Vol_i * Vol_[index_j] * dt / inner_neighborhood.r_ij_[n];
64 
65  // predicted quantity at particle j
66  VariableType variable_j = variable_[index_j] - parameter_k * parameter_b;
67  VariableType variable_derivative = (variable_i - variable_j);
68 
69  // exchange in conservation form
70  variable_[index_j] -= variable_derivative * parameter_b / mass_[index_j];
71  }
72  }
73  //=================================================================================================//
74  template <typename VariableType>
75  void DampingBySplittingInner<VariableType>::Interaction(size_t index_i, Real dt)
76  {
77  ErrorAndParameters<VariableType> error_and_parameters = computeErrorAndParameters(index_i, dt);
78  updateStates(index_i, dt, error_and_parameters);
79  }
80  //=================================================================================================//
81  template <typename VariableType>
82  DampingBySplittingComplex<VariableType>::
83  DampingBySplittingComplex(ComplexBodyRelation &complex_relation,
84  const std::string &variable_name, Real eta)
85  : DampingBySplittingInner<VariableType>(complex_relation.inner_relation_, variable_name, eta),
86  DissipationDataContact(complex_relation.contact_relation_)
87  {
88  for (size_t k = 0; k != contact_particles_.size(); ++k)
89  {
90  contact_Vol_.push_back(&(contact_particles_[k]->Vol_));
91  contact_mass_.push_back(&(contact_particles_[k]->mass_));
92  contact_variable_.push_back(contact_particles_[k]->template getVariableByName<VariableType>(variable_name));
93  }
94  }
95  //=================================================================================================//
96  template <typename VariableType>
97  ErrorAndParameters<VariableType>
99  {
100  ErrorAndParameters<VariableType> error_and_parameters =
102 
103  VariableType &variable_i = this->variable_[index_i];
104  Real Vol_i = this->Vol_[index_i];
106  for (size_t k = 0; k < this->contact_configuration_.size(); ++k)
107  {
108  StdLargeVec<Real> &Vol_k = *(this->contact_Vol_[k]);
109  StdLargeVec<Real> &mass_k = *(this->contact_mass_[k]);
110  StdLargeVec<VariableType> &variable_k = *(this->contact_variable_[k]);
111  Neighborhood &contact_neighborhood = (*this->contact_configuration_[k])[index_i];
112  for (size_t n = 0; n != contact_neighborhood.current_size_; ++n)
113  {
114  size_t index_j = contact_neighborhood.j_[n];
115 
116  // linear projection
117  VariableType variable_derivative = (variable_i - variable_k[index_j]);
118  Real parameter_b = 2.0 * this->eta_ * contact_neighborhood.dW_ij_[n] * Vol_i * Vol_k[index_j] * dt / contact_neighborhood.r_ij_[n];
119 
120  error_and_parameters.error_ -= variable_derivative * parameter_b;
121  error_and_parameters.a_ += parameter_b;
122  error_and_parameters.c_ += parameter_b * parameter_b;
123  }
124  return error_and_parameters;
125  }
126  }
127  //=================================================================================================//
128  template <typename VariableType>
130  updateStates(size_t index_i, Real dt, const ErrorAndParameters<VariableType> &error_and_parameters)
131  {
132  DampingBySplittingInner<VariableType>::updateStates(index_i, dt, error_and_parameters);
133 
134  Real parameter_l = error_and_parameters.a_ * error_and_parameters.a_ + error_and_parameters.c_;
135  VariableType parameter_k = error_and_parameters.error_ / (parameter_l + TinyReal);
136  VariableType &variable_i = this->variable_[index_i];
137  Real Vol_i = this->Vol_[index_i];
139  for (size_t k = 0; k < this->contact_configuration_.size(); ++k)
140  {
141  StdLargeVec<Real> &Vol_k = *(this->contact_Vol_[k]);
142  StdLargeVec<Real> &mass_k = *(this->contact_mass_[k]);
143  StdLargeVec<VariableType> &variable_k = *(this->contact_variable_[k]);
144  Neighborhood &contact_neighborhood = (*this->contact_configuration_[k])[index_i];
145  for (size_t n = 0; n != contact_neighborhood.current_size_; ++n)
146  {
147  size_t index_j = contact_neighborhood.j_[n];
148 
149  // linear projection
150  Real parameter_b = 2.0 * this->eta_ * contact_neighborhood.dW_ij_[n] * Vol_i * Vol_k[index_j] * dt / contact_neighborhood.r_ij_[n];
151 
152  // predicted quantity at particle j
153  VariableType variable_j = this->variable_k[index_j] - parameter_k * parameter_b;
154  VariableType variable_derivative = (variable_i - variable_j);
155 
156  // exchange in conservation form
157  this->variable_k[index_j] -= variable_derivative * parameter_b / mass_k[index_j];
158  }
159  }
160  }
161  //=================================================================================================//
162  template <typename VariableType,
163  template <typename BaseVariableType> class BaseDampingBySplittingType>
165  DampingBySplittingWithWall(ComplexBodyRelation &complex_wall_relation,
166  const std::string &variable_name, Real eta)
167  : BaseDampingBySplittingType<VariableType>(complex_wall_relation.inner_relation_, variable_name, eta),
168  DissipationDataWithWall(complex_wall_relation.contact_relation_)
169  {
170  for (size_t k = 0; k != DissipationDataWithWall::contact_particles_.size(); ++k)
171  {
172  wall_Vol_.push_back(&(contact_particles_[k]->Vol_));
173  wall_variable_.push_back(contact_particles_[k]->template getVariableByName<VariableType>(variable_name));
174  }
175  }
176  //=================================================================================================//
177  template <typename VariableType,
178  template <typename BaseVariableType> class BaseDampingBySplittingType>
179  ErrorAndParameters<VariableType>
181  computeErrorAndParameters(size_t index_i, Real dt)
182  {
183  ErrorAndParameters<VariableType> error_and_parameters =
185 
186  VariableType &variable_i = this->variable_[index_i];
187  Real Vol_i = this->Vol_[index_i];
189  for (size_t k = 0; k < this->contact_configuration_.size(); ++k)
190  {
191  StdLargeVec<Real> &Vol_k = *(this->wall_Vol_[k]);
192  StdLargeVec<VariableType> &variable_k = *(this->wall_variable_[k]);
193  Neighborhood &contact_neighborhood = (*DissipationDataWithWall::contact_configuration_[k])[index_i];
194  for (size_t n = 0; n != contact_neighborhood.current_size_; ++n)
195  {
196  size_t index_j = contact_neighborhood.j_[n];
197 
198  // linear projection
199  VariableType variable_derivative = (variable_i - variable_k[index_j]);
200  Real parameter_b = 2.0 * this->eta_ * contact_neighborhood.dW_ij_[n] * Vol_i * Vol_k[index_j] * dt / contact_neighborhood.r_ij_[n];
201 
202  error_and_parameters.error_ -= variable_derivative * parameter_b;
203  error_and_parameters.a_ += parameter_b;
204  error_and_parameters.c_ += parameter_b * parameter_b;
205  }
206  }
207  return error_and_parameters;
208  }
209  //=================================================================================================//
210  template <typename VariableType>
213  const std::string &variable_name, Real eta)
214  : InteractionDynamicsSplitting(*inner_relation.sph_body_),
215  DissipationDataInner(inner_relation),
216  Vol_(particles_->Vol_), mass_(particles_->mass_),
217  variable_(*particles_->getVariableByName<VariableType>(variable_name)),
218  eta_(eta) {}
219  //=================================================================================================//
220  template <typename VariableType>
221  void DampingPairwiseInner<VariableType>::Interaction(size_t index_i, Real dt)
222  {
223  Real Vol_i = Vol_[index_i];
224  Real mass_i = mass_[index_i];
225  VariableType &variable_i = variable_[index_i];
226 
227  std::array<Real, MaximumNeighborhoodSize> parameter_b;
228  Neighborhood &inner_neighborhood = inner_configuration_[index_i];
229  // forward sweep
230  for (size_t n = 0; n != inner_neighborhood.current_size_; ++n)
231  {
232  size_t index_j = inner_neighborhood.j_[n];
233  Real mass_j = mass_[index_j];
234 
235  VariableType variable_derivative = (variable_i - variable_[index_j]);
236  parameter_b[n] = eta_ * inner_neighborhood.dW_ij_[n] * Vol_i * Vol_[index_j] * dt / inner_neighborhood.r_ij_[n];
237 
238  VariableType increment = parameter_b[n] * variable_derivative / (mass_i * mass_j - parameter_b[n] * (mass_i + mass_j));
239  variable_[index_i] += increment * mass_j;
240  variable_[index_j] -= increment * mass_i;
241  }
242 
243  // backward sweep
244  for (size_t n = inner_neighborhood.current_size_; n != 0; --n)
245  {
246  size_t index_j = inner_neighborhood.j_[n - 1];
247  Real mass_j = mass_[index_j];
248 
249  VariableType variable_derivative = (variable_i - variable_[index_j]);
250  VariableType increment = parameter_b[n - 1] * variable_derivative / (mass_i * mass_j - parameter_b[n - 1] * (mass_i + mass_j));
251 
252  variable_[index_i] += increment * mass_j;
253  variable_[index_j] -= increment * mass_i;
254  }
255  }
256  //=================================================================================================//
257  template <typename VariableType>
258  DampingPairwiseComplex<VariableType>::DampingPairwiseComplex(BaseBodyRelationInner &inner_relation,
259  BaseBodyRelationContact &contact_relation, const std::string &variable_name, Real eta)
260  : DampingPairwiseInner<VariableType>(inner_relation, variable_name, eta),
261  DissipationDataContact(contact_relation)
262  {
263  for (size_t k = 0; k != contact_particles_.size(); ++k)
264  {
265  contact_Vol_.push_back(&(contact_particles_[k]->Vol_));
266  contact_mass_.push_back(&(contact_particles_[k]->mass_));
267  contact_variable_.push_back(contact_particles_[k]->template getVariableByName<VariableType>(variable_name));
268  }
269  }
270  //=================================================================================================//
271  template <typename VariableType>
272  DampingPairwiseComplex<VariableType>::
273  DampingPairwiseComplex(ComplexBodyRelation &complex_relation, const std::string &variable_name, Real eta)
274  : DampingPairwiseComplex(complex_relation.inner_relation_,
275  complex_relation.contact_relation_, variable_name, eta) {}
276  //=================================================================================================//
277  template <typename VariableType>
279  {
281 
282  Real Vol_i = this->Vol_[index_i];
283  Real mass_i = this->mass_[index_i];
284  VariableType &variable_i = this->variable_[index_i];
285 
286  std::array<Real, MaximumNeighborhoodSize> parameter_b;
287 
289  for (size_t k = 0; k < this->contact_configuration_.size(); ++k)
290  {
291  StdLargeVec<Real> &Vol_k = *(this->contact_Vol_[k]);
292  StdLargeVec<Real> &mass_k = *(this->contact_mass_[k]);
293  StdLargeVec<VariableType> &variable_k = *(this->contact_variable_[k]);
294  Neighborhood &contact_neighborhood = (*this->contact_configuration_[k])[index_i];
295  // forward sweep
296  for (size_t n = 0; n != contact_neighborhood.current_size_; ++n)
297  {
298  size_t index_j = contact_neighborhood.j_[n];
299  Real mass_j = mass_k[index_j];
300 
301  VariableType variable_derivative = (variable_i - variable_k[index_j]);
302  parameter_b[n] = this->eta_ * contact_neighborhood.dW_ij_[n] * Vol_i * Vol_k[index_j] * dt / contact_neighborhood.r_ij_[n];
303 
304  VariableType increment = parameter_b[n] * variable_derivative / (mass_i * mass_j - parameter_b[n] * (mass_i + mass_j));
305  this->variable_[index_i] += increment * mass_j;
306  variable_k[index_j] -= increment * mass_i;
307  }
308  // backward sweep
309  for (size_t n = contact_neighborhood.current_size_; n != 0; --n)
310  {
311  size_t index_j = contact_neighborhood.j_[n - 1];
312  Real mass_j = mass_k[index_j];
313 
314  VariableType variable_derivative = (variable_i - variable_k[index_j]);
315  VariableType increment = parameter_b[n - 1] * variable_derivative / (mass_i * mass_j - parameter_b[n - 1] * (mass_i + mass_j));
316 
317  this->variable_[index_i] += increment * mass_j;
318  variable_k[index_j] -= increment * mass_i;
319  }
320  }
321  }
322  //=================================================================================================//
323  template <typename VariableType,
324  template <typename BaseVariableType> class BaseDampingPairwiseType>
327  BaseBodyRelationContact &contact_relation, const std::string &variable_name, Real eta)
328  : BaseDampingPairwiseType<VariableType>(inner_relation, variable_name, eta),
329  DissipationDataWithWall(contact_relation)
330  {
331  for (size_t k = 0; k != DissipationDataWithWall::contact_particles_.size(); ++k)
332  {
333  wall_Vol_.push_back(&(contact_particles_[k]->Vol_));
334  wall_variable_.push_back(contact_particles_[k]->template getVariableByName<VariableType>(variable_name));
335  }
336  }
337  //=================================================================================================//
338  template <typename VariableType,
339  template <typename BaseVariableType> class BaseDampingPairwiseType>
340  DampingPairwiseWithWall<VariableType, BaseDampingPairwiseType>::
341  DampingPairwiseWithWall(ComplexBodyRelation &complex_wall_relation, const std::string &variable_name, Real eta)
342  : DampingPairwiseWithWall(complex_wall_relation.inner_relation_,
343  complex_wall_relation.contact_relation_, variable_name, eta) {}
344  //=================================================================================================//
345  template <typename VariableType,
346  template <typename BaseVariableType> class BaseDampingPairwiseType>
348  Interaction(size_t index_i, Real dt)
349  {
351 
352  Real Vol_i = this->Vol_[index_i];
353  Real mass_i = this->mass_[index_i];
354  VariableType &variable_i = this->variable_[index_i];
355 
356  std::array<Real, MaximumNeighborhoodSize> parameter_b;
357 
359  for (size_t k = 0; k < this->contact_configuration_.size(); ++k)
360  {
361  StdLargeVec<Real> &Vol_k = *(this->wall_Vol_[k]);
362  StdLargeVec<VariableType> &variable_k = *(this->wall_variable_[k]);
363  Neighborhood &contact_neighborhood = (*DissipationDataWithWall::contact_configuration_[k])[index_i];
364  // forward sweep
365  for (size_t n = 0; n != contact_neighborhood.current_size_; ++n)
366  {
367  size_t index_j = contact_neighborhood.j_[n];
368 
369  parameter_b[n] = this->eta_ * contact_neighborhood.dW_ij_[n] * Vol_i * Vol_k[index_j] * dt / contact_neighborhood.r_ij_[n];
370 
371  // only update particle i
372  this->variable_[index_i] += parameter_b[n] * (variable_i - variable_k[index_j]) / (mass_i - 2.0 * parameter_b[n]);
373  }
374  // backward sweep
375  for (size_t n = contact_neighborhood.current_size_; n != 0; --n)
376  {
377  size_t index_j = contact_neighborhood.j_[n - 1];
378 
379  // only update particle i
380  this->variable_[index_i] += parameter_b[n - 1] * (variable_i - variable_k[index_j]) / (mass_i - 2.0 * parameter_b[n - 1]);
381  }
382  }
383  }
384  //=================================================================================================//
385  template <typename VariableType>
387  DampingPairwiseFromWall(BaseBodyRelationContact &contact_relation, const std::string &variable_name, Real eta)
388  : InteractionDynamicsSplitting(*contact_relation.sph_body_),
390  eta_(eta), Vol_(particles_->Vol_), mass_(particles_->mass_),
391  variable_(*particles_->getVariableByName<VariableType>(variable_name))
392  {
393  for (size_t k = 0; k != contact_particles_.size(); ++k)
394  {
395  wall_Vol_.push_back(&(contact_particles_[k]->Vol_));
396  wall_variable_.push_back(contact_particles_[k]->template getVariableByName<VariableType>(variable_name));
397  }
398  }
399  //=================================================================================================//
400  template <typename VariableType>
402  {
403  Real Vol_i = Vol_[index_i];
404  Real mass_i = mass_[index_i];
405  VariableType &variable_i = variable_[index_i];
406 
407  std::array<Real, MaximumNeighborhoodSize> parameter_b;
408 
410  for (size_t k = 0; k < contact_configuration_.size(); ++k)
411  {
412  StdLargeVec<Real> &Vol_k = *(wall_Vol_[k]);
413  StdLargeVec<VariableType> &variable_k = *(wall_variable_[k]);
414  Neighborhood &contact_neighborhood = (*contact_configuration_[k])[index_i];
415  // forward sweep
416  for (size_t n = 0; n != contact_neighborhood.current_size_; ++n)
417  {
418  size_t index_j = contact_neighborhood.j_[n];
419 
420  parameter_b[n] = eta_ * contact_neighborhood.dW_ij_[n] * Vol_i * Vol_k[index_j] * dt / contact_neighborhood.r_ij_[n];
421 
422  // only update particle i
423  variable_[index_i] += parameter_b[n] * (variable_i - variable_k[index_j]) / (mass_i - 2.0 * parameter_b[n]);
424  }
425  // backward sweep
426  for (size_t n = contact_neighborhood.current_size_; n != 0; --n)
427  {
428  size_t index_j = contact_neighborhood.j_[n - 1];
429 
430  // only update particle i
431  variable_[index_i] += parameter_b[n - 1] * (variable_i - variable_k[index_j]) / (mass_i - 2.0 * parameter_b[n - 1]);
432  }
433  }
434  }
435  //=================================================================================================//
436  template <class DampingAlgorithmType>
437  template <typename... ConstructorArgs>
439  DampingWithRandomChoice(Real random_ratio, ConstructorArgs &&...args)
440  : DampingAlgorithmType(std::forward<ConstructorArgs>(args)...), random_ratio_(random_ratio)
441  {
442  this->eta_ /= random_ratio;
443  }
444  //=================================================================================================//
445  template <class DampingAlgorithmType>
446  bool DampingWithRandomChoice<DampingAlgorithmType>::RandomChoice()
447  {
448  return ((double)rand() / (RAND_MAX)) < random_ratio_ ? true : false;
449  }
450  //=================================================================================================//
451  template <class DampingAlgorithmType>
452  void DampingWithRandomChoice<DampingAlgorithmType>::exec(Real dt)
453  {
454  if (RandomChoice())
455  DampingAlgorithmType::exec(dt);
456  }
457  //=================================================================================================//
458  template <class DampingAlgorithmType>
459  void DampingWithRandomChoice<DampingAlgorithmType>::parallel_exec(Real dt)
460  {
461  if (RandomChoice())
462  DampingAlgorithmType::parallel_exec(dt);
463  }
464  //=================================================================================================//
465 }
466 #endif // PARTICLE_DYNAMICS_DISSIPATION_HPP
A neighborhood around particle i.
Definition: neighbor_relation.h:47
Particles with essential (geometric and kinematic) data. There are three types of particles, all par...
Definition: base_particles.h:81
prepare data for inner particle dynamics
Definition: base_particle_dynamics.h:216
The base relation between a SPH body and its contact SPH bodies.
Definition: base_body_relation.h:136
virtual void Interaction(size_t index_i, Real dt=0.0) override
Definition: particle_dynamics_dissipation.hpp:348
size_t current_size_
Definition: neighbor_relation.h:50
Definition: particle_dynamics_dissipation.h:98
Base of all materials.
Definition: base_material.h:52
Base class of all solid materials.
Definition: base_material.h:113
Definition: particle_dynamics_dissipation.h:61
virtual void updateStates(size_t index_i, Real dt, const ErrorAndParameters< VariableType > &error_and_parameters) override
Definition: particle_dynamics_dissipation.hpp:130
Declaration of solidbody which is used for Solid BCs and derived from RealBody.
Definition: solid_body.h:46
StdLargeVec< Real > r_ij_
Definition: neighbor_relation.h:56
Definition: particle_dynamics_dissipation.h:45
A group of particles with solid body particle data.
Definition: solid_particles.h:49
virtual ErrorAndParameters< VariableType > computeErrorAndParameters(size_t index_i, Real dt=0.0) override
Definition: particle_dynamics_dissipation.hpp:98
StdVec< ParticleConfiguration * > contact_configuration_
Definition: base_particle_dynamics.h:251
This is for the splitting algorithm.
Definition: particle_dynamics_algorithms.h:202
This is the particle dynamics aplliable for all type bodies.
Damping to wall by which the wall velocity is not updated and the mass of wall particle is not consid...
Definition: particle_dynamics_dissipation.h:183
prepare data for contact particle dynamics
Definition: base_particle_dynamics.h:240
StdLargeVec< Real > dW_ij_
Definition: neighbor_relation.h:55
The relation combined an inner and a contact body relation. The interaction is in a inner-boundary-co...
Definition: complex_body_relation.h:42
virtual void Interaction(size_t index_i, Real dt=0.0) override
Definition: particle_dynamics_dissipation.hpp:278
virtual ErrorAndParameters< VariableType > computeErrorAndParameters(size_t index_i, Real dt=0.0) override
Definition: particle_dynamics_dissipation.hpp:181
SPHBody is a base body with basic data and functions. Its derived class can be a real fluid body...
Definition: base_body.h:61
Damping with wall by which the wall velocity is not updated and the mass of wall particle is not cons...
Definition: particle_dynamics_dissipation.h:160
virtual void Interaction(size_t index_i, Real dt=0.0) override
Definition: particle_dynamics_dissipation.hpp:401
The abstract relation within a SPH body.
Definition: base_body_relation.h:117
StdLargeVec< size_t > j_
Definition: neighbor_relation.h:53
A quantity damping by a pairwise splitting scheme this method modifies the quantity directly Note tha...
Definition: particle_dynamics_dissipation.h:121
A random choice method for obstaining static equilibrium state Note that, if periodic boundary condit...
Definition: particle_dynamics_dissipation.h:210
Definition: solid_body_supplementary.cpp:9