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