Smooth-Joint Model Implementation
See this page for the documentation of this contact model.
contactmodelsmoothjoint.h
1#pragma once
2// contactmodelsmoothjoint.h
3
4#include "contactmodel/src/contactmodelmechanical.h"
5
6#ifdef SMOOTHJOINT_LIB
7# define SMOOTHJOINT_EXPORT EXPORT_TAG
8#elif defined(NO_MODEL_IMPORT)
9# define SMOOTHJOINT_EXPORT
10#else
11# define SMOOTHJOINT_EXPORT IMPORT_TAG
12#endif
13
14namespace cmodelsxd {
15 using namespace itasca;
16
17 class ContactModelSmoothJoint : public ContactModelMechanical {
18 public:
19 enum PropertyKeys {
20 kwKn=1
21 , kwKs
22 , kwFric
23 , kwDA
24 , kwState
25 , kwTen
26 , kwBCoh
27 , kwBFA
28 , kwShear
29 , kwRMul
30 , kwLarge
31 , kwFn
32 , kwFs
33 , kwGap
34 , kwNorm
35 , kwArea
36 , kwRad
37 , kwUn
38 , kwUs
39 , kwSlip
40 , kwDip
41 , kwDD
42 };
43
44 enum FishCallEvents { fBondBreak=0, fSlipChange };
45
46 SMOOTHJOINT_EXPORT ContactModelSmoothJoint();
47 SMOOTHJOINT_EXPORT ContactModelSmoothJoint(const ContactModelSmoothJoint &) noexcept;
48 SMOOTHJOINT_EXPORT const ContactModelSmoothJoint & operator=(const ContactModelSmoothJoint &);
49 SMOOTHJOINT_EXPORT void addToStorage(poly::vector<ContactModelMechanical> *s,int ww = -1) override;
50 SMOOTHJOINT_EXPORT virtual ~ContactModelSmoothJoint();
51 virtual void copy(const ContactModel *c) override;
52 virtual void archive(ArchiveStream &);
53 virtual string getName() const { return "smoothjoint"; }
54 virtual void setIndex(int i) { index_=i;}
55 virtual int getIndex() const {return index_;}
56
57 virtual string getProperties() const {
58 return "sj_kn"
59 ",sj_ks"
60 ",sj_fric"
61 ",sj_da"
62 ",sj_state"
63 ",sj_ten"
64 ",sj_coh"
65 ",sj_fa"
66 ",sj_shear"
67 ",sj_rmul"
68 ",sj_large"
69 ",sj_fn"
70 ",sj_fs"
71 ",sj_gap"
72 ",sj_unorm"
73 ",sj_area"
74 ",sj_radius"
75 ",sj_un"
76 ",sj_us"
77 ",sj_slip"
78 ",dip"
79#ifdef THREED
80 ",ddir"
81#endif
82 ;
83 }
84
85 virtual string getFishCallEvents() const { return "bond_break,slip_change"; }
86 virtual base::Property getProperty(uint32 i,const IContact *con=0) const;
87 virtual bool getPropertyGlobal(uint32 i) const;
88 virtual bool setProperty(uint32 i,const base::Property &v,IContact *con=0);
89 virtual bool getPropertyReadOnly(uint32 i) const;
90 virtual bool supportsInheritance(uint32 i) const;
91 virtual bool getInheritance(uint32 i) const { assert(i<32); uint32 mask = to<uint32>(1 << i); return (inheritanceField_ & mask) ? true : false; }
92 virtual void setInheritance(uint32 i,bool b) { assert(i<32); uint32 mask = to<uint32>(1 << i); if (b) inheritanceField_ |= mask; else inheritanceField_ &= ~mask; }
93
94 enum MethodKeys {
95 kwSetForce=1,kwBond,kwUnbond
96 };
97
98 virtual string getMethods() const {
99 return "sj_setforce,bond,unbond";
100 }
101
102 virtual string getMethodArguments(uint32 i) const;
103 virtual bool setMethod(uint32 i,const std::vector<base::Property> &vl,IContact *con=0); // Base 1 - returns true if timestep contributions need to be updated
104
105 virtual uint32 getMinorVersion() const;
106
107 enum EnergyKeys { kwEStrain=1,kwESlip};
108 virtual string getEnergies() const { return "energy-strain,energy-slip";}
109 virtual double getEnergy(uint32 i) const; // Base 1
110 virtual bool getEnergyAccumulate(uint32 i) const; // Base 1
111 virtual void setEnergy(uint32 i,const double &d); // Base 1
112 virtual void activateEnergy() { if (energies_) return; energies_ = NEW Energies();}
113 virtual bool getEnergyActivated() const {return (energies_ !=0);}
114
115 virtual bool validate(ContactModelMechanicalState *state,const double ×tep);
116 virtual bool endPropertyUpdated(const string &name,const IContactMechanical *c);
117 virtual bool forceDisplacementLaw(ContactModelMechanicalState *state,const double ×tep);
118 virtual DVect2 getEffectiveTranslationalStiffness() const {return effectiveTranslationalStiffness_;}
119 virtual DAVect getEffectiveRotationalStiffness() const {return DAVect(0.0);}
120
121 virtual ContactModelSmoothJoint *clone() const override { return NEW ContactModelSmoothJoint(); }
122 virtual double getActivityDistance() const {return 0.0;}
123 virtual void resetForcesAndMoments() { sj_Fn(0.0); sj_Fs(DVect(0.0)); }
124 virtual void setForce(const DVect &v,IContact *);
125 virtual void setArea(const double &) { throw Exception("The setArea method cannot be used with this contact model."); }
126 virtual double getArea() const { return 0.0; }
127
128 virtual bool isOKToDelete() const { return (!isBonded() && sj_large_); }
129
130 virtual bool checkActivity(const double &gap) { return ( !sj_large_ || gap <= 0.0 || isBonded()); }
131 virtual bool isSliding() const { return isjSliding_; }
132 virtual bool isBonded() const { return sj_state_ == 3; }
133 virtual void unbond() { sj_state_ = 0; }
134 virtual bool hasNormal() const { return true; }
135 virtual DVect3 getNormal() const { return toVect3(sj_unorm_); }
136
137 void sj_kn(const double &d) {sj_kn_ = d;}
138 void sj_ks(const double &d) {sj_ks_ = d;}
139 void sj_fric(const double &d) {sj_fric_ = d;}
140 void sj_da(const double &d) {sj_da_ = d;}
141 void sj_state(const double &d) {sj_state_ = d;}
142 void sj_bns(const double &d) {sj_bns_ = d;}
143 void sj_bcoh(const double &d) {sj_bcoh_ = d;}
144 void sj_bfa(const double &d) {sj_bfa_ = d;}
145 void dip(const double &d) {dip_ = d;}
146 void sj_rmul(const double &d) {sj_rmul_ = d;}
147 void sj_large(bool b) {sj_large_ = b;}
148
149 const double & sj_kn() const {return sj_kn_;}
150 const double & sj_ks() const {return sj_ks_;}
151 const double & sj_fric() const {return sj_fric_;}
152 const double & sj_da() const {return sj_da_;}
153 int sj_state() const {return sj_state_;}
154 const double & sj_bns() const {return sj_bns_;}
155 const double & sj_bcoh() const {return sj_bcoh_;}
156 const double & sj_bfa() const {return sj_bfa_;}
157 const double & dip() const {return dip_;}
158 const double & sj_rmul() const {return sj_rmul_;}
159 bool sj_large() const {return sj_large_;}
160
161#ifdef THREED
162 const double & dd() const {return dd_;}
163 void dd(const double &d) {dd_ =d;}
164#endif
165
166 void sj_unorm(const DVect &v) {sj_unorm_ = v;}
167 void sj_A(const double &d) {sj_A_ = d;}
168 void sj_rad(const double &d) {sj_rad_ = d;}
169 void sj_gap(const double &d) {sj_gap_ = d;}
170 void sj_Un(const double &d) {sj_Un_ = d;}
171 void sj_Us(const DVect &v) {sj_Us_ = v;}
172 void sj_Fn(const double &d) {sj_Fn_ = d;}
173 void sj_Fs(const DVect &v) {sj_Fs_ = v;}
174 void isjFlip(bool b) {isjFlip_ = b;}
175 void isjSliding(bool b) {isjSliding_ = b;}
176
177 const DVect & sj_unorm() const {return sj_unorm_;}
178 const double & sj_A() const {return sj_A_;}
179 const double & sj_rad() const {return sj_rad_;}
180 const double & sj_gap() const {return sj_gap_;}
181 const double & sj_Un() const {return sj_Un_;}
182 const DVect & sj_Us() const {return sj_Us_;}
183 const double & sj_Fn() const {return sj_Fn_;}
184 const DVect & sj_Fs() const {return sj_Fs_;}
185 bool isjFlip() const {return isjFlip_;}
186 bool isjSliding() const {return isjSliding_;}
187
188 bool hasEnergies() const {return energies_ ? true:false;}
189 double estrain() const {return hasEnergies() ? energies_->estrain_: 0.0;}
190 void estrain(const double &d) { if(!hasEnergies()) return; energies_->estrain_=d;}
191 double eslip() const {return hasEnergies() ? energies_->eslip_: 0.0;}
192 void eslip(const double &d) { if(!hasEnergies()) return; energies_->eslip_=d;}
193
194 uint32 inheritanceField() const {return inheritanceField_;}
195 void inheritanceField(uint32 i) {inheritanceField_ = i;}
196
197 const DVect2 & effectiveTranslationalStiffness() const {return effectiveTranslationalStiffness_;}
198 void effectiveTranslationalStiffness(const DVect2 &v ) {effectiveTranslationalStiffness_=v;}
199
200 bool geomRecomp() const {return geomRecomp_ ;}
201 void geomRecomp(bool b) {geomRecomp_ = b;}
202
203 /// Return the total force that the contact model holds.
204 virtual DVect getForce() const;
205
206 /// Return the total moment on 1 that the contact model holds
207 virtual DAVect getMomentOn1(const IContactMechanical *) const;
208
209 /// Return the total moment on 1 that the contact model holds
210 virtual DAVect getMomentOn2(const IContactMechanical *) const;
211
212 virtual DAVect getModelMomentOn1() const;
213 virtual DAVect getModelMomentOn2() const;
214
215 // Used to efficiently get properties from the contact model for the object pane.
216 // List of properties for the object pane, comma separated.
217 // All properties will be cast to doubles for comparison. No other comparisons
218 // are supported. This may not be the same as the entire property list.
219 // Return property name and type for plotting.
220 void objectPropsTypes(std::vector<std::pair<string,InfoTypes>> *) const override;
221 // All properties cast to doubles - this is what can be compared.
222 void objectPropValues(std::vector<double> *,const IContact *) const override;
223
224 private:
225 static int index_;
226
227 struct Energies {
228 Energies() : estrain_(0.0), eslip_(0.0) {}
229 double estrain_; // elastic energy stored in contact
230 double eslip_; // work dissipated by friction
231 };
232
233 bool updateKn(const IContactMechanical *con);
234 bool updateKs(const IContactMechanical *con);
235 bool updateFric(const IContactMechanical *con);
236 void updateAreaAndNormal(ContactModelMechanicalState *state);
237 void updateAreaAndNormalContact(const DVect2 &end1Curvature,const DVect2 &end2Curvature,const DVect &norm);
238 double calcBSS() const;
239
240 void updateEffectiveTranslationalStiffness();
241
242 // property set fields
243 uint32 inheritanceField_;
244
245 // smooth joint model - contact model properties
246 double sj_kn_ = 0.0; // normal stiffness
247 double sj_ks_ = 0.0; // shear stiffness
248 double sj_fric_ = 0.0; // Coulomb friction coefficient
249 double sj_da_ = 0.0; // Dilation angle (stored in radians, returned/set in degrees)
250 int sj_state_ = 0; // Bond state - 0 (NBNF), 1 (NBFT), 2 (NBFS), 3 (bonded)
251 double sj_bns_ = 0.0; // Bond normal (tensile) strength
252 double sj_bcoh_ = 0.0; // Bonded system cohesion
253 double sj_bfa_ = 0.0; // Bonded system friction angle (stored in radians, returned/set in degrees)
254 double dip_ = 0.0; // Dip angle (stored in radians, returned/set in degrees)
255 double sj_rmul_ = 1.0; // Radius multiplier
256 bool sj_large_ = false; // Large strain indicator
257
258 // Internal state variables
259 DVect sj_unorm_ = DVect(0.0); // Normal to the plane
260 double sj_A_ = 0.0; // Cross-sectional area
261 double sj_rad_ = 0.0; // Radius
262 double sj_gap_ = 0.0; // Gap - this can be user modified
263 double sj_Un_ = 0.0; // Normal displacement
264 DVect sj_Us_ = DVect(0.0); // Shear displacement
265 double sj_Fn_ = 0; // Normal force
266 DVect sj_Fs_ = DVect(0.0); // Shear force
267 bool isjFlip_ = false; // In order to flip the order
268 bool isjSliding_ = false;// True if this is sliding
269
270 DVect2 effectiveTranslationalStiffness_ = DVect2(0.0);
271 bool geomRecomp_ = true; // If true then there must be a validate before FD!
272#ifdef THREED
273 double dd_ = 0.0; // Dip direction (stored in radians, returned/set in degrees)
274#endif
275 CAxes localSystem_;
276 //DAVect effectiveRotationalStiffness_;
277
278 Energies *energies_ = nullptr;
279 };
280} // namespace itascaxd
281// EoF
contactmodelsmoothjoint.cpp
1// contactmodelsmoothjoint.cpp
2#include "contactmodelsmoothjoint.h"
3
4#include "../version.txt"
5#include "fish/src/parameter.h"
6#include "utility/src/tptr.h"
7
8#include "kernel/interface/iprogram.h"
9#include "module/interface/icontact.h"
10#include "module/interface/icontactmechanical.h"
11#include "module/interface/ifishcalllist.h"
12#include "module/interface/ipiece.h"
13
14#ifdef SMOOTHJOINT_LIB
15#ifdef _WIN32
16 int __stdcall DllMain(void *,unsigned, void *)
17 {
18 return 1;
19 }
20#endif
21
22 extern "C" EXPORT_TAG const char *getName()
23 {
24#if DIM==3
25 return "contactmodelmechanical3dsmoothjoint";
26#else
27 return "contactmodelmechanical2dsmoothjoint";
28#endif
29 }
30
31 extern "C" EXPORT_TAG unsigned getMajorVersion()
32 {
33 return MAJOR_VERSION;
34 }
35
36 extern "C" EXPORT_TAG unsigned getMinorVersion()
37 {
38 return MINOR_VERSION;
39 }
40
41 extern "C" EXPORT_TAG void *createInstance()
42 {
43 cmodelsxd::ContactModelSmoothJoint *m = NEW cmodelsxd::ContactModelSmoothJoint();
44 return (void *)m;
45 }
46#endif // SMOOTHJOINT_EXPORTS
47
48namespace cmodelsxd {
49 static const uint32 sjKnMask = 0x00002; // Base 1!
50 static const uint32 sjKsMask = 0x00004;
51 static const uint32 sjFricMask = 0x00008;
52
53 using namespace itasca;
54
55 int ContactModelSmoothJoint::index_ = -1;
56 uint32 ContactModelSmoothJoint::getMinorVersion() const { return MINOR_VERSION; }
57
58 ContactModelSmoothJoint::ContactModelSmoothJoint() : inheritanceField_(sjKnMask|sjKsMask|sjFricMask) {
59 }
60
61 ContactModelSmoothJoint::ContactModelSmoothJoint(const ContactModelSmoothJoint &m) noexcept {
62 inheritanceField(sjKnMask|sjKsMask|sjFricMask);
63 this->copy(&m);
64 }
65
66 const ContactModelSmoothJoint & ContactModelSmoothJoint::operator=(const ContactModelSmoothJoint &m) {
67 inheritanceField(sjKnMask|sjKsMask|sjFricMask);
68 this->copy(&m);
69 return *this;
70 }
71
72 void ContactModelSmoothJoint::addToStorage(poly::vector<ContactModelMechanical> *s,int ww) {
73 s->addToStorage<ContactModelSmoothJoint>(*this,ww);
74 }
75
76 ContactModelSmoothJoint::~ContactModelSmoothJoint() {
77 if (energies_)
78 delete energies_;
79 }
80
81 void ContactModelSmoothJoint::archive(ArchiveStream &stream) {
82 stream & sj_kn_;
83 stream & sj_ks_;
84 stream & sj_fric_;
85 stream & sj_da_;
86 stream & sj_state_;
87 stream & sj_bns_;
88 stream & sj_bcoh_;
89 stream & sj_bfa_;
90 stream & dip_;
91 stream & sj_rmul_;
92 stream & sj_large_;
93 stream & sj_unorm_;
94 stream & sj_A_;
95 stream & sj_rad_;
96 stream & sj_gap_;
97 stream & sj_Un_;
98 stream & sj_Us_;
99 stream & sj_Fn_;
100 stream & sj_Fs_;
101 stream & isjFlip_;
102 stream & isjSliding_;
103#ifdef THREED
104 stream & dd_;
105#endif
106 if (stream.getArchiveState()==ArchiveStream::Save) {
107 bool b = false;
108 if (energies_) {
109 b = true;
110 stream & b;
111 stream & energies_->estrain_;
112 stream & energies_->eslip_;
113 }
114 else
115 stream & b;
116 } else {
117 bool b(false);
118 stream & b;
119 if (b) {
120 if (!energies_)
121 energies_ = NEW Energies();
122 stream & energies_->estrain_;
123 stream & energies_->eslip_;
124 }
125 }
126
127 stream & inheritanceField_;
128 stream & geomRecomp_;
129 stream & effectiveTranslationalStiffness_;
130
131 if (stream.getArchiveState()==ArchiveStream::Save || stream.getRestoreVersion() > 2)
132 stream & localSystem_;
133 }
134
135 void ContactModelSmoothJoint::copy(const ContactModel *cm) {
136 ContactModelMechanical::copy(cm);
137 const ContactModelSmoothJoint *in = dynamic_cast<const ContactModelSmoothJoint*>(cm);
138 if (!in) throw std::runtime_error("Internal error: contact model dynamic cast failed.");
139 sj_kn(in->sj_kn());
140 sj_ks(in->sj_ks());
141 sj_fric(in->sj_fric());
142 sj_da(in->sj_da());
143 sj_state(in->sj_state());
144 sj_bns(in->sj_bns());
145 sj_bcoh(in->sj_bcoh());
146 sj_bfa(in->sj_bfa());
147 dip(in->dip());
148 sj_rmul(in->sj_rmul());
149 sj_large(in->sj_large());
150#ifdef THREED
151 dd(in->dd());
152#endif
153 sj_unorm(in->sj_unorm());
154 sj_A(in->sj_A());
155 sj_rad(in->sj_rad());
156 sj_gap(in->sj_gap());
157 sj_Un(in->sj_Un());
158 sj_Us(in->sj_Us());
159 sj_Fn(in->sj_Fn());
160 sj_Fs(in->sj_Fs());
161 isjFlip(in->isjFlip());
162 isjSliding(in->isjSliding());
163 localSystem_ = in->localSystem_;
164
165 if (in->hasEnergies()) {
166 if (!energies_)
167 energies_ = NEW Energies();
168 estrain(in->estrain());
169 eslip(in->eslip());
170 }
171 inheritanceField(in->inheritanceField());
172 effectiveTranslationalStiffness(in->effectiveTranslationalStiffness());
173 geomRecomp(in->geomRecomp());
174 }
175
176 base::Property ContactModelSmoothJoint::getProperty(uint32 i,const IContact *) const {
177 // The IContact pointer may be a nullptr!
178 base::Property var;
179 switch (i) {
180 case kwKn: return sj_kn_;
181 case kwKs: return sj_ks_;
182 case kwFric: return sj_fric_;
183 case kwDA: return sj_da_/dDegrad; // Returned in degrees
184 case kwState: return sj_state_;
185 case kwTen: return sj_bns_;
186 case kwBCoh: return sj_bcoh_;
187 case kwBFA: return sj_bfa_/dDegrad; // Returned in degrees
188 case kwShear: return calcBSS();
189 case kwDip: return dip_/dDegrad; // Returned in degrees
190#ifdef THREED
191 case kwDD: return dd_/dDegrad; // Returned in degrees
192#endif
193 case kwRMul: return sj_rmul_;
194 case kwLarge: return sj_large_;
195 case kwFn: return sj_Fn_;
196 case kwFs: {
197 var.setValue(sj_Fs_);
198 return var;
199 }
200 case kwGap: return sj_gap_;
201 case kwNorm: {
202 var.setValue(sj_unorm_);
203 return var;
204 }
205 case kwArea: return sj_A_;
206 case kwRad: return sj_rad_;
207 case kwUn: return sj_Un_;
208 case kwUs: {
209 var.setValue(sj_Us_);
210 return var;
211 }
212 case kwSlip: return isjSliding_;
213 }
214 assert(0);
215 return base::Property();
216 }
217
218 bool ContactModelSmoothJoint::getPropertyGlobal(uint32 ) const {
219 return true;
220 }
221
222 bool ContactModelSmoothJoint::setProperty(uint32 i,const base::Property &v,IContact *c) {
223 switch (i) {
224 case kwKn: {
225 if (!v.canConvert<double>())
226 throw Exception("sj_kn must be a double.");
227 double val = v.toDouble();
228 if (val<0.0)
229 throw Exception("Negative sj_kn not allowed.");
230 sj_kn_ = val;
231 updateEffectiveTranslationalStiffness();
232 return true;
233 }
234 case kwKs: {
235 if (!v.canConvert<double>())
236 throw Exception("sj_ks must be a double.");
237 double val = v.toDouble();
238 if (val<0.0)
239 throw Exception("Negative sj_ks not allowed.");
240 sj_ks_ = val;
241 updateEffectiveTranslationalStiffness();
242 return true;
243 }
244 case kwFric: {
245 if (!v.canConvert<double>())
246 throw Exception("sj_fric must be a double.");
247 double val = v.toDouble();
248 if (val<0.0)
249 throw Exception("Negative friction not allowed.");
250 sj_fric_ = val;
251 return false;
252 }
253 case kwDA: {
254 if (!v.canConvert<double>())
255 throw Exception("sj_da must be a double.");
256 sj_da_ = v.toDouble()*dDegrad; // Given in degrees
257 return false;
258 }
259 case kwState: {
260 if (!v.canConvert<int64>())
261 throw Exception("sj_state must be must be an integer between 0 and 3.");
262 int val = v.toInt();
263 if (val<0 || val>3)
264 throw Exception("The bond state must be an integer between 0 and 3.");
265 sj_state_ = val;
266 return false;
267 }
268 case kwTen: {
269 if (!v.canConvert<double>())
270 throw Exception("sj_ten must be a double.");
271 double val = v.toDouble();
272 if (val<0.0)
273 throw Exception("Negative bond normal (tensile) strength not allowed.");
274 sj_bns_ = val;
275 return false;
276 }
277 case kwBCoh: {
278 if (!v.canConvert<double>())
279 throw Exception("sj_coh must be a double.");
280 double val = v.toDouble();
281 if (val<0.0)
282 throw Exception("Negative bond system cohesion not allowed.");
283 sj_bcoh_ = val;
284 return false;
285 }
286 case kwBFA: {
287 if (!v.canConvert<double>())
288 throw Exception("sj_bfa must be a double.");
289 sj_bfa_ = v.toDouble()*dDegrad; // Given in degrees
290 return false;
291 }
292 case kwDip: {
293 if (!v.canConvert<double>())
294 throw Exception("dip must be a double.");
295 dip_ = v.toDouble()*dDegrad; // Given in degrees
296 if (c) {
297 auto con = convert_getcast<IContactMechanical>(c);
298 updateAreaAndNormalContact(con->getEnd1Curvature(),con->getEnd2Curvature(),toDVect(c->getNormal()));
299 } else
300 geomRecomp_ = true;
301 return true;
302 }
303 case kwDD: {
304#ifdef THREED
305 if (!v.canConvert<double>())
306 throw Exception("ddir must be a double.");
307 dd_ = v.toDouble()*dDegrad; // Given in degrees
308 if (c) {
309 auto con = convert_getcast<IContactMechanical>(c);
310 updateAreaAndNormalContact(con->getEnd1Curvature(),con->getEnd2Curvature(),c->getNormal());
311 } else
312 geomRecomp_ = true;
313#endif
314 return true;
315 }
316 case kwRMul: {
317 if (!v.canConvert<double>())
318 throw Exception("sj_rmul must be a double.");
319 double val = v.toDouble();
320 if (val<0.0)
321 throw Exception("Negative radius multiplier not allowed.");
322 sj_rmul_ = val;
323 if (!geomRecomp_) geomRecomp_ = true;
324 return false;
325 }
326 case kwLarge: {
327 if (!v.canConvert<bool>())
328 throw Exception("Large-strain flag must be a boolean.");
329 sj_large_ = v.to<bool>();
330 return false;
331 }
332 case kwFn: {
333 if (!v.canConvert<double>())
334 throw Exception("sj_fn must be a double.");
335 sj_Fn_ = v.toDouble();
336 return false;
337 }
338 case kwFs: {
339 if (!v.canConvert<DVect>())
340 throw Exception("sj_fs must be a vector.");
341 sj_Fs_ = v.value<DVect>();
342 return false;
343 }
344 case kwGap: {
345 if (!v.canConvert<double>())
346 throw Exception("sj_gap must be a double.");
347 sj_gap_ = v.toDouble();
348 return false;
349 }
350
351
352 // Following are read-only !
353 case kwNorm:
354 case kwRad:
355 case kwShear:
356 case kwUn:
357 case kwUs:
358 case kwSlip:
359 return false;
360 }
361 assert(0);
362 return false;
363 }
364
365 bool ContactModelSmoothJoint::getPropertyReadOnly(uint32 i) const {
366 switch (i) {
367 case kwNorm:
368 case kwRad:
369 case kwUn:
370 case kwUs:
371 case kwSlip:
372 case kwShear:
373 case kwArea:
374 return true;
375 default:
376 break;
377 }
378 return false;
379 }
380
381 bool ContactModelSmoothJoint::supportsInheritance(uint32 i) const {
382 switch (i) {
383 case kwKn:
384 case kwKs:
385 case kwFric:
386 return true;
387 default:
388 break;
389 }
390 return false;
391 }
392
393 string ContactModelSmoothJoint::getMethodArguments(uint32 i) const {
394 string def = string();
395 switch (i) {
396 case kwBond:
397 return "gap";
398 case kwUnbond:
399 return "gap";
400 }
401 return def;
402 }
403
404 bool ContactModelSmoothJoint::setMethod(uint32 i,const std::vector<base::Property> &vl,IContact *con) {
405 FP_S;
406 IContactMechanical *c(convert_getcast<IContactMechanical>(con));
407 switch (i) {
408 case kwSetForce: {
409 DVect gf = c->getGlobalForce();
410 if (isjFlip_)
411 gf *= -1.0;
412 sj_Fn_ = gf | sj_unorm_;
413 FP_S;
414 return false;
415 }
416 case kwBond: {
417 if (sj_state_ == 3) return false;
418 double mingap = -1.0 * limits<double>::max();
419 double maxgap = 0;
420 if (vl.at(0).canConvert<double>())
421 maxgap = vl.at(0).toDouble();
422 else if (vl.at(0).canConvert<DVect2>()) {
423 DVect2 value = vl.at(0).value<DVect2>();
424 mingap = value.minComp();
425 maxgap = value.maxComp();
426 } else if (!vl.at(0).isNull())
427 throw Exception("gap value {0} not recognized in method bond in contact model {1}.",vl.at(0),getName());
428 if ( sj_gap_ >= mingap && sj_gap_ <= maxgap) {
429 sj_state_ = 3;
430 FP_S;
431 return true;
432 }
433 FP_S;
434 return false;
435 }
436 case kwUnbond: {
437 if (sj_state_ == 0) return false;
438 double mingap = -1.0 * limits<double>::max();
439 double maxgap = 0;
440 if (vl.at(0).canConvert<double>())
441 maxgap = vl.at(0).toDouble();
442 else if (vl.at(0).canConvert<DVect2>()) {
443 DVect2 value = vl.at(0).value<DVect2>();
444 mingap = value.minComp();
445 maxgap = value.maxComp();
446 }
447 else if (!vl.at(0).isNull())
448 throw Exception("gap value {0} not recognized in method unbond in contact model {1}.",vl.at(0),getName());
449 if ( sj_gap_ >= mingap && sj_gap_ <= maxgap) {
450 sj_state_ = 0;
451 FP_S;
452 return true;
453 }
454 FP_S;
455 return false;
456 }
457
458 }
459 FP_S;
460 return false;
461 }
462
463 double ContactModelSmoothJoint::getEnergy(uint32 i) const {
464 double ret(0.0);
465 if (!energies_)
466 return ret;
467 switch (i) {
468 case kwEStrain: return energies_->estrain_;
469 case kwESlip: return energies_->eslip_;
470 }
471 assert(0);
472 return ret;
473 }
474
475 bool ContactModelSmoothJoint::getEnergyAccumulate(uint32 i) const {
476 bool ret(false);
477 if (!energies_) return ret;
478 switch (i) {
479 case kwEStrain: return false;
480 case kwESlip: return true;
481 }
482 assert(0);
483 return ret;
484 }
485
486 void ContactModelSmoothJoint::setEnergy(uint32 i,const double &d) {
487 if (!energies_) return;
488 switch (i) {
489 case kwEStrain: energies_->estrain_ = d; return;
490 case kwESlip: energies_->eslip_ = d; return;
491 }
492 assert(0);
493 return;
494 }
495
496 bool ContactModelSmoothJoint::validate(ContactModelMechanicalState *state,const double &) {
497 assert(state);
498 const IContactMechanical *c = state->getMechanicalContact();
499 assert(c);
500 localSystem_ = c->getContact()->getLocalSystem();
501
502 if (state->trackEnergy_)
503 activateEnergy();
504
505 // The radius multiplier has been set previously so calculate the sj_A_
506 // Need to do this regardless of whether or not the radius multiplier has been updated as this is the
507 // first place with the contact state to get the ball radii!
508 updateAreaAndNormal(state);
509
510 if (inheritanceField_ & sjKnMask)
511 updateKn(c);
512 if (inheritanceField_ & sjKsMask)
513 updateKs(c);
514 if (inheritanceField_ & sjFricMask)
515 updateFric(c);
516
517 updateEffectiveTranslationalStiffness();
518
519 return checkActivity(state->gap_);
520 }
521
522 void ContactModelSmoothJoint::updateAreaAndNormal(ContactModelMechanicalState *state) {
523 updateAreaAndNormalContact(state->end1Curvature_,state->end2Curvature_,state->axes_.e1());
524 }
525
526 void ContactModelSmoothJoint::updateAreaAndNormalContact(const DVect2 &end1Curvature,const DVect2 &end2Curvature,const DVect &norm) {
527 if (geomRecomp_) geomRecomp_ = false;
528 // Use the maximum value of the curvature here - not the min!
529 sj_rad_ = 1.0 / std::max(end1Curvature.y(),end2Curvature.y());
530 sj_rad_ = sj_rmul_ * sj_rad_;
531#ifdef THREED
532 sj_A_ = dPi * sj_rad_ * sj_rad_;
533 sj_unorm_.rx() = sin(dip_) * sin(dd_);
534 sj_unorm_.ry() = sin(dip_) * cos(dd_);
535 sj_unorm_.rz() = cos(dip_);
536#else
537 sj_A_ = 2.0 * sj_rad_; // Assumes thickness of 1 in 2D
538 sj_unorm_.rx() = sin(dip_);
539 sj_unorm_.ry() = cos(dip_);
540#endif
541 DVect nc = norm;
542 // Set the flip boolean so that the ordering is correct from side1 to side2
543 isjFlip_ = ( ((nc | sj_unorm_) >= 0.0 ) ? false : true );
544 }
545
546 static const string kn("sj_kn");
547 bool ContactModelSmoothJoint::updateKn(const IContactMechanical *con) {
548 assert(con);
549 base::Property v1 = con->getEnd1()->getProperty(kn);
550 base::Property v2 = con->getEnd2()->getProperty(kn);
551 if (!v1.isValid() || !v2.isValid())
552 return false;
553 double kn1 = v1.toDouble();
554 double kn2 = v2.toDouble();
555 double val = sj_kn_;
556 if (kn1 && kn2)
557 sj_kn_ = kn1*kn2/(kn1+kn2);
558 else if (kn1)
559 sj_kn_ = kn1;
560 else if (kn2)
561 sj_kn_ = kn2;
562 return ( (sj_kn_ != val) );
563 }
564
565 static const string ks("sj_ks");
566 bool ContactModelSmoothJoint::updateKs(const IContactMechanical *con) {
567 assert(con);
568 base::Property v1 = con->getEnd1()->getProperty(ks);
569 base::Property v2 = con->getEnd2()->getProperty(ks);
570 if (!v1.isValid() || !v2.isValid())
571 return false;
572 double kn1 = v1.toDouble();
573 double kn2 = v2.toDouble();
574 double val = sj_ks_;
575 if (kn1 && kn2)
576 sj_ks_ = kn1*kn2/(kn1+kn2);
577 else if (kn1)
578 sj_ks_ = kn1;
579 else if (kn2)
580 sj_ks_ = kn2;
581 return ( (sj_ks_ != val) );
582 }
583
584 static const string fric("sj_fric");
585 bool ContactModelSmoothJoint::updateFric(const IContactMechanical *con) {
586 assert(con);
587 base::Property v1 = con->getEnd1()->getProperty(fric);
588 base::Property v2 = con->getEnd2()->getProperty(fric);
589 if (!v1.isValid() || !v2.isValid())
590 return false;
591 double fric1 = std::max(0.0,v1.toDouble());
592 double fric2 = std::max(0.0,v2.toDouble());
593 double val = sj_fric_;
594 sj_fric_ = std::min(fric1,fric2);
595 return ( (sj_fric_ != val) );
596 }
597
598 bool ContactModelSmoothJoint::endPropertyUpdated(const string &name,const IContactMechanical *c) {
599 assert(c);
600 StringList availableProperties = split(replace(simplified(getProperties())," ",""),",");
601 auto idx = findRegex(availableProperties,name);
602 if (idx==string::npos) return false;
603 idx += 1;
604 bool ret=false;
605 switch(idx) {
606 case kwKn: { //sj_kn_
607 if (inheritanceField_ & sjKnMask)
608 ret = updateKn(c);
609 break;
610 }
611 case kwKs: { //sj_ks_
612 if (inheritanceField_ & sjKsMask)
613 ret =updateKs(c);
614 break;
615 }
616 case kwFric: { //sj_fric_
617 if (inheritanceField_ & sjFricMask)
618 updateFric(c);
619 break;
620 }
621 }
622
623 if (ret)
624 updateEffectiveTranslationalStiffness();
625 return ret;
626 }
627
628 void ContactModelSmoothJoint::updateEffectiveTranslationalStiffness() {
629 effectiveTranslationalStiffness_ = DVect2(sj_kn_,sj_ks_)*sj_A_;
630 }
631
632 bool ContactModelSmoothJoint::forceDisplacementLaw(ContactModelMechanicalState *state,const double &) {
633 assert(state);
634
635 if (geomRecomp_)
636 updateAreaAndNormal(state);
637
638 // Skip out if this should not be active
639 if (sj_large_ && state->gap_ > 0.0 && sj_state_ != 3) {
640 sj_Fn_ = 0.0;
641 sj_Fs_ = DVect(0.0);
642 sj_gap_ = 0.0;
643 sj_Un_ = 0.0;
644 sj_Us_ = DVect(0.0);
645 return false;
646 }
647
648 // Get the translational increment in the global system
649 localSystem_ = state->axes_;
650 DVect tInc = localSystem_.toGlobal(state->relativeTranslationalIncrement_);
651
652 // Now have the translational increment and the normal in the global coordinate system
653 // Compute the normal/shear displacement increments along the sj
654 if (isjFlip_)
655 tInc *= -1.0;
656 double nInc = tInc | sj_unorm_;
657 DVect sInc = tInc - sj_unorm_ * nInc;
658 sj_Un_ -= nInc;
659 sj_Us_ += sInc;
660
661 double nElInc(0.0);
662 DVect sElInc(0.0);
663
664 double g0 = sj_gap_, g1 = sj_gap_ + nInc;
665 sj_gap_ = g1;
666
667 if (!state->canFail_ || sj_state_ == 3 ) { // Bonded
668 nElInc = nInc;
669 sElInc = sInc;
670 } else {
671 if ( g0 <= 0.0 ) {
672 if ( g1 <= 0.0 ) {
673 nElInc = nInc;
674 sElInc = sInc;
675 } else { // g1 > 0.0
676 double xi = -g0 / (g1 - g0);
677 nElInc = nInc * xi;
678 sElInc = sInc * xi;
679 }
680 } else { // g0 > 0.0
681 if ( g1 >= 0.0 ) {
682 nElInc = 0.0;
683 sElInc.fill(0.0);
684 } else { // g1 < 0.0
685 double xi = -g0 / (g1 - g0);
686 nElInc = nInc * (1.0 - xi);
687 sElInc = sInc * (1.0 - xi);
688 }
689 }
690 }
691
692 double del_Fn = -sj_kn_ * sj_A_ * nElInc ;
693 sj_Fn_ += del_Fn ;
694 int slideChange(-1);
695 DVect sj_Fs_old = sj_Fs_;
696
697 if ( state->canFail_ && sj_state_ < 3 ) { // Coulomb sliding with dilation
698 if ( sj_Fn_ <= 0.0 ) {
699 sj_Fn_ = 0.0;
700 sj_Fs_.fill(0.0);
701 } else {
702 DVect del_Fs = sElInc * (-sj_ks_ * sj_A_);
703 sj_Fs_ += del_Fs;
704 double max_Fs = sj_Fn_ * sj_fric_;
705 double magFs = sj_Fs_.mag();
706 if ( magFs > max_Fs ) { // sliding
707 if (!isjSliding_) {
708 isjSliding_ = true;
709 slideChange = 0;
710 }
711 if ( sj_ks_ > 0.0 ) // dilation
712 sj_Fn_ += ( (magFs - max_Fs) / sj_ks_ ) * sj_kn_ * tan(sj_da_);
713 double rat = max_Fs / magFs ;
714 sj_Fs_ *= rat ;
715 } else {
716 if (isjSliding_) {
717 isjSliding_ = false;
718 slideChange = 1;
719 }
720 }
721 }
722 } else { // bonded behavior
723 if ( state->canFail_ && sj_Fn_ <= -sj_bns_ * sj_A_) {
724 sj_state_ = 1;
725 if (cmEvents_[fBondBreak] >= 0) {
726 auto c = state->getContact();
727 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
728 fish::Parameter((int64)sj_state_),
729 fish::Parameter(sj_bns_) };
730 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
731 fi->setCMFishCallArguments(c,arg,cmEvents_[fBondBreak]);
732 }
733 sj_Fn_ = 0.0;
734 sj_Fs_.fill(0.0);
735 } else {
736 DVect del_Fs = sElInc * (-sj_ks_ * sj_A_);
737 sj_Fs_ += del_Fs;
738 double magFs = sj_Fs_.mag();
739 double ss = calcBSS();
740 if ( state->canFail_ && magFs >= ss * sj_A_) { // break in shear
741 sj_state_ = 2;
742 if (cmEvents_[fBondBreak] >= 0) {
743 auto c = state->getContact();
744 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
745 fish::Parameter((int64)sj_state_),
746 fish::Parameter(ss) };
747 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
748 fi->setCMFishCallArguments(c,arg,cmEvents_[fBondBreak]);
749 }
750
751 if ( sj_Fn_ < 0.0 ) {
752 sj_Fn_ = 0.0;
753 sj_Fs_.fill(0.0);
754 } else { // was in compression // was in tension
755 double max_Fs = sj_Fn_ * sj_fric_ ;
756 if ( magFs > max_Fs) { // sliding, but no dilation
757 if (!isjSliding_) {
758 isjSliding_ = true;
759 slideChange = 0;
760 }
761 double rat = max_Fs / magFs ;
762 sj_Fs_ *= rat ;
763 } else {
764 if (isjSliding_ == true) {
765 isjSliding_ = false;
766 slideChange = 1;
767 }
768 }
769 }
770 }
771 }
772 }
773 if (slideChange >= 0 && cmEvents_[fSlipChange] >= 0) {
774 auto c = state->getContact();
775 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
776 fish::Parameter((int64)slideChange) };
777 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
778 fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
779 }
780
781 // Have updated the normal and shear forces so need to put them into the contact local
782 // coordinate system and update the forces
783 DVect Fj = sj_unorm_ * sj_Fn_ + sj_Fs_;
784 if (isjFlip_)
785 Fj *= -1.0;
786
787 // Return the correct activity status
788 bool isactive = true;
789 if (sj_large_ && state->gap_ > 0.0 && sj_state_ != 3) {
790 sj_Fn_ = 0.0;
791 sj_Fs_ = DVect(0.0);
792 sj_gap_ = 0.0;
793 sj_Un_ = 0.0;
794 sj_Us_ = DVect(0.0);
795 isactive = false;
796 }
797
798 // update energies
799 if (state->trackEnergy_) {
800 assert(energies_);
801 energies_->estrain_ = 0.0;
802 if (sj_kn_)
803 energies_->estrain_ = 0.5*sj_Fn_*sj_Fn_/sj_kn_;
804 if (sj_ks_) {
805 double smag2 = sj_Fs_.mag2();
806 energies_->estrain_ += 0.5*smag2 / sj_ks_;
807 if (isjSliding_) {
808 DVect avg_F_s = (sj_Fs_old + sj_Fs_)*0.5;
809 DVect u_s_el = (sj_Fs_ - sj_Fs_old) / sj_ks_;
810 energies_->eslip_ -= std::min(0.0,(avg_F_s | (sInc + u_s_el)));
811 }
812 }
813 }
814
815 return isactive ;
816 }
817
818 void ContactModelSmoothJoint::setForce(const DVect &v,IContact *c) {
819 // this is in the local coordinate system
820 localSystem_ = c->getLocalSystem();
821 DVect globForce = localSystem_.toGlobal(v);
822 if (isjFlip_)
823 globForce *= -1.0;
824 sj_Fn_ = (sj_unorm_ | globForce);
825 sj_Fs_ = globForce - sj_unorm_ * sj_Fn_;
826 }
827
828 DVect ContactModelSmoothJoint::getForce() const {
829 DVect Fj = sj_unorm_ * sj_Fn_ + sj_Fs_;
830 if (isjFlip_)
831 Fj *= -1.0;
832 DVect ret(localSystem_.toLocal(Fj));
833 return ret;
834 }
835
836 DAVect ContactModelSmoothJoint::getMomentOn1(const IContactMechanical *c) const {
837 DVect force = getForce();
838 DAVect ret(0.0);
839 c->updateResultingTorqueOn1Local(force,&ret);
840 return ret;
841 }
842
843 DAVect ContactModelSmoothJoint::getMomentOn2(const IContactMechanical *c) const {
844 DVect force = getForce();
845 DAVect ret(0.0);
846 c->updateResultingTorqueOn2Local(force,&ret);
847 return ret;
848 }
849
850 DAVect ContactModelSmoothJoint::getModelMomentOn1() const {
851 DAVect ret(0.0);
852 return ret;
853 }
854
855 DAVect ContactModelSmoothJoint::getModelMomentOn2() const {
856 DAVect ret(0.0);
857 return ret;
858 }
859
860 void ContactModelSmoothJoint::objectPropsTypes(std::vector<std::pair<string,InfoTypes>> *ret) const {
861 ret->clear();
862 ret->push_back({"sj_kn",ScalarInfo});
863 ret->push_back({"sj_ks",ScalarInfo});
864 ret->push_back({"sj_fric",ScalarInfo});
865 ret->push_back({"sj_da",ScalarInfo});
866 ret->push_back({"sj_state",ScalarInfo});
867 ret->push_back({"sj_ten",ScalarInfo});
868 ret->push_back({"sj_coh",ScalarInfo});
869 ret->push_back({"sj_fa",ScalarInfo});
870 ret->push_back({"sj_shear",ScalarInfo});
871 ret->push_back({"sj_rmul",ScalarInfo});
872 ret->push_back({"sj_large",ScalarInfo});
873 ret->push_back({"sj_fn",ScalarInfo});
874 ret->push_back({"sj_fs",VectorInfo});
875 ret->push_back({"sj_gap",ScalarInfo});
876 ret->push_back({"sj_unorm",VectorInfo});
877 ret->push_back({"sj_area",ScalarInfo});
878 ret->push_back({"sj_radius",ScalarInfo});
879 ret->push_back({"sj_un",ScalarInfo});
880 ret->push_back({"sj_us",VectorInfo});
881 ret->push_back({"sj_slip",ScalarInfo});
882 ret->push_back({"dip",ScalarInfo});
883#ifdef THREED
884 ret->push_back({"ddir",ScalarInfo});
885#endif
886
887 }
888
889 void ContactModelSmoothJoint::objectPropValues(std::vector<double> *ret,const IContact *) const {
890 FP_S;
891 ret->clear();
892 ret->push_back(sj_kn_);
893 ret->push_back(sj_ks_);
894 ret->push_back(sj_fric_);
895 ret->push_back(sj_da_/dDegrad);
896 ret->push_back(sj_state_);
897 ret->push_back(sj_bns_);
898 ret->push_back(sj_bcoh_);
899 ret->push_back(sj_bfa_/dDegrad);
900 ret->push_back(calcBSS());
901 ret->push_back(sj_rmul_);
902 ret->push_back(sj_large_);
903 ret->push_back(sj_Fn_);
904 ret->push_back(sj_Fs_.mag());
905 ret->push_back(sj_gap_);
906 ret->push_back(sj_unorm_.mag());
907 ret->push_back(sj_A_);
908 ret->push_back(sj_rad_);
909 ret->push_back(sj_Un_);
910 ret->push_back(sj_Us_.mag());
911 ret->push_back(isjSliding_);
912 ret->push_back(dip_/dDegrad);
913#ifdef THREED
914 ret->push_back(dd_/dDegrad);
915#endif
916 FP_S;
917 }
918
919 double ContactModelSmoothJoint::calcBSS() const {
920 if (sj_A_ > 0) {
921 double dSigma = sj_Fn_ / sj_A_;
922 return dSigma >= -sj_bns_ ? sj_bcoh_ + (tan(sj_bfa_) * dSigma)
923 : sj_bcoh_ + (tan(sj_bfa_) * (-sj_bns_));
924 }
925 else
926 return 0.0;
927 }
928
929
930} // namespace itascaxd
931// EoF
Was this helpful? ... | Itasca Software © 2024, Itasca | Updated: Jun 07, 2025 |