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 QString 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 QString 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 QString 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 QString getFishCallEvents() const override { return "contact_activated,bond_break,slip_change"; }
106 QVariant getProperty(uint32 i,const IContact *con=0) const override;
107 bool getPropertyGlobal(uint32 i) const override;
108 bool setProperty(uint32 i,const QVariant &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 QString getMethods() const override {
122 return "deformability"
123 ",pb_deformability"
124 ",bond"
125 ",unbond"
126 ",area";
127 }
128
129 QString getMethodArguments(uint32 i) const override;
130
131 bool setMethod(uint32 i,const QVector<QVariant> &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 QString &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<QString,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 QVariant 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 QVariant 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(0.0);
248 if (c->getEnd1Curvature().y())
249 rsum += 1.0/c->getEnd1Curvature().y();
250 if (c->getEnd2Curvature().y())
251 rsum += 1.0/c->getEnd2Curvature().y();
252 if (userArea_) {
253#ifdef THREED
254 rsq = std::sqrt(userArea_ / dPi);
255#else
256 rsq = userArea_ / 2.0;
257#endif
258 rsum = rsq + rsq;
259 rsq = 1. / rsq;
260 }
261#ifdef TWOD
262 return (kn_ * rsum * rsq / 2.0);
263#else
264 return (kn_ * rsum * rsq * rsq) / dPi;
265#endif
266 }
267 case kwKRatio: return (ks_ == 0.0) ? 0.0 : (kn_/ks_);
268 case kwDpNRatio: return dpProps_ ? dpProps_->dp_nratio_ : 0;
269 case kwDpSRatio: return dpProps_ ? dpProps_->dp_sratio_ : 0;
270 case kwDpMode: return dpProps_ ? dpProps_->dp_mode_ : 0;
271 case kwUserArea: return userArea_;
272 case kwDpF: {
273 dpProps_ ? var.setValue(dpProps_->dp_F_) : var.setValue(DVect(0.0));
274 return var;
275 }
276 case kwPbState: return pbProps_ ? pbProps_->pb_state_ : 0;
277 case kwPbRMul: return pbProps_ ? pbProps_->pb_rmul_ : 1.0;
278 case kwPbKn: return pbProps_ ? pbProps_->pb_kn_ : 0;
279 case kwPbKs: return pbProps_ ? pbProps_->pb_ks_ : 0;
280 case kwPbMcf: return pbProps_ ? pbProps_->pb_mcf_ : 1.0;
281 case kwPbTStrength: return pbProps_ ? pbProps_->pb_ten_ : 0.0;
282 case kwPbSStrength: {
283 if (!pbProps_ or not c) return 0.0;
284 double pbArea = pbData(c).x();
285 return pbShearStrength(pbArea);
286 }
287 case kwPbCoh: return pbProps_ ? pbProps_->pb_coh_ : 0;
288 case kwPbFa: return pbProps_ ? pbProps_->pb_fa_ : 0;
289 case kwPbSig: {
290 if (!pbProps_ or pbProps_->pb_state_ < 3 or not c) return 0.0;
291 return pbSMax(c).x();
292 }
293 case kwPbTau: {
294 if (!pbProps_ or pbProps_->pb_state_ < 3 or not c) return 0.0;
295 return pbSMax(c).y();
296 }
297 case kwPbF: {
298 pbProps_ ? var.setValue(pbProps_->pb_F_) : var.setValue(DVect(0.0));
299 return var;
300 }
301 case kwPbM: {
302 pbProps_ ? var.setValue(pbProps_->pb_M_) : var.setValue(DAVect(0.0));
303 return var;
304 }
305 case kwPbRadius: {
306 if (!pbProps_ or not c) return 0.0;
307 double Cmax1 = c->getEnd1Curvature().y();
308 double Cmax2 = c->getEnd2Curvature().y();
309 double br = pbProps_->pb_rmul_ * 1.0 / std::max(Cmax1,Cmax2);
310 if (userArea_)
311#ifdef THREED
312 br = std::sqrt(userArea_ / dPi);
313#else
314 br = userArea_ / 2.0;
315#endif
316 return br;
317 }
318 case kwPbEmod: {
319 if (!pbProps_ or not c) return 0.0;
320 double rsum(0.0);
321 if (c->getEnd1Curvature().y())
322 rsum += 1.0/c->getEnd1Curvature().y();
323 if (c->getEnd2Curvature().y())
324 rsum += 1.0/c->getEnd2Curvature().y();
325 if (userArea_) {
326#ifdef THREED
327 double rad = std::sqrt(userArea_ / dPi);
328#else
329 double rad = userArea_ / 2.0;
330#endif
331 rsum = 2 * rad;
332 }
333 double emod = pbProps_->pb_kn_ * rsum;
334 return emod;
335 }
336 case kwPbKRatio: {
337 if (!pbProps_) return 0.0;
338 return (pbProps_->pb_ks_ == 0.0) ? 0.0 : (pbProps_->pb_kn_/pbProps_->pb_ks_);
339 }
340 }
341 assert(0);
342 return QVariant();
343 }
344
345 bool ContactModelLinearPBond::getPropertyGlobal(uint32 i) const {
346 switch (i) {
347 case kwLinF:
348 case kwDpF:
349 case kwPbF:
350 return false;
351 }
352 return true;
353 }
354
355 bool ContactModelLinearPBond::setProperty(uint32 i,const QVariant &v,IContact *) {
356 pbProps pb;
357 dpProps dp;
358
359 switch (i) {
360 case kwLinKn: {
361 if (!v.canConvert<double>())
362 throw Exception("kn must be a double.");
363 double val(v.toDouble());
364 if (val<0.0)
365 throw Exception("Negative kn not allowed.");
366 kn_ = val;
367 return true;
368 }
369 case kwLinKs: {
370 if (!v.canConvert<double>())
371 throw Exception("ks must be a double.");
372 double val(v.toDouble());
373 if (val<0.0)
374 throw Exception("Negative ks not allowed.");
375 ks_ = val;
376 return true;
377 }
378 case kwLinFric: {
379 if (!v.canConvert<double>())
380 throw Exception("fric must be a double.");
381 double val(v.toDouble());
382 if (val<0.0)
383 throw Exception("Negative fric not allowed.");
384 fric_ = val;
385 return false;
386 }
387 case kwLinF: {
388 if (!v.canConvert<DVect>())
389 throw Exception("lin_force must be a vector.");
390 DVect val(v.value<DVect>());
391 lin_F_ = val;
392 return false;
393 }
394 case kwLinMode: {
395 if (!v.canConvert<uint32>())
396 throw Exception("lin_mode must be 0 (absolute) or 1 (incremental).");
397 uint32 val(v.toUInt());
398 if (val>1)
399 throw Exception("lin_mode must be 0 (absolute) or 1 (incremental).");
400 lin_mode_ = val;
401 return false;
402 }
403 case kwRGap: {
404 if (!v.canConvert<double>())
405 throw Exception("Reference gap must be a double.");
406 double val(v.toDouble());
407 rgap_ = val;
408 return false;
409 }
410 case kwPbRMul: {
411 if (!v.canConvert<double>())
412 throw Exception("pb_rmul must be a double.");
413 double val(v.toDouble());
414 if (val<=0.0)
415 throw Exception("pb_rmul must be positive.");
416 if (val == 1.0 && !pbProps_)
417 return false;
418 if (!pbProps_)
419 pbProps_ = NEW pbProps();
420 pbProps_->pb_rmul_ = val;
421 return false;
422 }
423 case kwPbKn: {
424 if (!v.canConvert<double>())
425 throw Exception("pb_kn must be a double.");
426 double val(v.toDouble());
427 if (val<0.0)
428 throw Exception("Negative pb_kn not allowed.");
429 if (val == 0.0 && !pbProps_)
430 return false;
431 if (!pbProps_)
432 pbProps_ = NEW pbProps();
433 pbProps_->pb_kn_ = val;
434 return true;
435 }
436 case kwPbKs: {
437 if (!v.canConvert<double>())
438 throw Exception("pb_ks must be a double.");
439 double val(v.toDouble());
440 if (val<0.0)
441 throw Exception("Negative pb_ks not allowed.");
442 if (val == 0.0 && !pbProps_)
443 return false;
444 if (!pbProps_)
445 pbProps_ = NEW pbProps();
446 pbProps_->pb_ks_ = val;
447 return true;
448 }
449 case kwPbMcf: {
450 if (!v.canConvert<double>())
451 throw Exception("pb_mcf must be a double.");
452 double val(v.toDouble());
453 if (val<0.0)
454 throw Exception("Negative pb_mcf not allowed.");
455 if (val > 1.0)
456 throw Exception("pb_mcf must be lower or equal to 1.0.");
457 if (val == 1.0 && !pbProps_)
458 return false;
459 if (!pbProps_)
460 pbProps_ = NEW pbProps();
461 pbProps_->pb_mcf_ = val;
462 return false;
463 }
464 case kwPbTStrength: {
465 if (!v.canConvert<double>())
466 throw Exception("pb_ten must be a double.");
467 double val(v.toDouble());
468 if (val < 0.0)
469 throw Exception("Negative pb_ten not allowed.");
470 if (val == 0.0 && !pbProps_)
471 return false;
472 if (!pbProps_)
473 pbProps_ = NEW pbProps();
474 pbProps_->pb_ten_ = val;
475 return false;
476 }
477 case kwPbCoh: {
478 if (!v.canConvert<double>())
479 throw Exception("pb_coh must be a double.");
480 double val(v.toDouble());
481 if (val<0.0)
482 throw Exception("Negative pb_coh not allowed.");
483 if (val == 0.0 && !pbProps_)
484 return false;
485 if (!pbProps_)
486 pbProps_ = NEW pbProps();
487 pbProps_->pb_coh_ = val;
488 return false;
489 }
490 case kwPbFa: {
491 if (!v.canConvert<double>())
492 throw Exception("pb_fa must be a double.");
493 double val(v.toDouble());
494 if (val<0.0)
495 throw Exception("Negative pb_fa not allowed.");
496 if (val>=90.0)
497 throw Exception("pb_fa must be lower than 90.0 degrees.");
498 if (val == 0.0 && !pbProps_)
499 return false;
500 if (!pbProps_)
501 pbProps_ = NEW pbProps();
502 pbProps_->pb_fa_ = val;
503 return false;
504 }
505 case kwPbF: {
506 if (!v.canConvert<DVect>())
507 throw Exception("pb_force must be a vector.");
508 DVect val(v.value<DVect>());
509 if (val.fsum() == 0.0 && !pbProps_)
510 return false;
511 if (!pbProps_)
512 pbProps_ = NEW pbProps();
513 pbProps_->pb_F_ = val;
514 return false;
515 }
516 case kwPbM: {
517 DAVect val(0.0);
518#ifdef TWOD
519 if (!v.canConvert<DAVect>() && !v.canConvert<double>())
520 throw Exception("pb_moment must be an angular vector.");
521 if (v.canConvert<DAVect>())
522 val = DAVect(v.value<DAVect>());
523 else
524 val = DAVect(v.toDouble());
525#else
526 if (!v.canConvert<DAVect>() && !v.canConvert<DVect>())
527 throw Exception("pb_moment must be an angular vector.");
528 if (v.canConvert<DAVect>())
529 val = DAVect(v.value<DAVect>());
530 else
531 val = DAVect(v.value<DVect>());
532#endif
533 if (val.fsum() == 0.0 && !pbProps_)
534 return false;
535 if (!pbProps_)
536 pbProps_ = NEW pbProps();
537 pbProps_->pb_M_ = val;
538 return false;
539 }
540 case kwDpNRatio: {
541 if (!v.canConvert<double>())
542 throw Exception("dp_nratio must be a double.");
543 double val(v.toDouble());
544 if (val<0.0)
545 throw Exception("Negative dp_nratio not allowed.");
546 if (val == 0.0 && !dpProps_)
547 return false;
548 if (!dpProps_)
549 dpProps_ = NEW dpProps();
550 dpProps_->dp_nratio_ = val;
551 return true;
552 }
553 case kwDpSRatio: {
554 if (!v.canConvert<double>())
555 throw Exception("dp_sratio must be a double.");
556 double val(v.toDouble());
557 if (val<0.0)
558 throw Exception("Negative dp_sratio not allowed.");
559 if (val == 0.0 && !dpProps_)
560 return false;
561 if (!dpProps_)
562 dpProps_ = NEW dpProps();
563 dpProps_->dp_sratio_ = val;
564 return true;
565 }
566 case kwDpMode: {
567 if (!v.canConvert<int>())
568 throw Exception("The viscous mode dp_mode must be 0, 1, 2, or 3.");
569 int val(v.toInt());
570 if (val == 0 && !dpProps_)
571 return false;
572 if (val < 0 || val > 3)
573 throw Exception("The viscous mode dp_mode must be 0, 1, 2, or 3.");
574 if (!dpProps_)
575 dpProps_ = NEW dpProps();
576 dpProps_->dp_mode_ = val;
577 return false;
578 }
579 case kwDpF: {
580 if (!v.canConvert<DVect>())
581 throw Exception("dp_force must be a vector.");
582 DVect val(v.value<DVect>());
583 if (val.fsum() == 0.0 && !dpProps_)
584 return false;
585 if (!dpProps_)
586 dpProps_ = NEW dpProps();
587 dpProps_->dp_F_ = val;
588 return false;
589 }
590 case kwUserArea: {
591 if (!v.canConvert<double>())
592 throw Exception("user_area must be a double.");
593 double val(v.toDouble());
594 if (val < 0.0)
595 throw Exception("Negative user_area not allowed.");
596 userArea_ = val;
597 return true;
598 }
599 }
600// assert(0);
601 return false;
602 }
603
604 bool ContactModelLinearPBond::getPropertyReadOnly(uint32 i) const {
605 switch (i) {
606 case kwDpF:
607 case kwLinS:
608 case kwEmod:
609 case kwKRatio:
610 case kwPbState:
611 case kwPbRadius:
612 case kwPbSStrength:
613 case kwPbSig:
614 case kwPbTau:
615 case kwPbEmod:
616 case kwPbKRatio:
617 return true;
618 default:
619 break;
620 }
621 return false;
622 }
623
624 bool ContactModelLinearPBond::supportsInheritance(uint32 i) const {
625 switch (i) {
626 case kwLinKn:
627 case kwLinKs:
628 case kwLinFric:
629 return true;
630 default:
631 break;
632 }
633 return false;
634 }
635
636 QString ContactModelLinearPBond::getMethodArguments(uint32 i) const {
637 QString def = QString();
638 switch (i) {
639 case kwDeformability:
640 return "emod,kratio";
641 case kwPbDeformability:
642 return "emod,kratio";
643 case kwPbBond:
644 return "gap";
645 case kwPbUnbond:
646 return "gap";
647 }
648 return def;
649 }
650
651 bool ContactModelLinearPBond::setMethod(uint32 i,const QVector<QVariant> &vl,IContact *con) {
652 IContactMechanical *c(convert_getcast<IContactMechanical>(con));
653 switch (i) {
654 case kwDeformability: {
655 double emod;
656 double krat;
657 if (vl.at(0).isNull())
658 throw Exception("Argument emod must be specified with method deformability in contact model {0}.",getName());
659 emod = vl.at(0).toDouble();
660 if (emod<0.0)
661 throw Exception("Negative emod not allowed in contact model {0}.",getName());
662 if (vl.at(1).isNull())
663 throw Exception("Argument kratio must be specified with method deformability in contact model {0}.",getName());
664 krat = vl.at(1).toDouble();
665 if (krat<0.0)
666 throw Exception("Negative linear stiffness ratio not allowed in contact model {0}.",getName());
667 double rsq(std::max(c->getEnd1Curvature().y(),c->getEnd2Curvature().y()));
668 double rsum(0.0);
669 if (c->getEnd1Curvature().y())
670 rsum += 1.0/c->getEnd1Curvature().y();
671 if (c->getEnd2Curvature().y())
672 rsum += 1.0/c->getEnd2Curvature().y();
673 if (userArea_) {
674#ifdef THREED
675 rsq = std::sqrt(userArea_ / dPi);
676#else
677 rsq = userArea_ / 2.0;
678#endif
679 rsum = rsq + rsq;
680 rsq = 1. / rsq;
681 }
682#ifdef TWOD
683 kn_ = 2.0 * emod / (rsq * rsum);
684#else
685 kn_ = dPi * emod / (rsq * rsq * rsum);
686#endif
687 ks_ = (krat == 0.0) ? 0.0 : kn_ / krat;
688 setInheritance(1,false);
689 setInheritance(2,false);
690 return true;
691 }
692 case kwPbDeformability: {
693 //if (!pbProps_ || pbProps_->pb_state_ != 3) return false;
694 double emod;
695 double krat;
696 if (vl.at(0).isNull())
697 throw Exception("Argument emod must be specified with method pb_deformability in contact model {0}.",getName());
698 emod = vl.at(0).toDouble();
699 if (emod<0.0)
700 throw Exception("Negative emod not allowed in contact model {0}.",getName());
701 if (vl.at(1).isNull())
702 throw Exception("Argument kratio must be specified with method pb_deformability in contact model {0}.",getName());
703 krat = vl.at(1).toDouble();
704 if (krat<0.0)
705 throw Exception("Negative parallel bond stiffness ratio not allowed in contact model {0}.",getName());
706 double rsum(0.0);
707 if (c->getEnd1Curvature().y())
708 rsum += 1.0/c->getEnd1Curvature().y();
709 if (c->getEnd2Curvature().y())
710 rsum += 1.0/c->getEnd2Curvature().y();
711 if (!pbProps_)
712 pbProps_ = NEW pbProps();
713 if (userArea_)
714#ifdef THREED
715 rsum = 2 * std::sqrt(userArea_ / dPi);
716#else
717 rsum = 2 * userArea_ / 2.0;
718#endif
719 pbProps_->pb_kn_ = emod / rsum;
720 pbProps_->pb_ks_ = (krat == 0.0) ? 0.0 : pbProps_->pb_kn_ / krat;
721 return true;
722 }
723 case kwPbBond: {
724 if (pbProps_ && pbProps_->pb_state_ == 3) return false;
725 double mingap = -1.0 * limits<double>::max();
726 double maxgap = 0;
727 if (vl.at(0).canConvert<double>())
728 maxgap = vl.at(0).toDouble();
729 else if (vl.at(0).canConvert<DVect2>()) {
730 DVect2 value = vl.at(0).value<DVect2>();
731 mingap = value.minComp();
732 maxgap = value.maxComp();
733 } else if (!vl.at(0).isNull())
734 throw Exception("gap value {0} not recognized in method bond in contact model {1}.",vl.at(0),getName());
735 double gap = c->getGap();
736 if ( gap >= mingap && gap <= maxgap) {
737 if (pbProps_)
738 pbProps_->pb_state_ = 3;
739 else {
740 pbProps_ = NEW pbProps();
741 pbProps_->pb_state_ = 3;
742 }
743 return true;
744 }
745 return false;
746 }
747 case kwPbUnbond: {
748 if (!pbProps_ || pbProps_->pb_state_ == 0) return false;
749 double mingap = -1.0 * limits<double>::max();
750 double maxgap = 0;
751 if (vl.at(0).canConvert<double>())
752 maxgap = vl.at(0).toDouble();
753 else if (vl.at(0).canConvert<DVect2>()) {
754 DVect2 value = vl.at(0).value<DVect2>();
755 mingap = value.minComp();
756 maxgap = value.maxComp();
757 }
758 else if (!vl.at(0).isNull())
759 throw Exception("gap value {0} not recognized in method unbond in contact model {1}.",vl.at(0),getName());
760 double gap = c->getGap();
761 if ( gap >= mingap && gap <= maxgap) {
762 pbProps_->pb_state_ = 0;
763 return true;
764 }
765 return false;
766 }
767 case kwArea: {
768 if (!userArea_) {
769 double rsq(1./std::max(c->getEnd1Curvature().y(),c->getEnd2Curvature().y()));
770#ifdef THREED
771 userArea_ = rsq * rsq * dPi;
772#else
773 userArea_ = rsq * 2.0;
774#endif
775 }
776 return true;
777 }
778 }
779 return false;
780 }
781
782 double ContactModelLinearPBond::getEnergy(uint32 i) const {
783 double ret(0.0);
784 if (!energies_)
785 return ret;
786 switch (i) {
787 case kwEStrain: return energies_->estrain_;
788 case kwESlip: return energies_->eslip_;
789 case kwEDashpot: return energies_->edashpot_;
790 case kwEPbStrain:return energies_->epbstrain_;
791 }
792 assert(0);
793 return ret;
794 }
795
796 bool ContactModelLinearPBond::getEnergyAccumulate(uint32 i) const {
797 switch (i) {
798 case kwEStrain: return false;
799 case kwESlip: return true;
800 case kwEDashpot: return true;
801 case kwEPbStrain: return false;
802 }
803 assert(0);
804 return false;
805 }
806
807 void ContactModelLinearPBond::setEnergy(uint32 i,const double &d) {
808 if (!energies_) return;
809 switch (i) {
810 case kwEStrain: energies_->estrain_ = d; return;
811 case kwESlip: energies_->eslip_ = d; return;
812 case kwEDashpot: energies_->edashpot_ = d; return;
813 case kwEPbStrain: energies_->epbstrain_= d; return;
814 }
815 assert(0);
816 return;
817 }
818
819 bool ContactModelLinearPBond::validate(ContactModelMechanicalState *state,const double &) {
820 assert(state);
821 const IContactMechanical *c = state->getMechanicalContact();
822 assert(c);
823
824 if (state->trackEnergy_)
825 activateEnergy();
826
827 if (inheritanceField_ & linKnMask)
828 updateKn(c);
829 if (inheritanceField_ & linKsMask)
830 updateKs(c);
831 if (inheritanceField_ & linFricMask)
832 updateFric(c);
833
834 updateEffectiveStiffness(state);
835 return checkActivity(state->gap_);
836 }
837
838 static const QString knstr("kn");
839 bool ContactModelLinearPBond::updateKn(const IContactMechanical *con) {
840 assert(con);
841 QVariant v1 = con->getEnd1()->getProperty(knstr);
842 QVariant v2 = con->getEnd2()->getProperty(knstr);
843 if (!v1.isValid() || !v2.isValid())
844 return false;
845 double kn1 = v1.toDouble();
846 double kn2 = v2.toDouble();
847 double val = kn_;
848 if (kn1 && kn2)
849 kn_ = kn1*kn2/(kn1+kn2);
850 else if (kn1)
851 kn_ = kn1;
852 else if (kn2)
853 kn_ = kn2;
854 return ( (kn_ != val) );
855 }
856
857 static const QString ksstr("ks");
858 bool ContactModelLinearPBond::updateKs(const IContactMechanical *con) {
859 assert(con);
860 QVariant v1 = con->getEnd1()->getProperty(ksstr);
861 QVariant v2 = con->getEnd2()->getProperty(ksstr);
862 if (!v1.isValid() || !v2.isValid())
863 return false;
864 double ks1 = v1.toDouble();
865 double ks2 = v2.toDouble();
866 double val = ks_;
867 if (ks1 && ks2)
868 ks_ = ks1*ks2/(ks1+ks2);
869 else if (ks1)
870 ks_ = ks1;
871 else if (ks2)
872 ks_ = ks2;
873 return ( (ks_ != val) );
874 }
875
876 static const QString fricstr("fric");
877 bool ContactModelLinearPBond::updateFric(const IContactMechanical *con) {
878 assert(con);
879 QVariant v1 = con->getEnd1()->getProperty(fricstr);
880 QVariant v2 = con->getEnd2()->getProperty(fricstr);
881 if (!v1.isValid() || !v2.isValid())
882 return false;
883 double fric1 = std::max(0.0,v1.toDouble());
884 double fric2 = std::max(0.0,v2.toDouble());
885 double val = fric_;
886 fric_ = std::min(fric1,fric2);
887 return ( (fric_ != val) );
888 }
889
890 bool ContactModelLinearPBond::endPropertyUpdated(const QString &name,const IContactMechanical *c) {
891 assert(c);
892 QStringList availableProperties = getProperties().simplified().replace(" ","").split(",",Qt::SkipEmptyParts);
893 QRegularExpression rx(name, QRegularExpression::CaseInsensitiveOption);
894 int idx = availableProperties.indexOf(rx)+1;
895 bool ret=false;
896
897 if (idx<=0)
898 return ret;
899
900 switch(idx) {
901 case kwLinKn: { //kn
902 if (inheritanceField_ & linKnMask)
903 ret = updateKn(c);
904 break;
905 }
906 case kwLinKs: { //ks
907 if (inheritanceField_ & linKsMask)
908 ret =updateKs(c);
909 break;
910 }
911 case kwLinFric: { //fric
912 if (inheritanceField_ & linFricMask)
913 updateFric(c);
914 break;
915 }
916 }
917 return ret;
918 }
919
920 void ContactModelLinearPBond::updateEffectiveStiffness(ContactModelMechanicalState *state) {
921 DVect2 ret(kn_,ks_);
922 // account for viscous damping
923 if (dpProps_) {
924 DVect2 correct(1.0);
925 if (dpProps_->dp_nratio_)
926 correct.rx() = sqrt(1.0+dpProps_->dp_nratio_*dpProps_->dp_nratio_) - dpProps_->dp_nratio_;
927 if (dpProps_->dp_sratio_)
928 correct.ry() = sqrt(1.0+dpProps_->dp_sratio_*dpProps_->dp_sratio_) - dpProps_->dp_sratio_;
929 ret /= (correct*correct);
930 }
931 effectiveTranslationalStiffness_ = ret;
932 if (isBonded()) {
933 double Cmin1 = state->end1Curvature_.x();
934 double Cmax1 = state->end1Curvature_.y();
935 double Cmax2 = state->end2Curvature_.y();
936 double dthick = (Cmin1 == 0.0) ? 1.0 : 0.0;
937 double br = pbProps_->pb_rmul_ * 1.0 / std::max(Cmax1,Cmax2);
938 if (userArea_)
939#ifdef THREED
940 br = std::sqrt(userArea_ / dPi);
941#else
942 br = userArea_ / 2.0;
943#endif
944 double br2 = br*br;
945 double pbArea = dthick <= 0.0 ? dPi*br2 : 2.0*br*dthick;
946 double bi = dthick <= 0.0 ? 0.25*pbArea*br2 : 2.0*br*br2*dthick/3.0;
947 pbProps_->pbTransStiff_.rx() = pbProps_->pb_kn_*pbArea;
948 pbProps_->pbTransStiff_.ry() = pbProps_->pb_ks_*pbArea;
949#if DIM==3
950 pbProps_->pbAngStiff_.rx() = pbProps_->pb_ks_* 2.0 * bi;
951 pbProps_->pbAngStiff_.ry() = pbProps_->pb_kn_* bi;
952#endif
953 pbProps_->pbAngStiff_.rz() = pbProps_->pb_kn_* bi;
954 }
955 }
956
957 double ContactModelLinearPBond::pbStrainEnergy() const {
958 double ret(0.0);
959 if (pbProps_->pb_kn_)
960 ret = 0.5 * pbProps_->pb_F_.x() * pbProps_->pb_F_.x() / pbProps_->pbTransStiff_.x();
961 if (pbProps_->pb_ks_) {
962 DVect tmp = pbProps_->pb_F_;
963 tmp.rx() = 0.0;
964 double smag2 = tmp.mag2();
965 ret += 0.5 * smag2 / pbProps_->pbTransStiff_.y();
966 }
967
968#ifdef THREED
969 if (pbProps_->pbAngStiff_.x())
970 ret += 0.5 * pbProps_->pb_M_.x() * pbProps_->pb_M_.x() / pbProps_->pbAngStiff_.x();
971#endif
972 if (pbProps_->pbAngStiff_.z()) {
973 DAVect tmp = pbProps_->pb_M_;
974#ifdef THREED
975 tmp.rx() = 0.0;
976 double smag2 = tmp.mag2();
977#else
978 double smag2 = tmp.z() * tmp.z();
979#endif
980 ret += 0.5 * smag2 / pbProps_->pbAngStiff_.z();
981 }
982 return ret;
983 }
984
985 bool ContactModelLinearPBond::forceDisplacementLaw(ContactModelMechanicalState *state,const double ×tep) {
986 assert(state);
987
988 double overlap = rgap_ - state->gap_;
989 DVect trans = state->relativeTranslationalIncrement_;
990 double correction = 1.0;
991
992 if (state->activated()) {
993 if (cmEvents_[fActivated] >= 0) {
994 auto c = state->getContact();
995 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()) };
996 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
997 fi->setCMFishCallArguments(c,arg,cmEvents_[fActivated]);
998 }
999 if (lin_mode_ == 0 && trans.x()) {
1000 correction = -1.0*overlap / trans.x();
1001 if (correction < 0)
1002 correction = 1.0;
1003 }
1004 }
1005
1006#ifdef THREED
1007 DVect norm(trans.x(),0.0,0.0);
1008#else
1009 DVect norm(trans.x(),0.0);
1010#endif
1011 DAVect ang = state->relativeAngularIncrement_;
1012 DVect ss_F_old = lin_F_;
1013
1014 if (lin_mode_==0)
1015 lin_F_.rx() = overlap * kn_;
1016 else
1017 lin_F_.rx() -= correction * norm.x() * kn_;
1018 lin_F_.rx() = std::max(0.0,lin_F_.x());
1019
1020 DVect u_s = trans;
1021 u_s.rx() = 0.0;
1022 DVect sforce = lin_F_ - u_s * ks_ * correction;
1023 sforce.rx() = 0.0;
1024 // Make sure that the shear force opposses the direction of translation - otherwise you can
1025 // have strange behavior
1026 //for (int j=1; j<dim; ++j)
1027 //{
1028 // qDebug()<<sforce.dof(j)<<trans.dof(j);
1029 // if (sign<double>(1,sforce.dof(j)) == sign<double>(1,trans.dof(j)))
1030 // sforce.rdof(j) = 0.0;
1031 //}
1032
1033 // Resolve sliding
1034 if (state->canFail_) {
1035 double crit = lin_F_.x() * fric_;
1036 double sfmag = sforce.mag();
1037 if (sfmag > crit) {
1038 double rat = crit / sfmag;
1039 sforce *= rat;
1040 if (!lin_S_ && cmEvents_[fSlipChange] >= 0) {
1041 auto c = state->getContact();
1042 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
1043 fish::Parameter() };
1044 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
1045 fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
1046 }
1047 lin_S_ = true;
1048 } else {
1049 if (lin_S_) {
1050 if (cmEvents_[fSlipChange] >= 0) {
1051 auto c = state->getContact();
1052 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
1053 fish::Parameter((qint64)1) };
1054 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
1055 fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
1056 }
1057 lin_S_ = false;
1058 }
1059 }
1060 }
1061
1062 sforce.rx() = lin_F_.x();
1063 lin_F_ = sforce; // total force in linear contact model
1064
1065 // Account for dashpot forces
1066 if (dpProps_) {
1067 dpProps_->dp_F_.fill(0.0);
1068 double vcn(0.0), vcs(0.0);
1069 setDampCoefficients(state->inertialMass_,&vcn,&vcs);
1070 // Need to change behavior based on the dp_mode
1071 if (dpProps_->dp_mode_ == 0) { // Damp all components
1072 dpProps_->dp_F_ = u_s * (-1.0* vcs) / timestep; // shear component
1073 dpProps_->dp_F_ -= norm * vcn / timestep; // normal component
1074 } else if (dpProps_->dp_mode_ == 1) { // limit the tensile
1075 dpProps_->dp_F_ -= norm * vcn / timestep; // normal component
1076 if (dpProps_->dp_F_.x() + lin_F_.x() < 0)
1077 dpProps_->dp_F_.rx() = - lin_F_.rx();
1078 } else if (dpProps_->dp_mode_ == 2) { // limit the shear
1079 if (!lin_S_)
1080 dpProps_->dp_F_ = u_s * (-1.0* vcs) / timestep; // shear component
1081 } else {
1082 if (!lin_S_)
1083 dpProps_->dp_F_ = u_s * (-1.0* vcs) / timestep; // shear component
1084 dpProps_->dp_F_ -= norm * vcn / timestep; // normal component
1085 if (dpProps_->dp_F_.x() + lin_F_.x() < 0)
1086 dpProps_->dp_F_.rx() = - lin_F_.rx();
1087 }
1088 }
1089
1090 // Account for parallel bonds
1091 bool doPb = false;
1092 if (pbProps_ && pbProps_->pb_state_ > 2) {
1093 doPb = true;
1094 // Parallel Bond Logic:
1095 // bond area and inertia
1096 // minimal curvature of end1
1097 double Cmin1 = state->end1Curvature_.x();
1098 double Cmax1 = state->end1Curvature_.y();
1099 double Cmax2 = state->end2Curvature_.y();
1100 double dthick = (Cmin1 == 0.0) ? 1.0 : 0.0;
1101 double br = pbProps_->pb_rmul_ * 1.0 / std::max(Cmax1,Cmax2);
1102 if (userArea_)
1103#ifdef THREED
1104 br = std::sqrt(userArea_ / dPi);
1105#else
1106 br = userArea_ / 2.0;
1107#endif
1108 double br2 = br*br;
1109 double pbArea = dthick <= 0.0 ? dPi*br2 : 2.0*br*dthick;
1110 double bi = dthick <= 0.0 ? 0.25*pbArea*br2 : 2.0*br*br2*dthick/3.0;
1111 pbProps_->pbTransStiff_.rx() = pbProps_->pb_kn_*pbArea;
1112 pbProps_->pbTransStiff_.ry() = pbProps_->pb_ks_*pbArea;
1113
1114 /* elastic force increments */
1115 pbProps_->pb_F_ -= norm *(pbProps_->pb_kn_*pbArea) + u_s * (pbProps_->pb_ks_*pbArea);
1116
1117 /* elastic moment increments */
1118 //DAVect pbMomentInc(0.0);
1119#if DIM==3
1120 pbProps_->pbAngStiff_.rx() = pbProps_->pb_ks_* 2.0 * bi;
1121 pbProps_->pbAngStiff_.ry() = pbProps_->pb_kn_* bi;
1122#endif
1123 pbProps_->pbAngStiff_.rz() = pbProps_->pb_kn_* bi;
1124
1125 DAVect pbMomentInc = ang * pbProps_->pbAngStiff_ *(-1.0);
1126 pbProps_->pb_M_ += pbMomentInc;
1127
1128 /* check bond failure */
1129 if (state->canFail_) {
1130 /* maximum stresses */
1131 double dbend = sqrt(pbProps_->pb_M_.y()*pbProps_->pb_M_.y() + pbProps_->pb_M_.z()*pbProps_->pb_M_.z());
1132 double dtwist = pbProps_->pb_M_.x();
1133 DVect bfs(pbProps_->pb_F_);
1134 bfs.rx() = 0.0;
1135 double dbfs = bfs.mag();
1136 double nsmax = -(pbProps_->pb_F_.x() / pbArea) + pbProps_->pb_mcf_ * dbend * br/bi;
1137 double ssmax = dbfs / pbArea + pbProps_->pb_mcf_ * std::abs(dtwist) * 0.5* br/bi;
1138 double ss ;
1139
1140 if (nsmax >= pbProps_->pb_ten_) {
1141 // Failed in tension
1142 double se = pbStrainEnergy(); // bond strain energy at the onset of failure
1143 pbProps_->pb_state_ = 1;
1144 pbProps_->pb_F_.fill(0.0);
1145 pbProps_->pb_M_.fill(0.0);
1146 if (cmEvents_[fBondBreak] >= 0) {
1147 auto c = state->getContact();
1148 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
1149 fish::Parameter((qint64)pbProps_->pb_state_),
1150 fish::Parameter(pbProps_->pb_ten_),
1151 fish::Parameter(se) };
1152 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
1153 fi->setCMFishCallArguments(c,arg,cmEvents_[fBondBreak]);
1154 }
1155 } else if ((ss = pbShearStrength(pbArea)) <= ssmax) {
1156 // Failed in shear
1157 double se = pbStrainEnergy(); // bond strain energy at the onset of failure
1158 pbProps_->pb_state_ = 2;
1159 pbProps_->pb_F_.fill(0.0);
1160 pbProps_->pb_M_.fill(0.0);
1161 if (cmEvents_[fBondBreak] >= 0) {
1162 auto c = state->getContact();
1163 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
1164 fish::Parameter((qint64)pbProps_->pb_state_),
1165 fish::Parameter(ss),
1166 fish::Parameter(se) };
1167 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
1168 fi->setCMFishCallArguments(c,arg,cmEvents_[fBondBreak]);
1169 }
1170 }
1171 }
1172 }
1173
1174 // Compute energies
1175 if (state->trackEnergy_) {
1176 assert(energies_);
1177 energies_->estrain_ = 0.0;
1178 energies_->epbstrain_ = 0.0;
1179 if (kn_)
1180 energies_->estrain_ = 0.5 * lin_F_.x()* lin_F_.x() /kn_;
1181 if (ks_) {
1182 DVect s = lin_F_;
1183 s.rx() = 0.0;
1184 double smag2 = s.mag2();
1185 energies_->estrain_ += 0.5* smag2 / ks_ ;
1186
1187 if (lin_S_) {
1188 ss_F_old.rx() = 0.0;
1189 DVect avg_F_s = (s + ss_F_old)*0.5;
1190 DVect u_s_el = (s - ss_F_old) / ks_;
1191 energies_->eslip_ -= std::min(0.0,(avg_F_s | (u_s + u_s_el)));
1192 }
1193 }
1194 if (dpProps_)
1195 energies_->edashpot_ -= dpProps_->dp_F_ | trans;
1196 if (doPb)
1197 energies_->epbstrain_ = pbStrainEnergy();
1198 }
1199
1200 assert(lin_F_ == lin_F_);
1201 return checkActivity(state->gap_);
1202 }
1203
1204 bool ContactModelLinearPBond::thermalCoupling(ContactModelMechanicalState *ms,ContactModelThermalState *ts, IContactThermal *ct,const double &) {
1205 // Account for thermal expansion in linear group in incremental mode
1206 bool ret = false;
1207 if (lin_mode_ > 0 && ts->gapInc_ > 0.0) {
1208 DVect finc(0.0);
1209 finc.rx() = kn_ * ts->gapInc_;
1210 lin_F_ -= finc;
1211 ret = true;
1212 }
1213
1214 if (!pbProps_) return ret;
1215 if (pbProps_->pb_state_ < 3) return ret;
1216 int idx = ct->getModel()->getContactModel()->isProperty("thexp");
1217 if (idx<=0 ) return ret;
1218
1219 double thexp = (ct->getModel()->getContactModel()->getProperty(idx)).toDouble();
1220 double length = ts->length_;
1221 double delTemp =ts->tempInc_;
1222 double delUn = length * thexp * delTemp;
1223 if (delUn == 0.0) return ret;
1224
1225 double dthick = 0.0;
1226 double Cmin1 = ms->end1Curvature_.x();
1227 double Cmax1 = ms->end1Curvature_.y();
1228 double Cmin2 = ms->end2Curvature_.x();
1229 double Cmax2 = ms->end2Curvature_.y();
1230
1231 Cmin2;
1232 if (Cmin1 == 0.0)
1233 dthick = 1.0;
1234
1235 double br = pbProps_->pb_rmul_ * 1.0 / std::max(Cmax1,Cmax2);
1236 if (userArea_)
1237#ifdef THREED
1238 br = std::sqrt(userArea_ / dPi);
1239#else
1240 br = userArea_ / 2.0;
1241#endif
1242 double br2 = br*br;
1243 double pbArea = dthick <= 0.0 ? dPi*br2 : 2.0*br*dthick;
1244 //
1245 DVect finc(0.0);
1246 finc.rx() = pbProps_->pb_kn_ * pbArea * delUn;
1247 pbProps_->pb_F_ += finc;
1248
1249 ret = true;
1250 return ret;
1251 }
1252
1253 void ContactModelLinearPBond::setForce(const DVect &v,IContact *c) {
1254 lin_F(v);
1255 if (v.x() > 0)
1256 rgap_ = c->getGap() + v.x() / kn_;
1257 }
1258
1259 void ContactModelLinearPBond::propagateStateInformation(IContactModelMechanical* old,const CAxes &oldSystem,const CAxes &newSystem) {
1260 // Only do something if the contact model is of the same type
1261 if (old->getContactModel()->getName().compare("linearpbond",Qt::CaseInsensitive) == 0 && !isBonded()) {
1262 ContactModelLinearPBond *oldCm = (ContactModelLinearPBond *)old;
1263#ifdef THREED
1264 // Need to rotate just the shear component from oldSystem to newSystem
1265
1266 // Step 1 - rotate oldSystem so that the normal is the same as the normal of newSystem
1267 DVect axis = oldSystem.e1() & newSystem.e1();
1268 double c, ang, s;
1269 DVect re2;
1270 if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
1271 axis = axis.unit();
1272 c = oldSystem.e1()|newSystem.e1();
1273 if (c > 0)
1274 c = std::min(c,1.0);
1275 else
1276 c = std::max(c,-1.0);
1277 ang = acos(c);
1278 s = sin(ang);
1279 double t = 1. - c;
1280 DMatrix<3,3> rm;
1281 rm.get(0,0) = t*axis.x()*axis.x() + c;
1282 rm.get(0,1) = t*axis.x()*axis.y() - axis.z()*s;
1283 rm.get(0,2) = t*axis.x()*axis.z() + axis.y()*s;
1284 rm.get(1,0) = t*axis.x()*axis.y() + axis.z()*s;
1285 rm.get(1,1) = t*axis.y()*axis.y() + c;
1286 rm.get(1,2) = t*axis.y()*axis.z() - axis.x()*s;
1287 rm.get(2,0) = t*axis.x()*axis.z() - axis.y()*s;
1288 rm.get(2,1) = t*axis.y()*axis.z() + axis.x()*s;
1289 rm.get(2,2) = t*axis.z()*axis.z() + c;
1290 re2 = rm*oldSystem.e2();
1291 }
1292 else
1293 re2 = oldSystem.e2();
1294 // Step 2 - get the angle between the oldSystem rotated shear and newSystem shear
1295 axis = re2 & newSystem.e2();
1296 DVect2 tpf;
1297 DMatrix<2,2> m;
1298 if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
1299 axis = axis.unit();
1300 c = re2|newSystem.e2();
1301 if (c > 0)
1302 c = std::min(c,1.0);
1303 else
1304 c = std::max(c,-1.0);
1305 ang = acos(c);
1306 if (!checktol(axis.x(),newSystem.e1().x(),1.0,100))
1307 ang *= -1;
1308 s = sin(ang);
1309 m.get(0,0) = c;
1310 m.get(1,0) = s;
1311 m.get(0,1) = -m.get(1,0);
1312 m.get(1,1) = m.get(0,0);
1313 tpf = m*DVect2(oldCm->lin_F_.y(),oldCm->lin_F_.z());
1314 } else {
1315 m.get(0,0) = 1.;
1316 m.get(0,1) = 0.;
1317 m.get(1,0) = 0.;
1318 m.get(1,1) = 1.;
1319 tpf = DVect2(oldCm->lin_F_.y(),oldCm->lin_F_.z());
1320 }
1321 DVect pforce = DVect(0,tpf.x(),tpf.y());
1322#else
1323 oldSystem;
1324 newSystem;
1325 DVect pforce = DVect(0,oldCm->lin_F_.y());
1326#endif
1327 for (int i=1; i<dim; ++i)
1328 lin_F_.rdof(i) += pforce.dof(i);
1329 if (lin_mode_ && oldCm->lin_mode_)
1330 lin_F_.rx() = oldCm->lin_F_.x();
1331 oldCm->lin_F_ = DVect(0.0);
1332 if (dpProps_ && oldCm->dpProps_) {
1333#ifdef THREED
1334 tpf = m*DVect2(oldCm->dpProps_->dp_F_.y(),oldCm->dpProps_->dp_F_.z());
1335 pforce = DVect(oldCm->dpProps_->dp_F_.x(),tpf.x(),tpf.y());
1336#else
1337 pforce = oldCm->dpProps_->dp_F_;
1338#endif
1339 dpProps_->dp_F_ += pforce;
1340 oldCm->dpProps_->dp_F_ = DVect(0.0);
1341 }
1342 if(oldCm->getEnergyActivated()) {
1343 activateEnergy();
1344 energies_->estrain_ = oldCm->energies_->estrain_;
1345 energies_->eslip_ = oldCm->energies_->eslip_;
1346 energies_->edashpot_ = oldCm->energies_->edashpot_;
1347 energies_->epbstrain_ = oldCm->energies_->epbstrain_;
1348 oldCm->energies_->estrain_ = 0.0;
1349 oldCm->energies_->edashpot_ = 0.0;
1350 oldCm->energies_->eslip_ = 0.0;
1351 oldCm->energies_->epbstrain_ = 0.0;
1352 }
1353 rgap_ = oldCm->rgap_;
1354 }
1355 assert(lin_F_ == lin_F_);
1356 }
1357
1358 void ContactModelLinearPBond::setNonForcePropsFrom(IContactModel *old) {
1359 // Only do something if the contact model is of the same type
1360 if (old->getName().compare("linearpbond",Qt::CaseInsensitive) == 0 && !isBonded()) {
1361 ContactModelLinearPBond *oldCm = (ContactModelLinearPBond *)old;
1362 kn_ = oldCm->kn_;
1363 ks_ = oldCm->ks_;
1364 fric_ = oldCm->fric_;
1365 lin_mode_ = oldCm->lin_mode_;
1366 rgap_ = oldCm->rgap_;
1367 userArea_ = oldCm->userArea_;
1368
1369 if (oldCm->dpProps_) {
1370 if (!dpProps_)
1371 dpProps_ = NEW dpProps();
1372 dpProps_->dp_nratio_ = oldCm->dpProps_->dp_nratio_;
1373 dpProps_->dp_sratio_ = oldCm->dpProps_->dp_sratio_;
1374 dpProps_->dp_mode_ = oldCm->dpProps_->dp_mode_;
1375 }
1376
1377 if (oldCm->pbProps_) {
1378 if (!pbProps_)
1379 pbProps_ = NEW pbProps();
1380 pbProps_->pb_rmul_ = oldCm->pbProps_->pb_rmul_;
1381 pbProps_->pb_kn_ = oldCm->pbProps_->pb_kn_;
1382 pbProps_->pb_ks_ = oldCm->pbProps_->pb_ks_;
1383 pbProps_->pb_mcf_ = oldCm->pbProps_->pb_mcf_;
1384 pbProps_->pb_fa_ = oldCm->pbProps_->pb_fa_;
1385 pbProps_->pb_state_ = oldCm->pbProps_->pb_state_;
1386 pbProps_->pb_coh_ = oldCm->pbProps_->pb_coh_;
1387 pbProps_->pb_ten_ = oldCm->pbProps_->pb_ten_;
1388 pbProps_->pbTransStiff_ = oldCm->pbProps_->pbTransStiff_;
1389 pbProps_->pbAngStiff_ = oldCm->pbProps_->pbAngStiff_;
1390 }
1391 }
1392 }
1393
1394 DVect ContactModelLinearPBond::getForce() const {
1395 DVect ret(lin_F_);
1396 if (dpProps_)
1397 ret += dpProps_->dp_F_;
1398 if (pbProps_)
1399 ret += pbProps_->pb_F_;
1400 return ret;
1401 }
1402
1403 DAVect ContactModelLinearPBond::getMomentOn1(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->updateResultingTorqueOn1Local(force,&ret);
1410 }
1411 return ret;
1412 }
1413
1414 DAVect ContactModelLinearPBond::getMomentOn2(const IContactMechanical *c) const {
1415 DAVect ret(0.0);
1416 if (pbProps_)
1417 ret = pbProps_->pb_M_;
1418 if (c) {
1419 DVect force = getForce();
1420 c->updateResultingTorqueOn2Local(force,&ret);
1421 }
1422 return ret;
1423 }
1424
1425 DAVect ContactModelLinearPBond::getModelMomentOn1() const {
1426 DAVect ret(0.0);
1427 if (pbProps_)
1428 ret = pbProps_->pb_M_;
1429 return ret;
1430 }
1431
1432 DAVect ContactModelLinearPBond::getModelMomentOn2() const {
1433 DAVect ret(0.0);
1434 if (pbProps_)
1435 ret = pbProps_->pb_M_;
1436 return ret;
1437 }
1438
1439 void ContactModelLinearPBond::objectPropsTypes(std::vector<std::pair<QString,InfoTypes>> *ret) const {
1440 ret->clear();
1441 ret->push_back({"kn",ScalarInfo});
1442 ret->push_back({"ks",ScalarInfo});
1443 ret->push_back({"fric",ScalarInfo});
1444 ret->push_back({"lin_force",VectorInfo});
1445 ret->push_back({"lin_slip",ScalarInfo});
1446 ret->push_back({"lin_mode",ScalarInfo});
1447 ret->push_back({"rgap",ScalarInfo});
1448 ret->push_back({"emod",ScalarInfo});
1449 ret->push_back({"kratio",ScalarInfo});
1450 ret->push_back({"dp_nratio",ScalarInfo});
1451 ret->push_back({"dp_sratio",ScalarInfo});
1452 ret->push_back({"dp_mode",ScalarInfo});
1453 ret->push_back({"dp_force",VectorInfo});
1454 ret->push_back({"pb_state",ScalarInfo});
1455 ret->push_back({"pb_rmul",ScalarInfo});
1456 ret->push_back({"pb_kn",ScalarInfo});
1457 ret->push_back({"pb_ks",ScalarInfo});
1458 ret->push_back({"pb_mcf",ScalarInfo});
1459 ret->push_back({"pb_ten",ScalarInfo});
1460 ret->push_back({"pb_shear",ScalarInfo});
1461 ret->push_back({"pb_coh",ScalarInfo});
1462 ret->push_back({"pb_fa",ScalarInfo});
1463 ret->push_back({"pb_sigma",ScalarInfo});
1464 ret->push_back({"pb_tau",ScalarInfo});
1465 ret->push_back({"pb_force",VectorInfo});
1466 ret->push_back({"pb_moment",VectorInfo});
1467 ret->push_back({"pb_radius",ScalarInfo});
1468 ret->push_back({"pb_emod",ScalarInfo});
1469 ret->push_back({"pb_kratio",ScalarInfo});
1470 ret->push_back({"user_area",ScalarInfo});
1471 }
1472
1473 void ContactModelLinearPBond::objectPropValues(std::vector<double> *ret,const IContact *con) const {
1474 ret->clear();
1475 ret->push_back(kn());
1476 ret->push_back(ks());
1477 ret->push_back(fric());
1478 ret->push_back(lin_F().mag());
1479 ret->push_back(lin_S());
1480 ret->push_back(lin_mode());
1481 ret->push_back(rgap());
1482 double d;
1483 const IContactMechanical *c(convert_getcast<IContactMechanical>(con));
1484 double rsq(std::max(c->getEnd1Curvature().y(),c->getEnd2Curvature().y()));
1485 double rsum(0.0);
1486 if (c->getEnd1Curvature().y())
1487 rsum += 1.0/c->getEnd1Curvature().y();
1488 if (c->getEnd2Curvature().y())
1489 rsum += 1.0/c->getEnd2Curvature().y();
1490 if (userArea_) {
1491#ifdef THREED
1492 rsq = std::sqrt(userArea_ / dPi);
1493#else
1494 rsq = userArea_ / 2.0;
1495#endif
1496 rsum = rsq + rsq;
1497 rsq = 1. / rsq;
1498 }
1499#ifdef TWOD
1500 d = (kn_ * rsum * rsq / 2.0);
1501#else
1502 d = (kn_ * rsum * rsq * rsq) / dPi;
1503#endif
1504 ret->push_back(d);
1505 ret->push_back((ks_ == 0.0) ? 0.0 : (kn_/ks_));
1506 ret->push_back(dp_nratio());
1507 ret->push_back(dp_sratio());
1508 ret->push_back(dp_mode());
1509 ret->push_back(dp_F().mag());
1510 ret->push_back(pbProps_ ? pbProps_->pb_state_ : 0);
1511 ret->push_back(pbProps_ ? pbProps_->pb_rmul_ : 1);
1512 ret->push_back(pbProps_ ? pbProps_->pb_kn_ : 0);
1513 ret->push_back(pbProps_ ? pbProps_->pb_ks_ : 0);
1514 ret->push_back(pbProps_ ? pbProps_->pb_mcf_ : 1);
1515 ret->push_back(pbProps_ ? pbProps_->pb_ten_ : 0);
1516 if (!pbProps_) d = 0; else d = pbShearStrength(pbData(c).x());
1517 ret->push_back(d);
1518 ret->push_back(pbProps_ ? pbProps_->pb_coh_ : 0);
1519 ret->push_back(pbProps_ ? pbProps_->pb_fa_ : 0);
1520 if (!pbProps_ || pbProps_->pb_state_ < 3) d =0.0; else pbSMax(c).x();
1521 ret->push_back(d);
1522 if (!pbProps_ || pbProps_->pb_state_ < 3) d =0.0; else pbSMax(c).y();
1523 ret->push_back(d);
1524 ret->push_back(pbProps_ ? (pbProps_->pb_F_).mag() : 0);
1525 ret->push_back(pbProps_ ? (pbProps_->pb_M_).mag() : 0);
1526 d = 0;
1527 if (pbProps_) {
1528 double Cmax1 = c->getEnd1Curvature().y();
1529 double Cmax2 = c->getEnd2Curvature().y();
1530 double br = pbProps_->pb_rmul_ * 1.0 / std::max(Cmax1,Cmax2);
1531 if (userArea_)
1532#ifdef THREED
1533 d = std::sqrt(userArea_ / dPi);
1534#else
1535 d = userArea_ / 2.0;
1536#endif
1537 }
1538 ret->push_back(d);
1539 d = 0;
1540 if (c->getEnd1Curvature().y())
1541 rsum += 1.0/c->getEnd1Curvature().y();
1542 if (c->getEnd2Curvature().y())
1543 rsum += 1.0/c->getEnd2Curvature().y();
1544 if (userArea_) {
1545#ifdef THREED
1546 double rad = std::sqrt(userArea_ / dPi);
1547#else
1548 double rad = userArea_ / 2.0;
1549#endif
1550 rsum = 2 * rad;
1551 }
1552 d = pbProps_ ? pbProps_->pb_kn_ * rsum : 0;
1553 ret->push_back(d);
1554 d = 0;
1555 if (pbProps_) d = (pbProps_->pb_ks_ == 0.0) ? 0.0 : (pbProps_->pb_kn_/pbProps_->pb_ks_);
1556 ret->push_back(d);
1557 ret->push_back(userArea_);
1558 }
1559
1560 DVect3 ContactModelLinearPBond::pbData(const IContactMechanical *c) const {
1561 double Cmax1 = c->getEnd1Curvature().y();
1562 double Cmax2 = c->getEnd2Curvature().y();
1563 double br = pbProps_->pb_rmul_ * 1.0 / std::max(Cmax1,Cmax2);
1564 if (userArea_)
1565#ifdef THREED
1566 br = std::sqrt(userArea_ / dPi);
1567#else
1568 br = userArea_ / 2.0;
1569#endif
1570 double br2 = br*br;
1571#ifdef TWOD
1572 double pbArea = 2.0*br;
1573 double bi = 2.0*br*br2/3.0;
1574#else
1575 double pbArea = dPi*br2;
1576 double bi = 0.25*pbArea*br2;
1577#endif
1578 return DVect3(pbArea,bi,br);
1579 }
1580
1581 DVect2 ContactModelLinearPBond::pbSMax(const IContactMechanical *c) const {
1582 DVect3 data = pbData(c);
1583 double pbArea = data.x();
1584 double bi = data.y();
1585 double br = data.z();
1586 /* maximum stresses */
1587 double dbend = sqrt(pbProps_->pb_M_.y()*pbProps_->pb_M_.y() + pbProps_->pb_M_.z()*pbProps_->pb_M_.z());
1588 double dtwist = pbProps_->pb_M_.x();
1589 DVect bfs(pbProps_->pb_F_);
1590 bfs.rx() = 0.0;
1591 double dbfs = bfs.mag();
1592 double nsmax = -(pbProps_->pb_F_.x() / pbArea) + pbProps_->pb_mcf_ * dbend * br/bi;
1593 double ssmax = dbfs / pbArea + pbProps_->pb_mcf_ * std::abs(dtwist) * 0.5* br/bi;
1594 return DVect2(nsmax,ssmax);
1595 }
1596
1597 double ContactModelLinearPBond::pbShearStrength(const double &pbArea) const {
1598 if (!pbProps_) return 0.0;
1599 double sig = -1.0*pbProps_->pb_F_.x() / pbArea;
1600 double nstr = pbProps_->pb_state_ > 2 ? pbProps_->pb_ten_ : 0.0;
1601 return sig <= nstr ? pbProps_->pb_coh_ - std::tan(dDegrad*pbProps_->pb_fa_)*sig
1602 : pbProps_->pb_coh_ - std::tan(dDegrad*pbProps_->pb_fa_)*nstr;
1603 }
1604
1605 void ContactModelLinearPBond::setDampCoefficients(const double &mass,double *vcn,double *vcs) {
1606 *vcn = dpProps_->dp_nratio_ * 2.0 * sqrt(mass*(kn_));
1607 *vcs = dpProps_->dp_sratio_ * 2.0 * sqrt(mass*(ks_));
1608 }
1609
1610} // namespace itascaxd
1611// EoF
Was this helpful? ... | Itasca Software © 2024, Itasca | Updated: Dec 19, 2024 |