SPH
Rotation.cpp
Go to the documentation of this file.
2 
4 
9 /*INLINE bool interacts(Size i, Size j, ArrayView<const Size> flag, ArrayView<const Float> reduce) {
10  return flag[i] == flag[j] && reduce[i] > 0._f && reduce[j] > 0._f;
11 }
12 
14 template <typename Term>
15 class RotationStressDivergence : public DerivativeTemplate<RotationStressDivergence<Term>> {
16 private:
17  ArrayView<const Float> rho, m, I;
18  ArrayView<const TracelessTensor> s;
19  ArrayView<const Float> reduce;
20  ArrayView<const Size> flag;
21  ArrayView<const Vector> r;
22  ArrayView<Vector> domega;
23 
24 public:
25  virtual void create(Accumulated& results) override {
26  results.insert<Vector>(QuantityId::ANGULAR_VELOCITY, OrderEnum::FIRST);
27  }
28 
29  virtual void initialize(const Storage& input, Accumulated& results) override {
30  tie(rho, m, I) =
31  input.getValues<Float>(QuantityId::DENSITY, QuantityId::MASS, QuantityId::MOMENT_OF_INERTIA);
32  s = input.getPhysicalValue<TracelessTensor>(QuantityId::DEVIATORIC_STRESS);
33  reduce = input.getValue<Float>(QuantityId::STRESS_REDUCING);
34  flag = input.getValue<Size>(QuantityId::FLAG);
35  r = input.getValue<Vector>(QuantityId::POSITION);
36  domega = results.getBuffer<Vector>(QuantityId::ANGULAR_VELOCITY, OrderEnum::FIRST);
37  }
38 
39 
40  template <bool Symmetrize>
41  INLINE void eval(const Size i, const Size j, const Vector& grad) {
42  if (!interacts(i, j, flag, reduce)) {
43  return;
44  }
45  const TracelessTensor t = Term::term(s, rho, i, j);
46  const Vector force = t * grad;
47  const Vector torque = 0.5_f * cross(r[j] - r[i], force);
48  SPH_ASSERT(isReal(force) && isReal(torque));
49  domega[i] += m[i] / I[i] * m[j] * torque;
50  SPH_ASSERT(isReal(domega[i]));
51 
52  if (Symmetrize) {
53  domega[j] += m[j] / I[j] * m[i] * torque;
54  SPH_ASSERT(isReal(domega[j]));
55  }
56  }
57 };
58 
59 template <QuantityId Id, typename TDerived>
60 class RotationStrengthVelocityTemplate : public SymmetricDerivative {
61 protected:
62  ArrayView<const Float> rho, m;
63  ArrayView<const Vector> r, omega;
64  ArrayView<const Size> flag;
65  ArrayView<const Float> reduce;
66  ArrayView<SymmetricTensor> gradv;
67 
68  bool useCorrectionTensor;
69  ArrayView<const SymmetricTensor> C;
70 
71 public:
72  explicit RotationStrengthVelocityTemplate(const RunSettings& settings) {
73  useCorrectionTensor = settings.get<bool>(RunSettingsId::SPH_STRAIN_RATE_CORRECTION_TENSOR);
74  }
75 
76  virtual void create(Accumulated& results) override {
77  results.insert<SymmetricTensor>(Id, OrderEnum::ZERO);
78  }
79 
80  virtual void initialize(const Storage& input, Accumulated& results) override {
81  tie(rho, m) = input.getValues<Float>(QuantityId::DENSITY, QuantityId::MASS);
82  tie(r, omega) = input.getValues<Vector>(QuantityId::POSITION, QuantityId::ANGULAR_VELOCITY);
83  flag = input.getValue<Size>(QuantityId::FLAG);
84  reduce = input.getValue<Float>(QuantityId::STRESS_REDUCING);
85 
86  gradv = results.getBuffer<SymmetricTensor>(Id, OrderEnum::ZERO);
87  if (useCorrectionTensor) {
88  // RotationStrengthVelocityGradient can only be used with StrengthVelocityGradient, that computes
89  // the correction tensor and saves it to the accumulated buffer. We don't compute it here, it must
90  // be already computed.
91  C = results.getBuffer<SymmetricTensor>(
92  QuantityId::STRAIN_RATE_CORRECTION_TENSOR, OrderEnum::ZERO);
93  }
94  }
95 
96  virtual void evalNeighs(const Size idx,
97  ArrayView<const Size> neighs,
98  ArrayView<const Vector> grads) override {
99  SPH_ASSERT(neighs.size() == grads.size());
100  if (useCorrectionTensor) {
101  for (Size k = 0; k < neighs.size(); ++k) {
102  SPH_ASSERT(C[idx] != SymmetricTensor::null()); // check that it has been computed
103  static_cast<TDerived*>(this)->template eval<false>(idx, neighs[k], C[idx] * grads[k]);
104  }
105  } else {
106  for (Size k = 0; k < neighs.size(); ++k) {
107  static_cast<TDerived*>(this)->template eval<false>(idx, neighs[k], grads[k]);
108  }
109  }
110  }
111 
112  virtual void evalSymmetric(const Size idx,
113  ArrayView<const Size> neighs,
114  ArrayView<const Vector> grads) override {
115  SPH_ASSERT(neighs.size() == grads.size());
116  SPH_ASSERT(!useCorrectionTensor);
117  for (Size k = 0; k < neighs.size(); ++k) {
118  static_cast<TDerived*>(this)->template eval<true>(idx, neighs[k], grads[k]);
119  }
120  }
121 };
122 
123 class RotationStrengthVelocityGradient
124  : public RotationStrengthVelocityTemplate<QuantityId::STRENGTH_VELOCITY_GRADIENT,
125  RotationStrengthVelocityGradient> {
126 public:
127  using RotationStrengthVelocityTemplate<QuantityId::STRENGTH_VELOCITY_GRADIENT,
128  RotationStrengthVelocityGradient>::RotationStrengthVelocityTemplate;
129 
130  template <bool Symmetrize>
131  INLINE void eval(const Size i, const Size j, const Vector& grad) {
132  // Here we modify the velocity gradient ONLY if particles interact. Equation using the velocity
133  // gradient shall use it only if the particles have nonzero reduction factor, otherwise use simple
134  // velocity divergence (see ContinuityEquation for example).
135  if (!interacts(i, j, flag, reduce)) {
136  return;
137  }
138  const Vector dr = r[j] - r[i];
139  const Vector dvj = cross(omega[j], dr);
140  const SymmetricTensor tj = outer(dvj, grad);
141  SPH_ASSERT(isReal(tj));
142  gradv[i] -= m[j] / rho[j] * tj;
143  if (Symmetrize) {
144  const Vector dvi = cross(omega[i], dr);
145  const SymmetricTensor ti = outer(dvi, grad);
146  gradv[j] -= m[i] / rho[i] * ti;
147  }
148  }
149 };
150 
151 class RotationVelocityGradient : public RotationTemplate<QuantityId::STRENGTH_DENSITY_VELOCITY_GRADIENT,
152  RotationStrengthDensityVelocityGradient> {
153 public:
154  using RotationStrengthVelocityTemplate<QuantityId::STRENGTH_DENSITY_VELOCITY_GRADIENT,
155  RotationStrengthDensityVelocityGradient>::RotationStrengthVelocityTemplate;
156 
157  template <bool Symmetrize>
158  INLINE void eval(const Size i, const Size j, const Vector& grad) {
159  if (flag[i] != flag[j] || reduce[i] == 0._f || reduce[j] == 0._f) {
160  return;
161  }
162  const Vector dr = r[j] - r[i];
163  const Vector dvj = cross(omega[j], dr);
164  const SymmetricTensor tj = outer(dvj, grad);
165  SPH_ASSERT(isReal(tj));
166  gradv[i] -= m[j] * tj;
167  if (Symmetrize) {
168  const Vector dvi = cross(omega[i], dr);
169  const SymmetricTensor ti = outer(dvi, grad);
170  gradv[j] -= m[i] * ti;
171  }
172  }
173 };
174 
175 BenzAsphaugSph::SolidStressTorque::SolidStressTorque(const RunSettings& settings) {
176  const KernelEnum kernel = settings.get<KernelEnum>(RunSettingsId::SPH_KERNEL);
177  switch (kernel) {
178  case KernelEnum::CUBIC_SPLINE:
179  inertia = 0.6_f;
180  break;
181  default:
182  NOT_IMPLEMENTED;
183  }
184 
185  evolveAngle = settings.get<bool>(RunSettingsId::SPH_PHASE_ANGLE);
186 }
187 
188 void BenzAsphaugSph::SolidStressTorque::setDerivatives(DerivativeHolder& derivatives,
189  const RunSettings& settings) {
190  struct Term {
191  INLINE static TracelessTensor term(ArrayView<const TracelessTensor> s,
192  ArrayView<const Float> rho,
193  const Size i,
194  const Size j) {
195  return BenzAsphaugSph::SolidStressForce::forceTerm(s, rho, i, j);
196  }
197  };
198  derivatives.require<RotationStressDivergence<Term>>(settings);
199 
200  // this derivative is never actually used by the equation term, but it accumulates additional
201  // values to the velocity gradient, used by other terms in the SPH formulation.
202  derivatives.require<RotationStrengthVelocityGradient>(settings);
203 }
204 
205 void BenzAsphaugSph::SolidStressTorque::initialize(Storage& storage) {
206  ArrayView<const Vector> r = storage.getValue<Vector>(QuantityId::POSITION);
207  ArrayView<const Float> m = storage.getValue<Float>(QuantityId::MASS);
208  ArrayView<Float> I = storage.getValue<Float>(QuantityId::MOMENT_OF_INERTIA);
209  for (Size i = 0; i < r.size(); ++i) {
210  I[i] = inertia * m[i] * sqr(r[i][H]);
211  SPH_ASSERT(isReal(I[i]) && I[i] > EPS);
212  }
213 }
214 
215 void BenzAsphaugSph::SolidStressTorque::finalize(Storage& storage) {
216  if (evolveAngle) {
217  // copy angular velocity into the phase angle derivative (they are separate quantities)
218  ArrayView<Vector> dphi = storage.getDt<Vector>(QuantityId::PHASE_ANGLE);
219  ArrayView<Vector> omega = storage.getValue<Vector>(QuantityId::ANGULAR_VELOCITY);
220  for (Size i = 0; i < omega.size(); ++i) {
221  dphi[i] = omega[i];
222  SPH_ASSERT(maxElement(abs(omega[i])) < 1.e6_f, omega[i]);
223  }
224  }
225 }
226 
227 void BenzAsphaugSph::SolidStressTorque::create(Storage& storage, IMaterial& material) const {
228  // although we should evolve phase angle as second-order quantity rather than angular velocity, the
229  // SPH particles are spherically symmetric, so there is no point of doing that
230  storage.insert<Vector>(QuantityId::ANGULAR_VELOCITY, OrderEnum::FIRST, Vector(0._f));
231 
232  // let the angular velocity be unbounded and not affecting timestepping
233  material.setRange(QuantityId::ANGULAR_VELOCITY, Interval::unbounded(), LARGE);
234 
235  // if needed (for testing purposes), evolve phase angle as a separate first order quantity; this is a
236  // waste of one buffer as we need to copy angular velocities between quantities, but it makes no sense
237  // to use in final runs anyway.
238  if (evolveAngle) {
239  storage.insert<Vector>(QuantityId::PHASE_ANGLE, OrderEnum::FIRST, Vector(0._f));
240  material.setRange(QuantityId::PHASE_ANGLE, Interval::unbounded(), LARGE);
241  }
242 
243  // we can set it to zero here, it will be overwritten in \ref initialize anyway
244  storage.insert<Float>(QuantityId::MOMENT_OF_INERTIA, OrderEnum::ZERO, 0._f);
245 }
246 
247 void StandardSph::SolidStressTorque::setDerivatives(DerivativeHolder& derivatives,
248  const RunSettings& settings) {
249  struct Term {
250  INLINE static TracelessTensor term(ArrayView<const TracelessTensor> s,
251  ArrayView<const Float> rho,
252  const Size i,
253  const Size j) {
254  // namespace specified for clarity
255  return StandardSph::SolidStressForce::forceTerm(s, rho, i, j);
256  }
257  };
258  derivatives.require<RotationStressDivergence<Term>>(settings);
259  derivatives.require<RotationStrengthDensityVelocityGradient>(settings);
260 }*/
261 
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
#define NAMESPACE_SPH_END
Definition: Object.h:12