Linear Contact Bond Model Implementation
See this file for the documentation of this contact model.
contactmodellinearcbond.h
1#pragma once
2// contactmodellinearcbond.h
3
4#include "contactmodel/src/contactmodelmechanical.h"
5
6#ifdef LINEARCBOND_LIB
7# define LINEARCBOND_EXPORT EXPORT_TAG
8#elif defined(NO_MODEL_IMPORT)
9# define LINEARCBOND_EXPORT
10#else
11# define LINEARCBOND_EXPORT IMPORT_TAG
12#endif
13
14namespace cmodelsxd {
15 using namespace itasca;
16
17 class ContactModelLinearCBond : public ContactModelMechanical {
18 public:
19 LINEARCBOND_EXPORT ContactModelLinearCBond();
20 LINEARCBOND_EXPORT virtual ~ContactModelLinearCBond();
21 void copy(const ContactModel *c) override;
22 void archive(ArchiveStream &) override;
23
24 QString getName() const override { return "linearcbond"; }
25 void setIndex(int i) override { index_=i;}
26 int getIndex() const override {return index_;}
27
28 enum PropertyKeys {
29 kwKn=1
30 , kwKs
31 , kwFric
32 , kwLinF
33 , kwLinS
34 , kwLinMode
35 , kwRGap
36 , kwEmod
37 , kwKRatio
38 , kwDpNRatio
39 , kwDpSRatio
40 , kwDpMode
41 , kwDpF
42 , kwCbState
43 , kwCbTenF
44 , kwCbShearF
45 , kwCbTStr
46 , kwCbSStr
47 , kwUserArea
48 };
49
50 QString getProperties() const override {
51 return "kn"
52 ",ks"
53 ",fric"
54 ",lin_force"
55 ",lin_slip"
56 ",lin_mode"
57 ",rgap"
58 ",emod"
59 ",kratio"
60 ",dp_nratio"
61 ",dp_sratio"
62 ",dp_mode"
63 ",dp_force"
64 ",cb_state"
65 ",cb_tenf"
66 ",cb_shearf"
67 ",cb_tens"
68 ",cb_shears"
69 ",user_area";
70 }
71
72 enum EnergyKeys { kwEStrain=1,kwESlip,kwEDashpot};
73 QString getEnergies() const override { return "energy-strain,energy-slip,energy-dashpot";}
74 double getEnergy(uint32 i) const override; // Base 1
75 bool getEnergyAccumulate(uint32 i) const override; // Base 1
76 void setEnergy(uint32 i,const double &d) override; // Base 1
77 void activateEnergy() override { if (energies_) return; energies_ = NEWC(Energies());}
78 bool getEnergyActivated() const override {return (energies_ !=0);}
79
80 enum FishCallEvents {fActivated=0,fBondBreak, fSlipChange };
81 QString getFishCallEvents() const override { return "contact_activated,bond_break,slip_change"; }
82 QVariant getProperty(uint32 i,const IContact *) const override;
83 bool getPropertyGlobal(uint32 i) const override;
84 bool setProperty(uint32 i,const QVariant &v,IContact *) override;
85 bool getPropertyReadOnly(uint32 i) const override;
86
87 bool supportsInheritance(uint32 i) const override;
88 bool getInheritance(uint32 i) const override { assert(i<32); uint32 mask = to<uint32>(1 << i); return (inheritanceField_ & mask) ? true : false; }
89 void setInheritance(uint32 i,bool b) override { assert(i<32); uint32 mask = to<uint32>(1 << i); if (b) inheritanceField_ |= mask; else inheritanceField_ &= ~mask; }
90
91 enum MethodKeys {
92 kwDeformability=1
93 , kwCbBond
94 , kwCbStrength
95 , kwCbUnbond
96 , kwArea
97 };
98
99 QString getMethods() const override {
100 return "deformability"
101 ",bond"
102 ",cb_strength"
103 ",unbond"
104 ",area";
105 }
106
107 QString getMethodArguments(uint32 i) const override;
108
109 bool setMethod(uint32 i,const QVector<QVariant> &vl,IContact *con=0) override; // Base 1 - returns true if timestep contributions need to be updated
110
111 uint32 getMinorVersion() const override;
112
113 bool validate(ContactModelMechanicalState *state,const double ×tep) override;
114 bool endPropertyUpdated(const QString &name,const IContactMechanical *c) override;
115 bool forceDisplacementLaw(ContactModelMechanicalState *state,const double ×tep) override;
116 DVect2 getEffectiveTranslationalStiffness() const override { DVect2 ret = effectiveTranslationalStiffness_; return ret;}
117 bool thermalCoupling(ContactModelMechanicalState*, ContactModelThermalState*, IContactThermal*, const double&) override;
118
119 DAVect getEffectiveRotationalStiffness() const override { return DAVect(0.0);}
120
121 ContactModelLinearCBond *clone() const override { return NEWC(ContactModelLinearCBond()); }
122 double getActivityDistance() const override {return rgap_;}
123 bool isOKToDelete() const override { return !isBonded(); }
124 void resetForcesAndMoments() override { lin_F(DVect(0.0)); dp_F(DVect(0.0)); if (energies_) energies_->estrain_ = 0.0; }
125 void setForce(const DVect &v,IContact *c) override;
126 void setArea(const double &d) override { userArea_ = d; }
127 double getArea() const override { return userArea_; }
128
129 bool checkActivity(const double &gap) override { return (gap <= rgap_ || isBonded()); }
130
131 bool isSliding() const override { return lin_S_; }
132 bool isBonded() const override { return (cb_state_==3); }
133 void unbond() override { cb_state_ = 0; }
134 void propagateStateInformation(IContactModelMechanical* oldCm,const CAxes &oldSystem=CAxes(),const CAxes &newSystem=CAxes()) override;
135 void setNonForcePropsFrom(IContactModel *oldCM) override;
136 /// Return the total force that the contact model holds.
137 DVect getForce(const IContactMechanical*) const override;
138 /// Return the total moment on 1 that the contact model holds
139 DAVect getMomentOn1(const IContactMechanical*) const override;
140 /// Return the total moment on 1 that the contact model holds
141 DAVect getMomentOn2(const IContactMechanical*) const override;
142
143 const double & kn() const {return kn_;}
144 void kn(const double &d) {kn_=d;}
145 const double & ks() const {return ks_;}
146 void ks(const double &d) {ks_=d;}
147 const double & fric() const {return fric_;}
148 void fric(const double &d) {fric_=d;}
149 const DVect & lin_F() const {return lin_F_;}
150 void lin_F(const DVect &f) { lin_F_=f;}
151 bool lin_S() const {return lin_S_;}
152 void lin_S(bool b) { lin_S_=b;}
153 uint32 lin_mode() const {return lin_mode_;}
154 void lin_mode(uint32 i) { lin_mode_=i;}
155 const double & rgap() const {return rgap_;}
156 void rgap(const double &d) {rgap_=d;}
157 uint32 cb_state() const {return cb_state_;}
158 void cb_state(uint32 b) { cb_state_=b;}
159 const double & cb_tenF() const {return cb_tenF_;}
160 void cb_tenF(const double &d) {cb_tenF_=d;}
161 const double & cb_shearF() const {return cb_shearF_;}
162 void cb_shearF(const double &d) {cb_shearF_=d;}
163
164 bool hasDamping() const {return dpProps_ ? true : false;}
165 double dp_nratio() const {return (hasDamping() ? (dpProps_->dp_nratio_) : 0.0);}
166 void dp_nratio(const double &d) { if(!hasDamping()) return; dpProps_->dp_nratio_=d;}
167 double dp_sratio() const {return hasDamping() ? dpProps_->dp_sratio_: 0.0;}
168 void dp_sratio(const double &d) { if(!hasDamping()) return; dpProps_->dp_sratio_=d;}
169 int dp_mode() const {return hasDamping() ? dpProps_->dp_mode_: -1;}
170 void dp_mode(int i) { if(!hasDamping()) return; dpProps_->dp_mode_=i;}
171 DVect dp_F() const {return hasDamping() ? dpProps_->dp_F_: DVect(0.0);}
172 void dp_F(const DVect &f) { if(!hasDamping()) return; dpProps_->dp_F_=f;}
173
174 bool hasEnergies() const {return energies_ ? true:false;}
175 double estrain() const {return hasEnergies() ? energies_->estrain_: 0.0;}
176 void estrain(const double &d) { if(!hasEnergies()) return; energies_->estrain_=d;}
177 double eslip() const {return hasEnergies() ? energies_->eslip_: 0.0;}
178 void eslip(const double &d) { if(!hasEnergies()) return; energies_->eslip_=d;}
179 double edashpot() const {return hasEnergies() ? energies_->edashpot_: 0.0;}
180 void edashpot(const double &d) { if(!hasEnergies()) return; energies_->edashpot_=d;}
181
182 uint32 inheritanceField() const {return inheritanceField_;}
183 void inheritanceField(uint32 i) {inheritanceField_ = i;}
184
185 const DVect2 & effectiveTranslationalStiffness() const {return effectiveTranslationalStiffness_;}
186 void effectiveTranslationalStiffness(const DVect2 &v ) {effectiveTranslationalStiffness_=v;}
187
188 private:
189 static int index_;
190
191 struct Energies {
192 Energies() : estrain_(0.0), eslip_(0.0),edashpot_(0.0) {}
193 double estrain_; // elastic energy stored in contact
194 double eslip_; // work dissipated by friction
195 double edashpot_; // work dissipated by dashpots
196 };
197
198 struct dpProps {
199 dpProps() : dp_nratio_(0.0), dp_sratio_(0.0), dp_mode_(0), dp_F_(DVect(0.0)) {}
200 double dp_nratio_; // normal viscous critical damping ratio
201 double dp_sratio_; // shear viscous critical damping ratio
202 int dp_mode_; // for viscous mode (0-4) 0 = dashpots, 1 = tensile limit, 2 = shear limit, 3 = limit both
203 DVect dp_F_; // Force in the dashpots
204 };
205
206 bool updateKn(const IContactMechanical *con);
207 bool updateKs(const IContactMechanical *con);
208 bool updateFric(const IContactMechanical *con);
209
210 void updateEffectiveStiffness(ContactModelMechanicalState *state);
211
212 void setDampCoefficients(const double &mass,double *vcn,double *vcs);
213
214 // inheritance fields
215 uint32 inheritanceField_;
216
217 // linear model
218 double kn_; // normal stiffness
219 double ks_; // shear stiffness
220 double fric_; // Coulomb friction coefficient
221 DVect lin_F_; // Force carried in the linear model
222 bool lin_S_; // current slip state
223 uint32 lin_mode_; // specifies incremental or absolute for the the linear part
224 double rgap_; // reference gap
225
226 uint32 cb_state_; // Bond state - 0 (NBNF), 1 (NBFT), 2 (NBFS), 3 (B)
227 double cb_tenF_;
228 double cb_shearF_;
229
230 dpProps * dpProps_; // The viscous properties
231
232 double userArea_; // Area as specified by the user
233
234 Energies * energies_; // energies
235
236 DVect2 effectiveTranslationalStiffness_;
237
238 };
239} // namespace itascaxd
240// EoF
contactmodellinearcbond.cpp
1// contactmodellinearcbond.cpp
2#include "contactmodellinearcbond.h"
3
4#include "../version.txt"
5#include "contactmodel/src/contactmodelthermal.h"
6#include "fish/src/parameter.h"
7#include "utility/src/tptr.h"
8#include "shared/src/mathutil.h"
9#include "base/src/basetoqt.h"
10
11#include "kernel/interface/iprogram.h"
12#include "module/interface/icontact.h"
13#include "module/interface/icontactmechanical.h"
14#include "module/interface/icontactthermal.h"
15#include "module/interface/ifishcalllist.h"
16#include "module/interface/ipiece.h"
17#include "module/interface/ipiecemechanical.h"
18
19
20
21
22#ifdef LINEARCBOND_LIB
23#ifdef _WIN32
24 int __stdcall DllMain(void *,unsigned, void *)
25 {
26 return 1;
27 }
28#endif
29
30 extern "C" EXPORT_TAG const char *getName()
31 {
32#if DIM==3
33 return "contactmodelmechanical3dlinearcbond";
34#else
35 return "contactmodelmechanical2dlinearcbond";
36#endif
37 }
38
39 extern "C" EXPORT_TAG unsigned getMajorVersion()
40 {
41 return MAJOR_VRESION;
42 }
43
44 extern "C" EXPORT_TAG unsigned getMinorVersion()
45 {
46 return MINOR_VERSION;
47 }
48
49 extern "C" EXPORT_TAG void *createInstance()
50 {
51 cmodelsxd::ContactModelLinearCBond *m = NEWC(cmodelsxd::ContactModelLinearCBond());
52 return (void *)m;
53 }
54#endif // LINEARCBOND_EXPORTS
55
56namespace cmodelsxd {
57 static const uint32 linKnMask = 0x00002; // Base 1!
58 static const uint32 linKsMask = 0x00004;
59 static const uint32 linFricMask = 0x00008;
60
61 using namespace itasca;
62
63 int ContactModelLinearCBond::index_ = -1;
64 uint32 ContactModelLinearCBond::getMinorVersion() const { return MINOR_VERSION;}
65
66 ContactModelLinearCBond::ContactModelLinearCBond() : inheritanceField_(linKnMask|linKsMask|linFricMask)
67 , kn_(0.0)
68 , ks_(0.0)
69 , fric_(0.0)
70 , lin_F_(DVect(0.0))
71 , lin_S_(false)
72 , lin_mode_(0)
73 , rgap_(0.0)
74 , cb_state_(0)
75 , cb_tenF_(0.0)
76 , cb_shearF_(0.0)
77 , dpProps_(0)
78 , userArea_(0)
79 , energies_(0)
80 , effectiveTranslationalStiffness_(DVect2(0.0)) {
81// setFromParent(ContactModelMechanicalList::instance()->find(getName()));
82 }
83
84 ContactModelLinearCBond::~ContactModelLinearCBond() {
85 if (dpProps_)
86 delete dpProps_;
87 if (energies_)
88 delete energies_;
89 }
90
91 void ContactModelLinearCBond::archive(ArchiveStream &stream) {
92 stream & kn_;
93 stream & ks_;
94 stream & fric_;
95 stream & lin_F_;
96 stream & lin_S_;
97 stream & lin_mode_;
98 stream & cb_state_;
99 stream & cb_tenF_;
100 stream & cb_shearF_;
101
102 if (stream.getArchiveState()==ArchiveStream::Save) {
103 bool b = false;
104 if (dpProps_) {
105 b = true;
106 stream & b;
107 stream & dpProps_->dp_nratio_;
108 stream & dpProps_->dp_sratio_;
109 stream & dpProps_->dp_mode_;
110 stream & dpProps_->dp_F_;
111 }
112 else
113 stream & b;
114
115 b = false;
116 if (energies_) {
117 b = true;
118 stream & b;
119 stream & energies_->estrain_;
120 stream & energies_->eslip_;
121 stream & energies_->edashpot_;
122 }
123 else
124 stream & b;
125 } else {
126 bool b(false);
127 stream & b;
128 if (b) {
129 if (!dpProps_)
130 dpProps_ = NEWC(dpProps());
131 stream & dpProps_->dp_nratio_;
132 stream & dpProps_->dp_sratio_;
133 stream & dpProps_->dp_mode_;
134 stream & dpProps_->dp_F_;
135 }
136 stream & b;
137 if (b) {
138 if (!energies_)
139 energies_ = NEWC(Energies());
140 stream & energies_->estrain_;
141 stream & energies_->eslip_;
142 stream & energies_->edashpot_;
143 }
144 }
145
146 stream & inheritanceField_;
147 stream & effectiveTranslationalStiffness_;
148
149 if (stream.getArchiveState()==ArchiveStream::Save || stream.getRestoreVersion() == getMinorVersion())
150 stream & rgap_;
151
152 if (stream.getArchiveState() == ArchiveStream::Save || stream.getRestoreVersion() > 2)
153 stream & userArea_;
154 }
155
156 void ContactModelLinearCBond::copy(const ContactModel *cm) {
157 ContactModelMechanical::copy(cm);
158 const ContactModelLinearCBond *in = dynamic_cast<const ContactModelLinearCBond*>(cm);
159 if (!in) throw std::runtime_error("Internal error: contact model dynamic cast failed.");
160 kn(in->kn());
161 ks(in->ks());
162 fric(in->fric());
163 lin_F(in->lin_F());
164 lin_S(in->lin_S());
165 lin_mode(in->lin_mode());
166 rgap(in->rgap());
167 cb_state(in->cb_state());
168 cb_tenF(in->cb_tenF());
169 cb_shearF(in->cb_shearF());
170 if (in->hasDamping()) {
171 if (!dpProps_)
172 dpProps_ = NEWC(dpProps());
173 dp_nratio(in->dp_nratio());
174 dp_sratio(in->dp_sratio());
175 dp_mode(in->dp_mode());
176 dp_F(in->dp_F());
177 }
178 if (in->hasEnergies()) {
179 if (!energies_)
180 energies_ = NEWC(Energies());
181 estrain(in->estrain());
182 eslip(in->eslip());
183 edashpot(in->edashpot());
184 }
185 userArea_ = in->userArea_;
186 inheritanceField(in->inheritanceField());
187 effectiveTranslationalStiffness(in->effectiveTranslationalStiffness());
188 }
189
190 QVariant ContactModelLinearCBond::getProperty(uint32 i,const IContact *con) const {
191 QVariant var;
192 bool nstr = false;
193 switch (i) {
194 case kwKn: return kn_;
195 case kwKs: return ks_;
196 case kwFric: return fric_;
197 case kwLinF: var.setValue(lin_F_); return var;
198 case kwLinS: return lin_S_;
199 case kwLinMode: return lin_mode_;
200 case kwRGap: return rgap_;
201 case kwEmod: {
202 const IContactMechanical *c(convert_getcast<IContactMechanical>(con));
203 if (c ==nullptr) return 0.0;
204 double rsq(std::max(c->getEnd1Curvature().y(),c->getEnd2Curvature().y()));
205 double rsum(0.0);
206 if (c->getEnd1Curvature().y())
207 rsum += 1.0/c->getEnd1Curvature().y();
208 if (c->getEnd2Curvature().y())
209 rsum += 1.0/c->getEnd2Curvature().y();
210 if (userArea_) {
211#ifdef THREED
212 rsq = std::sqrt(userArea_ / dPi);
213#else
214 rsq = userArea_ / 2.0;
215#endif
216 rsum = rsq + rsq;
217 rsq = 1. / rsq;
218 }
219#ifdef TWOD
220 return (kn_ * rsum * rsq / 2.0);
221#else
222 return (kn_ * rsum * rsq * rsq) / dPi;
223#endif
224 }
225 case kwKRatio: return (ks_ == 0.0) ? 0.0 : (kn_/ks_);
226 case kwDpNRatio: return dpProps_ ? dpProps_->dp_nratio_ : 0;
227 case kwDpSRatio: return dpProps_ ? dpProps_->dp_sratio_ : 0;
228 case kwDpMode: return dpProps_ ? dpProps_->dp_mode_ : 0;
229 case kwDpF: {
230 dpProps_ ? var.setValue(dpProps_->dp_F_) : var.setValue(DVect(0.0));
231 return var;
232 }
233 case kwCbState: return cb_state_;
234 case kwCbTenF: return cb_tenF_;
235 case kwCbShearF: return cb_shearF_;
236 case kwCbTStr: nstr = true;
237 [[fallthrough]];
238 case kwCbSStr: {
239 const IContactMechanical *c(convert_getcast<IContactMechanical>(con));
240 if (c ==nullptr) return 0.0;
241 double tmp(std::max(c->getEnd1Curvature().y(),c->getEnd2Curvature().y()));
242 if (userArea_) {
243#ifdef THREED
244 tmp = std::sqrt(userArea_ / dPi);
245#else
246 tmp = userArea_ / 2.0;
247#endif
248 tmp = 1. / tmp;
249 }
250 if (nstr) {
251#ifdef TWOD
252 return (cb_tenF_ * tmp / 2.0);
253#else
254 return (cb_tenF_ * tmp * tmp / dPi);
255#endif
256 } else {
257#ifdef TWOD
258 return (cb_shearF_ * tmp / 2.0);
259#else
260 return (cb_shearF_ * tmp * tmp / dPi);
261#endif
262 }
263 }
264 case kwUserArea: return userArea_;
265 }
266 assert(0);
267 return QVariant();
268 }
269
270 bool ContactModelLinearCBond::getPropertyGlobal(uint32 i) const {
271 switch (i) {
272 case kwLinF:
273 case kwDpF:
274 return false;
275 }
276 return true;
277 }
278
279 bool ContactModelLinearCBond::setProperty(uint32 i,const QVariant &v,IContact *) {
280 dpProps dp;
281 switch (i) {
282 case kwKn: {
283 if (!v.canConvert<double>())
284 throw Exception("kn must be a double.");
285 double val(v.toDouble());
286 if (val<0.0)
287 throw Exception("Negative kn not allowed.");
288 kn_ = val;
289 return true;
290 }
291 case kwKs: {
292 if (!v.canConvert<double>())
293 throw Exception("ks must be a double.");
294 double val(v.toDouble());
295 if (val<0.0)
296 throw Exception("Negative ks not allowed.");
297 ks_ = val;
298 return true;
299 }
300 case kwFric: {
301 if (!v.canConvert<double>())
302 throw Exception("fric must be a double.");
303 double val(v.toDouble());
304 if (val<0.0)
305 throw Exception("Negative fric not allowed.");
306 fric_ = val;
307 return false;
308 }
309 case kwCbTenF: {
310 if (!v.canConvert<double>())
311 throw Exception("cb_tenf must be a double.");
312 double val(v.toDouble());
313 if (val<0.0)
314 throw Exception("Negative cb_tenf not allowed.");
315 cb_tenF_ = val;
316 return false;
317 }
318 case kwCbShearF: {
319 if (!v.canConvert<double>())
320 throw Exception("cb_shearf must be a double.");
321 double val(v.toDouble());
322 if (val<0.0)
323 throw Exception("Negative cb_shearf not allowed.");
324 cb_shearF_ = val;
325 return false;
326 }
327 case kwLinF: {
328 if (!v.canConvert<DVect>())
329 throw Exception("lin_force must be a vector.");
330 DVect val(v.value<DVect>());
331 lin_F_ = val;
332 return false;
333 }
334 case kwLinMode: {
335 if (!v.canConvert<uint32>())
336 throw Exception("lin_mode must be 0 (absolute) or 1 (incremental).");
337 uint32 val(v.toUInt());
338 if (val>1)
339 throw Exception("lin_mode must be 0 (absolute) or 1 (incremental).");
340 lin_mode_ = val;
341 return false;
342 }
343 case kwRGap: {
344 if (!v.canConvert<double>())
345 throw Exception("Reference gap must be a double.");
346 double val(v.toDouble());
347 rgap_ = val;
348 return false;
349 }
350 case kwDpNRatio: {
351 if (!v.canConvert<double>())
352 throw Exception("dp_nratio must be a double.");
353 double val(v.toDouble());
354 if (val<0.0)
355 throw Exception("Negative dp_nratio not allowed.");
356 if (val == 0.0 && !dpProps_)
357 return false;
358 if (!dpProps_)
359 dpProps_ = NEWC(dpProps());
360 dpProps_->dp_nratio_ = val;
361 return true;
362 }
363 case kwDpSRatio: {
364 if (!v.canConvert<double>())
365 throw Exception("dp_sratio must be a double.");
366 double val(v.toDouble());
367 if (val<0.0)
368 throw Exception("Negative dp_sratio not allowed.");
369 if (val == 0.0 && !dpProps_)
370 return false;
371 if (!dpProps_)
372 dpProps_ = NEWC(dpProps());
373 dpProps_->dp_sratio_ = val;
374 return true;
375 }
376 case kwDpMode: {
377 if (!v.canConvert<int>())
378 throw Exception("The viscous mode dp_mode must be 0, 1, 2, or 3.");
379 int val(v.toInt());
380 if (val == 0 && !dpProps_)
381 return false;
382 if (val < 0 || val > 3)
383 throw Exception("The dashpot mode dp_mode must be 0, 1, 2, or 3.");
384 if (!dpProps_)
385 dpProps_ = NEWC(dpProps());
386 dpProps_->dp_mode_ = val;
387 return false;
388 }
389 case kwDpF: {
390 if (!v.canConvert<DVect>())
391 throw Exception("dp_force must be a vector.");
392 DVect val(v.value<DVect>());
393 if (val.fsum() == 0.0 && !dpProps_)
394 return false;
395 if (!dpProps_)
396 dpProps_ = NEWC(dpProps());
397 dpProps_->dp_F_ = val;
398 return false;
399 }
400 case kwUserArea: {
401 if (!v.canConvert<double>())
402 throw Exception("user_area must be a double.");
403 double val(v.toDouble());
404 if (val < 0.0)
405 throw Exception("Negative user_area not allowed.");
406 userArea_ = val;
407 return true;
408 }
409 }
410 return false;
411 }
412
413 bool ContactModelLinearCBond::getPropertyReadOnly(uint32 i) const {
414 switch (i) {
415 case kwDpF:
416 case kwLinS:
417 case kwEmod:
418 case kwKRatio:
419 case kwCbState:
420 case kwCbTStr:
421 case kwCbSStr:
422 return true;
423 default:
424 break;
425 }
426 return false;
427 }
428
429 bool ContactModelLinearCBond::supportsInheritance(uint32 i) const {
430 switch (i) {
431 case kwKn:
432 case kwKs:
433 case kwFric:
434 return true;
435 default:
436 break;
437 }
438 return false;
439 }
440
441 QString ContactModelLinearCBond::getMethodArguments(uint32 i) const {
442 switch (i) {
443 case kwCbBond:
444 return "gap";
445 case kwDeformability:
446 return "emod,kratio";
447 case kwCbStrength:
448 return "tensile,shear";
449 case kwCbUnbond:
450 return "gap";
451 case kwArea:
452 return QString();
453 }
454 assert(0);
455 return "";
456 }
457
458 bool ContactModelLinearCBond::setMethod(uint32 i,const QVector<QVariant> &vl,IContact *con) {
459 IContactMechanical *c(convert_getcast<IContactMechanical>(con));
460 switch (i) {
461 case kwCbBond: {
462 if (cb_state_ == 3) return false;
463 double mingap = -1.0 * limits<double>::max();
464 double maxgap = 0;
465 if (vl.at(0).canConvert<double>())
466 maxgap = vl.at(0).toDouble();
467 else if (vl.at(0).canConvert<DVect2>()) {
468 DVect2 value = vl.at(0).value<DVect2>();
469 mingap = value.minComp();
470 maxgap = value.maxComp();
471 } else if (!vl.at(0).isNull())
472 throw Exception("gap value %1 not recognized in method bond in contact model %2.",vl.at(0),getName());
473
474 double gap = c->getGap();
475 if ( gap >= mingap && gap <= maxgap)
476 cb_state_ = 3;
477 return false;
478 }
479 case kwCbUnbond: {
480 if (cb_state_ == 0) return false;
481 double mingap = -1.0 * limits<double>::max();
482 double maxgap = 0;
483 if (vl.at(0).canConvert<double>())
484 maxgap = vl.at(0).toDouble();
485 else if (vl.at(0).canConvert<DVect2>()) {
486 DVect2 value = vl.at(0).value<DVect2>();
487 mingap = value.minComp();
488 maxgap = value.maxComp();
489 }
490 else if (!vl.at(0).isNull())
491 throw Exception("gap value %1 not recognized in method unbond in contact model %2.",vl.at(0),getName());
492
493 double gap = c->getGap();
494 if ( gap >= mingap && gap <= maxgap)
495 cb_state_ = 0;
496 return false;
497 }
498 case kwDeformability: {
499 double emod(0.0);
500 double krat(0.0);
501 if (vl.at(0).isNull())
502 throw Exception("Argument emod must be specified with method deformability in contact model %1.",getName());
503 emod = vl.at(0).toDouble();
504 if (emod<0.0)
505 throw Exception("Negative emod not allowed in contact model %1.",getName());
506 if (vl.at(1).isNull())
507 throw Exception("Argument kratio must be specified with method deformability in contact model %1.",getName());
508 krat = vl.at(1).toDouble();
509 if (krat<0.0)
510 throw Exception("Negative linear stiffness ratio not allowed in contact model %1.",getName());
511 double rsq(std::max(c->getEnd1Curvature().y(),c->getEnd2Curvature().y()));
512 double rsum(0.0);
513 if (c->getEnd1Curvature().y())
514 rsum += 1.0/c->getEnd1Curvature().y();
515 if (c->getEnd2Curvature().y())
516 rsum += 1.0/c->getEnd2Curvature().y();
517 if (userArea_) {
518#ifdef THREED
519 rsq = std::sqrt(userArea_ / dPi);
520#else
521 rsq = userArea_ / 2.0;
522#endif
523 rsum = rsq + rsq;
524 rsq = 1. / rsq;
525 }
526#ifdef TWOD
527 kn_ = 2.0 * emod / (rsq * rsum);
528#else
529 kn_ = dPi * emod / (rsq * rsq * rsum);
530#endif
531 ks_ = (krat == 0.0) ? 0.0 : kn_ / krat;
532 setInheritance(1,false);
533 setInheritance(2,false);
534 return true;
535 }
536 case kwCbStrength: {
537 if (cb_state_ != 3) return false;
538 double nval(0.0);
539 double sval(0.0);
540 if (vl.at(0).isNull())
541 throw Exception("tensile value must be specified with method cb_strength in contact model %1.",getName());
542 nval = vl.at(0).toDouble();
543 if (nval<0.0)
544 throw Exception("Negative tensile strength not allowed in contact model %1.",getName());
545 if (vl.at(1).isNull())
546 throw Exception("shear value must be specified with method cb_strength in contact model %1.",getName());
547 sval = vl.at(1).toDouble();
548 if (sval<0.0)
549 throw Exception("Negative shear strength not allowed in contact model %1.",getName());
550 double tmp(std::max(c->getEnd1Curvature().y(),c->getEnd2Curvature().y()));
551 if (userArea_) {
552#ifdef THREED
553 tmp = std::sqrt(userArea_ / dPi);
554#else
555 tmp = userArea_ / 2.0;
556#endif
557 tmp = 1. / tmp;
558 }
559#ifdef TWOD
560 cb_tenF_ = nval * 2.0 / tmp;
561 cb_shearF_ = sval * 2.0 / tmp;
562#else
563 cb_tenF_ = nval * dPi / ( tmp * tmp );
564 cb_shearF_ = sval * dPi / (tmp * tmp);
565#endif
566 return false;
567 }
568 case kwArea: {
569 if (!userArea_) {
570 double rsq(1./std::max(c->getEnd1Curvature().y(),c->getEnd2Curvature().y()));
571#ifdef THREED
572 userArea_ = rsq * rsq * dPi;
573#else
574 userArea_ = rsq * 2.0;
575#endif
576 }
577 return true;
578 }
579
580 }
581 return false;
582 }
583
584 double ContactModelLinearCBond::getEnergy(uint32 i) const {
585 double ret(0.0);
586 if (!energies_)
587 return ret;
588 switch (i) {
589 case kwEStrain: return energies_->estrain_;
590 case kwESlip: return energies_->eslip_;
591 case kwEDashpot: return energies_->edashpot_;
592 }
593 assert(0);
594 return ret;
595 }
596
597 bool ContactModelLinearCBond::getEnergyAccumulate(uint32 i) const {
598 switch (i) {
599 case kwEStrain: return false;
600 case kwESlip: return true;
601 case kwEDashpot: return true;
602 }
603 assert(0);
604 return false;
605 }
606
607 void ContactModelLinearCBond::setEnergy(uint32 i,const double &d) {
608 if (!energies_) return;
609 switch (i) {
610 case kwEStrain: energies_->estrain_ = d; return;
611 case kwESlip: energies_->eslip_ = d; return;
612 case kwEDashpot: energies_->edashpot_= d; return;
613 }
614 assert(0);
615 return;
616 }
617
618 bool ContactModelLinearCBond::validate(ContactModelMechanicalState *state,const double &) {
619 assert(state);
620 const IContactMechanical *c = state->getMechanicalContact();
621 assert(c);
622
623 if (state->trackEnergy_)
624 activateEnergy();
625
626 if (inheritanceField_ & linKnMask)
627 updateKn(c);
628 if (inheritanceField_ & linKsMask)
629 updateKs(c);
630 if (inheritanceField_ & linFricMask)
631 updateFric(c);
632
633 updateEffectiveStiffness(state);
634 return checkActivity(state->gap_);
635 }
636
637 static const QString knstr("kn");
638 bool ContactModelLinearCBond::updateKn(const IContactMechanical *con) {
639 assert(con);
640 QVariant v1 = con->getEnd1()->getProperty(knstr);
641 QVariant v2 = con->getEnd2()->getProperty(knstr);
642 if (!v1.isValid() || !v2.isValid())
643 return false;
644 double kn1 = v1.toDouble();
645 double kn2 = v2.toDouble();
646 double val = kn_;
647 if (kn1 && kn2)
648 kn_ = kn1*kn2/(kn1+kn2);
649 else if (kn1)
650 kn_ = kn1;
651 else if (kn2)
652 kn_ = kn2;
653 return ( (kn_ != val) );
654 }
655
656 static const QString ksstr("ks");
657 bool ContactModelLinearCBond::updateKs(const IContactMechanical *con) {
658 assert(con);
659 QVariant v1 = con->getEnd1()->getProperty(ksstr);
660 QVariant v2 = con->getEnd2()->getProperty(ksstr);
661 if (!v1.isValid() || !v2.isValid())
662 return false;
663 double ks1 = v1.toDouble();
664 double ks2 = v2.toDouble();
665 double val = ks_;
666 if (ks1 && ks2)
667 ks_ = ks1*ks2/(ks1+ks2);
668 else if (ks1)
669 ks_ = ks1;
670 else if (ks2)
671 ks_ = ks2;
672 return ( (ks_ != val) );
673 }
674
675 static const QString fricstr("fric");
676 bool ContactModelLinearCBond::updateFric(const IContactMechanical *con) {
677 assert(con);
678 QVariant v1 = con->getEnd1()->getProperty(fricstr);
679 QVariant v2 = con->getEnd2()->getProperty(fricstr);
680 if (!v1.isValid() || !v2.isValid())
681 return false;
682 double fric1 = std::max(0.0,v1.toDouble());
683 double fric2 = std::max(0.0,v2.toDouble());
684 double val = fric_;
685 fric_ = std::min(fric1,fric2);
686 return ( (fric_ != val) );
687 }
688
689 bool ContactModelLinearCBond::endPropertyUpdated(const QString &name,const IContactMechanical *c) {
690 assert(c);
691 QStringList availableProperties = getProperties().simplified().replace(" ","").split(",",Qt::SkipEmptyParts);
692 QRegularExpression rx(name, QRegularExpression::CaseInsensitiveOption);
693 int idx = availableProperties.indexOf(rx)+1;
694 bool ret=false;
695
696 if (idx<=0)
697 return ret;
698
699 switch(idx) {
700 case kwKn: { //kn
701 if (inheritanceField_ & linKnMask)
702 ret = updateKn(c);
703 break;
704 }
705 case kwKs: { //ks
706 if (inheritanceField_ & linKsMask)
707 ret =updateKs(c);
708 break;
709 }
710 case kwFric: { //fric
711 if (inheritanceField_ & linFricMask)
712 updateFric(c);
713 break;
714 }
715 }
716 return ret;
717 }
718
719 void ContactModelLinearCBond::updateEffectiveStiffness(ContactModelMechanicalState *) {
720 DVect2 ret(kn_,ks_);
721 // correction if viscous damping active
722 if (dpProps_) {
723 DVect2 correct(1.0);
724 if (dpProps_->dp_nratio_)
725 correct.rx() = sqrt(1.0+dpProps_->dp_nratio_*dpProps_->dp_nratio_) - dpProps_->dp_nratio_;
726 if (dpProps_->dp_sratio_)
727 correct.ry() = sqrt(1.0+dpProps_->dp_sratio_*dpProps_->dp_sratio_) - dpProps_->dp_sratio_;
728 ret /= (correct*correct);
729 }
730 effectiveTranslationalStiffness_ = ret;
731 }
732
733 bool ContactModelLinearCBond::forceDisplacementLaw(ContactModelMechanicalState *state,const double ×tep) {
734 assert(state);
735
736 double overlap = rgap_ - state->gap_;
737 DVect trans = state->relativeTranslationalIncrement_;
738 double correction = 1.0;
739
740 if (state->activated()) {
741 if (cmEvents_[fActivated] >= 0) {
742 auto c = state->getContact();
743 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()) };
744 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
745 fi->setCMFishCallArguments(c,arg,cmEvents_[fActivated]);
746 }
747 if (lin_mode_ == 0 && trans.x()) {
748 correction = -1.0*overlap / trans.x();
749 if (correction < 0)
750 correction = 1.0;
751 }
752 }
753
754#ifdef THREED
755 DVect norm(trans.x(),0.0,0.0);
756#else
757 DVect norm(trans.x(),0.0);
758#endif
759 //DAVect ang = state->relativeAngularIncrement_;
760 DVect lin_F_old = lin_F_;
761
762 if (lin_mode_ == 0)
763 lin_F_.rx() = overlap * kn_;
764 else
765 lin_F_.rx() -= correction * norm.x() * kn_;
766
767 DVect u_s = trans;
768 u_s.rx() = 0.0;
769 DVect sforce = lin_F_ - u_s * ks_ * correction;
770 sforce.rx() = 0.0;
771
772 // Resolve failure (contact bonds and friction)
773 if (state->canFail_) {
774 // Resolve contact bond failure - done first so that this way, even if breaks, one can ensure a valid sliding state
775 if (cb_state_ == 3) { // bonded - Note: this means that isSliding is false!
776 if (lin_F_.x() <= -cb_tenF_) {
777 // Broke in tension
778 cb_state_ = 1;
779 if (cmEvents_[fBondBreak] >= 0) {
780 auto c = state->getContact();
781 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
782 fish::Parameter((qint64)cb_state_),
783 fish::Parameter(cb_tenF_) };
784 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
785 fi->setCMFishCallArguments(c,arg,cmEvents_[fBondBreak]);
786 }
787 } else if (sforce.mag() >= cb_shearF_) {
788 // Broke in shear
789 cb_state_ = 2;
790 if (cmEvents_[fBondBreak] >= 0) {
791 auto c = state->getContact();
792 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
793 fish::Parameter((qint64)cb_state_),
794 fish::Parameter(cb_shearF_) };
795 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
796 fi->setCMFishCallArguments(c,arg,cmEvents_[fBondBreak]);
797 }
798 }
799 }
800
801 // 2) Resolve sliding if no contact bond exists
802 if (cb_state_ < 3) {
803 // No contact bond - normal force is positive only
804 lin_F_.rx() = std::max(0.0,lin_F_.x());
805 // No contact bond - sliding can occur
806 double crit = lin_F_.x() * fric_;
807 double sfmag = sforce.mag();
808 if (sfmag > crit) {
809 double rat = crit / sfmag;
810 sforce *= rat;
811 if (!lin_S_ && cmEvents_[fSlipChange] >= 0) {
812 auto c = state->getContact();
813 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
814 fish::Parameter() };
815 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
816 fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
817 }
818 lin_S_ = true;
819 } else {
820 if (lin_S_) {
821 if (cmEvents_[fSlipChange] >= 0) {
822 auto c = state->getContact();
823 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
824 fish::Parameter((qint64)1) };
825 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
826 fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
827 }
828 lin_S_ = false;
829 }
830 }
831 }
832 }
833
834 sforce.rx() = lin_F_.x();
835 lin_F_ = sforce; // total force in linear contact model
836
837 // 3) Account for dashpot forces
838 if (dpProps_) {
839 dpProps_->dp_F_.fill(0.0);
840 double vcn(0.0), vcs(0.0);
841 setDampCoefficients(state->inertialMass_,&vcn,&vcs);
842 // First damp all components
843 dpProps_->dp_F_ = u_s * (-1.0* vcs) / timestep; // shear component
844 dpProps_->dp_F_ -= norm * vcn / timestep; // normal component
845 // Need to change behavior based on the dp_mode
846 if (cb_state_ !=3 && (dpProps_->dp_mode_ == 1 || dpProps_->dp_mode_ == 3)) { // limit the tensile if not bonded
847 if (dpProps_->dp_F_.x() + lin_F_.x() < 0)
848 dpProps_->dp_F_.rx() = - lin_F_.rx();
849 }
850 if (lin_S_ && dpProps_->dp_mode_ > 1) { // limit the shear if not sliding
851 double dfn = dpProps_->dp_F_.rx();
852 dpProps_->dp_F_.fill(0.0);
853 dpProps_->dp_F_.rx() = dfn;
854 }
855 }
856
857 // 5) Compute energies
858 if (state->trackEnergy_) {
859 assert(energies_);
860 energies_->estrain_ = 0.0;
861 if (kn_)
862 energies_->estrain_ = 0.5*lin_F_.x()*lin_F_.x()/kn_;
863 if (ks_) {
864 DVect s = lin_F_;
865 s.rx() = 0.0;
866 double smag2 = s.mag2();
867 energies_->estrain_ += 0.5*smag2 / ks_;
868
869 if (lin_S_) {
870 lin_F_old.rx() = 0.0;
871 DVect avg_F_s = (s + lin_F_old)*0.5;
872 DVect u_s_el = (s - lin_F_old) / ks_;
873 energies_->eslip_ -= std::min(0.0,(avg_F_s | (u_s + u_s_el)));
874 }
875 }
876 if (dpProps_) {
877 energies_->edashpot_ -= dpProps_->dp_F_ | trans;
878 }
879 }
880 assert(lin_F_ == lin_F_);
881 return checkActivity(state->gap_);
882 }
883
884 bool ContactModelLinearCBond::thermalCoupling(ContactModelMechanicalState*, ContactModelThermalState* ts, IContactThermal*, const double&) {
885 // Account for thermal expansion in incremental mode
886 if (lin_mode_ == 0 || ts->gapInc_ == 0.0) return false;
887 DVect finc(0.0);
888 finc.rx() = kn_ * ts->gapInc_;
889 lin_F_ -= finc;
890 return true;
891 }
892
893 void ContactModelLinearCBond::setForce(const DVect &v,IContact *c) {
894 lin_F(v);
895 if (v.x() > 0)
896 rgap_ = c->getGap() + v.x() / kn_;
897 }
898
899 void ContactModelLinearCBond::propagateStateInformation(IContactModelMechanical* old,const CAxes &oldSystem,const CAxes &newSystem) {
900 // Only do something if the contact model is of the same type
901 if (old->getContactModel()->getName().compare("linearcbond",Qt::CaseInsensitive) == 0 && !isBonded()) {
902 ContactModelLinearCBond *oldCm = (ContactModelLinearCBond *)old;
903#ifdef THREED
904 // Need to rotate just the shear component from oldSystem to newSystem
905
906 // Step 1 - rotate oldSystem so that the normal is the same as the normal of newSystem
907 DVect axis = oldSystem.e1() & newSystem.e1();
908 double c, ang, s;
909 DVect re2;
910 if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
911 axis = axis.unit();
912 c = oldSystem.e1()|newSystem.e1();
913 if (c > 0)
914 c = std::min(c,1.0);
915 else
916 c = std::max(c,-1.0);
917 ang = acos(c);
918 s = sin(ang);
919 double t = 1. - c;
920 DMatrix<3,3> rm;
921 rm.get(0,0) = t*axis.x()*axis.x() + c;
922 rm.get(0,1) = t*axis.x()*axis.y() - axis.z()*s;
923 rm.get(0,2) = t*axis.x()*axis.z() + axis.y()*s;
924 rm.get(1,0) = t*axis.x()*axis.y() + axis.z()*s;
925 rm.get(1,1) = t*axis.y()*axis.y() + c;
926 rm.get(1,2) = t*axis.y()*axis.z() - axis.x()*s;
927 rm.get(2,0) = t*axis.x()*axis.z() - axis.y()*s;
928 rm.get(2,1) = t*axis.y()*axis.z() + axis.x()*s;
929 rm.get(2,2) = t*axis.z()*axis.z() + c;
930 re2 = rm*oldSystem.e2();
931 }
932 else
933 re2 = oldSystem.e2();
934 // Step 2 - get the angle between the oldSystem rotated shear and newSystem shear
935 axis = re2 & newSystem.e2();
936 DVect2 tpf;
937 DMatrix<2,2> m;
938 if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
939 axis = axis.unit();
940 c = re2|newSystem.e2();
941 if (c > 0)
942 c = std::min(c,1.0);
943 else
944 c = std::max(c,-1.0);
945 ang = acos(c);
946 if (!checktol(axis.x(),newSystem.e1().x(),1.0,100))
947 ang *= -1;
948 s = sin(ang);
949 m.get(0,0) = c;
950 m.get(1,0) = s;
951 m.get(0,1) = -m.get(1,0);
952 m.get(1,1) = m.get(0,0);
953 tpf = m*DVect2(oldCm->lin_F_.y(),oldCm->lin_F_.z());
954 } else {
955 m.get(0,0) = 1.;
956 m.get(0,1) = 0.;
957 m.get(1,0) = 0.;
958 m.get(1,1) = 1.;
959 tpf = DVect2(oldCm->lin_F_.y(),oldCm->lin_F_.z());
960 }
961 DVect pforce = DVect(0,tpf.x(),tpf.y());
962#else
963 oldSystem;
964 newSystem;
965 DVect pforce = DVect(0,oldCm->lin_F_.y());
966#endif
967 for (int i=1; i<dim; ++i)
968 lin_F_.rdof(i) += pforce.dof(i);
969 if (lin_mode_ && oldCm->lin_mode_)
970 lin_F_.rx() = oldCm->lin_F_.x();
971 oldCm->lin_F_ = DVect(0.0);
972 if (dpProps_ && oldCm->dpProps_) {
973#ifdef THREED
974 tpf = m*DVect2(oldCm->dpProps_->dp_F_.y(),oldCm->dpProps_->dp_F_.z());
975 pforce = DVect(oldCm->dpProps_->dp_F_.x(),tpf.x(),tpf.y());
976#else
977 pforce = oldCm->dpProps_->dp_F_;
978#endif
979 dpProps_->dp_F_ += pforce;
980 oldCm->dpProps_->dp_F_ = DVect(0.0);
981 }
982 if(oldCm->getEnergyActivated()) {
983 activateEnergy();
984 energies_->estrain_ = oldCm->energies_->estrain_;
985 energies_->eslip_ = oldCm->energies_->eslip_;
986 energies_->edashpot_ = oldCm->energies_->edashpot_;
987 oldCm->energies_->estrain_ = 0.0;
988 oldCm->energies_->edashpot_ = 0.0;
989 oldCm->energies_->eslip_ = 0.0;
990 }
991 rgap_ = oldCm->rgap_;
992 }
993 assert(lin_F_ == lin_F_);
994 }
995
996 void ContactModelLinearCBond::setNonForcePropsFrom(IContactModel *old) {
997 // Only do something if the contact model is of the same type
998 if (old->getName().compare("linearcbond",Qt::CaseInsensitive) == 0 && !isBonded()) {
999 ContactModelLinearCBond *oldCm = (ContactModelLinearCBond *)old;
1000 kn_ = oldCm->kn_;
1001 ks_ = oldCm->ks_;
1002 fric_ = oldCm->fric_;
1003 lin_mode_ = oldCm->lin_mode_;
1004 rgap_ = oldCm->rgap_;
1005 userArea_ = oldCm->userArea_;
1006
1007 if (oldCm->dpProps_) {
1008 if (!dpProps_)
1009 dpProps_ = NEWC(dpProps());
1010 dpProps_->dp_nratio_ = oldCm->dpProps_->dp_nratio_;
1011 dpProps_->dp_sratio_ = oldCm->dpProps_->dp_sratio_;
1012 dpProps_->dp_mode_ = oldCm->dpProps_->dp_mode_;
1013 }
1014 }
1015 }
1016
1017 DVect ContactModelLinearCBond::getForce(const IContactMechanical *) const {
1018 DVect ret(lin_F_);
1019 if (dpProps_)
1020 ret += dpProps_->dp_F_;
1021 return ret;
1022 }
1023
1024 DAVect ContactModelLinearCBond::getMomentOn1(const IContactMechanical *c) const {
1025 DVect force = getForce(c);
1026 DAVect ret(0.0);
1027 c->updateResultingTorqueOn1Local(force,&ret);
1028 return ret;
1029 }
1030
1031 DAVect ContactModelLinearCBond::getMomentOn2(const IContactMechanical *c) const {
1032 DVect force = getForce(c);
1033 DAVect ret(0.0);
1034 c->updateResultingTorqueOn2Local(force,&ret);
1035 return ret;
1036 }
1037
1038 void ContactModelLinearCBond::setDampCoefficients(const double &mass,double *vcn,double *vcs) {
1039 *vcn = dpProps_->dp_nratio_ * 2.0 * sqrt(mass*(kn_));
1040 *vcs = dpProps_->dp_sratio_ * 2.0 * sqrt(mass*(ks_));
1041 }
1042
1043} // namespace itascaxd
1044// EoF
Was this helpful? ... | Itasca Software © 2024, Itasca | Updated: Aug 13, 2024 |