Hysteretic Model Implementation
See this page for the documentation of this contact model.
contactmodelhysteretic.h
1#pragma once
2// contactmodelhysteretic.h
3
4#include "contactmodel/src/contactmodelmechanical.h"
5
6#ifdef HYSTERETIC_LIB
7# define HYSTERETIC_EXPORT EXPORT_TAG
8#elif defined(NO_MODEL_IMPORT)
9# define HYSTERETIC_EXPORT
10#else
11# define HYSTERETIC_EXPORT IMPORT_TAG
12#endif
13
14namespace cmodelsxd {
15 using namespace itasca;
16
17 class ContactModelHysteretic : public ContactModelMechanical {
18 public:
19 enum PropertyKeys { kwHzShear=1
20 , kwHzPoiss
21 , kwFric
22 , kwHzF
23 , kwHzS
24 , kwHzSd
25 , kwHzAlpha
26 , kwDpMode
27 , kwDpEn
28 , kwDpEnMin
29 , kwDpF
30 };
31
32 HYSTERETIC_EXPORT ContactModelHysteretic();
33 HYSTERETIC_EXPORT ContactModelHysteretic(const ContactModelHysteretic &) noexcept;
34 HYSTERETIC_EXPORT const ContactModelHysteretic & operator=(const ContactModelHysteretic &);
35 HYSTERETIC_EXPORT void addToStorage(poly::vector<ContactModelMechanical> *s,int ww = -1) override;
36
37 HYSTERETIC_EXPORT virtual ~ContactModelHysteretic();
38 virtual void copy(const ContactModel *c) override;
39 virtual void archive(ArchiveStream &);
40
41 virtual string getName() const { return "hysteretic"; }
42 virtual void setIndex(int i) { index_=i;}
43 virtual int getIndex() const {return index_;}
44
45 virtual string getProperties() const {
46 return "hz_shear"
47 ",hz_poiss"
48 ",fric"
49 ",hz_force"
50 ",hz_slip"
51 ",hz_mode"
52 ",hz_alpha"
53 ",dp_mode"
54 ",dp_en"
55 ",dp_enmin"
56 ",dp_force"
57 ;
58 }
59
60 enum EnergyKeys { kwEStrain=1,kwESlip,kwEDashpot};
61 virtual string getEnergies() const { return "energy-strain,energy-slip,energy-dashpot";}
62 virtual double getEnergy(uint32 i) const; // Base 1
63 virtual bool getEnergyAccumulate(uint32 i) const; // Base 1
64 virtual void setEnergy(uint32 i,const double &d); // Base 1
65 virtual void activateEnergy() { if (energies_) return; energies_ = NEW Energies();}
66 virtual bool getEnergyActivated() const {return (energies_ !=0);}
67
68 enum FishCallEvents { fActivated=0, fSlipChange};
69 virtual string getFishCallEvents() const { return "contact_activated,slip_change"; }
70 virtual base::Property getProperty(uint32 i,const IContact *) const;
71 virtual bool getPropertyGlobal(uint32 i) const;
72 virtual bool setProperty(uint32 i,const base::Property &v,IContact *);
73 virtual bool getPropertyReadOnly(uint32 i) const;
74
75 virtual bool supportsInheritance(uint32 i) const;
76 virtual bool getInheritance(uint32 i) const { assert(i<32); uint32 mask = to<uint32>(1 << i); return (inheritanceField_ & mask) ? true : false; }
77 virtual void setInheritance(uint32 i,bool b) { assert(i<32); uint32 mask = to<uint32>(1 << i); if (b) inheritanceField_ |= mask; else inheritanceField_ &= ~mask; }
78
79 virtual uint32 getMinorVersion() const;
80
81 virtual bool validate(ContactModelMechanicalState *state,const double ×tep);
82 virtual bool endPropertyUpdated(const string &name,const IContactMechanical *c);
83 virtual bool forceDisplacementLaw(ContactModelMechanicalState *state,const double ×tep);
84 virtual DVect2 getEffectiveTranslationalStiffness() const { return effectiveTranslationalStiffness_;}
85 virtual DAVect getEffectiveRotationalStiffness() const { return DAVect(0.0);}
86
87 virtual ContactModelHysteretic *clone() const override { return NEW ContactModelHysteretic(); }
88 virtual double getActivityDistance() const {return 0.0;}
89 virtual bool isOKToDelete() const { return !isBonded(); }
90 virtual void resetForcesAndMoments() { hz_F(DVect(0.0)); dp_F(DVect(0.0)); if (energies_) energies_->estrain_ = 0.0;}
91 virtual void setForce(const DVect &v,IContact *) { hz_F(v); }
92 virtual void setArea(const double &) { throw Exception("The setArea method cannot be used with this contact model."); }
93 virtual double getArea() const { return 0.0; }
94
95 virtual bool checkActivity(const double &gap) { return gap <= 0.0; }
96
97 virtual bool isSliding() const { return hz_slip_; }
98 virtual bool isBonded() const { return false; }
99 virtual void propagateStateInformation(IContactModelMechanical* oldCm,const CAxes &oldSystem=CAxes(),const CAxes &newSystem=CAxes());
100 virtual void setNonForcePropsFrom(IContactModel *oldCM);
101
102 const double & hz_shear() const {return hz_shear_;}
103 void hz_shear(const double &d) {hz_shear_=d;}
104 const double & hz_poiss() const {return hz_poiss_;}
105 void hz_poiss(const double &d) {hz_poiss_=d;}
106 const double & fric() const {return fric_;}
107 void fric(const double &d) {fric_=d;}
108 uint32 hz_mode() const {return hz_mode_;}
109 void hz_mode(uint32 i) {hz_mode_=i;}
110 const DVect & hz_F() const {return hz_F_;}
111 void hz_F(const DVect &f) { hz_F_=f;}
112 bool hz_S() const {return hz_slip_;}
113 void hz_S(bool b) { hz_slip_=b;}
114 const double & hz_alpha() const {return hz_alpha_;}
115 void hz_alpha(const double &d) {hz_alpha_=d;}
116 int dp_mode() const {return dp_mode_;}
117 void dp_mode(int i) {dp_mode_=i;}
118 const double & dp_en() const {return dp_en_;}
119 void dp_en(const double &d) {dp_en_=d;}
120 const double & dp_enmin() const {return dp_enmin_;}
121 void dp_enmin(const double &d) {dp_enmin_=d;}
122 const DVect & dp_F() const {return dp_F_;}
123 void dp_F(const DVect &f) { dp_F_=f;}
124 const double & hn() const {return hn_;}
125 void hn(const double &d) {hn_=d;}
126 const double & hs() const {return hs_;}
127 void hs(const double &d) {hs_=d;}
128 const double & vni() const {return vni_;}
129 void vni(const double &d) {vni_=d;}
130 double pfac() const {return pfac_;}
131 void pfac(int i) {pfac_=i;}
132
133 bool hasEnergies() const {return energies_ ? true:false;}
134 double estrain() const {return hasEnergies() ? energies_->estrain_: 0.0;}
135 void estrain(const double &d) { if(!hasEnergies()) return; energies_->estrain_=d;}
136 double eslip() const {return hasEnergies() ? energies_->eslip_: 0.0;}
137 void eslip(const double &d) { if(!hasEnergies()) return; energies_->eslip_=d;}
138 double edashpot() const {return hasEnergies() ? energies_->edashpot_: 0.0;}
139 void edashpot(const double &d) { if(!hasEnergies()) return; energies_->edashpot_=d;}
140
141 uint32 inheritanceField() const {return inheritanceField_;}
142 void inheritanceField(uint32 i) {inheritanceField_ = i;}
143
144 const DVect2 & effectiveTranslationalStiffness() const {return effectiveTranslationalStiffness_;}
145 void effectiveTranslationalStiffness(const DVect2 &v ) {effectiveTranslationalStiffness_=v;}
146
147 /// Return the total force that the contact model holds.
148 virtual DVect getForce() const;
149
150 /// Return the total moment on 1 that the contact model holds
151 virtual DAVect getMomentOn1(const IContactMechanical *) const;
152
153 /// Return the total moment on 1 that the contact model holds
154 virtual DAVect getMomentOn2(const IContactMechanical *) const;
155
156 virtual DAVect getModelMomentOn1() const;
157 virtual DAVect getModelMomentOn2() const;
158
159 // Used to efficiently get properties from the contact model for the object pane.
160 // List of properties for the object pane, comma separated.
161 // All properties will be cast to doubles for comparison. No other comparisons
162 // are supported. This may not be the same as the entire property list.
163 // Return property name and type for plotting.
164 void objectPropsTypes(std::vector<std::pair<string,InfoTypes>> *) const override;
165 // All properties cast to doubles - this is what can be compared.
166 void objectPropValues(std::vector<double> *,const IContact *) const override;
167
168 private:
169 static int index_;
170
171 bool updateStiffCoef(const IContactMechanical *con);
172 bool updateEndStiffCoef(const IContactMechanical *con);
173 bool updateEndFric(const IContactMechanical *con);
174 void updateEffectiveStiffness(ContactModelMechanicalState *state);
175 // inheritance fields
176 uint32 inheritanceField_;
177
178 // hertz model
179 double hz_shear_ = 0.0; // Shear modulus
180 double hz_poiss_ = 0.0; // Poisson ratio
181 double fric_ = 0.0; // Coulomb friction coefficient
182 DVect hz_F_ = DVect(0.0); // Force carried in the hertz model
183 bool hz_slip_ = false; // the current sliding state
184 uint32 hz_mode_ = 0; // specifies down-scaling of the shear force when normal unloading occurs
185 double hz_alpha_ = 1.5; // alpha exponent
186 int dp_mode_ = 0; // Damping scheme mode
187 double dp_en_ = 1.0; // normal restitution coefficient
188 double dp_enmin_ = 0.0; // minimal normal restitution coefficient in default mode
189 DVect dp_F_ = DVect(0.0); // Damping Force
190
191 // energies
192 struct Energies {
193 Energies() : estrain_(0.0), eslip_(0.0),edashpot_(0.0) {}
194 double estrain_; // elastic energy stored in contact
195 double eslip_; // work dissipated by friction
196 double edashpot_; // work dissipated by dashpots
197 };
198 Energies * energies_ = nullptr;
199
200 double hn_ = 0.0; // normal stiffness coefficient
201 double hs_ = 0.0; // shear stiffness coefficient
202 DVect2 effectiveTranslationalStiffness_ = DVect2(0.0); // effective stiffness
203 double vni_ = 0.0; // normal impact velocity
204 double pfac_ = 0.0; // previous damping factor
205
206 };
207
208} // namespace cmodelsxd
209// EoF
contactmodelhysteretic.cpp
1// contactmodelhysteretic.cpp
2#include "contactmodelhysteretic.h"
3
4#include "../version.txt"
5#include "fish/src/parameter.h"
6#include "utility/src/tptr.h"
7#include "shared/src/mathutil.h"
8
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#include "kernel/interface/iprogram.h"
14
15
16#ifdef HYSTERETIC_LIB
17#ifdef _WIN32
18 int __stdcall DllMain(void *,unsigned, void *) {
19 return 1;
20 }
21#endif
22
23 extern "C" EXPORT_TAG const char *getName() {
24#if DIM==3
25 return "contactmodelmechanical3dhysteretic";
26#else
27 return "contactmodelmechanical2dhysteretic";
28#endif
29 }
30
31 extern "C" EXPORT_TAG unsigned getMajorVersion() {
32 return MAJOR_VERSION;
33 }
34
35 extern "C" EXPORT_TAG unsigned getMinorVersion() {
36 return MINOR_VERSION;
37 }
38
39 extern "C" EXPORT_TAG void *createInstance() {
40 cmodelsxd::ContactModelHysteretic *m = NEW cmodelsxd::ContactModelHysteretic();
41 return (void *)m;
42 }
43#endif // HYSTERETIC_LIB
44
45namespace cmodelsxd {
46
47 static const uint32 shearMask = 0x00002;
48 static const uint32 poissMask = 0x00004;
49 static const uint32 fricMask = 0x00008;
50
51 using namespace itasca;
52
53 int ContactModelHysteretic::index_ = -1;
54 uint32 ContactModelHysteretic::getMinorVersion() const { return MINOR_VERSION; }
55
56 ContactModelHysteretic::ContactModelHysteretic() : inheritanceField_(shearMask|poissMask|fricMask) {
57 }
58
59 ContactModelHysteretic::ContactModelHysteretic(const ContactModelHysteretic &m) noexcept {
60 inheritanceField(shearMask|poissMask|fricMask);
61 this->copy(&m);
62 }
63
64 const ContactModelHysteretic & ContactModelHysteretic::operator=(const ContactModelHysteretic &m) {
65 inheritanceField(shearMask|poissMask|fricMask);
66 this->copy(&m);
67 return *this;
68 }
69
70 void ContactModelHysteretic::addToStorage(poly::vector<ContactModelMechanical> *s,int ww) {
71 s->addToStorage<ContactModelHysteretic>(*this,ww);
72 }
73
74 ContactModelHysteretic::~ContactModelHysteretic() {
75 if (energies_)
76 delete energies_;
77 }
78
79 void ContactModelHysteretic::archive(ArchiveStream &stream) {
80 stream & hz_shear_;
81 stream & hz_poiss_;
82 stream & fric_;
83 stream & hz_F_;
84 stream & hz_slip_;
85 stream & hz_mode_;
86 stream & hz_alpha_;
87 stream & dp_mode_;
88 stream & dp_en_;
89 stream & dp_enmin_;
90 stream & dp_F_;
91 stream & hn_;
92 stream & hs_;
93 stream & vni_;
94 stream & pfac_;
95
96 if (stream.getArchiveState()==ArchiveStream::Save) {
97 bool b = false;
98 if (energies_) {
99 b = true;
100 stream & b;
101 stream & energies_->estrain_;
102 stream & energies_->eslip_;
103 stream & energies_->edashpot_;
104 } else
105 stream & b;
106 } else {
107 bool b(false);
108 stream & b;
109 if (b) {
110 if (!energies_)
111 energies_ = NEW Energies();
112 stream & energies_->estrain_;
113 stream & energies_->eslip_;
114 stream & energies_->edashpot_;
115 }
116 }
117
118 stream & inheritanceField_;
119 stream & effectiveTranslationalStiffness_;
120 }
121
122 void ContactModelHysteretic::copy(const ContactModel *cm) {
123 ContactModelMechanical::copy(cm);
124 const ContactModelHysteretic *in = dynamic_cast<const ContactModelHysteretic*>(cm);
125 if (!in) throw std::runtime_error("Internal error: contact model dynamic cast failed.");
126
127 hz_shear(in->hz_shear());
128 hz_poiss(in->hz_poiss());
129 fric(in->fric());
130 hz_F(in->hz_F());
131 hz_S(in->hz_S());
132 hz_mode(in->hz_mode());
133 hz_alpha(in->hz_alpha());
134 dp_mode(in->dp_mode());
135 dp_en(in->dp_en());
136 dp_enmin(in->dp_enmin());
137 hn(in->hn());
138 hs(in->hs());
139 vni(in->vni());
140 pfac(in->pfac());
141 if (in->hasEnergies()) {
142 if (!energies_)
143 energies_ = NEW Energies();
144 estrain(in->estrain());
145 eslip(in->eslip());
146 edashpot(in->edashpot());
147 }
148 inheritanceField(in->inheritanceField());
149 effectiveTranslationalStiffness(in->effectiveTranslationalStiffness());
150 }
151
152 base::Property ContactModelHysteretic::getProperty(uint32 i,const IContact *) const {
153 // The IContact pointer may be a nullptr!
154 base::Property var;
155 switch (i) {
156 case kwHzShear: return hz_shear_;
157 case kwHzPoiss: return hz_poiss_;
158 case kwFric: return fric_;
159 case kwHzF: var.setValue(hz_F_); return var;
160 case kwHzS: return hz_slip_;
161 case kwHzSd: return hz_mode_;
162 case kwHzAlpha: return hz_alpha_;
163 case kwDpMode: return dp_mode_;
164 case kwDpEn: return dp_en_;
165 case kwDpEnMin: return dp_enmin_;
166 case kwDpF: var.setValue(dp_F_); return var;
167 }
168 assert(0);
169 return base::Property();
170 }
171
172 bool ContactModelHysteretic::getPropertyGlobal(uint32 i) const {
173 switch (i) {
174 case kwHzF: return false;
175 case kwDpF: return false;
176 }
177 return true;
178 }
179
180 bool ContactModelHysteretic::setProperty(uint32 i,const base::Property &v,IContact *) {
181 switch (i) {
182 case kwHzShear: {
183 if (!v.canConvert<double>())
184 throw Exception("hz_shear must be a double.");
185 double val(v.toDouble());
186 if (val<0.0)
187 throw Exception("Negative shear modulus (hz_shear) not allowed.");
188 hz_shear_ = val;
189 return true;
190 }
191 case kwHzPoiss: {
192 if (!v.canConvert<double>())
193 throw Exception("hz_poiss must be a double.");
194 double val(v.toDouble());
195 if (val<=-1.0 || val>0.5)
196 throw Exception("Poisson ratio (hz_poiss) must be in range (-1.0,0.5] ");
197 hz_poiss_ = val;
198 return true;
199 }
200 case kwFric: {
201 if (!v.canConvert<double>())
202 throw Exception("fric must be a double.");
203 double val(v.toDouble());
204 if (val<0.0)
205 throw Exception("Negative fric not allowed.");
206 fric_ = val;
207 return false;
208 }
209 case kwHzSd: {
210 if (!v.canConvert<int64>())
211 throw Exception("hz_mode must be 0 or 1.");
212 uint32 val(v.toUInt());
213 if (val >1)
214 throw Exception("hz_mode must be 0 or 1.");
215 hz_mode_ = val;
216 return false;
217 }
218 case kwHzAlpha: {
219 if (!v.canConvert<double>())
220 throw Exception("hz_alpha must be a double.");
221 double val(v.toDouble());
222 if (val<0.0)
223 throw Exception("Alpha exponent (hz_alpha) must be positive.");
224 hz_alpha_ = val;
225 return false;
226 }
227 case kwDpMode: {
228 if (!v.canConvert<int64>())
229 throw Exception("dp_mode must be an integer.");
230 int val(v.toInt());
231 dp_mode_ = val;
232 return false;
233 }
234 case kwDpEn: {
235 if (!v.canConvert<double>())
236 throw Exception("dp_en must be a double.");
237 double val(v.toDouble());
238 if (val<0.0 || val>1.0)
239 throw Exception("Restitution coefficient (dp_en) must be in range [0.0,1.0] ");
240 dp_en_ = val;
241 return false;
242 }
243 case kwDpEnMin: {
244 if (!v.canConvert<double>())
245 throw Exception("dp_enmin must be a double.");
246 double val(v.toDouble());
247 if (val<0.0 || val>1.0)
248 throw Exception("Minimal restitution coefficient (dp_enmin) must be in range [0.0,1.0] ");
249 dp_enmin_ = val;
250 return false;
251 }
252 }
253 return false;
254 }
255
256 bool ContactModelHysteretic::getPropertyReadOnly(uint32 i) const {
257 switch (i) {
258 case kwHzF:
259 case kwHzS:
260 case kwDpF:
261 return true;
262 default:
263 break;
264 }
265 return false;
266 }
267
268 bool ContactModelHysteretic::supportsInheritance(uint32 i) const {
269 switch (i) {
270 case kwHzShear:
271 case kwHzPoiss:
272 case kwFric:
273 return true;
274 default:
275 break;
276 }
277 return false;
278 }
279
280 double ContactModelHysteretic::getEnergy(uint32 i) const {
281 double ret(0.0);
282 if (!energies_)
283 return ret;
284 switch (i) {
285 case kwEStrain: return energies_->estrain_;
286 case kwESlip: return energies_->eslip_;
287 case kwEDashpot: return energies_->edashpot_;
288 }
289 assert(0);
290 return ret;
291 }
292
293 bool ContactModelHysteretic::getEnergyAccumulate(uint32 i) const {
294 switch (i) {
295 case kwEStrain: return false;
296 case kwESlip: return true;
297 case kwEDashpot: return true;
298 }
299 assert(0);
300 return false;
301 }
302
303 void ContactModelHysteretic::setEnergy(uint32 i,const double &d) {
304 if (!energies_) return;
305 switch (i) {
306 case kwEStrain: energies_->estrain_ = d; return;
307 case kwESlip: energies_->eslip_ = d; return;
308 case kwEDashpot: energies_->edashpot_ = d; return;
309 }
310 assert(0);
311 return;
312 }
313
314 bool ContactModelHysteretic::validate(ContactModelMechanicalState *state,const double &) {
315 assert(state);
316 const IContactMechanical *c = state->getMechanicalContact();
317 assert(c);
318
319 if (state->trackEnergy_)
320 activateEnergy();
321
322 updateStiffCoef(c);
323 if ((inheritanceField_ & shearMask) || (inheritanceField_ & poissMask))
324 updateEndStiffCoef(c);
325
326 if (inheritanceField_ & fricMask)
327 updateEndFric(c);
328
329 updateEffectiveStiffness(state);
330 return checkActivity(state->gap_);
331 }
332
333 bool ContactModelHysteretic::updateStiffCoef(const IContactMechanical *con) {
334 double hnold = hn_;
335 double hsold = hs_;
336 double c12 = con->getEnd1Curvature().y();
337 double c22 = con->getEnd2Curvature().y();
338 double reff = c12+c22;
339 if (reff == 0.0)
340 throw Exception("Hysteretic contact model undefined for 2 non-curved surfaces");
341 reff = 2.0 /reff;
342 hn_ = 2.0/3.0 * (hz_shear_/(1 -hz_poiss_)) * sqrt(2.0*reff);
343 hs_ = (2.0*pow(hz_shear_*hz_shear_*3.0*(1-hz_poiss_)*(reff),1.0/3.0)) / (2.0- hz_poiss_);
344 return ( (hn_ != hnold) || (hs_ != hsold) );
345 }
346
347 static const string gstr("hz_shear");
348 static const string nustr("hz_poiss");
349 bool ContactModelHysteretic::updateEndStiffCoef(const IContactMechanical *con) {
350 assert(con);
351 double g1 = hz_shear_;
352 double g2 = hz_shear_;
353 double nu1 = hz_poiss_;
354 double nu2 = hz_poiss_;
355 base::Property vg1 = con->getEnd1()->getProperty(gstr);
356 base::Property vg2 = con->getEnd2()->getProperty(gstr);
357 base::Property vnu1 = con->getEnd1()->getProperty(nustr);
358 base::Property vnu2 = con->getEnd2()->getProperty(nustr);
359 if (vg1.isValid() && vg2.isValid()) {
360 g1 = vg1.toDouble();
361 g2 = vg2.toDouble();
362 if (g1 < 0.0 || g2 < 0.0)
363 throw Exception("Negative shear modulus not allowed in Hysteretic contact model");
364 }
365 if (vnu1.isValid() && vnu2.isValid()) {
366 nu1 = vnu1.toDouble();
367 nu2 = vnu2.toDouble();
368 if (nu1 <= -1.0 || nu1 > 0.5 || nu2 <= -1.0 || nu2 > 0.5)
369 throw Exception("Poisson ratio should be in range (-1.0,0.5] in Hysteretic contact model");
370 }
371 if (g1*g2 == 0.0) return false;
372 double es = 1.0 / ((1.0-nu1) / (2.0*g1) + (1.0-nu2) / (2.0*g2));
373 double gs = 1.0 / ((2.0-nu1) / g1 + (2.0-nu2) /g2);
374 hz_poiss_ = (4.0*gs-es)/(2.0*gs-es);
375 hz_shear_ = 2.0*gs*(2-hz_poiss_);
376 if (hz_shear_ < 0.0)
377 throw Exception("Negative shear modulus not allowed in Hysteretic contact model");
378 if (hz_poiss_ <= -1.0 || hz_poiss_ > 0.5)
379 throw Exception("Poisson ratio should be in range (-1.0,0.5] in Hysteretic contact model");
380 return updateStiffCoef(con);
381 }
382
383 static const string fricstr("fric");
384 bool ContactModelHysteretic::updateEndFric(const IContactMechanical *con) {
385 assert(con);
386 base::Property v1 = con->getEnd1()->getProperty(fricstr);
387 base::Property v2 = con->getEnd2()->getProperty(fricstr);
388 if (!v1.isValid() || !v2.isValid())
389 return false;
390 double fric1 = std::max(0.0,v1.toDouble());
391 double fric2 = std::max(0.0,v2.toDouble());
392 double val = fric_;
393 fric_ = std::min(fric1,fric2);
394 return ( (fric_ != val) );
395 }
396
397 bool ContactModelHysteretic::endPropertyUpdated(const string &name,const IContactMechanical *c) {
398 assert(c);
399 StringList availableProperties = split(replace(simplified(getProperties())," ",""),",");
400 auto idx = findRegex(availableProperties,name);
401 if (idx==string::npos) return false;
402 idx += 1;
403 bool ret = false;
404
405 switch(idx) {
406 case kwHzShear: {
407 if (inheritanceField_ & shearMask)
408 ret = updateEndStiffCoef(c);
409 break;
410 }
411 case kwHzPoiss: {
412 if (inheritanceField_ & poissMask)
413 ret = updateEndStiffCoef(c);
414 break;
415 }
416 case kwFric: {
417 if (inheritanceField_ & fricMask)
418 ret = updateEndFric(c);
419 break;
420 }
421 }
422 return ret;
423 }
424
425 void ContactModelHysteretic::updateEffectiveStiffness(ContactModelMechanicalState *state) {
426 effectiveTranslationalStiffness_ = DVect2(hn_,hs_);
427 if (state->gap_ >= 0.0) return;
428 double overlap = - state->gap_;
429 double kn = 1.5*hn_*sqrt(overlap);
430 double ks = hs_ * pow(hz_F_.x(),(1.0/3.0));
431 DVect2 ret(kn,ks);
432 effectiveTranslationalStiffness_ = ret;
433 }
434
435 bool ContactModelHysteretic::forceDisplacementLaw(ContactModelMechanicalState *state,const double ×tep) {
436 assert(state);
437 bool firstActive = false;
438 if (state->activated()) {
439 if (cmEvents_[fActivated] >= 0) {
440 auto c = state->getContact();
441 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()) };
442 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
443 fi->setCMFishCallArguments(c,arg,cmEvents_[fActivated]);
444 }
445 firstActive = true;
446 }
447
448 double overlap = - state->gap_;
449 DVect trans = state->relativeTranslationalIncrement_;
450#ifdef THREED
451 DVect norm(trans.x(),0.0,0.0);
452#else
453 DVect norm(trans.x(),0.0);
454#endif
455
456 //DAVect ang = state->relativeAngularIncrement_;
457 DVect hz_F_old = hz_F_;
458 hz_F_ = DVect(0.0);
459 dp_F_ = DVect(0.0);
460 double ks_old = hs_ * pow(hz_F_old.x(),(1.0/3.0));
461 DVect fs_old = hz_F_old;
462 fs_old.rx() = 0.0;
463 if (overlap > 0) {
464
465 double kn = 1.5 * hn_ * sqrt(overlap);
466
467 double vn = norm.x() / timestep;
468 if (firstActive) {
469 if (vn <= 0.0)
470 vni_= vn;
471 else
472 vni_ = 0.0;
473 fs_old = DVect(0.0);
474 ks_old = 0.0;
475 hz_F_old = DVect(0.0);
476 pfac_ = 0.0;
477 }
478 hz_F_.rx() = hn_*pow(overlap,hz_alpha_);
479
480 double ks = hs_ * pow(hz_F_.x(),(1.0/3.0));
481 effectiveTranslationalStiffness_ = DVect2(kn,ks);
482
483 //damping force
484 if (std::abs(vni_) <= limits<double>::epsilon()*1000.0)
485 dp_F_.rx() = 0.0;
486 else {
487 double ratio = vn/vni_;
488 double fac(0.0);
489 switch (dp_mode_) {
490 default:
491 {
492 double used = max(dp_en_,dp_enmin_);
493 fac = max(0.0,(1.0-used*used)/used)*ratio; //Gonthier et al.
494 }
495 break;
496 case 1:
497 fac = 0.75*(1.0-dp_en_*dp_en_)*ratio; // Lankarani et al (1989).
498 break;
499 case 2:
500 fac = 0.75*(1.0-dp_en_*dp_en_)*exp(2.0*(1-dp_en_))*ratio; // Zhiying et al.
501 break;
502 }
503
504 if (fac <= -1.0) { // sucking
505 if (pfac_ >= 0.0) { //switch in one timestep from pushing to sucking - instability
506 fac = 0.0;
507 pfac_ = 0.0;
508 } else
509 pfac_ = fac;
510 } else if (pfac_ != 0.0 && abs(fac) > 10.0*abs(pfac_)) { // growing too fast - instability
511 fac = 0.0;
512 pfac_ = 0.0;
513 } else
514 pfac_ = fac;
515
516 dp_F_.rx() = hz_F_.x()*fac;
517 }
518
519 DVect u_s = trans;
520 u_s.rx() = 0.0;
521 DVect vec = u_s * ks;
522 if (hz_mode_ && (hz_F_.x() < hz_F_old.x())) {
523 double rat = ks / ks_old;
524 fs_old *= rat;
525 }
526 DVect fs = fs_old - vec;
527
528 if (state->canFail_) {
529 // resolve sliding
530 double crit = hz_F_.x() * fric_;
531 double sfmag = fs.mag();
532 if (sfmag > crit) {
533 double rat = crit / sfmag;
534 fs *= rat;
535 if (!hz_slip_ && cmEvents_[fSlipChange] >= 0) {
536 auto c = state->getContact();
537 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
538 fish::Parameter() };
539 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
540 fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
541 }
542 hz_slip_ = true;
543 } else {
544 if (hz_slip_) {
545 if (cmEvents_[fSlipChange] >= 0) {
546 auto c = state->getContact();
547 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
548 fish::Parameter((int64)1) };
549 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
550 fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
551 }
552 hz_slip_ = false;
553 }
554 }
555 }
556
557 fs.rx() = hz_F_.x();
558 hz_F_ = fs; // total force in hertz part
559
560 // 5) Compute energies
561 if (state->trackEnergy_) {
562 assert(energies_);
563 energies_->estrain_ = 0.0;
564 if (kn)
565 energies_->estrain_ = hz_alpha_*hz_F_.x()*hz_F_.x()/((hz_alpha_+1)*kn);
566 if (ks) {
567 DVect s = hz_F_;
568 s.rx() = 0.0;
569 double smag2 = s.mag2();
570 energies_->estrain_ += 0.5*smag2 / ks;
571 if (hz_slip_) {
572 hz_F_old.rx() = 0.0;
573 DVect avg_F_s = (s + hz_F_old)*0.5;
574 DVect u_s_el = (s - hz_F_old) / ks;
575 energies_->eslip_ -= std::min(0.0,(avg_F_s | (u_s + u_s_el)));
576 }
577 }
578 energies_->edashpot_ -= dp_F_ | trans;
579 }
580
581 } else {
582 hz_F_ = DVect(0.0);
583 dp_F_ = DVect(0.0);
584 pfac_ = 0.0;
585 }
586
587
588 return true;
589 }
590
591 void ContactModelHysteretic::propagateStateInformation(IContactModelMechanical* old,const CAxes &oldSystem,const CAxes &newSystem) {
592 // Only do something if the contact model is of the same type
593 if (equal(old->getContactModel()->getName(),"hysteretic")) {
594 ContactModelHysteretic *oldCm = (ContactModelHysteretic *)old;
595#ifdef THREED
596 // Need to rotate just the shear component from oldSystem to newSystem
597
598 // Step 1 - rotate oldSystem so that the normal is the same as the normal of newSystem
599 DVect axis = oldSystem.e1() & newSystem.e1();
600 double c, ang, s;
601 DVect re2;
602 if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
603 axis = axis.unit();
604 c = oldSystem.e1()|newSystem.e1();
605 if (c > 0)
606 c = std::min(c,1.0);
607 else
608 c = std::max(c,-1.0);
609 ang = acos(c);
610 s = sin(ang);
611 double t = 1. - c;
612 DMatrix<3,3> rm;
613 rm.get(0,0) = t*axis.x()*axis.x() + c;
614 rm.get(0,1) = t*axis.x()*axis.y() - axis.z()*s;
615 rm.get(0,2) = t*axis.x()*axis.z() + axis.y()*s;
616 rm.get(1,0) = t*axis.x()*axis.y() + axis.z()*s;
617 rm.get(1,1) = t*axis.y()*axis.y() + c;
618 rm.get(1,2) = t*axis.y()*axis.z() - axis.x()*s;
619 rm.get(2,0) = t*axis.x()*axis.z() - axis.y()*s;
620 rm.get(2,1) = t*axis.y()*axis.z() + axis.x()*s;
621 rm.get(2,2) = t*axis.z()*axis.z() + c;
622 re2 = rm*oldSystem.e2();
623 } else
624 re2 = oldSystem.e2();
625
626 // Step 2 - get the angle between the oldSystem rotated shear and newSystem shear
627 axis = re2 & newSystem.e2();
628 DVect2 tpf;
629 DMatrix<2,2> m;
630 if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
631 axis = axis.unit();
632 c = re2|newSystem.e2();
633 if (c > 0)
634 c = std::min(c,1.0);
635 else
636 c = std::max(c,-1.0);
637 ang = acos(c);
638 if (!checktol(axis.x(),newSystem.e1().x(),1.0,100))
639 ang *= -1;
640 s = sin(ang);
641 m.get(0,0) = c;
642 m.get(1,0) = s;
643 m.get(0,1) = -m.get(1,0);
644 m.get(1,1) = m.get(0,0);
645 tpf = m*DVect2(oldCm->hz_F_.y(),oldCm->hz_F_.z());
646 } else {
647 m.get(0,0) = 1.;
648 m.get(0,1) = 0.;
649 m.get(1,0) = 0.;
650 m.get(1,1) = 1.;
651 tpf = DVect2(oldCm->hz_F_.y(),oldCm->hz_F_.z());
652 }
653 DVect pforce = DVect(0,tpf.x(),tpf.y());
654#else
655 oldSystem;
656 newSystem;
657 DVect pforce = DVect(0,oldCm->hz_F_.y());
658#endif
659 for (int i=1; i<dim; ++i)
660 hz_F_.rdof(i) += pforce.dof(i);
661 oldCm->hz_F_ = DVect(0.0);
662
663 if(oldCm->getEnergyActivated()) {
664 activateEnergy();
665 energies_->estrain_ = oldCm->energies_->estrain_;
666 energies_->eslip_ = oldCm->energies_->eslip_;
667 energies_->edashpot_ = oldCm->energies_->edashpot_;
668 oldCm->energies_->estrain_ = 0.0;
669 oldCm->energies_->eslip_ = 0.0;
670 oldCm->energies_->edashpot_ = 0.0;
671 }
672 }
673 }
674
675 void ContactModelHysteretic::setNonForcePropsFrom(IContactModel *old) {
676 // Only do something if the contact model is of the same type
677 if (equal(old->getName(),"hysteretic") && !isBonded()) {
678 ContactModelHysteretic *oldCm = (ContactModelHysteretic *)old;
679 hn_ = oldCm->hn_;
680 hs_ = oldCm->hs_;
681 fric_ = oldCm->fric_;
682 vni_ = oldCm->vni_;
683 pfac_ = oldCm->pfac_;
684 }
685 }
686
687 DVect ContactModelHysteretic::getForce() const {
688 DVect ret(hz_F_);
689 ret += dp_F_;
690 return ret;
691 }
692
693 DAVect ContactModelHysteretic::getMomentOn1(const IContactMechanical *c) const {
694 DVect force = getForce();
695 DAVect ret(0.0);
696 c->updateResultingTorqueOn1Local(force,&ret);
697 return ret;
698 }
699
700 DAVect ContactModelHysteretic::getMomentOn2(const IContactMechanical *c) const {
701 DVect force = getForce();
702 DAVect ret(0.0);
703 c->updateResultingTorqueOn2Local(force,&ret);
704 return ret;
705 }
706
707 DAVect ContactModelHysteretic::getModelMomentOn1() const {
708 DAVect ret(0.0);
709 return ret;
710 }
711
712 DAVect ContactModelHysteretic::getModelMomentOn2() const {
713 DAVect ret(0.0);
714 return ret;
715 }
716
717 void ContactModelHysteretic::objectPropsTypes(std::vector<std::pair<string,InfoTypes>> *ret) const {
718 ret->clear();
719 ret->push_back({"hz_shear",ScalarInfo});
720 ret->push_back({"hz_poiss",ScalarInfo});
721 ret->push_back({"fric",ScalarInfo});
722 ret->push_back({"hz_force",VectorInfo});
723 ret->push_back({"hz_slip",ScalarInfo});
724 ret->push_back({"hz_mode",ScalarInfo});
725 ret->push_back({"hz_alpha",ScalarInfo});
726 ret->push_back({"dp_mode",ScalarInfo});
727 ret->push_back({"dp_en",ScalarInfo});
728 ret->push_back({"dp_enmin",ScalarInfo});
729 ret->push_back({"dp_force",VectorInfo});
730 }
731
732 void ContactModelHysteretic::objectPropValues(std::vector<double> *ret,const IContact *) const {
733 FP_S;
734 ret->clear();
735 ret->push_back(hz_shear_);
736 ret->push_back(hz_poiss_);
737 ret->push_back(fric_);
738 ret->push_back(hz_F_.mag());
739 ret->push_back(hz_slip_);
740 ret->push_back(hz_mode_);
741 ret->push_back(hz_alpha_);
742 ret->push_back(dp_mode_);
743 ret->push_back(dp_en_);
744 ret->push_back(dp_enmin_);
745 ret->push_back(dp_F_.mag());
746 FP_S;
747 }
748
749} // namespace cmodelsxd
750// EoF
Was this helpful? ... | Itasca Software © 2024, Itasca | Updated: Jun 07, 2025 |