Linear Parallel Bond Model Implementation
See this page for the documentation of this contact model.
contactmodellinearpbond.h
1#pragma once
2// contactmodellinearpbond.h
3
4#include "contactmodel/src/contactmodelmechanical.h"
5
6#ifdef LINEARPBOND_LIB
7# define LINEARPBOND_EXPORT EXPORT_TAG
8#elif defined(NO_MODEL_IMPORT)
9# define LINEARPBOND_EXPORT
10#else
11# define LINEARPBOND_EXPORT IMPORT_TAG
12#endif
13
14namespace cmodelsxd {
15 using namespace itasca;
16
17 class ContactModelLinearPBond : public ContactModelMechanical {
18 public:
19 LINEARPBOND_EXPORT ContactModelLinearPBond();
20 LINEARPBOND_EXPORT ContactModelLinearPBond(const ContactModelLinearPBond &) noexcept;
21 LINEARPBOND_EXPORT const ContactModelLinearPBond & operator=(const ContactModelLinearPBond &);
22 LINEARPBOND_EXPORT void addToStorage(poly::vector<ContactModelMechanical> *s,int ww = -1) override;
23 LINEARPBOND_EXPORT virtual ~ContactModelLinearPBond();
24 void copy(const ContactModel *c) override;
25 void archive(ArchiveStream &) override;
26 string getName() const override { return "linearpbond"; }
27 void setIndex(int i) override { index_=i;}
28 int getIndex() const override {return index_;}
29
30 enum PropertyKeys {
31 kwLinKn=1
32 , kwLinKs
33 , kwLinFric
34 , kwLinF
35 , kwLinS
36 , kwLinMode
37 , kwRGap
38 , kwEmod
39 , kwKRatio
40 , kwDpNRatio
41 , kwDpSRatio
42 , kwDpMode
43 , kwDpF
44 , kwPbState
45 , kwPbRMul
46 , kwPbKn
47 , kwPbKs
48 , kwPbMcf
49 , kwPbTStrength
50 , kwPbSStrength
51 , kwPbCoh
52 , kwPbFa
53 , kwPbSig
54 , kwPbTau
55 , kwPbF
56 , kwPbM
57 , kwPbRadius
58 , kwPbEmod
59 , kwPbKRatio
60 , kwUserArea
61 };
62
63 string getProperties() const override {
64 return "kn"
65 ",ks"
66 ",fric"
67 ",lin_force"
68 ",lin_slip"
69 ",lin_mode"
70 ",rgap"
71 ",emod"
72 ",kratio"
73 ",dp_nratio"
74 ",dp_sratio"
75 ",dp_mode"
76 ",dp_force"
77 ",pb_state"
78 ",pb_rmul"
79 ",pb_kn"
80 ",pb_ks"
81 ",pb_mcf"
82 ",pb_ten"
83 ",pb_shear"
84 ",pb_coh"
85 ",pb_fa"
86 ",pb_sigma"
87 ",pb_tau"
88 ",pb_force"
89 ",pb_moment"
90 ",pb_radius"
91 ",pb_emod"
92 ",pb_kratio"
93 ",user_area";
94 }
95
96 enum EnergyKeys { kwEStrain=1,kwESlip,kwEDashpot,kwEPbStrain};
97 string getEnergies() const override { return "energy-strain,energy-slip,energy-dashpot,energy-pbstrain";}
98 double getEnergy(uint32 i) const override; // Base 1
99 bool getEnergyAccumulate(uint32 i) const override; // Base 1
100 void setEnergy(uint32 i,const double &d) override; // Base 1
101 void activateEnergy() override { if (energies_) return; energies_ = NEW Energies();}
102 bool getEnergyActivated() const override {return (energies_ !=0);}
103
104 enum FishCallEvents {fActivated=0,fBondBreak,fSlipChange};
105 string getFishCallEvents() const override { return "contact_activated,bond_break,slip_change"; }
106 base::Property getProperty(uint32 i,const IContact *con=0) const override;
107 bool getPropertyGlobal(uint32 i) const override;
108 bool setProperty(uint32 i,const base::Property &v,IContact *con=0);
109 bool getPropertyReadOnly(uint32 i) const override;
110 bool supportsInheritance(uint32 i) const override;
111 bool getInheritance(uint32 i) const override { assert(i<32); uint32 mask = to<uint32>(1 << i); return (inheritanceField_ & mask) ? true : false; }
112 void setInheritance(uint32 i,bool b) override { assert(i<32); uint32 mask = to<uint32>(1 << i); if (b) inheritanceField_ |= mask; else inheritanceField_ &= ~mask; }
113
114 enum MethodKeys { kwDeformability=1
115 , kwPbDeformability
116 , kwPbBond
117 , kwPbUnbond
118 , kwArea
119 };
120
121 string getMethods() const override {
122 return "deformability"
123 ",pb_deformability"
124 ",bond"
125 ",unbond"
126 ",area";
127 }
128
129 string getMethodArguments(uint32 i) const override;
130
131 bool setMethod(uint32 i,const std::vector<base::Property> &vl,IContact *con=0) override; // Base 1 - returns true if timestep contributions need to be updated
132
133 uint32 getMinorVersion() const override;
134
135 bool validate(ContactModelMechanicalState *state,const double ×tep) override;
136 bool endPropertyUpdated(const string &name,const IContactMechanical *c) override;
137 bool forceDisplacementLaw(ContactModelMechanicalState *state,const double ×tep) override;
138 DVect2 getEffectiveTranslationalStiffness() const override { DVect2 ret = effectiveTranslationalStiffness_; if(pbProps_) ret+= pbProps_->pbTransStiff_ ;return ret;}
139 DAVect getEffectiveRotationalStiffness() const override {if (!pbProps_) return DAVect(0.0); return pbProps_->pbAngStiff_;}
140
141 bool thermalCoupling(ContactModelMechanicalState *, ContactModelThermalState * , IContactThermal *,const double &) override;
142
143 ContactModelLinearPBond *clone() const override { return NEW ContactModelLinearPBond(); }
144 double getActivityDistance() const override {return rgap_;}
145 bool isOKToDelete() const override { return !isBonded(); }
146 void resetForcesAndMoments() override { lin_F(DVect(0.0)); dp_F(DVect(0.0)); pbF(DVect(0.0)); pbM(DAVect(0.0)); if (energies_) { energies_->estrain_ = 0.0; if (energies_) energies_->epbstrain_ = 0.0;}}
147 void setForce(const DVect &v,IContact *c) override;
148 void setArea(const double &d) override { userArea_ = d; }
149 double getArea() const override { return userArea_; }
150 bool checkActivity(const double &gap) override { return (gap <= rgap_ || isBonded()); }
151 bool isSliding() const override { return lin_S_; }
152 bool isBonded() const override { return pbProps_ ? (pbProps_->pb_state_==3) : false; }
153 void unbond() override { if (pbProps_) pbProps_->pb_state_= 0; }
154 void propagateStateInformation(IContactModelMechanical* oldCm,const CAxes &oldSystem=CAxes(),const CAxes &newSystem=CAxes()) override;
155 void setNonForcePropsFrom(IContactModel *oldCM) override;
156 /// Return the total force that the contact model holds.
157 DVect getForce() const override;
158 /// Return the total moment on 1 that the contact model holds
159 DAVect getMomentOn1(const IContactMechanical*) const override;
160 /// Return the total moment on 1 that the contact model holds
161 DAVect getMomentOn2(const IContactMechanical*) const override;
162
163 DAVect getModelMomentOn1() const override;
164 DAVect getModelMomentOn2() const override;
165
166 // Used to efficiently get properties from the contact model for the object pane.
167 // List of properties for the object pane, comma separated.
168 // All properties will be cast to doubles for comparison. No other comparisons
169 // are supported. This may not be the same as the entire property list.
170 // Return property name and type for plotting.
171 void objectPropsTypes(std::vector<std::pair<string,InfoTypes>> *) const override;
172 // All properties cast to doubles - this is what can be compared.
173 void objectPropValues(std::vector<double> *,const IContact *) const override;
174
175 const double & kn() const {return kn_;}
176 void kn(const double &d) {kn_=d;}
177 const double & ks() const {return ks_;}
178 void ks(const double &d) {ks_=d;}
179 const double & fric() const {return fric_;}
180 void fric(const double &d) {fric_=d;}
181 const DVect & lin_F() const {return lin_F_;}
182 void lin_F(const DVect &f) { lin_F_=f;}
183 bool lin_S() const {return lin_S_;}
184 void lin_S(bool b) { lin_S_=b;}
185 uint32 lin_mode() const {return lin_mode_;}
186 void lin_mode(uint32 i) { lin_mode_=i;}
187 const double & rgap() const {return rgap_;}
188 void rgap(const double &d) {rgap_=d;}
189
190 bool hasDamping() const {return dpProps_ ? true : false;}
191 double dp_nratio() const {return (hasDamping() ? (dpProps_->dp_nratio_) : 0.0);}
192 void dp_nratio(const double &d) { if(!hasDamping()) return; dpProps_->dp_nratio_=d;}
193 double dp_sratio() const {return hasDamping() ? dpProps_->dp_sratio_: 0.0;}
194 void dp_sratio(const double &d) { if(!hasDamping()) return; dpProps_->dp_sratio_=d;}
195 int dp_mode() const {return hasDamping() ? dpProps_->dp_mode_: -1;}
196 void dp_mode(int i) { if(!hasDamping()) return; dpProps_->dp_mode_=i;}
197 DVect dp_F() const {return hasDamping() ? dpProps_->dp_F_: DVect(0.0);}
198 void dp_F(const DVect &f) { if(!hasDamping()) return; dpProps_->dp_F_=f;}
199
200 bool hasEnergies() const {return energies_ ? true:false;}
201 double estrain() const {return hasEnergies() ? energies_->estrain_: 0.0;}
202 void estrain(const double &d) { if(!hasEnergies()) return; energies_->estrain_=d;}
203 double eslip() const {return hasEnergies() ? energies_->eslip_: 0.0;}
204 void eslip(const double &d) { if(!hasEnergies()) return; energies_->eslip_=d;}
205 double edashpot() const {return hasEnergies() ? energies_->edashpot_: 0.0;}
206 void edashpot(const double &d) { if(!hasEnergies()) return; energies_->edashpot_=d;}
207 double epbstrain() const {return hasEnergies() ? energies_->epbstrain_: 0.0;}
208 void epbstrain(const double &d) { if(!hasEnergies()) return; energies_->epbstrain_=d;}
209
210 bool hasPBond() const {return pbProps_ ? true:false;}
211 int pbState() const {return hasPBond() ? pbProps_->pb_state_: 0;}
212 void pbState(int i) { if(!hasPBond()) return; pbProps_->pb_state_=i;}
213 double pbRmul() const {return (hasPBond() ? (pbProps_->pb_rmul_) : 0.0);}
214 void pbRmul(const double &d) { if(!hasPBond()) return; pbProps_->pb_rmul_=d;}
215 double pbKn() const {return (hasPBond() ? (pbProps_->pb_kn_) : 0.0);}
216 void pbKn(const double &d) { if(!hasPBond()) return; pbProps_->pb_kn_=d;}
217 double pbKs() const {return (hasPBond() ? (pbProps_->pb_ks_) : 0.0);}
218 void pbKs(const double &d) { if(!hasPBond()) return; pbProps_->pb_ks_=d;}
219 double pbMCF() const {return (hasPBond() ? (pbProps_->pb_mcf_) : 0.0);}
220 void pbMCF(const double &d) { if(!hasPBond()) return; pbProps_->pb_mcf_=d;}
221 double pbTen() const {return (hasPBond() ? (pbProps_->pb_ten_) : 0.0);}
222 void pbTen(const double &d) { if(!hasPBond()) return; pbProps_->pb_ten_=d;}
223 double pbCoh() const {return (hasPBond() ? (pbProps_->pb_coh_) : 0.0);}
224 void pbCoh(const double &d) { if(!hasPBond()) return; pbProps_->pb_coh_=d;}
225 double pbFA() const {return (hasPBond() ? (pbProps_->pb_fa_) : 0.0);}
226 void pbFA(const double &d) { if(!hasPBond()) return; pbProps_->pb_fa_=d;}
227 DVect pbF() const {return hasPBond() ? pbProps_->pb_F_: DVect(0.0);}
228 void pbF(const DVect &f) { if(!hasPBond()) return; pbProps_->pb_F_=f;}
229 DAVect pbM() const {return hasPBond() ? pbProps_->pb_M_: DAVect(0.0);}
230 void pbM(const DAVect &m) { if(!hasPBond()) return; pbProps_->pb_M_=m;}
231 DVect2 pbTransStiff() const {return hasPBond() ? pbProps_->pbTransStiff_: DVect2(0.0);}
232 void pbTransStiff(const DVect2 &f) { if(!hasPBond()) return; pbProps_->pbTransStiff_=f;}
233 DAVect pbAngStiff() const {return hasPBond() ? pbProps_->pbAngStiff_: DAVect(0.0);}
234 void pbAngStiff(const DAVect &m) { if(!hasPBond()) return; pbProps_->pbAngStiff_=m;}
235
236 uint32 inheritanceField() const {return inheritanceField_;}
237 void inheritanceField(uint32 i) {inheritanceField_ = i;}
238
239 const DVect2 & effectiveTranslationalStiffness() const {return effectiveTranslationalStiffness_;}
240 void effectiveTranslationalStiffness(const DVect2 &v ) {effectiveTranslationalStiffness_=v;}
241
242 private:
243 static int index_;
244
245 struct Energies {
246 Energies() : estrain_(0.0), eslip_(0.0), edashpot_(0.0), epbstrain_(0.0) {}
247 double estrain_; // elastic energy stored in contact
248 double eslip_; // work dissipated by friction
249 double edashpot_; // work dissipated by dashpots
250 double epbstrain_; // parallel bond strain energy
251 };
252
253 struct dpProps {
254 dpProps() : dp_nratio_(0.0), dp_sratio_(0.0), dp_mode_(0), dp_F_(DVect(0.0)) {}
255 double dp_nratio_; // normal viscous critical damping ratio
256 double dp_sratio_; // shear viscous critical damping ratio
257 int dp_mode_; // for viscous mode (0-4) 0 = dashpots, 1 = tensile limit, 2 = shear limit, 3 = limit both
258 DVect dp_F_; // Force in the dashpots
259 };
260
261 struct pbProps {
262 pbProps() : pb_state_(0), pb_rmul_(1.0), pb_kn_(0.0), pb_ks_(0.0),
263 pb_mcf_(1.0), pb_ten_(0.0), pb_coh_(0.0), pb_fa_(0.0), pb_F_(DVect(0.0)), pb_M_(DAVect(0.0)),
264 pbTransStiff_(0.0), pbAngStiff_(0.0){}
265 // parallel bond
266 int pb_state_; // Bond mode - 0 (NBNF), 1 (NBFT), 2 (NBFS), 3 (B)
267 double pb_rmul_; // Radius multiplier
268 double pb_kn_; // normal stiffness
269 double pb_ks_; // shear stiffness
270 double pb_mcf_; // Moment contribution factor
271 double pb_ten_; // normal strength
272 double pb_coh_; // cohesion
273 double pb_fa_; // friction angle
274 DVect pb_F_; // Force in parallel bond
275 DAVect pb_M_; // moment in parallel bond
276 DVect2 pbTransStiff_; // (Normal,Shear) Translational stiffness of the parallel bond
277 DAVect pbAngStiff_; // (Normal,Shear) Rotational stiffness of the parallel bond
278 };
279
280 bool updateKn(const IContactMechanical *con);
281 bool updateKs(const IContactMechanical *con);
282 bool updateFric(const IContactMechanical *con);
283 double pbStrainEnergy() const; // Compute bond strain energy
284
285 void updateEffectiveStiffness(ContactModelMechanicalState *state);
286
287 DVect3 pbData(const IContactMechanical *con) const; // Bond area and inertia
288 DVect2 pbSMax(const IContactMechanical *con) const; // Maximum stress (tensile,shear) at bond periphery
289 double pbShearStrength(const double &pbArea) const; // Bond shear strength
290 void setDampCoefficients(const double &mass,double *vcn,double *vcs);
291
292 // inheritance fields
293 uint32 inheritanceField_;
294
295 // linear model
296 double kn_ = 0; // normal stiffness
297 double ks_ = 0; // shear stiffness
298 double fric_ = 0; // Coulomb friction coefficient
299 DVect lin_F_ = DVect(0.0); // Force carried in the linear model
300 bool lin_S_ = false; // the current sliding state
301 uint32 lin_mode_ = 0; // specifies absolute (0) or incremental (1) behavior for the the linear part
302 double rgap_ = 0; // reference gap for the linear part
303
304 dpProps * dpProps_ = nullptr; // The viscous properties
305 pbProps * pbProps_ = nullptr; // The parallel bond properties
306
307 double userArea_ = 0; // User specified area
308
309 Energies * energies_ = nullptr; // energies
310
311 DVect2 effectiveTranslationalStiffness_ = DVect2(0.0);
312
313 };
314} // namespace itascaxd
315// EoF
contactmodellinearpbond.cpp
1// contactmodellinear.cpp
2#include "contactmodellinearpbond.h"
3
4#include "../version.txt"
5#include "contactmodel/src/contactmodelthermal.h"
6#include "fish/src/parameter.h"
7#include "utility/src/tptr.h"
8#include "shared/src/mathutil.h"
9
10#include "kernel/interface/iprogram.h"
11#include "module/interface/icontact.h"
12#include "module/interface/icontactmechanical.h"
13#include "module/interface/icontactthermal.h"
14#include "module/interface/ifishcalllist.h"
15#include "module/interface/ipiece.h"
16
17#ifdef LINEARPBOND_LIB
18#ifdef _WIN32
19 int __stdcall DllMain(void *,unsigned, void *)
20 {
21 return 1;
22 }
23#endif
24
25 extern "C" EXPORT_TAG const char *getName()
26 {
27#if DIM==3
28 return "contactmodelmechanical3dlinearpbond";
29#else
30 return "contactmodelmechanical2dlinearpbond";
31#endif
32 }
33
34 extern "C" EXPORT_TAG unsigned getMajorVersion()
35 {
36 return MAJOR_VERSION;
37 }
38
39 extern "C" EXPORT_TAG unsigned getMinorVersion()
40 {
41 return MINOR_VERSION;
42 }
43
44 extern "C" EXPORT_TAG void *createInstance()
45 {
46 cmodelsxd::ContactModelLinearPBond *m = NEW cmodelsxd::ContactModelLinearPBond();
47 return (void *)m;
48 }
49#endif // LINEARPBOND_EXPORTS
50
51namespace cmodelsxd {
52 static const uint32 linKnMask = 0x00002; // Base 1!
53 static const uint32 linKsMask = 0x00004;
54 static const uint32 linFricMask = 0x00008;
55
56 using namespace itasca;
57
58 int ContactModelLinearPBond::index_ = -1;
59 uint32 ContactModelLinearPBond::getMinorVersion() const { return MINOR_VERSION; }
60
61 ContactModelLinearPBond::ContactModelLinearPBond() : inheritanceField_(linKnMask|linKsMask|linFricMask)
62 { }
63
64 ContactModelLinearPBond::ContactModelLinearPBond(const ContactModelLinearPBond &m) noexcept {
65 inheritanceField(linKnMask|linKsMask|linFricMask);
66 this->copy(&m);
67 }
68
69 const ContactModelLinearPBond & ContactModelLinearPBond::operator=(const ContactModelLinearPBond &m) {
70 inheritanceField(linKnMask|linKsMask|linFricMask);
71 this->copy(&m);
72 return *this;
73 }
74
75 void ContactModelLinearPBond::addToStorage(poly::vector<ContactModelMechanical> *s,int ww) {
76 s->addToStorage<ContactModelLinearPBond>(*this,ww);
77 }
78
79 ContactModelLinearPBond::~ContactModelLinearPBond() {
80 if (dpProps_)
81 delete dpProps_;
82 if (pbProps_)
83 delete pbProps_;
84 if (energies_)
85 delete energies_;
86 }
87
88 void ContactModelLinearPBond::archive(ArchiveStream &stream) {
89 stream & kn_;
90 stream & ks_;
91 stream & fric_;
92 stream & lin_F_;
93 stream & lin_S_;
94 stream & lin_mode_;
95 if (stream.getArchiveState()==ArchiveStream::Save) {
96 bool b = false;
97 if (dpProps_) {
98 b = true;
99 stream & b;
100 stream & dpProps_->dp_nratio_;
101 stream & dpProps_->dp_sratio_;
102 stream & dpProps_->dp_mode_;
103 stream & dpProps_->dp_F_;
104 }
105 else
106 stream & b;
107
108 b = false;
109 if (energies_) {
110 b = true;
111 stream & b;
112 stream & energies_->estrain_;
113 stream & energies_->eslip_;
114 stream & energies_->edashpot_;
115 stream & energies_->epbstrain_;
116 }
117 else
118 stream & b;
119
120 b = false;
121 if (pbProps_) {
122 b = true;
123 stream & b;
124 stream & pbProps_->pb_state_;
125 stream & pbProps_->pb_rmul_;
126 stream & pbProps_->pb_kn_;
127 stream & pbProps_->pb_ks_;
128 stream & pbProps_->pb_mcf_;
129 stream & pbProps_->pb_ten_;
130 stream & pbProps_->pb_coh_;
131 stream & pbProps_->pb_fa_;
132 stream & pbProps_->pb_F_;
133 stream & pbProps_->pb_M_;
134 }
135 else
136 stream & b;
137 } else {
138 bool b(false);
139 stream & b;
140 if (b) {
141 if (!dpProps_)
142 dpProps_ = NEW dpProps();
143 stream & dpProps_->dp_nratio_;
144 stream & dpProps_->dp_sratio_;
145 stream & dpProps_->dp_mode_;
146 stream & dpProps_->dp_F_;
147 }
148 stream & b;
149 if (b) {
150 if (!energies_)
151 energies_ = NEW Energies();
152 stream & energies_->estrain_;
153 stream & energies_->eslip_;
154 stream & energies_->edashpot_;
155 stream & energies_->epbstrain_;
156 }
157 stream & b;
158 if (b) {
159 if (!pbProps_)
160 pbProps_ = NEW pbProps();
161 stream & pbProps_->pb_state_;
162 stream & pbProps_->pb_rmul_;
163 stream & pbProps_->pb_kn_;
164 stream & pbProps_->pb_ks_;
165 stream & pbProps_->pb_mcf_;
166 stream & pbProps_->pb_ten_;
167 stream & pbProps_->pb_coh_;
168 stream & pbProps_->pb_fa_;
169 stream & pbProps_->pb_F_;
170 stream & pbProps_->pb_M_;
171 }
172 }
173
174 stream & inheritanceField_;
175 stream & effectiveTranslationalStiffness_;
176
177 if (stream.getArchiveState()==ArchiveStream::Save || stream.getRestoreVersion() == getMinorVersion())
178 stream & rgap_;
179
180 if (stream.getArchiveState() == ArchiveStream::Save || stream.getRestoreVersion() > 1)
181 stream & userArea_;
182 }
183
184 void ContactModelLinearPBond::copy(const ContactModel *cm) {
185 ContactModelMechanical::copy(cm);
186 const ContactModelLinearPBond *in = dynamic_cast<const ContactModelLinearPBond*>(cm);
187 if (!in) throw std::runtime_error("Internal error: contact model dynamic cast failed.");
188 kn(in->kn());
189 ks(in->ks());
190 fric(in->fric());
191 lin_F(in->lin_F());
192 lin_S(in->lin_S());
193 lin_mode(in->lin_mode());
194 rgap(in->rgap());
195 if (in->hasDamping()) {
196 if (!dpProps_)
197 dpProps_ = NEW dpProps();
198 dp_nratio(in->dp_nratio());
199 dp_sratio(in->dp_sratio());
200 dp_mode(in->dp_mode());
201 dp_F(in->dp_F());
202 }
203 if (in->hasEnergies()) {
204 if (!energies_)
205 energies_ = NEW Energies();
206 estrain(in->estrain());
207 eslip(in->eslip());
208 edashpot(in->edashpot());
209 epbstrain(in->epbstrain());
210 }
211 if (in->hasPBond()) {
212 if (!pbProps_)
213 pbProps_ = NEW pbProps();
214 pbState(in->pbState());
215 pbRmul(in->pbRmul());
216 pbKn(in->pbKn());
217 pbKs(in->pbKs());
218 pbMCF(in->pbMCF());
219 pbTen(in->pbTen());
220 pbCoh(in->pbCoh());
221 pbFA(in->pbFA());
222 pbF(in->pbF());
223 pbM(in->pbM());
224 pbTransStiff(in->pbTransStiff());
225 pbAngStiff(in->pbAngStiff());
226 }
227 userArea_ = in->userArea_;
228 inheritanceField(in->inheritanceField());
229 effectiveTranslationalStiffness(in->effectiveTranslationalStiffness());
230 }
231
232 base::Property ContactModelLinearPBond::getProperty(uint32 i,const IContact *con) const {
233 // The IContact pointer may be a nullptr!
234 const IContactMechanical *c(convert_getcast<IContactMechanical>(con));
235 base::Property var;
236 switch (i) {
237 case kwLinKn: return kn_;
238 case kwLinKs: return ks_;
239 case kwLinFric: return fric_;
240 case kwLinMode: return lin_mode_;
241 case kwLinF: var.setValue(lin_F_); return var;
242 case kwLinS: return lin_S_;
243 case kwRGap: return rgap_;
244 case kwEmod: {
245 if (c ==nullptr) return 0.0;
246 double rsq(std::max(c->getEnd1Curvature().y(),c->getEnd2Curvature().y()));
247 double rsum = calcRSum(c);
248 if (userArea_) {
249#ifdef THREED
250 rsq = std::sqrt(userArea_ / dPi);
251#else
252 rsq = userArea_ / 2.0;
253#endif
254 rsum = rsq + rsq;
255 rsq = 1. / rsq;
256 }
257#ifdef TWOD
258 return (kn_ * rsum * rsq / 2.0);
259#else
260 return (kn_ * rsum * rsq * rsq) / dPi;
261#endif
262 }
263 case kwKRatio: return (ks_ == 0.0) ? 0.0 : (kn_/ks_);
264 case kwDpNRatio: return dpProps_ ? dpProps_->dp_nratio_ : 0;
265 case kwDpSRatio: return dpProps_ ? dpProps_->dp_sratio_ : 0;
266 case kwDpMode: return dpProps_ ? dpProps_->dp_mode_ : 0;
267 case kwUserArea: return userArea_;
268 case kwDpF: {
269 dpProps_ ? var.setValue(dpProps_->dp_F_) : var.setValue(DVect(0.0));
270 return var;
271 }
272 case kwPbState: return pbProps_ ? pbProps_->pb_state_ : 0;
273 case kwPbRMul: return pbProps_ ? pbProps_->pb_rmul_ : 1.0;
274 case kwPbKn: return pbProps_ ? pbProps_->pb_kn_ : 0;
275 case kwPbKs: return pbProps_ ? pbProps_->pb_ks_ : 0;
276 case kwPbMcf: return pbProps_ ? pbProps_->pb_mcf_ : 1.0;
277 case kwPbTStrength: return pbProps_ ? pbProps_->pb_ten_ : 0.0;
278 case kwPbSStrength: {
279 if (!pbProps_ or not c) return 0.0;
280 double pbArea = pbData(c).x();
281 return pbShearStrength(pbArea);
282 }
283 case kwPbCoh: return pbProps_ ? pbProps_->pb_coh_ : 0;
284 case kwPbFa: return pbProps_ ? pbProps_->pb_fa_ : 0;
285 case kwPbSig: {
286 if (!pbProps_ or pbProps_->pb_state_ < 3 or not c) return 0.0;
287 return pbSMax(c).x();
288 }
289 case kwPbTau: {
290 if (!pbProps_ or pbProps_->pb_state_ < 3 or not c) return 0.0;
291 return pbSMax(c).y();
292 }
293 case kwPbF: {
294 pbProps_ ? var.setValue(pbProps_->pb_F_) : var.setValue(DVect(0.0));
295 return var;
296 }
297 case kwPbM: {
298 pbProps_ ? var.setValue(pbProps_->pb_M_) : var.setValue(DAVect(0.0));
299 return var;
300 }
301 case kwPbRadius: {
302 if (!pbProps_ or not c) return 0.0;
303 double Cmax1 = c->getEnd1Curvature().y();
304 double Cmax2 = c->getEnd2Curvature().y();
305 double br = pbProps_->pb_rmul_ * 1.0 / std::max(Cmax1,Cmax2);
306 if (userArea_)
307#ifdef THREED
308 br = std::sqrt(userArea_ / dPi);
309#else
310 br = userArea_ / 2.0;
311#endif
312 return br;
313 }
314 case kwPbEmod: {
315 if (!pbProps_ or not c) return 0.0;
316 double rsum = calcRSum(c);
317 if (userArea_) {
318#ifdef THREED
319 double rad = std::sqrt(userArea_ / dPi);
320#else
321 double rad = userArea_ / 2.0;
322#endif
323 rsum = 2 * rad;
324 }
325 double emod = pbProps_->pb_kn_ * rsum;
326 return emod;
327 }
328 case kwPbKRatio: {
329 if (!pbProps_) return 0.0;
330 return (pbProps_->pb_ks_ == 0.0) ? 0.0 : (pbProps_->pb_kn_/pbProps_->pb_ks_);
331 }
332 }
333 assert(0);
334 return base::Property();
335 }
336
337 bool ContactModelLinearPBond::getPropertyGlobal(uint32 i) const {
338 switch (i) {
339 case kwLinF:
340 case kwDpF:
341 case kwPbF:
342 return false;
343 }
344 return true;
345 }
346
347 bool ContactModelLinearPBond::setProperty(uint32 i,const base::Property &v,IContact *) {
348 pbProps pb;
349 dpProps dp;
350
351 switch (i) {
352 case kwLinKn: {
353 if (!v.canConvert<double>())
354 throw Exception("kn must be a double.");
355 double val(v.toDouble());
356 if (val<0.0)
357 throw Exception("Negative kn not allowed.");
358 kn_ = val;
359 return true;
360 }
361 case kwLinKs: {
362 if (!v.canConvert<double>())
363 throw Exception("ks must be a double.");
364 double val(v.toDouble());
365 if (val<0.0)
366 throw Exception("Negative ks not allowed.");
367 ks_ = val;
368 return true;
369 }
370 case kwLinFric: {
371 if (!v.canConvert<double>())
372 throw Exception("fric must be a double.");
373 double val(v.toDouble());
374 if (val<0.0)
375 throw Exception("Negative fric not allowed.");
376 fric_ = val;
377 return false;
378 }
379 case kwLinF: {
380 if (!v.canConvert<DVect>())
381 throw Exception("lin_force must be a vector.");
382 DVect val(v.value<DVect>());
383 lin_F_ = val;
384 return false;
385 }
386 case kwLinMode: {
387 if (!v.canConvert<int64>())
388 throw Exception("lin_mode must be 0 (absolute) or 1 (incremental).");
389 uint32 val(v.toUInt());
390 if (val>1)
391 throw Exception("lin_mode must be 0 (absolute) or 1 (incremental).");
392 lin_mode_ = val;
393 return false;
394 }
395 case kwRGap: {
396 if (!v.canConvert<double>())
397 throw Exception("Reference gap must be a double.");
398 double val(v.toDouble());
399 rgap_ = val;
400 return false;
401 }
402 case kwPbRMul: {
403 if (!v.canConvert<double>())
404 throw Exception("pb_rmul must be a double.");
405 double val(v.toDouble());
406 if (val<=0.0)
407 throw Exception("pb_rmul must be positive.");
408 if (val == 1.0 && !pbProps_)
409 return false;
410 if (!pbProps_)
411 pbProps_ = NEW pbProps();
412 pbProps_->pb_rmul_ = val;
413 return false;
414 }
415 case kwPbKn: {
416 if (!v.canConvert<double>())
417 throw Exception("pb_kn must be a double.");
418 double val(v.toDouble());
419 if (val<0.0)
420 throw Exception("Negative pb_kn not allowed.");
421 if (val == 0.0 && !pbProps_)
422 return false;
423 if (!pbProps_)
424 pbProps_ = NEW pbProps();
425 pbProps_->pb_kn_ = val;
426 return true;
427 }
428 case kwPbKs: {
429 if (!v.canConvert<double>())
430 throw Exception("pb_ks must be a double.");
431 double val(v.toDouble());
432 if (val<0.0)
433 throw Exception("Negative pb_ks not allowed.");
434 if (val == 0.0 && !pbProps_)
435 return false;
436 if (!pbProps_)
437 pbProps_ = NEW pbProps();
438 pbProps_->pb_ks_ = val;
439 return true;
440 }
441 case kwPbMcf: {
442 if (!v.canConvert<double>())
443 throw Exception("pb_mcf must be a double.");
444 double val(v.toDouble());
445 if (val<0.0)
446 throw Exception("Negative pb_mcf not allowed.");
447 if (val > 1.0)
448 throw Exception("pb_mcf must be lower or equal to 1.0.");
449 if (val == 1.0 && !pbProps_)
450 return false;
451 if (!pbProps_)
452 pbProps_ = NEW pbProps();
453 pbProps_->pb_mcf_ = val;
454 return false;
455 }
456 case kwPbTStrength: {
457 if (!v.canConvert<double>())
458 throw Exception("pb_ten must be a double.");
459 double val(v.toDouble());
460 if (val < 0.0)
461 throw Exception("Negative pb_ten not allowed.");
462 if (val == 0.0 && !pbProps_)
463 return false;
464 if (!pbProps_)
465 pbProps_ = NEW pbProps();
466 pbProps_->pb_ten_ = val;
467 return false;
468 }
469 case kwPbCoh: {
470 if (!v.canConvert<double>())
471 throw Exception("pb_coh must be a double.");
472 double val(v.toDouble());
473 if (val<0.0)
474 throw Exception("Negative pb_coh not allowed.");
475 if (val == 0.0 && !pbProps_)
476 return false;
477 if (!pbProps_)
478 pbProps_ = NEW pbProps();
479 pbProps_->pb_coh_ = val;
480 return false;
481 }
482 case kwPbFa: {
483 if (!v.canConvert<double>())
484 throw Exception("pb_fa must be a double.");
485 double val(v.toDouble());
486 if (val<0.0)
487 throw Exception("Negative pb_fa not allowed.");
488 if (val>=90.0)
489 throw Exception("pb_fa must be lower than 90.0 degrees.");
490 if (val == 0.0 && !pbProps_)
491 return false;
492 if (!pbProps_)
493 pbProps_ = NEW pbProps();
494 pbProps_->pb_fa_ = val;
495 return false;
496 }
497 case kwPbF: {
498 if (!v.canConvert<DVect>())
499 throw Exception("pb_force must be a vector.");
500 DVect val(v.value<DVect>());
501 if (val.fsum() == 0.0 && !pbProps_)
502 return false;
503 if (!pbProps_)
504 pbProps_ = NEW pbProps();
505 pbProps_->pb_F_ = val;
506 return false;
507 }
508 case kwPbM: {
509 DAVect val(0.0);
510#ifdef TWOD
511 if (!v.canConvert<DAVect>() && !v.canConvert<double>())
512 throw Exception("pb_moment must be an angular vector.");
513 if (v.canConvert<DAVect>())
514 val = DAVect(v.value<DAVect>());
515 else
516 val = DAVect(v.toDouble());
517#else
518 if (!v.canConvert<DAVect>() && !v.canConvert<DVect>())
519 throw Exception("pb_moment must be an angular vector.");
520 if (v.canConvert<DAVect>())
521 val = DAVect(v.value<DAVect>());
522 else
523 val = DAVect(v.value<DVect>());
524#endif
525 if (val.fsum() == 0.0 && !pbProps_)
526 return false;
527 if (!pbProps_)
528 pbProps_ = NEW pbProps();
529 pbProps_->pb_M_ = val;
530 return false;
531 }
532 case kwDpNRatio: {
533 if (!v.canConvert<double>())
534 throw Exception("dp_nratio must be a double.");
535 double val(v.toDouble());
536 if (val<0.0)
537 throw Exception("Negative dp_nratio not allowed.");
538 if (val == 0.0 && !dpProps_)
539 return false;
540 if (!dpProps_)
541 dpProps_ = NEW dpProps();
542 dpProps_->dp_nratio_ = val;
543 return true;
544 }
545 case kwDpSRatio: {
546 if (!v.canConvert<double>())
547 throw Exception("dp_sratio must be a double.");
548 double val(v.toDouble());
549 if (val<0.0)
550 throw Exception("Negative dp_sratio not allowed.");
551 if (val == 0.0 && !dpProps_)
552 return false;
553 if (!dpProps_)
554 dpProps_ = NEW dpProps();
555 dpProps_->dp_sratio_ = val;
556 return true;
557 }
558 case kwDpMode: {
559 if (!v.canConvert<int64>())
560 throw Exception("The viscous mode dp_mode must be 0, 1, 2, or 3.");
561 int val(v.toInt());
562 if (val == 0 && !dpProps_)
563 return false;
564 if (val < 0 || val > 3)
565 throw Exception("The viscous mode dp_mode must be 0, 1, 2, or 3.");
566 if (!dpProps_)
567 dpProps_ = NEW dpProps();
568 dpProps_->dp_mode_ = val;
569 return false;
570 }
571 case kwDpF: {
572 if (!v.canConvert<DVect>())
573 throw Exception("dp_force must be a vector.");
574 DVect val(v.value<DVect>());
575 if (val.fsum() == 0.0 && !dpProps_)
576 return false;
577 if (!dpProps_)
578 dpProps_ = NEW dpProps();
579 dpProps_->dp_F_ = val;
580 return false;
581 }
582 case kwUserArea: {
583 if (!v.canConvert<double>())
584 throw Exception("user_area must be a double.");
585 double val(v.toDouble());
586 if (val < 0.0)
587 throw Exception("Negative user_area not allowed.");
588 userArea_ = val;
589 return true;
590 }
591 }
592// assert(0);
593 return false;
594 }
595
596 bool ContactModelLinearPBond::getPropertyReadOnly(uint32 i) const {
597 switch (i) {
598 case kwDpF:
599 case kwLinS:
600 case kwEmod:
601 case kwKRatio:
602 case kwPbState:
603 case kwPbRadius:
604 case kwPbSStrength:
605 case kwPbSig:
606 case kwPbTau:
607 case kwPbEmod:
608 case kwPbKRatio:
609 return true;
610 default:
611 break;
612 }
613 return false;
614 }
615
616 bool ContactModelLinearPBond::supportsInheritance(uint32 i) const {
617 switch (i) {
618 case kwLinKn:
619 case kwLinKs:
620 case kwLinFric:
621 return true;
622 default:
623 break;
624 }
625 return false;
626 }
627
628 string ContactModelLinearPBond::getMethodArguments(uint32 i) const {
629 string def = string();
630 switch (i) {
631 case kwDeformability:
632 return "emod,kratio";
633 case kwPbDeformability:
634 return "emod,kratio";
635 case kwPbBond:
636 return "gap";
637 case kwPbUnbond:
638 return "gap";
639 }
640 return def;
641 }
642
643 bool ContactModelLinearPBond::setMethod(uint32 i,const std::vector<base::Property> &vl,IContact *con) {
644 FP_S;
645 IContactMechanical *c(convert_getcast<IContactMechanical>(con));
646 switch (i) {
647 case kwDeformability: {
648 double emod;
649 double krat;
650 if (vl.at(0).isNull())
651 throw Exception("Argument emod must be specified with method deformability in contact model {0}.",getName());
652 emod = vl.at(0).toDouble();
653 if (emod<0.0)
654 throw Exception("Negative emod not allowed in contact model {0}.",getName());
655 if (vl.at(1).isNull())
656 throw Exception("Argument kratio must be specified with method deformability in contact model {0}.",getName());
657 krat = vl.at(1).toDouble();
658 if (krat<0.0)
659 throw Exception("Negative linear stiffness ratio not allowed in contact model {0}.",getName());
660 double rsq(std::max(c->getEnd1Curvature().y(),c->getEnd2Curvature().y()));
661 double rsum = calcRSum(c);
662 if (userArea_) {
663#ifdef THREED
664 rsq = std::sqrt(userArea_ / dPi);
665#else
666 rsq = userArea_ / 2.0;
667#endif
668 rsum = rsq + rsq;
669 rsq = safeDiv(1. , rsq);
670 }
671#ifdef TWOD
672 kn_ = safeDiv(2.0 * emod ,rsq * rsum);
673#else
674 kn_ = safeDiv(dPi * emod , rsq * rsq * rsum);
675#endif
676 ks_ = safeDiv(kn_,krat);
677 setInheritance(1,false);
678 setInheritance(2,false);
679 FP_S;
680 return true;
681 }
682 case kwPbDeformability: {
683 //if (!pbProps_ || pbProps_->pb_state_ != 3) return false;
684 double emod;
685 double krat;
686 if (vl.at(0).isNull())
687 throw Exception("Argument emod must be specified with method pb_deformability in contact model {0}.",getName());
688 emod = vl.at(0).toDouble();
689 if (emod<0.0)
690 throw Exception("Negative emod not allowed in contact model {0}.",getName());
691 if (vl.at(1).isNull())
692 throw Exception("Argument kratio must be specified with method pb_deformability in contact model {0}.",getName());
693 krat = vl.at(1).toDouble();
694 if (krat<0.0)
695 throw Exception("Negative parallel bond stiffness ratio not allowed in contact model {0}.",getName());
696 double rsum = calcRSum(c);
697 if (!pbProps_)
698 pbProps_ = NEW pbProps();
699 if (userArea_)
700#ifdef THREED
701 rsum = 2 * std::sqrt(userArea_ / dPi);
702#else
703 rsum = 2 * userArea_ / 2.0;
704#endif
705 pbProps_->pb_kn_ = emod / rsum;
706 pbProps_->pb_ks_ = (krat == 0.0) ? 0.0 : pbProps_->pb_kn_ / krat;
707 FP_S;
708 return true;
709 }
710 case kwPbBond: {
711 if (pbProps_ && pbProps_->pb_state_ == 3) return false;
712 double mingap = -1.0 * limits<double>::max();
713 double maxgap = 0;
714 if (vl.at(0).canConvert<double>())
715 maxgap = vl.at(0).toDouble();
716 else if (vl.at(0).canConvert<DVect2>()) {
717 DVect2 value = vl.at(0).value<DVect2>();
718 mingap = value.minComp();
719 maxgap = value.maxComp();
720 } else if (!vl.at(0).isNull())
721 throw Exception("gap value {0} not recognized in method bond in contact model {1}.",vl.at(0),getName());
722 double gap = c->getGap();
723 if ( gap >= mingap && gap <= maxgap) {
724 if (pbProps_)
725 pbProps_->pb_state_ = 3;
726 else {
727 pbProps_ = NEW pbProps();
728 pbProps_->pb_state_ = 3;
729 }
730 FP_S;
731 return true;
732 }
733 FP_S;
734 return false;
735 }
736 case kwPbUnbond: {
737 if (!pbProps_ || pbProps_->pb_state_ == 0) return false;
738 double mingap = -1.0 * limits<double>::max();
739 double maxgap = 0;
740 if (vl.at(0).canConvert<double>())
741 maxgap = vl.at(0).toDouble();
742 else if (vl.at(0).canConvert<DVect2>()) {
743 DVect2 value = vl.at(0).value<DVect2>();
744 mingap = value.minComp();
745 maxgap = value.maxComp();
746 }
747 else if (!vl.at(0).isNull())
748 throw Exception("gap value {0} not recognized in method unbond in contact model {1}.",vl.at(0),getName());
749 double gap = c->getGap();
750 if ( gap >= mingap && gap <= maxgap) {
751 pbProps_->pb_state_ = 0;
752 return true;
753 }
754 FP_S;
755 return false;
756 }
757 case kwArea: {
758 if (!userArea_) {
759 double rsq = calcRSQ(c);
760#ifdef THREED
761 userArea_ = rsq * rsq * dPi;
762#else
763 userArea_ = rsq * 2.0;
764#endif
765 }
766 FP_S;
767 return true;
768 }
769 }
770 FP_S;
771 return false;
772 }
773
774 double ContactModelLinearPBond::getEnergy(uint32 i) const {
775 double ret(0.0);
776 if (!energies_)
777 return ret;
778 switch (i) {
779 case kwEStrain: return energies_->estrain_;
780 case kwESlip: return energies_->eslip_;
781 case kwEDashpot: return energies_->edashpot_;
782 case kwEPbStrain:return energies_->epbstrain_;
783 }
784 assert(0);
785 return ret;
786 }
787
788 bool ContactModelLinearPBond::getEnergyAccumulate(uint32 i) const {
789 switch (i) {
790 case kwEStrain: return false;
791 case kwESlip: return true;
792 case kwEDashpot: return true;
793 case kwEPbStrain: return false;
794 }
795 assert(0);
796 return false;
797 }
798
799 void ContactModelLinearPBond::setEnergy(uint32 i,const double &d) {
800 if (!energies_) return;
801 switch (i) {
802 case kwEStrain: energies_->estrain_ = d; return;
803 case kwESlip: energies_->eslip_ = d; return;
804 case kwEDashpot: energies_->edashpot_ = d; return;
805 case kwEPbStrain: energies_->epbstrain_= d; return;
806 }
807 assert(0);
808 return;
809 }
810
811 bool ContactModelLinearPBond::validate(ContactModelMechanicalState *state,const double &) {
812 assert(state);
813 const IContactMechanical *c = state->getMechanicalContact();
814 assert(c);
815
816 if (state->trackEnergy_)
817 activateEnergy();
818
819 if (inheritanceField_ & linKnMask)
820 updateKn(c);
821 if (inheritanceField_ & linKsMask)
822 updateKs(c);
823 if (inheritanceField_ & linFricMask)
824 updateFric(c);
825
826 updateEffectiveStiffness(state);
827 return checkActivity(state->gap_);
828 }
829
830 static const string knstr("kn");
831 bool ContactModelLinearPBond::updateKn(const IContactMechanical *con) {
832 assert(con);
833 base::Property v1 = con->getEnd1()->getProperty(knstr);
834 base::Property v2 = con->getEnd2()->getProperty(knstr);
835 if (!v1.isValid() || !v2.isValid())
836 return false;
837 double kn1 = v1.toDouble();
838 double kn2 = v2.toDouble();
839 double val = kn_;
840 if (kn1 && kn2)
841 kn_ = kn1*kn2/(kn1+kn2);
842 else if (kn1)
843 kn_ = kn1;
844 else if (kn2)
845 kn_ = kn2;
846 return ( (kn_ != val) );
847 }
848
849 static const string ksstr("ks");
850 bool ContactModelLinearPBond::updateKs(const IContactMechanical *con) {
851 assert(con);
852 base::Property v1 = con->getEnd1()->getProperty(ksstr);
853 base::Property v2 = con->getEnd2()->getProperty(ksstr);
854 if (!v1.isValid() || !v2.isValid())
855 return false;
856 double ks1 = v1.toDouble();
857 double ks2 = v2.toDouble();
858 double val = ks_;
859 if (ks1 && ks2)
860 ks_ = ks1*ks2/(ks1+ks2);
861 else if (ks1)
862 ks_ = ks1;
863 else if (ks2)
864 ks_ = ks2;
865 return ( (ks_ != val) );
866 }
867
868 static const string fricstr("fric");
869 bool ContactModelLinearPBond::updateFric(const IContactMechanical *con) {
870 assert(con);
871 base::Property v1 = con->getEnd1()->getProperty(fricstr);
872 base::Property v2 = con->getEnd2()->getProperty(fricstr);
873 if (!v1.isValid() || !v2.isValid())
874 return false;
875 double fric1 = std::max(0.0,v1.toDouble());
876 double fric2 = std::max(0.0,v2.toDouble());
877 double val = fric_;
878 fric_ = std::min(fric1,fric2);
879 return ( (fric_ != val) );
880 }
881
882 bool ContactModelLinearPBond::endPropertyUpdated(const string &name,const IContactMechanical *c) {
883 assert(c);
884 StringList availableProperties = split(replace(simplified(getProperties())," ",""),",");
885 auto idx = findRegex(availableProperties,name);
886 if (idx==string::npos) return false;
887 idx += 1;
888 bool ret=false;
889 switch(idx) {
890 case kwLinKn: { //kn
891 if (inheritanceField_ & linKnMask)
892 ret = updateKn(c);
893 break;
894 }
895 case kwLinKs: { //ks
896 if (inheritanceField_ & linKsMask)
897 ret =updateKs(c);
898 break;
899 }
900 case kwLinFric: { //fric
901 if (inheritanceField_ & linFricMask)
902 updateFric(c);
903 break;
904 }
905 }
906 return ret;
907 }
908
909 void ContactModelLinearPBond::updateEffectiveStiffness(ContactModelMechanicalState *state) {
910 DVect2 ret(kn_,ks_);
911 // account for viscous damping
912 if (dpProps_) {
913 DVect2 correct(1.0);
914 if (dpProps_->dp_nratio_)
915 correct.rx() = sqrt(1.0+dpProps_->dp_nratio_*dpProps_->dp_nratio_) - dpProps_->dp_nratio_;
916 if (dpProps_->dp_sratio_)
917 correct.ry() = sqrt(1.0+dpProps_->dp_sratio_*dpProps_->dp_sratio_) - dpProps_->dp_sratio_;
918 ret /= (correct*correct);
919 }
920 effectiveTranslationalStiffness_ = ret;
921 if (isBonded()) {
922 double Cmin1 = state->end1Curvature_.x();
923 double Cmax1 = state->end1Curvature_.y();
924 double Cmax2 = state->end2Curvature_.y();
925 double dthick = (Cmin1 == 0.0) ? 1.0 : 0.0;
926 double br = pbProps_->pb_rmul_ * 1.0 / std::max(Cmax1,Cmax2);
927 if (userArea_)
928#ifdef THREED
929 br = std::sqrt(userArea_ / dPi);
930#else
931 br = userArea_ / 2.0;
932#endif
933 double br2 = br*br;
934 double pbArea = dthick <= 0.0 ? dPi*br2 : 2.0*br*dthick;
935 double bi = dthick <= 0.0 ? 0.25*pbArea*br2 : 2.0*br*br2*dthick/3.0;
936 pbProps_->pbTransStiff_.rx() = pbProps_->pb_kn_*pbArea;
937 pbProps_->pbTransStiff_.ry() = pbProps_->pb_ks_*pbArea;
938#if DIM==3
939 pbProps_->pbAngStiff_.rx() = pbProps_->pb_ks_* 2.0 * bi;
940 pbProps_->pbAngStiff_.ry() = pbProps_->pb_kn_* bi;
941#endif
942 pbProps_->pbAngStiff_.rz() = pbProps_->pb_kn_* bi;
943 }
944 }
945
946 double ContactModelLinearPBond::pbStrainEnergy() const {
947 double ret(0.0);
948 if (pbProps_->pb_kn_)
949 ret = 0.5 * pbProps_->pb_F_.x() * pbProps_->pb_F_.x() / pbProps_->pbTransStiff_.x();
950 if (pbProps_->pb_ks_) {
951 DVect tmp = pbProps_->pb_F_;
952 tmp.rx() = 0.0;
953 double smag2 = tmp.mag2();
954 ret += 0.5 * smag2 / pbProps_->pbTransStiff_.y();
955 }
956
957#ifdef THREED
958 if (pbProps_->pbAngStiff_.x())
959 ret += 0.5 * pbProps_->pb_M_.x() * pbProps_->pb_M_.x() / pbProps_->pbAngStiff_.x();
960#endif
961 if (pbProps_->pbAngStiff_.z()) {
962 DAVect tmp = pbProps_->pb_M_;
963#ifdef THREED
964 tmp.rx() = 0.0;
965 double smag2 = tmp.mag2();
966#else
967 double smag2 = tmp.z() * tmp.z();
968#endif
969 ret += 0.5 * smag2 / pbProps_->pbAngStiff_.z();
970 }
971 return ret;
972 }
973
974 bool ContactModelLinearPBond::forceDisplacementLaw(ContactModelMechanicalState *state,const double ×tep) {
975 assert(state);
976
977 double overlap = rgap_ - state->gap_;
978 DVect trans = state->relativeTranslationalIncrement_;
979 double correction = 1.0;
980
981 if (state->activated()) {
982 if (cmEvents_[fActivated] >= 0) {
983 auto c = state->getContact();
984 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()) };
985 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
986 fi->setCMFishCallArguments(c,arg,cmEvents_[fActivated]);
987 }
988 if (lin_mode_ == 0 && trans.x()) {
989 correction = -1.0*overlap / trans.x();
990 if (correction < 0)
991 correction = 1.0;
992 }
993 }
994
995#ifdef THREED
996 DVect norm(trans.x(),0.0,0.0);
997#else
998 DVect norm(trans.x(),0.0);
999#endif
1000 DAVect ang = state->relativeAngularIncrement_;
1001 DVect ss_F_old = lin_F_;
1002
1003 if (lin_mode_==0)
1004 lin_F_.rx() = overlap * kn_;
1005 else
1006 lin_F_.rx() -= correction * norm.x() * kn_;
1007 lin_F_.rx() = std::max(0.0,lin_F_.x());
1008
1009 DVect u_s = trans;
1010 u_s.rx() = 0.0;
1011 DVect sforce = lin_F_ - u_s * ks_ * correction;
1012 sforce.rx() = 0.0;
1013 // Make sure that the shear force opposses the direction of translation - otherwise you can
1014 // have strange behavior
1015 //for (int j=1; j<dim; ++j)
1016 //{
1017 // qDebug()<<sforce.dof(j)<<trans.dof(j);
1018 // if (sign<double>(1,sforce.dof(j)) == sign<double>(1,trans.dof(j)))
1019 // sforce.rdof(j) = 0.0;
1020 //}
1021
1022 // Resolve sliding
1023 if (state->canFail_) {
1024 double crit = lin_F_.x() * fric_;
1025 double sfmag = sforce.mag();
1026 if (sfmag > crit) {
1027 double rat = crit / sfmag;
1028 sforce *= rat;
1029 if (!lin_S_ && cmEvents_[fSlipChange] >= 0) {
1030 auto c = state->getContact();
1031 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
1032 fish::Parameter() };
1033 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
1034 fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
1035 }
1036 lin_S_ = true;
1037 } else {
1038 if (lin_S_) {
1039 if (cmEvents_[fSlipChange] >= 0) {
1040 auto c = state->getContact();
1041 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
1042 fish::Parameter((int64)1) };
1043 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
1044 fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
1045 }
1046 lin_S_ = false;
1047 }
1048 }
1049 }
1050
1051 sforce.rx() = lin_F_.x();
1052 lin_F_ = sforce; // total force in linear contact model
1053
1054 // Account for dashpot forces
1055 if (dpProps_) {
1056 dpProps_->dp_F_.fill(0.0);
1057 double vcn(0.0), vcs(0.0);
1058 setDampCoefficients(state->inertialMass_,&vcn,&vcs);
1059 // Need to change behavior based on the dp_mode
1060 if (dpProps_->dp_mode_ == 0) { // Damp all components
1061 dpProps_->dp_F_ = u_s * (-1.0* vcs) / timestep; // shear component
1062 dpProps_->dp_F_ -= norm * vcn / timestep; // normal component
1063 } else if (dpProps_->dp_mode_ == 1) { // limit the tensile
1064 dpProps_->dp_F_ -= norm * vcn / timestep; // normal component
1065 if (dpProps_->dp_F_.x() + lin_F_.x() < 0)
1066 dpProps_->dp_F_.rx() = - lin_F_.rx();
1067 } else if (dpProps_->dp_mode_ == 2) { // limit the shear
1068 if (!lin_S_)
1069 dpProps_->dp_F_ = u_s * (-1.0* vcs) / timestep; // shear component
1070 } else {
1071 if (!lin_S_)
1072 dpProps_->dp_F_ = u_s * (-1.0* vcs) / timestep; // shear component
1073 dpProps_->dp_F_ -= norm * vcn / timestep; // normal component
1074 if (dpProps_->dp_F_.x() + lin_F_.x() < 0)
1075 dpProps_->dp_F_.rx() = - lin_F_.rx();
1076 }
1077 }
1078
1079 // Account for parallel bonds
1080 bool doPb = false;
1081 if (pbProps_ && pbProps_->pb_state_ > 2) {
1082 doPb = true;
1083 // Parallel Bond Logic:
1084 // bond area and inertia
1085 // minimal curvature of end1
1086 double Cmin1 = state->end1Curvature_.x();
1087 double Cmax1 = state->end1Curvature_.y();
1088 double Cmax2 = state->end2Curvature_.y();
1089 double dthick = (Cmin1 == 0.0) ? 1.0 : 0.0;
1090 double br = pbProps_->pb_rmul_ * 1.0 / std::max(Cmax1,Cmax2);
1091 if (userArea_)
1092#ifdef THREED
1093 br = std::sqrt(userArea_ / dPi);
1094#else
1095 br = userArea_ / 2.0;
1096#endif
1097 double br2 = br*br;
1098 double pbArea = dthick <= 0.0 ? dPi*br2 : 2.0*br*dthick;
1099 double bi = dthick <= 0.0 ? 0.25*pbArea*br2 : 2.0*br*br2*dthick/3.0;
1100 pbProps_->pbTransStiff_.rx() = pbProps_->pb_kn_*pbArea;
1101 pbProps_->pbTransStiff_.ry() = pbProps_->pb_ks_*pbArea;
1102
1103 /* elastic force increments */
1104 pbProps_->pb_F_ -= norm *(pbProps_->pb_kn_*pbArea) + u_s * (pbProps_->pb_ks_*pbArea);
1105
1106 /* elastic moment increments */
1107 //DAVect pbMomentInc(0.0);
1108#if DIM==3
1109 pbProps_->pbAngStiff_.rx() = pbProps_->pb_ks_* 2.0 * bi;
1110 pbProps_->pbAngStiff_.ry() = pbProps_->pb_kn_* bi;
1111#endif
1112 pbProps_->pbAngStiff_.rz() = pbProps_->pb_kn_* bi;
1113
1114 DAVect pbMomentInc = ang * pbProps_->pbAngStiff_ *(-1.0);
1115 pbProps_->pb_M_ += pbMomentInc;
1116
1117 /* check bond failure */
1118 if (state->canFail_) {
1119 /* maximum stresses */
1120 double dbend = sqrt(pbProps_->pb_M_.y()*pbProps_->pb_M_.y() + pbProps_->pb_M_.z()*pbProps_->pb_M_.z());
1121 double dtwist = pbProps_->pb_M_.x();
1122 DVect bfs(pbProps_->pb_F_);
1123 bfs.rx() = 0.0;
1124 double dbfs = bfs.mag();
1125 double nsmax = -(pbProps_->pb_F_.x() / pbArea) + pbProps_->pb_mcf_ * dbend * br/bi;
1126 double ssmax = dbfs / pbArea + pbProps_->pb_mcf_ * std::abs(dtwist) * 0.5* br/bi;
1127 double ss ;
1128
1129 if (nsmax >= pbProps_->pb_ten_) {
1130 // Failed in tension
1131 double se = pbStrainEnergy(); // bond strain energy at the onset of failure
1132 pbProps_->pb_state_ = 1;
1133 pbProps_->pb_F_.fill(0.0);
1134 pbProps_->pb_M_.fill(0.0);
1135 if (cmEvents_[fBondBreak] >= 0) {
1136 auto c = state->getContact();
1137 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
1138 fish::Parameter((int64)pbProps_->pb_state_),
1139 fish::Parameter(pbProps_->pb_ten_),
1140 fish::Parameter(se) };
1141 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
1142 fi->setCMFishCallArguments(c,arg,cmEvents_[fBondBreak]);
1143 }
1144 } else if ((ss = pbShearStrength(pbArea)) <= ssmax) {
1145 // Failed in shear
1146 double se = pbStrainEnergy(); // bond strain energy at the onset of failure
1147 pbProps_->pb_state_ = 2;
1148 pbProps_->pb_F_.fill(0.0);
1149 pbProps_->pb_M_.fill(0.0);
1150 if (cmEvents_[fBondBreak] >= 0) {
1151 auto c = state->getContact();
1152 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
1153 fish::Parameter((int64)pbProps_->pb_state_),
1154 fish::Parameter(ss),
1155 fish::Parameter(se) };
1156 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
1157 fi->setCMFishCallArguments(c,arg,cmEvents_[fBondBreak]);
1158 }
1159 }
1160 }
1161 }
1162
1163 // Compute energies
1164 if (state->trackEnergy_) {
1165 assert(energies_);
1166 energies_->estrain_ = 0.0;
1167 energies_->epbstrain_ = 0.0;
1168 if (kn_)
1169 energies_->estrain_ = 0.5 * lin_F_.x()* lin_F_.x() /kn_;
1170 if (ks_) {
1171 DVect s = lin_F_;
1172 s.rx() = 0.0;
1173 double smag2 = s.mag2();
1174 energies_->estrain_ += 0.5* smag2 / ks_ ;
1175
1176 if (lin_S_) {
1177 ss_F_old.rx() = 0.0;
1178 DVect avg_F_s = (s + ss_F_old)*0.5;
1179 DVect u_s_el = (s - ss_F_old) / ks_;
1180 energies_->eslip_ -= std::min(0.0,(avg_F_s | (u_s + u_s_el)));
1181 }
1182 }
1183 if (dpProps_)
1184 energies_->edashpot_ -= dpProps_->dp_F_ | trans;
1185 if (doPb)
1186 energies_->epbstrain_ = pbStrainEnergy();
1187 }
1188
1189 assert(lin_F_ == lin_F_);
1190 return checkActivity(state->gap_);
1191 }
1192
1193 bool ContactModelLinearPBond::thermalCoupling(ContactModelMechanicalState *ms,ContactModelThermalState *ts, IContactThermal *ct,const double &) {
1194 // Account for thermal expansion in linear group in incremental mode
1195 bool ret = false;
1196 if (lin_mode_ > 0 && ts->gapInc_ > 0.0) {
1197 DVect finc(0.0);
1198 finc.rx() = kn_ * ts->gapInc_;
1199 lin_F_ -= finc;
1200 ret = true;
1201 }
1202
1203 if (!pbProps_) return ret;
1204 if (pbProps_->pb_state_ < 3) return ret;
1205 int idx = ct->getModel()->getContactModel()->isProperty("thexp");
1206 if (idx<=0 ) return ret;
1207
1208 double thexp = (ct->getModel()->getContactModel()->getProperty(idx)).toDouble();
1209 double length = ts->length_;
1210 double delTemp =ts->tempInc_;
1211 double delUn = length * thexp * delTemp;
1212 if (delUn == 0.0) return ret;
1213
1214 double dthick = 0.0;
1215 double Cmin1 = ms->end1Curvature_.x();
1216 double Cmax1 = ms->end1Curvature_.y();
1217 double Cmin2 = ms->end2Curvature_.x();
1218 double Cmax2 = ms->end2Curvature_.y();
1219
1220 Cmin2;
1221 if (Cmin1 == 0.0)
1222 dthick = 1.0;
1223
1224 double br = pbProps_->pb_rmul_ * 1.0 / std::max(Cmax1,Cmax2);
1225 if (userArea_)
1226#ifdef THREED
1227 br = std::sqrt(userArea_ / dPi);
1228#else
1229 br = userArea_ / 2.0;
1230#endif
1231 double br2 = br*br;
1232 double pbArea = dthick <= 0.0 ? dPi*br2 : 2.0*br*dthick;
1233 //
1234 DVect finc(0.0);
1235 finc.rx() = pbProps_->pb_kn_ * pbArea * delUn;
1236 pbProps_->pb_F_ += finc;
1237
1238 ret = true;
1239 return ret;
1240 }
1241
1242 void ContactModelLinearPBond::setForce(const DVect &v,IContact *c) {
1243 lin_F(v);
1244 if (v.x() > 0)
1245 rgap_ = c->getGap() + v.x() / kn_;
1246 }
1247
1248 void ContactModelLinearPBond::propagateStateInformation(IContactModelMechanical* old,const CAxes &oldSystem,const CAxes &newSystem) {
1249 // Only do something if the contact model is of the same type
1250 if (equal(old->getContactModel()->getName(),"linearpbond") && !isBonded()) {
1251 ContactModelLinearPBond *oldCm = (ContactModelLinearPBond *)old;
1252#ifdef THREED
1253 // Need to rotate just the shear component from oldSystem to newSystem
1254
1255 // Step 1 - rotate oldSystem so that the normal is the same as the normal of newSystem
1256 DVect axis = oldSystem.e1() & newSystem.e1();
1257 double c, ang, s;
1258 DVect re2;
1259 if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
1260 axis = axis.unit();
1261 c = oldSystem.e1()|newSystem.e1();
1262 if (c > 0)
1263 c = std::min(c,1.0);
1264 else
1265 c = std::max(c,-1.0);
1266 ang = acos(c);
1267 s = sin(ang);
1268 double t = 1. - c;
1269 DMatrix<3,3> rm;
1270 rm.get(0,0) = t*axis.x()*axis.x() + c;
1271 rm.get(0,1) = t*axis.x()*axis.y() - axis.z()*s;
1272 rm.get(0,2) = t*axis.x()*axis.z() + axis.y()*s;
1273 rm.get(1,0) = t*axis.x()*axis.y() + axis.z()*s;
1274 rm.get(1,1) = t*axis.y()*axis.y() + c;
1275 rm.get(1,2) = t*axis.y()*axis.z() - axis.x()*s;
1276 rm.get(2,0) = t*axis.x()*axis.z() - axis.y()*s;
1277 rm.get(2,1) = t*axis.y()*axis.z() + axis.x()*s;
1278 rm.get(2,2) = t*axis.z()*axis.z() + c;
1279 re2 = rm*oldSystem.e2();
1280 }
1281 else
1282 re2 = oldSystem.e2();
1283 // Step 2 - get the angle between the oldSystem rotated shear and newSystem shear
1284 axis = re2 & newSystem.e2();
1285 DVect2 tpf;
1286 DMatrix<2,2> m;
1287 if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
1288 axis = axis.unit();
1289 c = re2|newSystem.e2();
1290 if (c > 0)
1291 c = std::min(c,1.0);
1292 else
1293 c = std::max(c,-1.0);
1294 ang = acos(c);
1295 if (!checktol(axis.x(),newSystem.e1().x(),1.0,100))
1296 ang *= -1;
1297 s = sin(ang);
1298 m.get(0,0) = c;
1299 m.get(1,0) = s;
1300 m.get(0,1) = -m.get(1,0);
1301 m.get(1,1) = m.get(0,0);
1302 tpf = m*DVect2(oldCm->lin_F_.y(),oldCm->lin_F_.z());
1303 } else {
1304 m.get(0,0) = 1.;
1305 m.get(0,1) = 0.;
1306 m.get(1,0) = 0.;
1307 m.get(1,1) = 1.;
1308 tpf = DVect2(oldCm->lin_F_.y(),oldCm->lin_F_.z());
1309 }
1310 DVect pforce = DVect(0,tpf.x(),tpf.y());
1311#else
1312 oldSystem;
1313 newSystem;
1314 DVect pforce = DVect(0,oldCm->lin_F_.y());
1315#endif
1316 for (int i=1; i<dim; ++i)
1317 lin_F_.rdof(i) += pforce.dof(i);
1318 if (lin_mode_ && oldCm->lin_mode_)
1319 lin_F_.rx() = oldCm->lin_F_.x();
1320 oldCm->lin_F_ = DVect(0.0);
1321 if (dpProps_ && oldCm->dpProps_) {
1322#ifdef THREED
1323 tpf = m*DVect2(oldCm->dpProps_->dp_F_.y(),oldCm->dpProps_->dp_F_.z());
1324 pforce = DVect(oldCm->dpProps_->dp_F_.x(),tpf.x(),tpf.y());
1325#else
1326 pforce = oldCm->dpProps_->dp_F_;
1327#endif
1328 dpProps_->dp_F_ += pforce;
1329 oldCm->dpProps_->dp_F_ = DVect(0.0);
1330 }
1331 if(oldCm->getEnergyActivated()) {
1332 activateEnergy();
1333 energies_->estrain_ = oldCm->energies_->estrain_;
1334 energies_->eslip_ = oldCm->energies_->eslip_;
1335 energies_->edashpot_ = oldCm->energies_->edashpot_;
1336 energies_->epbstrain_ = oldCm->energies_->epbstrain_;
1337 oldCm->energies_->estrain_ = 0.0;
1338 oldCm->energies_->edashpot_ = 0.0;
1339 oldCm->energies_->eslip_ = 0.0;
1340 oldCm->energies_->epbstrain_ = 0.0;
1341 }
1342 rgap_ = oldCm->rgap_;
1343 }
1344 assert(lin_F_ == lin_F_);
1345 }
1346
1347 void ContactModelLinearPBond::setNonForcePropsFrom(IContactModel *old) {
1348 // Only do something if the contact model is of the same type
1349 if (equal(old->getName(),"linearpbond") && !isBonded()) {
1350 ContactModelLinearPBond *oldCm = (ContactModelLinearPBond *)old;
1351 kn_ = oldCm->kn_;
1352 ks_ = oldCm->ks_;
1353 fric_ = oldCm->fric_;
1354 lin_mode_ = oldCm->lin_mode_;
1355 rgap_ = oldCm->rgap_;
1356 userArea_ = oldCm->userArea_;
1357
1358 if (oldCm->dpProps_) {
1359 if (!dpProps_)
1360 dpProps_ = NEW dpProps();
1361 dpProps_->dp_nratio_ = oldCm->dpProps_->dp_nratio_;
1362 dpProps_->dp_sratio_ = oldCm->dpProps_->dp_sratio_;
1363 dpProps_->dp_mode_ = oldCm->dpProps_->dp_mode_;
1364 }
1365
1366 if (oldCm->pbProps_) {
1367 if (!pbProps_)
1368 pbProps_ = NEW pbProps();
1369 pbProps_->pb_rmul_ = oldCm->pbProps_->pb_rmul_;
1370 pbProps_->pb_kn_ = oldCm->pbProps_->pb_kn_;
1371 pbProps_->pb_ks_ = oldCm->pbProps_->pb_ks_;
1372 pbProps_->pb_mcf_ = oldCm->pbProps_->pb_mcf_;
1373 pbProps_->pb_fa_ = oldCm->pbProps_->pb_fa_;
1374 pbProps_->pb_state_ = oldCm->pbProps_->pb_state_;
1375 pbProps_->pb_coh_ = oldCm->pbProps_->pb_coh_;
1376 pbProps_->pb_ten_ = oldCm->pbProps_->pb_ten_;
1377 pbProps_->pbTransStiff_ = oldCm->pbProps_->pbTransStiff_;
1378 pbProps_->pbAngStiff_ = oldCm->pbProps_->pbAngStiff_;
1379 }
1380 }
1381 }
1382
1383 DVect ContactModelLinearPBond::getForce() const {
1384 DVect ret(lin_F_);
1385 if (dpProps_)
1386 ret += dpProps_->dp_F_;
1387 if (pbProps_)
1388 ret += pbProps_->pb_F_;
1389 return ret;
1390 }
1391
1392 DAVect ContactModelLinearPBond::getMomentOn1(const IContactMechanical *c) const {
1393 DAVect ret(0.0);
1394 if (pbProps_)
1395 ret = pbProps_->pb_M_;
1396 if (c) {
1397 DVect force = getForce();
1398 c->updateResultingTorqueOn1Local(force,&ret);
1399 }
1400 return ret;
1401 }
1402
1403 DAVect ContactModelLinearPBond::getMomentOn2(const IContactMechanical *c) const {
1404 DAVect ret(0.0);
1405 if (pbProps_)
1406 ret = pbProps_->pb_M_;
1407 if (c) {
1408 DVect force = getForce();
1409 c->updateResultingTorqueOn2Local(force,&ret);
1410 }
1411 return ret;
1412 }
1413
1414 DAVect ContactModelLinearPBond::getModelMomentOn1() const {
1415 DAVect ret(0.0);
1416 if (pbProps_)
1417 ret = pbProps_->pb_M_;
1418 return ret;
1419 }
1420
1421 DAVect ContactModelLinearPBond::getModelMomentOn2() const {
1422 DAVect ret(0.0);
1423 if (pbProps_)
1424 ret = pbProps_->pb_M_;
1425 return ret;
1426 }
1427
1428 void ContactModelLinearPBond::objectPropsTypes(std::vector<std::pair<string,InfoTypes>> *ret) const {
1429 ret->clear();
1430 ret->push_back({"kn",ScalarInfo});
1431 ret->push_back({"ks",ScalarInfo});
1432 ret->push_back({"fric",ScalarInfo});
1433 ret->push_back({"lin_force",VectorInfo});
1434 ret->push_back({"lin_slip",ScalarInfo});
1435 ret->push_back({"lin_mode",ScalarInfo});
1436 ret->push_back({"rgap",ScalarInfo});
1437 ret->push_back({"emod",ScalarInfo});
1438 ret->push_back({"kratio",ScalarInfo});
1439 ret->push_back({"dp_nratio",ScalarInfo});
1440 ret->push_back({"dp_sratio",ScalarInfo});
1441 ret->push_back({"dp_mode",ScalarInfo});
1442 ret->push_back({"dp_force",VectorInfo});
1443 ret->push_back({"pb_state",ScalarInfo});
1444 ret->push_back({"pb_rmul",ScalarInfo});
1445 ret->push_back({"pb_kn",ScalarInfo});
1446 ret->push_back({"pb_ks",ScalarInfo});
1447 ret->push_back({"pb_mcf",ScalarInfo});
1448 ret->push_back({"pb_ten",ScalarInfo});
1449 ret->push_back({"pb_shear",ScalarInfo});
1450 ret->push_back({"pb_coh",ScalarInfo});
1451 ret->push_back({"pb_fa",ScalarInfo});
1452 ret->push_back({"pb_sigma",ScalarInfo});
1453 ret->push_back({"pb_tau",ScalarInfo});
1454 ret->push_back({"pb_force",VectorInfo});
1455 ret->push_back({"pb_moment",VectorInfo});
1456 ret->push_back({"pb_radius",ScalarInfo});
1457 ret->push_back({"pb_emod",ScalarInfo});
1458 ret->push_back({"pb_kratio",ScalarInfo});
1459 ret->push_back({"user_area",ScalarInfo});
1460 }
1461
1462 void ContactModelLinearPBond::objectPropValues(std::vector<double> *ret,const IContact *con) const {
1463 FP_S;
1464 ret->clear();
1465 ret->push_back(kn());
1466 ret->push_back(ks());
1467 ret->push_back(fric());
1468 ret->push_back(lin_F().mag());
1469 ret->push_back(lin_S());
1470 ret->push_back(lin_mode());
1471 ret->push_back(rgap());
1472 double d;
1473 const IContactMechanical *c(convert_getcast<IContactMechanical>(con));
1474 double rsq(std::max(c->getEnd1Curvature().y(),c->getEnd2Curvature().y()));
1475 double rsum = calcRSum(c);
1476 if (userArea_) {
1477 FP_S;
1478#ifdef THREED
1479 rsq = std::sqrt(userArea_ / dPi);
1480#else
1481 rsq = userArea_ / 2.0;
1482#endif
1483 rsum = rsq + rsq;
1484 rsq = safeDiv(1. , rsq);
1485 }
1486#ifdef TWOD
1487 d = (kn_ * rsum * rsq / 2.0);
1488#else
1489 d = (kn_ * rsum * rsq * rsq) / dPi;
1490#endif
1491 ret->push_back(d);
1492 ret->push_back(safeDiv(kn_,ks_));
1493 ret->push_back(dp_nratio());
1494 ret->push_back(dp_sratio());
1495 ret->push_back(dp_mode());
1496 FP_S;
1497 ret->push_back(dp_F().mag());
1498 FP_S;
1499 ret->push_back(pbProps_ ? pbProps_->pb_state_ : 0);
1500 ret->push_back(pbProps_ ? pbProps_->pb_rmul_ : 1);
1501 ret->push_back(pbProps_ ? pbProps_->pb_kn_ : 0);
1502 ret->push_back(pbProps_ ? pbProps_->pb_ks_ : 0);
1503 ret->push_back(pbProps_ ? pbProps_->pb_mcf_ : 1);
1504 ret->push_back(pbProps_ ? pbProps_->pb_ten_ : 0);
1505 if (!pbProps_) d = 0; else d = pbShearStrength(pbData(c).x());
1506 ret->push_back(d);
1507 ret->push_back(pbProps_ ? pbProps_->pb_coh_ : 0);
1508 ret->push_back(pbProps_ ? pbProps_->pb_fa_ : 0);
1509 if (!pbProps_ || pbProps_->pb_state_ < 3) d =0.0; else pbSMax(c).x();
1510 ret->push_back(d);
1511 if (!pbProps_ || pbProps_->pb_state_ < 3) d =0.0; else pbSMax(c).y();
1512 ret->push_back(d);
1513 ret->push_back(pbProps_ ? (pbProps_->pb_F_).mag() : 0);
1514 ret->push_back(pbProps_ ? (pbProps_->pb_M_).mag() : 0);
1515 FP_S;
1516 d = 0;
1517 if (pbProps_) {
1518 double Cmax1 = c->getEnd1Curvature().y();
1519 double Cmax2 = c->getEnd2Curvature().y();
1520 double br = safeDiv(pbProps_->pb_rmul_ * 1.0 , std::max(Cmax1,Cmax2));
1521 if (userArea_)
1522#ifdef THREED
1523 d = std::sqrt(userArea_ / dPi);
1524#else
1525 d = userArea_ / 2.0;
1526#endif
1527 }
1528 ret->push_back(d);
1529 d = 0;
1530 rsum += calcRSum(c); /// ??
1531 if (userArea_) {
1532#ifdef THREED
1533 double rad = std::sqrt(userArea_ / dPi);
1534#else
1535 double rad = userArea_ / 2.0;
1536#endif
1537 rsum = 2 * rad;
1538 }
1539 d = pbProps_ ? pbProps_->pb_kn_ * rsum : 0;
1540 ret->push_back(d);
1541 d = 0;
1542 if (pbProps_)
1543 d = safeDiv(pbProps_->pb_kn_,pbProps_->pb_ks_);
1544 ret->push_back(d);
1545 ret->push_back(userArea_);
1546 FP_S;
1547 }
1548
1549 DVect3 ContactModelLinearPBond::pbData(const IContactMechanical *c) const {
1550 double Cmax1 = c->getEnd1Curvature().y();
1551 double Cmax2 = c->getEnd2Curvature().y();
1552 double br = pbProps_->pb_rmul_ * 1.0 / std::max(Cmax1,Cmax2);
1553 if (userArea_)
1554#ifdef THREED
1555 br = std::sqrt(userArea_ / dPi);
1556#else
1557 br = userArea_ / 2.0;
1558#endif
1559 double br2 = br*br;
1560#ifdef TWOD
1561 double pbArea = 2.0*br;
1562 double bi = 2.0*br*br2/3.0;
1563#else
1564 double pbArea = dPi*br2;
1565 double bi = 0.25*pbArea*br2;
1566#endif
1567 return DVect3(pbArea,bi,br);
1568 }
1569
1570 DVect2 ContactModelLinearPBond::pbSMax(const IContactMechanical *c) const {
1571 DVect3 data = pbData(c);
1572 double pbArea = data.x();
1573 double bi = data.y();
1574 double br = data.z();
1575 /* maximum stresses */
1576 double dbend = sqrt(pbProps_->pb_M_.y()*pbProps_->pb_M_.y() + pbProps_->pb_M_.z()*pbProps_->pb_M_.z());
1577 double dtwist = pbProps_->pb_M_.x();
1578 DVect bfs(pbProps_->pb_F_);
1579 bfs.rx() = 0.0;
1580 double dbfs = bfs.mag();
1581 double nsmax = -(pbProps_->pb_F_.x() / pbArea) + pbProps_->pb_mcf_ * dbend * br/bi;
1582 double ssmax = dbfs / pbArea + pbProps_->pb_mcf_ * std::abs(dtwist) * 0.5* br/bi;
1583 return DVect2(nsmax,ssmax);
1584 }
1585
1586 double ContactModelLinearPBond::pbShearStrength(const double &pbArea) const {
1587 if (!pbProps_) return 0.0;
1588 double sig = -1.0*pbProps_->pb_F_.x() / pbArea;
1589 double nstr = pbProps_->pb_state_ > 2 ? pbProps_->pb_ten_ : 0.0;
1590 return sig <= nstr ? pbProps_->pb_coh_ - std::tan(dDegrad*pbProps_->pb_fa_)*sig
1591 : pbProps_->pb_coh_ - std::tan(dDegrad*pbProps_->pb_fa_)*nstr;
1592 }
1593
1594 void ContactModelLinearPBond::setDampCoefficients(const double &mass,double *vcn,double *vcs) {
1595 *vcn = dpProps_->dp_nratio_ * 2.0 * sqrt(mass*(kn_));
1596 *vcs = dpProps_->dp_sratio_ * 2.0 * sqrt(mass*(ks_));
1597 }
1598
1599} // namespace itascaxd
1600// EoF
Was this helpful? ... | Itasca Software © 2024, Itasca | Updated: Jun 07, 2025 |