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 QString getName() const { return "smoothjoint"; }
54 virtual void setIndex(int i) { index_=i;}
55 virtual int getIndex() const {return index_;}
56
57 virtual QString 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 QString getFishCallEvents() const { return "bond_break,slip_change"; }
86 virtual QVariant getProperty(uint32 i,const IContact *con=0) const;
87 virtual bool getPropertyGlobal(uint32 i) const;
88 virtual bool setProperty(uint32 i,const QVariant &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 QString getMethods() const {
99 return "sj_setforce,bond,unbond";
100 }
101
102 virtual QString getMethodArguments(uint32 i) const;
103 virtual bool setMethod(uint32 i,const QVector<QVariant> &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 QString 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 QString &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<QString,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 QVariant ContactModelSmoothJoint::getProperty(uint32 i,const IContact *) const {
177 // The IContact pointer may be a nullptr!
178 QVariant 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 QVariant();
216 }
217
218 bool ContactModelSmoothJoint::getPropertyGlobal(uint32 ) const {
219 return true;
220 }
221
222 bool ContactModelSmoothJoint::setProperty(uint32 i,const QVariant &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<uint32>())
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.toBool();
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 QString ContactModelSmoothJoint::getMethodArguments(uint32 i) const {
394 QString def = QString();
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 QVector<QVariant> &vl,IContact *con) {
405 IContactMechanical *c(convert_getcast<IContactMechanical>(con));
406 switch (i) {
407 case kwSetForce: {
408 DVect gf = c->getGlobalForce();
409 if (isjFlip_)
410 gf *= -1.0;
411 sj_Fn_ = gf | sj_unorm_;
412 return false;
413 }
414 case kwBond: {
415 if (sj_state_ == 3) return false;
416 double mingap = -1.0 * limits<double>::max();
417 double maxgap = 0;
418 if (vl.at(0).canConvert<double>())
419 maxgap = vl.at(0).toDouble();
420 else if (vl.at(0).canConvert<DVect2>()) {
421 DVect2 value = vl.at(0).value<DVect2>();
422 mingap = value.minComp();
423 maxgap = value.maxComp();
424 } else if (!vl.at(0).isNull())
425 throw Exception("gap value {0} not recognized in method bond in contact model {1}.",vl.at(0),getName());
426 if ( sj_gap_ >= mingap && sj_gap_ <= maxgap) {
427 sj_state_ = 3;
428 return true;
429 }
430 return false;
431 }
432 case kwUnbond: {
433 if (sj_state_ == 0) return false;
434 double mingap = -1.0 * limits<double>::max();
435 double maxgap = 0;
436 if (vl.at(0).canConvert<double>())
437 maxgap = vl.at(0).toDouble();
438 else if (vl.at(0).canConvert<DVect2>()) {
439 DVect2 value = vl.at(0).value<DVect2>();
440 mingap = value.minComp();
441 maxgap = value.maxComp();
442 }
443 else if (!vl.at(0).isNull())
444 throw Exception("gap value {0} not recognized in method unbond in contact model {1}.",vl.at(0),getName());
445 if ( sj_gap_ >= mingap && sj_gap_ <= maxgap) {
446 sj_state_ = 0;
447 return true;
448 }
449 return false;
450 }
451
452 }
453 return false;
454 }
455
456 double ContactModelSmoothJoint::getEnergy(uint32 i) const {
457 double ret(0.0);
458 if (!energies_)
459 return ret;
460 switch (i) {
461 case kwEStrain: return energies_->estrain_;
462 case kwESlip: return energies_->eslip_;
463 }
464 assert(0);
465 return ret;
466 }
467
468 bool ContactModelSmoothJoint::getEnergyAccumulate(uint32 i) const {
469 bool ret(false);
470 if (!energies_) return ret;
471 switch (i) {
472 case kwEStrain: return false;
473 case kwESlip: return true;
474 }
475 assert(0);
476 return ret;
477 }
478
479 void ContactModelSmoothJoint::setEnergy(uint32 i,const double &d) {
480 if (!energies_) return;
481 switch (i) {
482 case kwEStrain: energies_->estrain_ = d; return;
483 case kwESlip: energies_->eslip_ = d; return;
484 }
485 assert(0);
486 return;
487 }
488
489 bool ContactModelSmoothJoint::validate(ContactModelMechanicalState *state,const double &) {
490 assert(state);
491 const IContactMechanical *c = state->getMechanicalContact();
492 assert(c);
493 localSystem_ = c->getContact()->getLocalSystem();
494
495 if (state->trackEnergy_)
496 activateEnergy();
497
498 // The radius multiplier has been set previously so calculate the sj_A_
499 // Need to do this regardless of whether or not the radius multiplier has been updated as this is the
500 // first place with the contact state to get the ball radii!
501 updateAreaAndNormal(state);
502
503 if (inheritanceField_ & sjKnMask)
504 updateKn(c);
505 if (inheritanceField_ & sjKsMask)
506 updateKs(c);
507 if (inheritanceField_ & sjFricMask)
508 updateFric(c);
509
510 updateEffectiveTranslationalStiffness();
511
512 return checkActivity(state->gap_);
513 }
514
515 void ContactModelSmoothJoint::updateAreaAndNormal(ContactModelMechanicalState *state) {
516 updateAreaAndNormalContact(state->end1Curvature_,state->end2Curvature_,state->axes_.e1());
517 }
518
519 void ContactModelSmoothJoint::updateAreaAndNormalContact(const DVect2 &end1Curvature,const DVect2 &end2Curvature,const DVect &norm) {
520 if (geomRecomp_) geomRecomp_ = false;
521 // Use the maximum value of the curvature here - not the min!
522 sj_rad_ = 1.0 / std::max(end1Curvature.y(),end2Curvature.y());
523 sj_rad_ = sj_rmul_ * sj_rad_;
524#ifdef THREED
525 sj_A_ = dPi * sj_rad_ * sj_rad_;
526 sj_unorm_.rx() = sin(dip_) * sin(dd_);
527 sj_unorm_.ry() = sin(dip_) * cos(dd_);
528 sj_unorm_.rz() = cos(dip_);
529#else
530 sj_A_ = 2.0 * sj_rad_; // Assumes thickness of 1 in 2D
531 sj_unorm_.rx() = sin(dip_);
532 sj_unorm_.ry() = cos(dip_);
533#endif
534 DVect nc = norm;
535 // Set the flip boolean so that the ordering is correct from side1 to side2
536 isjFlip_ = ( ((nc | sj_unorm_) >= 0.0 ) ? false : true );
537 }
538
539 static const QString kn("sj_kn");
540 bool ContactModelSmoothJoint::updateKn(const IContactMechanical *con) {
541 assert(con);
542 QVariant v1 = con->getEnd1()->getProperty(kn);
543 QVariant v2 = con->getEnd2()->getProperty(kn);
544 if (!v1.isValid() || !v2.isValid())
545 return false;
546 double kn1 = v1.toDouble();
547 double kn2 = v2.toDouble();
548 double val = sj_kn_;
549 if (kn1 && kn2)
550 sj_kn_ = kn1*kn2/(kn1+kn2);
551 else if (kn1)
552 sj_kn_ = kn1;
553 else if (kn2)
554 sj_kn_ = kn2;
555 return ( (sj_kn_ != val) );
556 }
557
558 static const QString ks("sj_ks");
559 bool ContactModelSmoothJoint::updateKs(const IContactMechanical *con) {
560 assert(con);
561 QVariant v1 = con->getEnd1()->getProperty(ks);
562 QVariant v2 = con->getEnd2()->getProperty(ks);
563 if (!v1.isValid() || !v2.isValid())
564 return false;
565 double kn1 = v1.toDouble();
566 double kn2 = v2.toDouble();
567 double val = sj_ks_;
568 if (kn1 && kn2)
569 sj_ks_ = kn1*kn2/(kn1+kn2);
570 else if (kn1)
571 sj_ks_ = kn1;
572 else if (kn2)
573 sj_ks_ = kn2;
574 return ( (sj_ks_ != val) );
575 }
576
577 static const QString fric("sj_fric");
578 bool ContactModelSmoothJoint::updateFric(const IContactMechanical *con) {
579 assert(con);
580 QVariant v1 = con->getEnd1()->getProperty(fric);
581 QVariant v2 = con->getEnd2()->getProperty(fric);
582 if (!v1.isValid() || !v2.isValid())
583 return false;
584 double fric1 = std::max(0.0,v1.toDouble());
585 double fric2 = std::max(0.0,v2.toDouble());
586 double val = sj_fric_;
587 sj_fric_ = std::min(fric1,fric2);
588 return ( (sj_fric_ != val) );
589 }
590
591 bool ContactModelSmoothJoint::endPropertyUpdated(const QString &name,const IContactMechanical *c) {
592 assert(c);
593 QStringList availableProperties = getProperties().simplified().replace(" ","").split(",",Qt::SkipEmptyParts);
594 QRegularExpression rx(name, QRegularExpression::CaseInsensitiveOption);
595 int idx = availableProperties.indexOf(rx) + 1;
596 bool ret=false;
597
598 if (idx<=0)
599 return ret;
600
601 switch(idx) {
602 case kwKn: { //sj_kn_
603 if (inheritanceField_ & sjKnMask)
604 ret = updateKn(c);
605 break;
606 }
607 case kwKs: { //sj_ks_
608 if (inheritanceField_ & sjKsMask)
609 ret =updateKs(c);
610 break;
611 }
612 case kwFric: { //sj_fric_
613 if (inheritanceField_ & sjFricMask)
614 updateFric(c);
615 break;
616 }
617 }
618
619 if (ret)
620 updateEffectiveTranslationalStiffness();
621 return ret;
622 }
623
624 void ContactModelSmoothJoint::updateEffectiveTranslationalStiffness() {
625 effectiveTranslationalStiffness_ = DVect2(sj_kn_,sj_ks_)*sj_A_;
626 }
627
628 bool ContactModelSmoothJoint::forceDisplacementLaw(ContactModelMechanicalState *state,const double &) {
629 assert(state);
630
631 if (geomRecomp_)
632 updateAreaAndNormal(state);
633
634 // Skip out if this should not be active
635 if (sj_large_ && state->gap_ > 0.0 && sj_state_ != 3) {
636 sj_Fn_ = 0.0;
637 sj_Fs_ = DVect(0.0);
638 sj_gap_ = 0.0;
639 sj_Un_ = 0.0;
640 sj_Us_ = DVect(0.0);
641 return false;
642 }
643
644 // Get the translational increment in the global system
645 localSystem_ = state->axes_;
646 DVect tInc = localSystem_.toGlobal(state->relativeTranslationalIncrement_);
647
648 // Now have the translational increment and the normal in the global coordinate system
649 // Compute the normal/shear displacement increments along the sj
650 if (isjFlip_)
651 tInc *= -1.0;
652 double nInc = tInc | sj_unorm_;
653 DVect sInc = tInc - sj_unorm_ * nInc;
654 sj_Un_ -= nInc;
655 sj_Us_ += sInc;
656
657 double nElInc(0.0);
658 DVect sElInc(0.0);
659
660 double g0 = sj_gap_, g1 = sj_gap_ + nInc;
661 sj_gap_ = g1;
662
663 if (!state->canFail_ || sj_state_ == 3 ) { // Bonded
664 nElInc = nInc;
665 sElInc = sInc;
666 } else {
667 if ( g0 <= 0.0 ) {
668 if ( g1 <= 0.0 ) {
669 nElInc = nInc;
670 sElInc = sInc;
671 } else { // g1 > 0.0
672 double xi = -g0 / (g1 - g0);
673 nElInc = nInc * xi;
674 sElInc = sInc * xi;
675 }
676 } else { // g0 > 0.0
677 if ( g1 >= 0.0 ) {
678 nElInc = 0.0;
679 sElInc.fill(0.0);
680 } else { // g1 < 0.0
681 double xi = -g0 / (g1 - g0);
682 nElInc = nInc * (1.0 - xi);
683 sElInc = sInc * (1.0 - xi);
684 }
685 }
686 }
687
688 double del_Fn = -sj_kn_ * sj_A_ * nElInc ;
689 sj_Fn_ += del_Fn ;
690 int slideChange(-1);
691 DVect sj_Fs_old = sj_Fs_;
692
693 if ( state->canFail_ && sj_state_ < 3 ) { // Coulomb sliding with dilation
694 if ( sj_Fn_ <= 0.0 ) {
695 sj_Fn_ = 0.0;
696 sj_Fs_.fill(0.0);
697 } else {
698 DVect del_Fs = sElInc * (-sj_ks_ * sj_A_);
699 sj_Fs_ += del_Fs;
700 double max_Fs = sj_Fn_ * sj_fric_;
701 double magFs = sj_Fs_.mag();
702 if ( magFs > max_Fs ) { // sliding
703 if (!isjSliding_) {
704 isjSliding_ = true;
705 slideChange = 0;
706 }
707 if ( sj_ks_ > 0.0 ) // dilation
708 sj_Fn_ += ( (magFs - max_Fs) / sj_ks_ ) * sj_kn_ * tan(sj_da_);
709 double rat = max_Fs / magFs ;
710 sj_Fs_ *= rat ;
711 } else {
712 if (isjSliding_) {
713 isjSliding_ = false;
714 slideChange = 1;
715 }
716 }
717 }
718 } else { // bonded behavior
719 if ( state->canFail_ && sj_Fn_ <= -sj_bns_ * sj_A_) {
720 sj_state_ = 1;
721 if (cmEvents_[fBondBreak] >= 0) {
722 auto c = state->getContact();
723 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
724 fish::Parameter((qint64)sj_state_),
725 fish::Parameter(sj_bns_) };
726 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
727 fi->setCMFishCallArguments(c,arg,cmEvents_[fBondBreak]);
728 }
729 sj_Fn_ = 0.0;
730 sj_Fs_.fill(0.0);
731 } else {
732 DVect del_Fs = sElInc * (-sj_ks_ * sj_A_);
733 sj_Fs_ += del_Fs;
734 double magFs = sj_Fs_.mag();
735 double ss = calcBSS();
736 if ( state->canFail_ && magFs >= ss * sj_A_) { // break in shear
737 sj_state_ = 2;
738 if (cmEvents_[fBondBreak] >= 0) {
739 auto c = state->getContact();
740 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
741 fish::Parameter((qint64)sj_state_),
742 fish::Parameter(ss) };
743 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
744 fi->setCMFishCallArguments(c,arg,cmEvents_[fBondBreak]);
745 }
746
747 if ( sj_Fn_ < 0.0 ) {
748 sj_Fn_ = 0.0;
749 sj_Fs_.fill(0.0);
750 } else { // was in compression // was in tension
751 double max_Fs = sj_Fn_ * sj_fric_ ;
752 if ( magFs > max_Fs) { // sliding, but no dilation
753 if (!isjSliding_) {
754 isjSliding_ = true;
755 slideChange = 0;
756 }
757 double rat = max_Fs / magFs ;
758 sj_Fs_ *= rat ;
759 } else {
760 if (isjSliding_ == true) {
761 isjSliding_ = false;
762 slideChange = 1;
763 }
764 }
765 }
766 }
767 }
768 }
769 if (slideChange >= 0 && cmEvents_[fSlipChange] >= 0) {
770 auto c = state->getContact();
771 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
772 fish::Parameter((qint64)slideChange) };
773 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
774 fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
775 }
776
777 // Have updated the normal and shear forces so need to put them into the contact local
778 // coordinate system and update the forces
779 DVect Fj = sj_unorm_ * sj_Fn_ + sj_Fs_;
780 if (isjFlip_)
781 Fj *= -1.0;
782
783 // Return the correct activity status
784 bool isactive = true;
785 if (sj_large_ && state->gap_ > 0.0 && sj_state_ != 3) {
786 sj_Fn_ = 0.0;
787 sj_Fs_ = DVect(0.0);
788 sj_gap_ = 0.0;
789 sj_Un_ = 0.0;
790 sj_Us_ = DVect(0.0);
791 isactive = false;
792 }
793
794 // update energies
795 if (state->trackEnergy_) {
796 assert(energies_);
797 energies_->estrain_ = 0.0;
798 if (sj_kn_)
799 energies_->estrain_ = 0.5*sj_Fn_*sj_Fn_/sj_kn_;
800 if (sj_ks_) {
801 double smag2 = sj_Fs_.mag2();
802 energies_->estrain_ += 0.5*smag2 / sj_ks_;
803 if (isjSliding_) {
804 DVect avg_F_s = (sj_Fs_old + sj_Fs_)*0.5;
805 DVect u_s_el = (sj_Fs_ - sj_Fs_old) / sj_ks_;
806 energies_->eslip_ -= std::min(0.0,(avg_F_s | (sInc + u_s_el)));
807 }
808 }
809 }
810
811 return isactive ;
812 }
813
814 void ContactModelSmoothJoint::setForce(const DVect &v,IContact *c) {
815 // this is in the local coordinate system
816 localSystem_ = c->getLocalSystem();
817 DVect globForce = localSystem_.toGlobal(v);
818 if (isjFlip_)
819 globForce *= -1.0;
820 sj_Fn_ = (sj_unorm_ | globForce);
821 sj_Fs_ = globForce - sj_unorm_ * sj_Fn_;
822 }
823
824 DVect ContactModelSmoothJoint::getForce() const {
825 DVect Fj = sj_unorm_ * sj_Fn_ + sj_Fs_;
826 if (isjFlip_)
827 Fj *= -1.0;
828 DVect ret(localSystem_.toLocal(Fj));
829 return ret;
830 }
831
832 DAVect ContactModelSmoothJoint::getMomentOn1(const IContactMechanical *c) const {
833 DVect force = getForce();
834 DAVect ret(0.0);
835 c->updateResultingTorqueOn1Local(force,&ret);
836 return ret;
837 }
838
839 DAVect ContactModelSmoothJoint::getMomentOn2(const IContactMechanical *c) const {
840 DVect force = getForce();
841 DAVect ret(0.0);
842 c->updateResultingTorqueOn2Local(force,&ret);
843 return ret;
844 }
845
846 DAVect ContactModelSmoothJoint::getModelMomentOn1() const {
847 DAVect ret(0.0);
848 return ret;
849 }
850
851 DAVect ContactModelSmoothJoint::getModelMomentOn2() const {
852 DAVect ret(0.0);
853 return ret;
854 }
855
856 void ContactModelSmoothJoint::objectPropsTypes(std::vector<std::pair<QString,InfoTypes>> *ret) const {
857 ret->clear();
858 ret->push_back({"sj_kn",ScalarInfo});
859 ret->push_back({"sj_ks",ScalarInfo});
860 ret->push_back({"sj_fric",ScalarInfo});
861 ret->push_back({"sj_da",ScalarInfo});
862 ret->push_back({"sj_state",ScalarInfo});
863 ret->push_back({"sj_ten",ScalarInfo});
864 ret->push_back({"sj_coh",ScalarInfo});
865 ret->push_back({"sj_fa",ScalarInfo});
866 ret->push_back({"sj_shear",ScalarInfo});
867 ret->push_back({"sj_rmul",ScalarInfo});
868 ret->push_back({"sj_large",ScalarInfo});
869 ret->push_back({"sj_fn",ScalarInfo});
870 ret->push_back({"sj_fs",VectorInfo});
871 ret->push_back({"sj_gap",ScalarInfo});
872 ret->push_back({"sj_unorm",VectorInfo});
873 ret->push_back({"sj_area",ScalarInfo});
874 ret->push_back({"sj_radius",ScalarInfo});
875 ret->push_back({"sj_un",ScalarInfo});
876 ret->push_back({"sj_us",VectorInfo});
877 ret->push_back({"sj_slip",ScalarInfo});
878 ret->push_back({"dip",ScalarInfo});
879#ifdef THREED
880 ret->push_back({"ddir",ScalarInfo});
881#endif
882
883 }
884
885 void ContactModelSmoothJoint::objectPropValues(std::vector<double> *ret,const IContact *) const {
886 ret->clear();
887 ret->push_back(sj_kn_);
888 ret->push_back(sj_ks_);
889 ret->push_back(sj_fric_);
890 ret->push_back(sj_da_/dDegrad);
891 ret->push_back(sj_state_);
892 ret->push_back(sj_bns_);
893 ret->push_back(sj_bcoh_);
894 ret->push_back(sj_bfa_/dDegrad);
895 ret->push_back(calcBSS());
896 ret->push_back(sj_rmul_);
897 ret->push_back(sj_large_);
898 ret->push_back(sj_Fn_);
899 ret->push_back(sj_Fs_.mag());
900 ret->push_back(sj_gap_);
901 ret->push_back(sj_unorm_.mag());
902 ret->push_back(sj_A_);
903 ret->push_back(sj_rad_);
904 ret->push_back(sj_Un_);
905 ret->push_back(sj_Us_.mag());
906 ret->push_back(isjSliding_);
907 ret->push_back(dip_/dDegrad);
908#ifdef THREED
909 ret->push_back(dd_/dDegrad);
910#endif
911 }
912
913 double ContactModelSmoothJoint::calcBSS() const {
914 if (sj_A_ > 0) {
915 double dSigma = sj_Fn_ / sj_A_;
916 return dSigma >= -sj_bns_ ? sj_bcoh_ + (tan(sj_bfa_) * dSigma)
917 : sj_bcoh_ + (tan(sj_bfa_) * (-sj_bns_));
918 }
919 else
920 return 0.0;
921 }
922
923
924} // namespace itascaxd
925// EoF
Was this helpful? ... | Itasca Software © 2024, Itasca | Updated: Dec 19, 2024 |