Flat-Joint Model Implementation
See this page for the documentation of this contact model.
contactmodelflatjoint.h
1#pragma once
2// contactmodelflatjoint.h
3
4#include "contactmodel/src/contactmodelmechanical.h"
5
6#ifdef FLATJOINT_LIB
7# define FLATJOINT_EXPORT EXPORT_TAG
8#elif defined(NO_MODEL_IMPORT)
9# define FLATJOINT_EXPORT
10#else
11# define FLATJOINT_EXPORT IMPORT_TAG
12#endif
13
14namespace cmodelsxd {
15 using namespace itasca;
16
17 class ContactModelFlatJoint : public ContactModelMechanical {
18 public:
19 enum PropertyKeys {
20 kwFjNr=1
21 , kwFjElem
22 , kwFjKn
23 , kwFjKs
24 , kwFjFric
25 , kwFjEmod
26 , kwFjKRatio
27 , kwFjRmul
28 , kwFjRadius
29 , kwFjGap0
30 , kwFjTen
31 , kwFjCoh
32 , kwFjFa
33 , kwFjF
34 , kwFjM
35 , kwFjState
36 , kwFjSlip
37 , kwFjMType
38 , kwFjA
39 , kwFjEgap
40 , kwFjGap
41 , kwFjNstr
42 , kwFjSstr
43 , kwFjSs
44#ifdef THREED
45 , kwFjNa
46#endif
47 , kwFjRelBr
48 , kwFjCen
49 , kwFjTrack
50 , kwUserArea
51 , kwFjCohRes
52 , kwFjResMode
53 };
54
55 FLATJOINT_EXPORT ContactModelFlatJoint();
56 FLATJOINT_EXPORT ContactModelFlatJoint(const ContactModelFlatJoint &) noexcept;
57 FLATJOINT_EXPORT const ContactModelFlatJoint & operator=(const ContactModelFlatJoint &);
58 FLATJOINT_EXPORT void addToStorage(poly::vector<ContactModelMechanical> *s,int ww = -1) override;
59 FLATJOINT_EXPORT virtual ~ContactModelFlatJoint();
60 void copy(const ContactModel *c) override;
61 void archive(ArchiveStream &) override;
62 string getName() const override { return "flatjoint"; }
63 void setIndex(int i) override { index_=i;}
64 int getIndex() const override {return index_;}
65 string getProperties() const override { return "fj_nr"
66 ",fj_elem"
67 ",fj_kn"
68 ",fj_ks"
69 ",fj_fric"
70 ",fj_emod"
71 ",fj_kratio"
72 ",fj_rmul"
73 ",fj_radius"
74 ",fj_gap0"
75 ",fj_ten"
76 ",fj_coh"
77 ",fj_fa"
78 ",fj_force"
79 ",fj_moment"
80 ",fj_state"
81 ",fj_slip"
82 ",fj_mtype"
83 ",fj_area"
84 ",fj_egap"
85 ",fj_gap"
86 ",fj_sigma"
87 ",fj_tau"
88 ",fj_shear"
89#ifdef THREED
90 ",fj_nal"
91#endif
92 ",fj_relbr"
93 ",fj_cen"
94 ",fj_track"
95 ",user_area"
96 ",fj_cohres"
97 ",fj_resmode"
98 ;}
99
100 enum EnergyKeys { kwEStrain=1,kwESlip};
101 string getEnergies() const { return "energy-strain,energy-slip";}
102 double getEnergy(uint32 i) const override; // Base 1
103 bool getEnergyAccumulate(uint32 i) const override; // Base 1
104 void setEnergy(uint32 i,const double &d) override; // Base 1
105 void activateEnergy() override { if (energies_) return; energies_ = NEW Energies();}
106 bool getEnergyActivated() const override {return (energies_ !=0);}
107
108 enum FishCallEvents {fActivated=0,fBondBreak,fBroken,fSlipChange};
109 string getFishCallEvents() const override { return "contact_activated,bond_break,broken,all_slip_change"; }
110 base::Property getProperty(uint32 i,const IContact *) const override;
111 bool getPropertyGlobal(uint32 i) const override;
112 bool setProperty(uint32 i,const base::Property &v,IContact *) override;
113 bool getPropertyReadOnly(uint32 i) const override;
114
115 bool supportsInheritance(uint32 ) const override { return false; }
116
117 enum MethodKeys { kwBond=1, kwUnbond, KwDeformability, KwUpdateGeom, kwArea, kwInitialize};
118
119 string getMethods() const override { return "bond"
120 ",unbond"
121 ",deformability"
122 ",update_geometry"
123 ",area"
124 ",initialize"
125 ;}
126
127 string getMethodArguments(uint32 i) const override;
128
129 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
130
131 uint32 getMinorVersion() const override;
132
133 bool validate(ContactModelMechanicalState *state,const double ×tep) override;
134 bool endPropertyUpdated(const string &,const IContactMechanical *) override { return false; }
135 bool forceDisplacementLaw(ContactModelMechanicalState *state,const double ×tep) override;
136 bool thermalCoupling(ContactModelMechanicalState*, ContactModelThermalState*, IContactThermal*, const double&) override;
137 DVect2 getEffectiveTranslationalStiffness() const override { return effectiveTranslationalStiffness(); }
138 DAVect getEffectiveRotationalStiffness() const override { return effectiveRotationalStiffness(); }
139
140 ContactModelFlatJoint *clone() const override { return NEW ContactModelFlatJoint(); }
141 double getActivityDistance() const override {return 0.0;}
142 bool isOKToDelete() const override { return !isBonded(); }
143 void resetForcesAndMoments() override { fj_f(DVect(0.0)); fj_m(DAVect(0.0)); for (int i=0; i<f_.size(); ++i) f_[i] = DVect(0.0); }
144 void setForce(const DVect &v,IContact *) override;
145 void setArea(const double &d) override { userArea_ = d; }
146 double getArea() const override { return userArea_; }
147 bool checkActivity(const double &inGap) override;
148
149 /// Return the total force that the contact model holds.
150 DVect getForce() const override;
151 /// Return the total moment on 1 that the contact model holds
152 DAVect getMomentOn1(const IContactMechanical*) const override;
153 /// Return the total moment on 1 that the contact model holds
154 DAVect getMomentOn2(const IContactMechanical*) const override;
155
156 DAVect getModelMomentOn1() const override;
157 DAVect getModelMomentOn2() const override;
158
159 // Used to efficiently get properties from the contact model for the object pane.
160 // List of properties for the object pane, comma separated.
161 // All properties will be cast to doubles for comparison. No other comparisons
162 // are supported. This may not be the same as the entire property list.
163 // Return property name and type for plotting.
164 void objectPropsTypes(std::vector<std::pair<string,InfoTypes>> *) const override;
165 // All properties cast to doubles - this is what can be compared.
166 void objectPropValues(std::vector<double> *,const IContact *) const override;
167
168 //virtual bool isSliding() const { return fj_s_; }
169 bool isBonded() const override { FOR(it,bmode_) if ((*it) == 3) return true; return false; }
170 void unbond() override { FOR(it,bmode_) *it = 0; }
171
172 // For contact specific plotting
173 void getSphereList(const IContact* con, std::vector<DVect>* pos, std::vector<double>* rad, std::vector<double>* val) override;
174#ifdef THREED
175 void getDiskList(const IContact* con, std::vector<DVect>* pos, std::vector<DVect>* normal, std::vector<double>* radius, std::vector<double>* val) override;
176#endif
177 void getCylinderList(const IContact* con, std::vector<DVect>* bot, std::vector<DVect>* top, std::vector<double>* radlow, std::vector<double>* radhi, std::vector<double>* val) override;
178
179 int fj_nr() const {return fj_nr_;}
180 void fj_nr(int d) { fj_nr_= d;}
181#ifdef THREED
182 int fj_n() const { return fj_na_ * fj_nr_; }
183 int fj_na() const {return fj_na_;}
184 void fj_na(int d) { fj_na_= d;}
185#else
186 int fj_n() const { return fj_nr_; }
187#endif
188 int fj_elem() const {return fj_elem_;}
189 void fj_elem(int d) { fj_elem_= d;}
190 const double & fj_kn() const {return fj_kn_;}
191 void fj_kn(const double &d) { fj_kn_ = d;}
192 const double & fj_ks() const {return fj_ks_;}
193 void fj_ks(const double &d) { fj_ks_ = d;}
194 const double & fj_fric() const {return fj_fric_;}
195 void fj_fric(const double &d) { fj_fric_ = d;}
196 const double & fj_rmul() const {return fj_rmul_;}
197 void fj_rmul(const double &d) { fj_rmul_ = d;}
198 const double & fj_gap0() const {return fj_gap0_;}
199 void fj_gap0(const double &d) { fj_gap0_ = d;}
200 const double & fj_ten() const {return fj_ten_;}
201 void fj_ten(const double &d) { fj_ten_ = d;}
202 const double & fj_coh() const {return fj_coh_;}
203 void fj_coh(const double &d) { fj_coh_ = d;}
204 const double & fj_cohres() const {return fj_cohres_;}
205 void fj_cohres(const double &d) { fj_cohres_ = d;}
206 const double & fj_fa() const {return fj_fa_;}
207 void fj_fa(const double &d) { fj_fa_ = d;}
208 const DVect & fj_f() const {return fj_f_;}
209 void fj_f(const DVect &f) { fj_f_=f;}
210 const DAVect & fj_m() const {return fj_m_;}
211 void fj_m(const DAVect &f) { fj_m_=f;}
212 const DAVect & fj_m_set() const {return fj_m_set_;}
213 void fj_m_set(const DAVect &f) { fj_m_set_=f;}
214 const double & rmin() const {return rmin_;}
215 void rmin(const double &d) { rmin_ = d;}
216 const double & rbar() const {return rbar_;}
217 void rbar(const double &d) { rbar_ = d;}
218 const int & fj_resmode() const {return fj_resmode_;}
219 void fj_resmode(const int &i) { fj_resmode_ = i;}
220 const double & atot() const {return atot_;}
221 void atot(const double &d) { atot_ = d;}
222 bool propsFixed() const {return propsFixed_; }
223 void propsFixed(bool d) { propsFixed_ = d;}
224 int mType() const {return mType_; }
225 void mType(int d) { mType_ = d;}
226 const DVect & gap() const {return gap_; }
227 void gap(const DVect &d) { gap_ = d;}
228 const double & theta() const {return theta_; }
229 void theta(const double & d) { theta_ = d;}
230#ifdef THREED
231 const double & thetaM() const {return thetaM_; }
232 void thetaM(const double & d) { thetaM_ = d;}
233#else
234 double thetaM() const {return 0.0;}
235#endif
236
237 bool hasEnergies() const {return energies_ ? true:false;}
238 double estrain() const {return hasEnergies() ? energies_->estrain_: 0.0;}
239 void estrain(const double &d) { if(!hasEnergies()) return; energies_->estrain_=d;}
240 double eslip() const {return hasEnergies() ? energies_->eslip_: 0.0;}
241 void eslip(const double &d) { if(!hasEnergies()) return; energies_->eslip_=d;}
242
243 uint32 inheritanceField() const {return inheritanceField_;}
244 void inheritanceField(uint32 i) {inheritanceField_ = i;}
245
246 const DVect2 & effectiveTranslationalStiffness() const {return effectiveTranslationalStiffness_;}
247 void effectiveTranslationalStiffness(const DVect2 &v ) {effectiveTranslationalStiffness_=v;}
248 const DAVect & effectiveRotationalStiffness() const {return effectiveRotationalStiffness_;}
249 void effectiveRotationalStiffness(const DAVect &v ) {effectiveRotationalStiffness_=v;}
250
251 private:
252 static int index_;
253
254 struct Energies {
255 Energies() : estrain_(0.0), eslip_(0.0) {}
256 double estrain_; // elastic energy stored in contact
257 double eslip_; // work dissipated by friction
258 };
259
260 void updateEffectiveStiffness(ContactModelMechanicalState *state);
261
262 // inheritance fields
263 uint32 inheritanceField_;
264
265 int fj_nr_ = 2; // radial number of elements >= 1 (total in 2D)
266#ifdef THREED
267 int fj_na_ = 4; // circumferential number of elements >= 3
268#endif
269 int fj_elem_ = 1; // Element to be queried
270 double fj_kn_ = 0.0; // normal stiffness
271 double fj_ks_ = 0.0; // shear stiffness
272 double fj_fric_ = 0.0; // Coulomb friction coefficient
273 double fj_rmul_ = 1.0; // Radius multiplier
274 double fj_gap0_ = 0.0; // Initial gap
275 double fj_ten_ = 0.0; // Tensile strength
276 double fj_coh_ = 0.0; // Cohesive strength
277 double fj_cohres_ = 0.0; // Residual cohesive strength
278 double fj_fa_ = 0.0; // Friction angle
279 DVect fj_f_ = DVect(0.0); // Force carried in the model
280 DAVect fj_m_ = DAVect(0.0); // Moment carried in the model
281 DAVect fj_m_set_ = DAVect(0.0); // When initializing forces then need an extra moment term
282 // Area related quantities
283 double rmin_ = 1.0; // min(Ra,Rb) where Ra & Rb are particle radii
284 double rbar_ = 0.0; // flat-joint radius [m]
285 double atot_ = 0.0; // flat-joint area [m^2]
286 std::vector<double> a_ = std::vector<double>(2); // cross-sectional area of elem[fj_elem-1] [m^2]
287#ifdef THREED
288 std::vector<DVect2> rBarl_= std::vector<DVect2>(2); // centroid relative position of elem[fj_elem-1] [m] (3D)
289#else
290 std::vector<double> rBarl_ = std::vector<double>(2); // centroid relative position of elem[fj_elem-1] [m] (2D)
291#endif
292 int fj_resmode_ = 0; // Residual mode
293 void setAreaQuantities(); // Set Rbar, Atot and A[]
294 DVect getRelElemPos(const IContact*,int ) const; // Return the relative location of element i
295 void setRelElemPos(const IContact*,int ,const DVect &); // Set the relative location of element i
296
297 bool propsFixed_ = false; // {Rmul, N, G, bstate, mType} fixed, cannot reset
298 int mType_ = 3; // initial microstructural type
299 int getmType() const; // {1,2,3,4}={bonded, gapped, slit, other}
300
301 std::vector<int> bmode_ = std::vector<int>(2); // bond mode - 0 unbonded, 1 failed in tension, 2 failed in shear, 3 bonded
302 std::vector<bool> smode_ = std::vector<bool>(2); // slip mode
303 bool Bonded(int e) const { return bmode_[e-1] == 3 ? true : false; }
304
305 // Set bstate and bmode (can only bond if fj_gap0_==0.0)
306 void bondElem(int iSeg,bool bBond);
307 // Set bstate & bmode
308 void breakBond(int iSeg,int fmode,ContactModelMechanicalState *state);
309 void slipChange(int iSeg,bool smode,ContactModelMechanicalState *state);
310
311 // For use in 2D only!
312 double tauC(const double &dSig,bool bBonded) const; // shear strength (positive) [N/m^2]
313
314 // INTERFACE RESPONSE QUANTITIES:
315 DVect gap_ = DVect(0.0); // total relative displacement [m]
316 double theta_ = 0.0; // total relative rotation [rad]
317#ifdef THREED
318 double thetaM_ = 0.0; // total relative rotation [rad]
319 double thbMag() const { return sqrt(std::max(0.0,theta_*theta_ + thetaM_*thetaM_)); }
320 // unit-vector xi of middle surface system xi-eta
321 // (If both thb_l and thb_m are zero, then xi is undefined
322 // and returns zero for both components.)
323 double xi(int comp /* component (l,m) = (1,2) */) const;
324#endif
325 std::vector<double> egap_ = std::vector<double>(2); // gap at centroid of elem[fj_elem-1] [N]
326 std::vector<DVect> f_ = std::vector<DVect>(2); // force on elem[fj_elem-1] [N]
327
328 void initVectors(); // Resize and zero all vector types based on current value of N
329#ifdef TWOD
330 double gap(const double &x) const; // Gap (g>0 is open) along the interface, x in [0, 2*Rbar]
331#else
332 double gap(const double &rl,const double &rm) const; // Gap (g>0 is open) gap at relative position (l,m) [m]
333 double sigBar( int e /* element, e = 1,2,...,Nel */ ) const; // normal stress at centroid of elem[eN-1] [N/m^2]
334 double tauBar( int e /* element, e = 1,2,...,Nel */ ) const; // shear stress at centroid of elem[eN-1] [N/m^2]
335#endif
336 double computeStrainEnergy(int e /* element, e = 1,2,...,Nel */) const; // strain energy in elem[eN-1]
337 // For use in 2D only! Segment normal stress
338 double computeSig(const double &g0, /* gap at left end */
339 const double &g1, /* gap at right end */
340 const double &rbar, /* length is 2*rbar */
341 const double &dA, /* area */
342 bool bBonded /* bond state */
343 ) const;
344 // For use in 2D only! Segment moment
345 double computeM(const double &g0, /* gap at left end */
346 const double &g1, /* gap at right end */
347 const double &rbar, /* length is 2*rbar */
348 bool bBonded /* bond state */
349 ) const;
350 // For use in 2D only! getCase used by ComputeSig and ComputeM
351 int getCase(const double &g0, /* gap at left end */
352 const double &g1 /* gap at right end */
353 ) const;
354 // Segment elastic shear-displacement increment, which is portion of
355 // increment that occurs while gap is negative.
356 double delUse(const double &gapStart, /* gap at start of FDlaw */
357 const double &gapEnd, /* gap at end of FDlaw */
358 bool bBonded, /* bond state */
359 const double &delUs /* shear displ. increment */
360 ) const;
361 double userArea_ = 0.0; // Area as specified by the user
362 Energies * energies_ = nullptr; // energies
363
364 DVect2 effectiveTranslationalStiffness_ = DVect2(0.0);
365 DAVect effectiveRotationalStiffness_ = DAVect(0.0);
366
367 struct orientProps {
368 orientProps() : origNormal_(DVect(0.0)) {}
369 Quat orient1_;
370 Quat orient2_;
371 DVect origNormal_;
372 };
373
374 orientProps *orientProps_ = nullptr;
375 };
376} // namespace itascaxd
377
378
379// EoF
contactmodelflatjoint.cpp
1// contactmodelflatjoint.cpp
2#include "contactmodelflatjoint.h"
3
4#include "../version.txt"
5#include "fish/src/parameter.h"
6//#include "utility/src/tptr.h"
7//#include "shared/src/mathutil.h"
8//#include "baseqt/src/basetoqt.h"
9#include "contactmodel/src/contactmodelthermal.h"
10//#include "contactmodel/src/contactmodelfluid.h"
11
12#include "kernel/interface/iprogram.h"
13#include "module/interface/icontact.h"
14#include "module/interface/icontactmechanical.h"
15#include "module/interface/icontactthermal.h"
16//#include "module/interface/icontactfluid.h"
17#include "module/interface/ifishcalllist.h"
18#include "module/interface/ipiece.h"
19#include "module/interface/ipiecemechanical.h"
20
21#ifdef FLATJOINT_LIB
22#ifdef _WIN32
23 int __stdcall DllMain(void *,unsigned, void *)
24 {
25 return 1;
26 }
27#endif
28
29 extern "C" EXPORT_TAG const char *getName()
30 {
31#if DIM==3
32 return "contactmodelmechanical3dflatjoint";
33#else
34 return "contactmodelmechanical2dflatjoint";
35#endif
36 }
37
38 extern "C" EXPORT_TAG unsigned getMajorVersion()
39 {
40 return MAJOR_VERSION;
41 }
42
43 extern "C" EXPORT_TAG unsigned getMinorVersion()
44 {
45 return MINOR_VERSION;
46 }
47
48 extern "C" EXPORT_TAG void *createInstance()
49 {
50 cmodelsxd::ContactModelFlatJoint *m = NEW cmodelsxd::ContactModelFlatJoint();
51 return (void *)m;
52 }
53#endif // FLATJOINT_LIB
54
55namespace cmodelsxd {
56 static const uint32 fjKnMask = 0x00002; // Base 1!
57 static const uint32 fjKsMask = 0x00004;
58 static const uint32 fjFricMask = 0x00008;
59
60 using namespace itasca;
61
62 int ContactModelFlatJoint::index_ = -1;
63 uint32 ContactModelFlatJoint::getMinorVersion() const { return MINOR_VERSION; ;}
64
65 ContactModelFlatJoint::ContactModelFlatJoint() : inheritanceField_(fjKnMask|fjKsMask|fjFricMask) {
66 initVectors();
67 setAreaQuantities();
68 //setFromParent(ContactModelMechanicalList::instance()->find(getName()));
69 }
70
71 ContactModelFlatJoint::ContactModelFlatJoint(const ContactModelFlatJoint &m) noexcept {
72 inheritanceField(fjKnMask|fjKsMask|fjFricMask);
73 initVectors();
74 setAreaQuantities();
75 this->copy(&m);
76 }
77
78 const ContactModelFlatJoint & ContactModelFlatJoint::operator=(const ContactModelFlatJoint &m) {
79 inheritanceField(fjKnMask|fjKsMask|fjFricMask);
80 initVectors();
81 setAreaQuantities();
82 this->copy(&m);
83 return *this;
84 }
85
86 void ContactModelFlatJoint::addToStorage(poly::vector<ContactModelMechanical> *s,int ww) {
87 s->addToStorage<ContactModelFlatJoint>(*this,ww);
88 }
89
90 ContactModelFlatJoint::~ContactModelFlatJoint() {
91 if (orientProps_)
92 delete orientProps_;
93 if (energies_)
94 delete energies_;
95 }
96
97 void ContactModelFlatJoint::archive(ArchiveStream &stream) {
98 stream & fj_nr_;
99#ifdef THREED
100 stream & fj_na_;
101#endif
102 stream & fj_elem_;
103 stream & fj_kn_;
104 stream & fj_ks_;
105 stream & fj_fric_;
106 stream & fj_rmul_;
107 stream & fj_gap0_;
108 stream & fj_ten_;
109 stream & fj_coh_;
110 stream & fj_fa_;
111 stream & fj_f_;
112 stream & fj_m_;
113 stream & rmin_;
114 stream & rbar_;
115 stream & atot_;
116 stream & a_;
117 stream & rBarl_;
118 stream & propsFixed_;
119 stream & mType_;
120 stream & bmode_;
121 stream & smode_;
122 stream & gap_;
123 stream & theta_;
124#ifdef THREED
125 stream & thetaM_;
126#endif
127 stream & egap_;
128 stream & f_;
129
130 if (stream.getArchiveState()==ArchiveStream::Save) {
131 bool b = false;
132 if (orientProps_) {
133 b = true;
134 stream & b;
135 stream & orientProps_->orient1_;
136 stream & orientProps_->orient2_;
137 stream & orientProps_->origNormal_;
138 } else
139 stream & b;
140 b = false;
141 if (energies_) {
142 b = true;
143 stream & b;
144 stream & energies_->estrain_;
145 stream & energies_->eslip_;
146 } else
147 stream & b;
148 } else {
149 bool b(false);
150 stream & b;
151 if (b) {
152 if (!orientProps_)
153 orientProps_ = NEW orientProps();
154 stream & orientProps_->orient1_;
155 stream & orientProps_->orient2_;
156 stream & orientProps_->origNormal_;
157 }
158 stream & b;
159 if (b) {
160 if (!energies_)
161 energies_ = NEW Energies();
162 stream & energies_->estrain_;
163 stream & energies_->eslip_;
164 }
165 }
166
167 stream & inheritanceField_;
168 stream & effectiveTranslationalStiffness_;
169 stream & effectiveRotationalStiffness_;
170
171 if (stream.getArchiveState()==ArchiveStream::Save || stream.getRestoreVersion() > 1)
172 stream & userArea_;
173
174 if (stream.getArchiveState()==ArchiveStream::Save || stream.getRestoreVersion() > 2)
175 stream & fj_m_set_;
176
177 if (stream.getArchiveState()==ArchiveStream::Save || stream.getRestoreVersion() > 3) {
178 stream & fj_cohres_;
179 stream & fj_resmode_;
180 }
181 }
182
183 void ContactModelFlatJoint::copy(const ContactModel *cm) {
184 ContactModelMechanical::copy(cm);
185 const ContactModelFlatJoint *in = dynamic_cast<const ContactModelFlatJoint*>(cm);
186 if (!in) throw std::runtime_error("Internal error: contact model dynamic cast failed.");
187 fj_nr(in->fj_nr());
188#ifdef THREED
189 fj_na(in->fj_na());
190#endif
191 fj_elem(in->fj_elem());
192 fj_kn(in->fj_kn());
193 fj_ks(in->fj_ks());
194 fj_fric(in->fj_fric());
195 fj_rmul(in->fj_rmul());
196 fj_gap0(in->fj_gap0());
197 fj_ten(in->fj_ten());
198 fj_coh(in->fj_coh());
199 fj_cohres(in->fj_cohres());
200 fj_fa(in->fj_fa());
201 fj_f(in->fj_f());
202 fj_m(in->fj_m());
203 fj_m_set(in->fj_m_set());
204 rmin(in->rmin());
205 rbar(in->rbar());
206 fj_resmode(in->fj_resmode());
207 atot(in->atot());
208 a_ = in->a_;
209 rBarl_ = in->rBarl_;
210 propsFixed(in->propsFixed());
211 mType(in->mType());
212 bmode_ = in->bmode_;
213 smode_ = in->smode_;
214 gap(in->gap());
215 theta(in->theta());
216#ifdef THREED
217 thetaM(in->thetaM());
218#endif
219 egap_ = in->egap_;
220 f_ = in->f_;
221 if (in->orientProps_) {
222 if (!orientProps_)
223 orientProps_ = NEW orientProps();
224 orientProps_->orient1_ = in->orientProps_->orient1_;
225 orientProps_->orient2_ = in->orientProps_->orient2_;
226 orientProps_->origNormal_ = in->orientProps_->origNormal_;
227 }
228 if (in->hasEnergies()) {
229 if (!energies_)
230 energies_ = NEW Energies();
231 estrain(in->estrain());
232 eslip(in->eslip());
233 }
234 userArea_ = in->userArea_;
235 inheritanceField(in->inheritanceField());
236 effectiveTranslationalStiffness(in->effectiveTranslationalStiffness());
237 effectiveRotationalStiffness(in->effectiveRotationalStiffness());
238 }
239
240
241 base::Property ContactModelFlatJoint::getProperty(uint32 i,const IContact *con) const {
242 // The IContact pointer may be a nullptr!
243 const IContactMechanical *c(convert_getcast<IContactMechanical>(con));
244 base::Property var;
245 switch (i) {
246 case kwFjNr : return fj_nr();
247 case kwFjElem : return fj_elem();
248 case kwFjKn : return fj_kn();
249 case kwFjKs : return fj_ks();
250 case kwFjFric : return fj_fric();
251 case kwFjEmod : {
252 if (c ==nullptr) return 0.0;
253 double rsum = calcRSum(c);
254 if (userArea_) {
255#ifdef THREED
256 rsum = std::sqrt(std::max(0.0,userArea_ / dPi));
257#else
258 rsum = userArea_ / 2.0;
259#endif
260 rsum += rsum;
261 }
262 return (fj_kn_ * rsum);
263 }
264 case kwFjKRatio : return safeDiv(fj_kn_,fj_ks_);
265 case kwFjRmul : return fj_rmul();
266 case kwFjRadius : return rbar();
267 case kwFjGap0 : return fj_gap0();
268 case kwFjTen : return fj_ten();
269 case kwFjCoh : return fj_coh();
270 case kwFjFa : return fj_fa();
271 case kwFjF : var.setValue(fj_f()); return var;
272 case kwFjM : var.setValue(fj_m()); return var;
273 case kwFjState : return bmode_[fj_elem()-1];
274 case kwFjSlip : return smode_[fj_elem()-1];
275 case kwFjMType : return getmType();
276 case kwFjA : return a_[fj_elem()-1];
277 case kwFjEgap : return egap_[fj_elem()-1];
278 case kwFjGap : return gap().x();
279 case kwFjNstr : return safeDiv(-f_[fj_elem()-1].x() , a_[fj_elem()-1]);
280 case kwFjSstr : return safeDiv(f_[fj_elem()-1].y() , a_[fj_elem()-1]);
281 case kwFjSs : return tauC((-f_[fj_elem()-1].x() / a_[fj_elem()-1]),(bmode_[fj_elem()-1]==3));
282 case kwFjRelBr : var.setValue(DVect2(theta(),thetaM())); return var;
283 case kwFjCen : var.setValue(getRelElemPos(con,fj_elem()-1)); return var;
284#ifdef THREED
285 case kwFjNa : return fj_na();
286#endif
287 case kwFjTrack : var.setValue(orientProps_ ? true : false); return var;
288 case kwUserArea : return userArea_;
289 case kwFjCohRes : return fj_cohres();
290 case kwFjResMode: return fj_resmode();
291 }
292 assert(0);
293 return base::Property();
294 }
295
296 bool ContactModelFlatJoint::getPropertyGlobal(uint32 i) const {
297 switch (i) {
298 case kwFjF:
299 return false;
300 }
301 return true;
302 }
303
304 bool ContactModelFlatJoint::setProperty(uint32 i,const base::Property &v,IContact *c) {
305 bool ok(true);
306 switch (i) {
307 case kwFjNr: {
308 if (!propsFixed()) {
309 int val(v.toInt(&ok));
310 if (!ok || val < 1)
311 throw Exception("fj_nr must be an integer greater than 0.");
312 fj_nr(val);
313 if (fj_elem() > fj_n())
314 fj_elem(fj_n());
315 initVectors();
316 setAreaQuantities();
317 } else
318 throw Exception("fj_nr cannot be modified.");
319 return true;
320 }
321
322 case kwFjElem: {
323 int val(v.toInt(&ok));
324 if (!ok || val < 1 || val > fj_n())
325 throw Exception("fj_elem must be an integer between 1 and {0}.",fj_n());
326 fj_elem(val);
327 return false;
328 }
329 case kwFjKn: {
330 double val(v.toDouble(&ok));
331 if (!ok || val<0.0)
332 throw Exception("fj_kn must be a positive double.");
333 fj_kn(val);
334 return true;
335 }
336 case kwFjKs: {
337 double val(v.toDouble(&ok));
338 if (!ok || val<0.0)
339 throw Exception("fj_ks must be a positive double.");
340 fj_ks(val);
341 return true;
342 }
343 case kwFjFric: {
344 double val(v.toDouble(&ok));
345 if (!ok || val<0.0)
346 throw Exception("fj_fric must be a positive double.");
347 fj_fric(val);
348 return false;
349 }
350 case kwFjRmul: {
351 if (!propsFixed()) {
352 double val(v.toDouble(&ok));
353 if (!ok || val<0.01)
354 throw Exception("fj_rmul must be a double greater than or equal to 0.01.");
355 fj_rmul(val);
356 setAreaQuantities();
357 return true;
358 } else
359 throw Exception("fj_rmul cannot be modified.");
360
361 return false;
362 }
363 case kwFjGap0: {
364 if (!propsFixed()) {
365 double val(v.toDouble(&ok));
366 if (!ok || val<0.0)
367 throw Exception("fj_gap0 must be a positive double.");
368 fj_gap0(val);
369 if (fj_gap0() > 0.0) {
370 for(int i=1; i<=fj_n(); ++i)
371 bondElem(i,false);
372 // surfaces are parallel w/ gap G
373 DVect temp(0.0);
374 temp.rx() = fj_gap0();
375 gap(temp);
376 theta(0.0);
377 }
378 } else
379 throw Exception("fj_gap0 cannot be modified.");
380 return true;
381 }
382 case kwFjTen: {
383 double val(v.toDouble(&ok));
384 if (!ok || val<0.0)
385 throw Exception("fj_ten must be a positive double.");
386 fj_ten(val);
387 return false;
388 }
389 case kwFjFa: {
390 double val(v.toDouble(&ok));
391 if (!ok || val<0.0)
392 throw Exception("fj_fa must be a positive double.");
393 fj_fa(val);
394 return false;
395 }
396 case kwFjCoh: {
397 double val(v.toDouble(&ok));
398 if (!ok || val<0.0)
399 throw Exception("fj_coh must be a positive double.");
400 fj_coh(val);
401 return false;
402 }
403 case kwFjA: {
404 double val(v.toDouble(&ok));
405 if (!ok || val<0.0)
406 throw Exception("fj_area must be a positive double.");
407 a_[fj_elem()-1] = val;
408 return false;
409 }
410 case kwFjNstr: {
411 double val(v.toDouble(&ok));
412 if (!ok || val<0.0)
413 throw Exception("fj_sigma must be a positive double.");
414 f_[fj_elem()-1].rx() = -val * a_[fj_elem()-1];
415 return false;
416 }
417 case kwFjSstr: {
418 double val(v.toDouble(&ok));
419 if (!ok || val<0.0)
420 throw Exception("fj_tau must be a positive double.");
421 f_[fj_elem()-1].ry() = val * a_[fj_elem()-1];
422 return false;
423 }
424#ifdef THREED
425 case kwFjNa: {
426 if (!propsFixed()) {
427 int val(v.toInt(&ok));
428 if (!ok || val < 1)
429 throw Exception("fj_na must be an integer greater than 0.");
430 fj_na(val);
431 if (fj_elem() > fj_n())
432 fj_elem(fj_n());
433 initVectors();
434 setAreaQuantities();
435 } else
436 throw Exception("fj_na cannot be modified.");
437 return true;
438 }
439#endif
440 case kwFjCen: {
441 if (!v.canConvert<DVect>())
442 throw Exception("fj_cen cannot be modified.");
443 DVect val(v.value<DVect>());
444 int el = fj_elem()-1;
445 setRelElemPos(c,el,val);
446 return false;
447 }
448 case kwFjTrack: {
449 if (!v.canConvert<bool>())
450 throw Exception("fj_track must be a boolean.");
451 bool b = v.to<bool>();
452 if (b) {
453 if (!orientProps_)
454 orientProps_ = NEW orientProps();
455 } else {
456 if (orientProps_) {
457 delete orientProps_;
458 orientProps_ = 0;
459 }
460 }
461 return true;
462 }
463 case kwUserArea: {
464 if (!v.canConvert<double>())
465 throw Exception("user_area must be a double.");
466 double val(v.toDouble());
467 if (val < 0.0)
468 throw Exception("Negative user_area not allowed.");
469 userArea_ = val;
470 propsFixed_ = false;
471 return true;
472 }
473 case kwFjCohRes: {
474 double val(v.toDouble(&ok));
475 if (!ok || val<0.0)
476 throw Exception("fj_cohres must be a positive double.");
477 fj_cohres(val);
478 return false;
479 }
480 case kwFjResMode: {
481 int val(v.toInt(&ok));
482 if (!ok || (val != 0 && val != 1))
483 throw Exception("fj_resmode must be 0 or 1.");
484 fj_resmode(val);
485 return false;
486 }
487 }
488 return false;
489 }
490
491 bool ContactModelFlatJoint::getPropertyReadOnly(uint32 i) const {
492 switch (i) {
493 case kwFjF:
494 case kwFjM:
495 case kwFjGap:
496 case kwFjRelBr:
497 case kwFjState:
498 case kwFjSlip:
499 case kwFjEgap:
500 case kwFjNstr:
501 case kwFjSstr:
502 case kwFjSs:
503 case kwFjRadius:
504 return true;
505 default:
506 break;
507 }
508 return false;
509 }
510
511 string ContactModelFlatJoint::getMethodArguments(uint32 i) const {
512 switch (i) {
513 case kwBond:
514 case kwUnbond:
515 return "gap,element";
516 case KwDeformability:
517 return "emod,kratio";
518 case kwInitialize:
519 return "force,moment";
520 }
521 return string();
522 }
523
524 bool ContactModelFlatJoint::setMethod(uint32 i,const std::vector<base::Property> &vl,IContact *con) {
525 FP_S;
526 IContactMechanical *c(convert_getcast<IContactMechanical>(con));
527 bool bond(false);
528 switch (i) {
529 case kwBond:
530 bond = true;
531 [[fallthrough]];
532 case kwUnbond: {
533 int seg(0);
534 double mingap = -1.0 * limits<double>::max();
535 double maxgap = 0;
536 if (vl.size()==2) {
537 // The first is the gap
538 base::Property arg = vl.at(0);
539 if (!arg.isNull()) {
540 if (arg.canConvert<double>())
541 maxgap = vl.at(0).toDouble();
542 else if (arg.canConvert<DVect2>()) {
543 DVect2 value = vl.at(0).value<DVect2>();
544 mingap = value.minComp();
545 maxgap = value.maxComp();
546 } else
547 throw Exception("Argument {0} not recognized in method {1} in contact model {2}.",vl.at(0),bond ? "bond":"unbond",getName());
548 }
549 arg = vl.at(1);
550 if (!arg.isNull()) {
551 seg = vl.at(1).toUInt();
552 if (seg < 1)
553 throw Exception("Element indices start at 1 in method {0} in contact model {1}.",bond ? "bond":"unbond",getName());
554 if (seg > fj_n())
555 throw Exception("Element index {0} exceeds segments number ({1}) in method {2} in contact model {3}.",seg,fj_n(),bond ? "bond":"unbond",getName());
556 }
557 }
558 double gap = c->getGap();
559 if (gap >= mingap && gap <= maxgap) {
560 if (!seg) {
561 for(int iSeg=1; iSeg<=fj_n(); ++iSeg)
562 bondElem(iSeg,bond);
563 } else {
564 bondElem(seg,bond);
565 }
566 // If have installed bonds and tracking is enabled then set the contact normal appropriately
567 if (orientProps_) {
568 orientProps_->orient1_ = Quat::identity();
569 orientProps_->orient2_ = Quat::identity();
570 orientProps_->origNormal_ = toVect(con->getNormal());
571 }
572 }
573 FP_S;
574 return true;
575 }
576 case KwDeformability:
577 {
578 FP_S;
579 double emod;
580 double krat;
581 if (vl.at(0).isNull())
582 throw Exception("Argument emod must be specified with method deformability in contact model {0}.",getName());
583 emod = vl.at(0).toDouble();
584 if (emod<0.0)
585 throw Exception("Negative emod not allowed in contact model {0}.",getName());
586 if (vl.at(1).isNull())
587 throw Exception("Argument kratio must be specified with method deformability in contact model {0}.",getName());
588 krat = vl.at(1).toDouble();
589 if (krat<0.0)
590 throw Exception("Negative stiffness ratio not allowed in contact model {0}.",getName());
591 double rsum = calcRSum(c);
592 //if (c->getEnd1Curvature().y())
593 // rsum += 1.0/c->getEnd1Curvature().y();
594 //if (c->getEnd2Curvature().y())
595 // rsum += 1.0/c->getEnd2Curvature().y();
596 if (userArea_) {
597#ifdef THREED
598 rsum = std::sqrt(std::max(0.0,userArea_ / dPi));
599#else
600 rsum = userArea_ / 2.0;
601#endif
602 rsum += rsum;
603 }
604 fj_kn_ = safeDiv(emod , rsum);
605 fj_ks_ = (krat == 0.0) ? 0.0 : fj_kn_ / krat;
606 FP_S;
607 return true;
608 }
609 case KwUpdateGeom: {
610 // go through and update the total area (atot) and the
611 // radius rbar
612 double at = 0.0;
613 for (int i=1; i<=fj_n(); ++i)
614 at += a_[i-1];
615 atot(at);
616 //get the equivalent radius
617#ifdef THREED
618 rbar(sqrt(std::max(0.0,at/dPi)));
619#else
620 rbar(at/2.0);
621#endif
622 FP_S;
623 return true;
624 }
625 case kwArea: {
626 if (!userArea_) {
627 double rsq = calcRSQ(c);
628#ifdef THREED
629 userArea_ = rsq * rsq * dPi;
630#else
631 userArea_ = rsq * 2.0;
632#endif
633 }
634 FP_S;
635 return true;
636 }
637 case kwInitialize: {
638 DVect force;
639 DAVect moment;
640 if (vl.at(0).isNull())
641 throw Exception("Argument force must be specified with method initialize in contact model {0}.",getName());
642 force = vl.at(0).value<DVect>();
643 if (vl.at(1).isNull())
644 throw Exception("Argument moment must be specified with method initialize in contact model {0}.",getName());
645#ifdef THREED
646 moment = vl.at(1).value<DVect>();
647#else
648 moment.rz() = vl.at(1).toDouble();
649#endif
650 // Set the gap accordingly to get the correct force
651 setForce(force,con);
652 fj_m_set(moment);
653 FP_S;
654 return true;
655 }
656 }
657 FP_S;
658 return false;
659 }
660
661 double ContactModelFlatJoint::getEnergy(uint32 i) const {
662 double ret(0.0);
663 if (!energies_)
664 return ret;
665 switch (i) {
666 case kwEStrain: return energies_->estrain_;
667 case kwESlip: return energies_->eslip_;
668 }
669 assert(0);
670 return ret;
671 }
672
673 bool ContactModelFlatJoint::getEnergyAccumulate(uint32 i) const {
674 switch (i) {
675 case kwEStrain: return false;
676 case kwESlip: return true;
677 }
678 assert(0);
679 return false;
680 }
681
682 void ContactModelFlatJoint::setEnergy(uint32 i,const double &d) {
683 if (!energies_) return;
684 switch (i) {
685 case kwEStrain: energies_->estrain_ = d; return;
686 case kwESlip: energies_->eslip_ = d; return;
687 }
688 assert(0);
689 return;
690 }
691
692 bool ContactModelFlatJoint::validate(ContactModelMechanicalState *state,const double &) {
693 assert(state);
694 const IContactMechanical *c = state->getMechanicalContact();
695 assert(c);
696 // This presumes that one of the ends has a non-zero curvature
697 rmin(calcRSQ(c));
698 if (userArea_) {
699#ifdef THREED
700 rmin(std::sqrt(std::max(0.0,userArea_ / dPi)));
701#else
702 rmin(userArea_ / 2.0);
703#endif
704 }
705 if (!propsFixed()) {
706 setAreaQuantities();
707 mType(getmType());
708 }
709
710 // Initialize the tracking if not initialized
711 if (orientProps_ && orientProps_->origNormal_ == DVect(0.0)) {
712 orientProps_->origNormal_ = toVect(c->getContact()->getNormal());
713 orientProps_->orient1_ = Quat::identity();
714 orientProps_->orient2_ = Quat::identity();
715 }
716
717 if (state->trackEnergy_)
718 activateEnergy();
719
720 updateEffectiveStiffness(state);
721 return checkActivity(state->gap_);
722 }
723
724 void ContactModelFlatJoint::updateEffectiveStiffness(ContactModelMechanicalState *) {
725 DVect2 ret(fj_kn_,fj_ks_);
726 ret *= atot();
727 effectiveTranslationalStiffness(ret);
728#ifdef TWOD
729 effectiveRotationalStiffness(DAVect(fj_kn() * (2.0/3.0)*rbar()*rbar()*rbar()));
730#else
731 double piR4 = dPi * rbar() * rbar() * rbar() * rbar();
732 double t = fj_kn() * 0.25 * piR4;
733 effectiveRotationalStiffness(DAVect(fj_ks() * 0.50 * piR4,t,t));
734#endif
735 }
736
737 bool ContactModelFlatJoint::forceDisplacementLaw(ContactModelMechanicalState *state,const double ×tep) {
738 FP_S;
739 if (!propsFixed())
740 propsFixed(true);
741 FP_S;
742 timestep;
743 assert(state);
744
745 FP_S;
746 if (state->activated()) {
747 if (cmEvents_[fActivated] >= 0) {
748 auto c = state->getContact();
749 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()) };
750 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
751 fi->setCMFishCallArguments(c,arg,cmEvents_[fActivated]);
752 }
753 }
754 FP_S;
755
756 // Update the orientations
757 if (orientProps_) {
758 orientProps_->orient1_.increment(state->getMechanicalContact()->getEnd1Mechanical()->getAngVelocity()*timestep);
759 orientProps_->orient2_.increment(state->getMechanicalContact()->getEnd2Mechanical()->getAngVelocity()*timestep);
760 }
761 FP_S;
762
763#ifdef TWOD
764 // Translational increment in local coordinates
765 DVect del_U = state->relativeTranslationalIncrement_;
766 double del_theta = state->relativeAngularIncrement_.z();
767 gap(gap() + del_U); // in normal and shear direction in 2D
768 theta(theta() + del_theta);
769 double dSig=0.0, dTau=0.0;
770 double delX = 2*rbar() / fj_n();
771 double rbar2 = rbar() / fj_n();
772 DVect dFSum(0.0);
773 double dMSum = 0.0;
774 if (state->trackEnergy_) {
775 assert(energies_);
776 energies_->estrain_ = 0.0;
777 }
778 bool oneBonded = false;
779 for(int i=0; i<fj_n(); ++i) {
780 double g0 = gap((i )*delX);
781 double g1 = gap((i+1)*delX);
782 double gMid = 0.5*(g0 + g1);
783 if (bmode_[i] != 3 && gMid > 0) {
784 egap_[i] = gMid;
785 f_[i] = DVect(0.0);
786 continue;
787 }
788 dSig = computeSig(g0,g1,rbar2,a_[i],(bmode_[i]==3));
789 bool tensileBreak = false;
790 if (bmode_[i]==3) {
791 if (state->canFail_ && dSig >= fj_ten()) {
792 breakBond(i+1,1,state);
793 dSig = dTau = 0.0;
794 tensileBreak = true;
795 }
796 }
797 if (!tensileBreak) {
798 dTau = f_[i].y() / a_[i];
799 double dUse = delUse(egap_[i],gMid,(bmode_[i]==3),del_U.y());
800 double dtauP = dTau - fj_ks()*dUse;
801 double dtauPabs = abs(dtauP);
802 if (bmode_[i]==3) { // bonded
803 if (dtauPabs < tauC(dSig,true))
804 dTau = dtauP;
805 else {
806 if (state->canFail_) {
807 breakBond(i+1,2,state);
808 if (fj_resmode() == 0)
809 dSig = dTau = 0.0;
810 else
811 dTau = fj_cohres() - dSig * fj_fric();
812 }
813 }
814 } else { // unbonded
815 double dtauC = tauC(dSig,false);
816 if (dtauPabs <= dtauC) {
817 dTau = dtauP;
818 slipChange(i+1,false,state);
819 } else {
820 dTau = dtauP * ( dtauC / dtauPabs );
821 slipChange(i+1,true,state);
822 if (state->trackEnergy_) { energies_->eslip_ += dtauC*a_[i]*abs(dUse);}
823 }
824 }
825 }
826 oneBonded = true;
827 egap_[i] = gMid;
828 f_[i] = DVect(-dSig*a_[i],dTau*a_[i]);
829 dFSum += f_[i];
830 double m = computeM(g0,g1,rbar2,(bmode_[i]==3)) + fj_m_set().z()/fj_n();
831 dMSum += m - rBarl_[i]*f_[i].x();
832 if (state->trackEnergy_) {
833 if (fj_kn_) {
834 double ie = 2.0*rBarl_[i]*rBarl_[i]*rBarl_[i] / 3.0;
835 energies_->estrain_ += 0.5*(dSig*dSig*a_[i] + m*m/ie) / fj_kn_;
836 }
837 if (fj_ks_) {
838 energies_->estrain_ += 0.5 * dTau*dTau*a_[i] / fj_ks_;
839 }
840 }
841 }
842 //
843 fj_f(dFSum);
844 fj_m(DAVect(dMSum));
845 if (!oneBonded)
846 fj_m_set(DAVect(0.0));
847#else
848 FP_S;
849 CAxes localSys = state->axes_;
850 DVect trans = state->relativeTranslationalIncrement_; // translation increment in local coordinates
851 DAVect ang = state->relativeAngularIncrement_; // rotational increment in local coordinates
852 DVect shear(0.0,trans.y(),trans.z());
853 DVect del_Us = localSys.toGlobal(shear); // In global coordinates
854 // What is the twist in global coordinates?
855 DVect del_Theta_t = localSys.e1()*ang.x();
856 theta_ += ang.y();
857 thetaM_ += ang.z();
858
859 FP_S;
860 gap(gap() + trans);
861 if (state->trackEnergy_) {
862 assert(energies_);
863 energies_->estrain_ = 0.0;
864 }
865 FP_S;
866 DVect force(0.0);
867 DAVect mom(0.0);
868 bool oneBonded = false;
869 FP_S;
870 for (int e=1,i=0; e<=fj_n(); ++e, ++i) {
871 FP_S;
872 double gBar1 = gap( rBarl_[i].x(),rBarl_[i].y());
873 FP_S;
874 if (!Bonded(e) && gBar1 > 0) {
875 FP_S;
876 egap_[i] = gBar1;
877 f_[i] = DVect(0.0);
878 FP_S;
879 continue;
880 }
881 FP_S;
882 DVect r = localSys.e2()*rBarl_[i].x() + localSys.e3()*rBarl_[i].y(); // location of element point
883 FP_S;
884 double sigBar_e = sigBar(e);
885 f_[i].rx() = -sigBar_e * a_[i]; // Step 1...
886 FP_S;
887 if (Bonded(e) && (sigBar_e >= fj_ten())) { // break bond in tension
888 FP_S;
889 if (state->canFail_) {
890 FP_S;
891 breakBond(e,1,state);
892 FP_S;
893 f_[i] = DVect(0.0);
894 }
895 FP_S;
896 } else {
897 FP_S;
898 DVect del_us = del_Us + (del_Theta_t & r); // In global - has the twist in there
899 double del_usl = delUse(egap_[i],gBar1,Bonded(e),(del_us | localSys.e2()));
900 double del_usm = delUse(egap_[i],gBar1,Bonded(e),(del_us | localSys.e3()));
901 double Fs_lP = f_[i].y() - fj_ks() * a_[i] * del_usl;
902 double Fs_mP = f_[i].z() - fj_ks() * a_[i] * del_usm;
903 FP_S;
904 double FsPMag = sqrt(std::max(0.0,Fs_lP*Fs_lP + Fs_mP*Fs_mP));
905 FP_S;
906 double tauBarP = safeDiv(FsPMag , a_[i]);
907 FP_S;
908 if ( !Bonded(e) ) {
909 FP_S;
910 double tau_c = sigBar_e < 0.0 ? fj_cohres()-fj_fric()*sigBar_e : 0.0;
911 if ( tauBarP <= tau_c ) {
912 f_[i].ry() = Fs_lP;
913 f_[i].rz() = Fs_mP;
914 slipChange(e,false,state);
915 } else { // enforce sliding
916 FP_S;
917 double sFac = safeDiv(tau_c * a_[i] , FsPMag);
918 FP_S;
919 f_[i].ry() = Fs_lP * sFac;
920 f_[i].rz() = Fs_mP * sFac;
921 slipChange(e,true,state);
922 if (state->trackEnergy_) { energies_->eslip_ += tau_c*a_[i]*sqrt(std::max(0.0,del_usl*del_usl+del_usm*del_usm));}
923 }
924 } else { // Bonded(e)
925 FP_S;
926 double tau_c = fj_coh() - sigBar_e * tan(dDegrad*fj_fa());
927 if ( tauBarP <= tau_c ) {
928 f_[i].ry() = Fs_lP;
929 f_[i].rz() = Fs_mP;
930 } else { // break bond in shear
931 if (state->canFail_) {
932 breakBond(e,2,state);
933 if (fj_resmode() == 0)
934 f_[i] = DVect(0.0);
935 else {
936 double newForce = fj_cohres() - sigBar_e * fj_fric();
937 if (!userArea_)
938 newForce *= a_[i];
939 else
940 newForce *= safeDiv(userArea_ , to<double>(fj_n()));
941 FP_S;
942 newForce = safeDiv(newForce,std::sqrt(std::max(0.0,f_[i].y()*f_[i].y() + f_[i].z()*f_[i].z())));
943 //newForce /= std::sqrt(f_[i].y()*f_[i].y() + f_[i].z()*f_[i].z());
944 FP_S;
945 f_[i].ry() *= newForce;
946 f_[i].rz() *= newForce;
947 }
948 }
949 }
950 FP_S;
951 }
952 }
953 oneBonded = true;
954 force += f_[i];
955 FP_S;
956 mom += (localSys.toLocal(r) & f_[i]) + safeDiv(fj_m_set(),to<double>(fj_n()));
957 FP_S;
958 egap_[i] = gBar1;
959 if (state->trackEnergy_) {
960 energies_->estrain_ += computeStrainEnergy(e);
961 FP_S;
962 }
963 FP_S;
964 }
965 FP_S;
966 fj_f(force);
967 fj_m(mom);
968 if (!oneBonded)
969 fj_m_set(DAVect(0.0));
970 FP_S;
971#endif
972 assert(fj_f_ == fj_f_);
973 FP_S;
974 return checkActivity(0.0);
975 }
976
977 bool ContactModelFlatJoint::thermalCoupling(ContactModelMechanicalState*, ContactModelThermalState* ts, IContactThermal*, const double&) {
978 // Account for thermal expansion in incremental mode
979 if (ts->gapInc_ == 0.0) return false;
980 DVect dg(0.0);
981 dg.rx() = ts->gapInc_;
982 gap(gap() + dg);
983 return true;
984 }
985
986 void ContactModelFlatJoint::setAreaQuantities() {
987 rbar(fj_rmul() * rmin());
988#ifdef TWOD
989 atot(2.0 * rbar());
990 double v = atot()/fj_n();
991 for (int i=1; i<=fj_n(); ++i) {
992 a_[i-1] = v;
993 rBarl_[i-1] = rbar() * (double(-2*i + 1 + fj_n()) / fj_n());
994 }
995#else
996 atot(dPi * rbar() * rbar());
997 double del_r = safeDiv(rbar() , to<double>(fj_nr()));
998 double del_al = safeDiv(2.0*dPi , to<double>(fj_na()));
999 double fac = 2.0/3.0;
1000 for (int i=0; i < fj_n(); ++i) {
1001 double dVal = i / fj_na();
1002 int I = (int)floor( dVal );
1003 int J = i - I*fj_na();
1004 double r1 = I * del_r;
1005 double r2 = (I + 1) * del_r;
1006 double al1 = J * del_al;
1007 double al2 = (J + 1) * del_al;
1008 a_[i] = 0.5 * (al2 - al1) * (r2*r2 - r1*r1);
1009 rBarl_[i] = DVect2((safeDiv((sin(al2) - sin(al1)) , (al2 - al1)))*(safeDiv((r2*r2*r2 - r1*r1*r1),(r2*r2 - r1*r1))),
1010 (safeDiv((cos(al1) - cos(al2)) , (al2 - al1)))*(safeDiv((r2*r2*r2 - r1*r1*r1),(r2*r2 - r1*r1))))*fac;
1011 }
1012#endif
1013 updateEffectiveStiffness(0);
1014 }
1015
1016 DVect ContactModelFlatJoint::getRelElemPos(const IContact* c,int i) const {
1017 DVect ret(0.0);
1018 if (c) {
1019 ret = c->getPosition();
1020 CAxes localSys = c->getLocalSystem();
1021#ifdef TWOD
1022 ret += localSys.e2()*rBarl_[i];
1023#else
1024 ret += localSys.e2()*rBarl_[i].x() + localSys.e3()*rBarl_[i].y();
1025#endif
1026 }
1027 return ret;
1028 }
1029
1030 void ContactModelFlatJoint::setRelElemPos(const IContact* c,int i,const DVect &pos) {
1031 // pos is a position in space in global coordinates
1032 propsFixed(true);
1033 if (c) {
1034 // project onto the plane
1035 DVect cp = c->getPosition();
1036 DVect norm = toVect(c->getNormal());
1037 double sd = norm|(cp - pos);
1038 // np is the point on the plane
1039 DVect np = pos+norm*sd;
1040 np = np-cp;
1041 CAxes localSys = c->getLocalSystem();
1042 np = localSys.toLocal(np);
1043#ifdef TWOD
1044 rBarl_[i] = np.y();
1045#else
1046 rBarl_[i] = DVect2(np.y(),np.z());
1047#endif
1048 }
1049 }
1050
1051 int ContactModelFlatJoint::getmType() const {
1052 if (propsFixed()) return mType();
1053 //
1054 if (fj_gap0() > 0.0) return 2;
1055 //
1056 // If we get to here, then G == 0.0.
1057 bool AllBonded = true;
1058 bool AllSlit = true;
1059 for(int i=0; i<fj_n(); ++i) {
1060 if (bmode_[i] != 3) AllBonded = false;
1061 else AllSlit = false;
1062 }
1063 if (AllBonded) return 1;
1064 if (AllSlit) return 3;
1065 //
1066 return 4;
1067 }
1068
1069 void ContactModelFlatJoint::bondElem(int iSeg,bool bBond ) {
1070 if (bBond) {
1071 if (fj_gap0() == 0.0) {
1072 bmode_[iSeg-1] = 3;
1073 } else
1074 bmode_[iSeg-1] = 0;
1075 } else
1076 bmode_[iSeg-1] = 0;
1077 }
1078
1079 void ContactModelFlatJoint::breakBond(int iSeg,int fmode,ContactModelMechanicalState *state) {
1080 if (cmEvents_[fBondBreak] >= 0) {
1081 auto c = state->getContact();
1082 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
1083 fish::Parameter((int64)iSeg),
1084 fish::Parameter((int64)fmode),
1085 fish::Parameter(computeStrainEnergy(iSeg))
1086 };
1087 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
1088 fi->setCMFishCallArguments(c,arg,cmEvents_[fBondBreak]);
1089 }
1090 if (!isBonded() && cmEvents_[fBroken] >= 0) {
1091 auto c = state->getContact();
1092 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()) };
1093 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
1094 fi->setCMFishCallArguments(c,arg,cmEvents_[fBroken]);
1095 }
1096 bmode_[iSeg-1] = fmode;
1097 }
1098
1099 void ContactModelFlatJoint::slipChange(int iSeg,bool smode,ContactModelMechanicalState *state) {
1100 bool emitEvent = false;
1101 if (smode) {
1102 if (!smode_[iSeg-1]) {
1103 emitEvent = true;
1104 smode_[iSeg-1] = smode;
1105 }
1106 } else {
1107 if (smode_[iSeg-1]) {
1108 emitEvent = true;
1109 smode_[iSeg-1] = smode;
1110 }
1111 }
1112 if (emitEvent && cmEvents_[fSlipChange] >= 0) {
1113 auto c = state->getContact();
1114 std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
1115 fish::Parameter((int64)iSeg),
1116 fish::Parameter(smode) };
1117 IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
1118 fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
1119 }
1120 }
1121
1122 double ContactModelFlatJoint::tauC(const double &dSig,bool bBonded) const {
1123 if (bBonded) return (fj_coh() + (tan(dDegrad*fj_fa()) * (-dSig)) );
1124 else
1125 return (dSig < 0.0 ? fj_cohres() - fj_fric() * dSig : 0.0 );
1126 }
1127
1128#ifdef THREED
1129 double ContactModelFlatJoint::xi(int comp) const {
1130 if (comp == 1) return abs(theta_) <= 1e-12 ? 0.0 : theta_/thbMag();
1131 else return abs(thetaM_) <= 1e-12 ? 0.0 : thetaM_/thbMag();
1132 }
1133#endif
1134
1135 void ContactModelFlatJoint::initVectors() {
1136 a_.resize(fj_n());
1137 rBarl_.resize(fj_n());
1138 bmode_.resize(fj_n());
1139 smode_.resize(fj_n());
1140 egap_.resize(fj_n());
1141 f_.resize(fj_n());
1142 for (int i=0; i<fj_n(); ++i) {
1143 a_[i] = egap_[i] = 0.0;
1144#ifdef THREED
1145 rBarl_[i] = DVect2(0.0);
1146#else
1147 rBarl_[i] = 0.0;
1148#endif
1149 f_[i] = DVect(0.0);
1150 bmode_[i] = 0;
1151 smode_[i] = false;
1152 }
1153 }
1154
1155#ifdef TWOD
1156 double ContactModelFlatJoint::gap(const double &x) const {
1157 return gap().x() + theta()*(x - rbar());
1158 }
1159#else
1160 double ContactModelFlatJoint::gap(const double &r_l,const double &r_m ) const {
1161 FP_S;
1162 auto ret = gap().x() + ( r_m*xi(1) - r_l*xi(2) ) * thbMag();
1163 FP_S;
1164 return ret;
1165 }
1166
1167 double ContactModelFlatJoint::sigBar(int e) const {
1168 FP_S;
1169 if (!Bonded(e) && gap(rBarl_[e-1].x(),rBarl_[e-1].y()) >= 0.0) {
1170 FP_S;
1171 return 0.0;
1172 } else {
1173 auto ret = fj_kn() * gap(rBarl_[e-1].x(),rBarl_[e-1].y());
1174 FP_S;
1175 return ret;
1176 }
1177 }
1178
1179 double ContactModelFlatJoint::tauBar(int e) const {
1180 return safeDiv(sqrt(std::max(0.0,f_[e-1].y()*f_[e-1].y() + f_[e-1].z()*f_[e-1].z())),a_[e-1]);
1181 //return a_[e-1] <= 1e-12 ?
1182 //0.0 : sqrt(f_[e-1].y()*f_[e-1].y() + f_[e-1].z()*f_[e-1].z())/a_[e-1] ;
1183 }
1184
1185#endif
1186
1187 double ContactModelFlatJoint::computeStrainEnergy(int e) const {
1188 double ret(0.0);
1189 int i = e - 1;
1190#ifdef TWOD
1191 double delX = 2 * rbar() / fj_n();
1192 double g0 = gap((i)*delX);
1193 double g1 = gap((i + 1)*delX);
1194 double rbar2 = rbar() / fj_n();
1195 double dSig = computeSig(g0, g1, rbar2, a_[i], (bmode_[i] == 3));
1196 double m = computeM(g0, g1, rbar2, (bmode_[i] == 3));
1197 double dTau = f_[i].y() / a_[i]; // only valid before failure
1198 if (fj_kn_) {
1199 double ie = 2.0*rBarl_[i] * rBarl_[i] * rBarl_[i] / 3.0;
1200 ret += 0.5*(dSig*dSig*a_[i] + m * m / ie) / fj_kn_;
1201 }
1202 if (fj_ks_) {
1203 ret += 0.5 * dTau*dTau*a_[i] / fj_ks_;
1204 }
1205#else
1206 if (fj_kn_) {
1207 ret += safeDiv(0.5*(sigBar(e)*sigBar(e)*a_[i]) , fj_kn_);
1208 }
1209 if (fj_ks_) {
1210 ret += 0.5 * safeDiv((f_[i].y()*f_[i].y() + f_[i].z()*f_[i].z()) , (fj_ks_*a_[i]));
1211 }
1212#endif
1213 return ret;
1214 }
1215
1216 double ContactModelFlatJoint::computeSig(const double &g0,const double &g1,const double &rbar,
1217 const double &dA,bool bBonded ) const {
1218 double gTerm;
1219 switch (getCase(g0, g1)) {
1220 case 1:
1221 if (bBonded) gTerm = (g0 + g1);
1222 else if (g0 < 0.0) gTerm = -safeDiv( g0*g0 , (g1 - g0) );
1223 else gTerm = safeDiv( g1*g1 , (g1 - g0) );
1224 break;
1225 case 2:
1226 if (bBonded) gTerm = (g0 + g1);
1227 else gTerm = 0.0;
1228 break;
1229 case 3:
1230 gTerm = (g0 + g1);
1231 break;
1232 default: gTerm = 0.0; break;
1233 }
1234 return safeDiv(fj_kn() * gTerm * rbar , dA);
1235 }
1236
1237 double ContactModelFlatJoint::computeM(const double &g0,const double &g1,const double &rbar,
1238 bool bBonded) const {
1239 double gTerm;
1240 switch (getCase(g0,g1)) {
1241 case 1:
1242 if (bBonded) gTerm = -((g1 - g0) / 3.0);
1243 else if (g0 < 0.0) gTerm = safeDiv(g0*g0*(g0 - 3.0*g1) , (3.0*(g1-g0)*(g1-g0)));
1244 else gTerm = -( safeDiv(((g1-g0)*(g1-g0)*(g1-g0) + g0*g0*(g0 - 3.0*g1))
1245 , (3.0*(g1-g0)*(g1-g0))) );
1246 break;
1247 case 2:
1248 if (bBonded) gTerm = -((g1 - g0) / 3.0);
1249 else gTerm = 0.0;
1250 break;
1251 case 3:
1252 gTerm = -((g1 - g0) / 3.0);
1253 break;
1254 default: gTerm = 0.0; break;
1255 }
1256 return fj_kn() * gTerm * rbar*rbar;
1257 }
1258
1259 int ContactModelFlatJoint::getCase(const double &g0,const double &g1) const {
1260 if (g0 * g1 < 0.0) // Case 1: gap changes sign
1261 return 1;
1262 else if (g0 >= 0.0 && g1 >= 0.0) // Case 2: gap remains positive or zero
1263 return 2;
1264 else // Case 3: gap remains negative
1265 return 3;
1266 }
1267
1268 double ContactModelFlatJoint::delUse(const double &gapStart,const double &gapEnd,bool bBonded,
1269 const double &delUs) const {
1270 if ( bBonded ) return delUs;
1271 if ( gapStart <= 0.0 ) {
1272 if ( gapEnd <= 0.0 )
1273 return delUs;
1274 else { // gapEnd > 0.0
1275 double xi = -safeDiv(gapStart , (gapEnd - gapStart));
1276 return delUs * xi;
1277 }
1278 } else { // gapStart > 0.0
1279 if ( gapEnd >= 0.0 )
1280 return 0.0;
1281 else { // gapEnd < 0.0
1282 double xi = -safeDiv(gapStart , (gapEnd - gapStart));
1283 return delUs * (1.0 - xi);
1284 }
1285 }
1286 }
1287
1288 bool ContactModelFlatJoint::checkActivity(const double &inGap) {
1289 FP_S;
1290 // If any subcontact is bonded return true
1291 FOR(it,bmode_) if ((*it) == 3)
1292 return true;
1293 FP_S;
1294 // If the normal gap is less than 2*rbar return true
1295 if (gap().x() < 2.0*rbar())
1296 return true;
1297 FP_S;
1298 // check to see if there is overlap (based on the initial gap) to reset activity if the contact has been previously deactivated
1299 if (inGap < 0) {
1300 // reset the relative rotation
1301 theta(0.0);
1302#ifdef THREED
1303 thetaM(0.0);
1304#endif
1305 // set the gap to be the current gap, removing the shear displacement
1306 DVect inp(inGap,0.0);
1307 gap(inp);
1308 FP_S;
1309 return true;
1310 }
1311 FP_S;
1312 return false;
1313 }
1314
1315 void ContactModelFlatJoint::setForce(const DVect &v,IContact *) {
1316 fj_f_ = v;
1317 DVect df = v / f_.size();
1318 for (int i=0; i<f_.size(); ++i)
1319 f_[i] = df;
1320 // Set gap consistent with normal force
1321 double at = userArea_;
1322 if (!userArea_) {
1323 for (int i = 1; i <= fj_n(); ++i)
1324 at += a_[i - 1];
1325 }
1326 gap_.rx() = safeDiv(-1.0 * v.x() , (fj_kn_ * at));
1327 }
1328
1329 void ContactModelFlatJoint::getSphereList(const IContact *con,std::vector<DVect> *pos,std::vector<double> *rad,std::vector<double> *val) {
1330 assert(pos);
1331 assert(rad);
1332 assert(val);
1333 if (!orientProps_)
1334 return;
1335 // find minimal radii for end1
1336 double br = convert_getcast<IContactMechanical>(con)->getEnd1Curvature().y();
1337 if (br) {
1338 const IPiece *p = con->getEnd1();
1339 FArray<const IContact*> arr;
1340 p->getContactList(&arr);
1341 double maxgap = 0.0;
1342 FOR(ic,arr) {
1343 const IContactMechanical *mc = convert_getcast<IContactMechanical>(*ic);
1344 const IContactModelMechanical *mcm = mc->getModelMechanical();
1345 if (mcm->getContactModel()->getIndex() == ContactModelFlatJoint::getIndex()) {
1346 const ContactModelFlatJoint *in = dynamic_cast<const ContactModelFlatJoint*>(mcm);
1347 maxgap = std::max<double>(maxgap,in->gap().x()- mc->getGap());
1348 }
1349 }
1350 br = 1.0 / br - 0.5*maxgap;
1351 const IContactMechanical *mc = convert_getcast<IContactMechanical>(con);
1352 pos->push_back(convert_getcast<IPieceMechanical>(mc->getEnd1())->getPosition());
1353 rad->push_back(br);
1354 val->push_back(mc->getEnd1()->getIThing()->getID());
1355 }
1356
1357 // Give the end2 sphere - bummer
1358 br = convert_getcast<IContactMechanical>(con)->getEnd2Curvature().y();
1359 if (br) {
1360 const IPiece *p = con->getEnd2();
1361 FArray<const IContact*> arr;
1362 p->getContactList(&arr);
1363 double maxgap = 0.0;
1364 FOR(ic,arr) {
1365 const IContactMechanical *mc = convert_getcast<IContactMechanical>(*ic);
1366 const IContactModelMechanical *mcm = mc->getModelMechanical();
1367 if (mcm->getContactModel()->getIndex() == ContactModelFlatJoint::getIndex()) {
1368 const ContactModelFlatJoint *in = dynamic_cast<const ContactModelFlatJoint*>(mcm);
1369 maxgap = std::max<double>(maxgap,in->gap().x()- mc->getGap());
1370 }
1371 }
1372 br = 1.0 / br - 0.5*maxgap;
1373 const IContactMechanical *mc = convert_getcast<IContactMechanical>(con);
1374 pos->push_back(convert_getcast<IPieceMechanical>(mc->getEnd2())->getPosition());
1375 rad->push_back(br);
1376 val->push_back(mc->getEnd2()->getIThing()->getID());
1377 }
1378 }
1379
1380#ifdef THREED
1381
1382 void ContactModelFlatJoint::getDiskList(const IContact *con,std::vector<DVect> *pos,std::vector<DVect> *normal,std::vector<double> *radius,std::vector<double> *val) {
1383 assert(pos);
1384 assert(normal);
1385 assert(radius);
1386 assert(val);
1387 if (!orientProps_)
1388 return;
1389 // plot the contact plane right in the middle of the 2 normals
1390 double rad = fj_rmul()*rmin();
1391 DVect axis1 = orientProps_->orient1_.rotate(orientProps_->origNormal_);
1392 DVect axis2 = orientProps_->orient2_.rotate(orientProps_->origNormal_);
1393 DVect norm = safeUnit(((safeUnit(axis1)+safeUnit(axis2))*0.5));
1394 pos->push_back(con->getPosition());
1395 normal->push_back(norm);
1396 radius->push_back(rad);
1397 const IContactMechanical *mc = convert_getcast<IContactMechanical>(con);
1398 val->push_back(safeMag(mc->getLocalForce()));
1399 }
1400
1401#endif
1402
1403 void ContactModelFlatJoint::getCylinderList(const IContact *con,std::vector<DVect> *bot,std::vector<DVect> *top,std::vector<double> *radlow,std::vector<double> *radhi,std::vector<double> *val) {
1404 assert(bot);
1405 assert(top);
1406 assert(radlow);
1407 assert(radhi);
1408 assert(val);
1409 if (!orientProps_)
1410 return;
1411 const IContactMechanical *mc = convert_getcast<IContactMechanical>(con);
1412 double br = mc->getEnd1Curvature().y(), br2 = mc->getEnd2Curvature().y();
1413 if (userArea_) {
1414#ifdef THREED
1415 br = std::sqrt(std::max(0.0,userArea_ / dPi));
1416#else
1417 br = userArea_ / 2.0;
1418#endif
1419 br = safeDiv(1. , br);
1420 br2 = br;
1421 }
1422
1423 double cgap = mc->getGap();
1424 if (br > 0 && br2 > 0) {
1425 br = 1.0 / br;
1426 br2 = 1.0 / br2;
1427 double rad = fj_rmul()*rmin();
1428 DVect bp = convert_getcast<IPieceMechanical>(mc->getEnd1())->getPosition();
1429 DVect axis = orientProps_->orient1_.rotate(orientProps_->origNormal_);
1430 bot->push_back(safeUnit(axis)*(br-0.5*(gap().x()- cgap))+bp);
1431 top->push_back(bp);
1432 radlow->push_back(rad);
1433 radhi->push_back(0.0);
1434 val->push_back(mc->getEnd1()->getIThing()->getID());
1435 bp = convert_getcast<IPieceMechanical>(mc->getEnd2())->getPosition();
1436 axis = orientProps_->orient2_.rotate(orientProps_->origNormal_);
1437 bot->push_back(safeUnit(axis)*(br2-0.5*(gap().x()-cgap))*(-1.0)+bp);
1438 top->push_back(bp);
1439 radlow->push_back(rad);
1440 radhi->push_back(0.0);
1441 val->push_back(mc->getEnd2()->getIThing()->getID());
1442 }
1443 }
1444
1445 DVect ContactModelFlatJoint::getForce() const {
1446 DVect ret(fj_f_);
1447 return ret;
1448 }
1449
1450 DAVect ContactModelFlatJoint::getMomentOn1(const IContactMechanical *c) const {
1451 DAVect ret(fj_m_);
1452 if (c) {
1453 DVect force = getForce();
1454 c->updateResultingTorqueOn1Local(force,&ret);
1455 }
1456 return ret;
1457 }
1458
1459 DAVect ContactModelFlatJoint::getMomentOn2(const IContactMechanical *c) const {
1460 DAVect ret(fj_m_);
1461 if (c) {
1462 DVect force = getForce();
1463 c->updateResultingTorqueOn2Local(force,&ret);
1464 }
1465 return ret;
1466 }
1467
1468 DAVect ContactModelFlatJoint::getModelMomentOn1() const {
1469 DAVect ret(fj_m_);
1470 return ret;
1471 }
1472
1473 DAVect ContactModelFlatJoint::getModelMomentOn2() const {
1474 DAVect ret(fj_m_);
1475 return ret;
1476 }
1477
1478 void ContactModelFlatJoint::objectPropsTypes(std::vector<std::pair<string,InfoTypes>> *ret) const {
1479 ret->clear();
1480 ret->push_back({"fj_nr",ScalarInfo});
1481 ret->push_back({"fj_elem",ScalarInfo});
1482 ret->push_back({"fj_kn",ScalarInfo});
1483 ret->push_back({"fj_ks",ScalarInfo});
1484 ret->push_back({"fj_fric",ScalarInfo});
1485 ret->push_back({"fj_emod",ScalarInfo});
1486 ret->push_back({"fj_kratio",ScalarInfo});
1487 ret->push_back({"fj_rmul",ScalarInfo});
1488 ret->push_back({"fj_radius",ScalarInfo});
1489 ret->push_back({"fj_gap0",ScalarInfo});
1490 ret->push_back({"fj_ten",ScalarInfo});
1491 ret->push_back({"fj_coh",ScalarInfo});
1492 ret->push_back({"fj_fa",ScalarInfo});
1493 ret->push_back({"fj_force",VectorInfo});
1494 ret->push_back({"fj_moment",VectorInfo});
1495 ret->push_back({"fj_state",ScalarInfo});
1496 ret->push_back({"fj_slip",ScalarInfo});
1497 ret->push_back({"fj_mtype",ScalarInfo});
1498 ret->push_back({"fj_area",ScalarInfo});
1499 ret->push_back({"fj_egap",ScalarInfo});
1500 ret->push_back({"fj_gap",ScalarInfo});
1501 ret->push_back({"fj_sigma",ScalarInfo});
1502 ret->push_back({"fj_tau",ScalarInfo});
1503 ret->push_back({"fj_shear",ScalarInfo});
1504#ifdef THREED
1505 ret->push_back({"fj_nal",ScalarInfo});
1506#endif
1507 ret->push_back({"fj_relbr",VectorInfo});
1508 ret->push_back({"fj_cen",VectorInfo});
1509 ret->push_back({"fj_track",ScalarInfo});
1510 ret->push_back({"user_area",ScalarInfo});
1511 ret->push_back({"fj_cohres",ScalarInfo});
1512 ret->push_back({"fj_resmode",ScalarInfo});
1513
1514 }
1515
1516 void ContactModelFlatJoint::objectPropValues(std::vector<double> *ret,const IContact *con) const {
1517 FP_S;
1518 ret->clear();
1519 ret->push_back(fj_nr());
1520 ret->push_back(fj_elem());
1521 ret->push_back(fj_kn());
1522 ret->push_back(fj_ks());
1523 ret->push_back(fj_fric());
1524 const IContactMechanical *c(convert_getcast<IContactMechanical>(con));
1525 double rsum = calcRSum(c);
1526 //if (c->getEnd1Curvature().y())
1527 // rsum += 1.0/c->getEnd1Curvature().y();
1528 //if (c->getEnd2Curvature().y())
1529 // rsum += 1.0/c->getEnd2Curvature().y();
1530 if (userArea_) {
1531#ifdef THREED
1532 rsum = std::sqrt(std::max(0.0,userArea_ / dPi));
1533#else
1534 rsum = userArea_ / 2.0;
1535#endif
1536 rsum += rsum;
1537 }
1538 ret->push_back(fj_kn_ * rsum);
1539 ret->push_back(safeDiv(fj_kn_,fj_ks_));
1540 ret->push_back(fj_rmul());
1541 ret->push_back(rbar());
1542 ret->push_back(fj_gap0());
1543 ret->push_back(fj_ten());
1544 ret->push_back(fj_coh());
1545 ret->push_back(fj_fa());
1546 ret->push_back(safeMag(fj_f()));
1547 ret->push_back(safeMag(fj_m()));
1548 ret->push_back(bmode_[fj_elem()-1]);
1549 ret->push_back(smode_[fj_elem()-1]);
1550 ret->push_back(getmType());
1551 ret->push_back(a_[fj_elem()-1]);
1552 ret->push_back(egap_[fj_elem()-1]);
1553 ret->push_back(gap().x());
1554 ret->push_back(safeDiv(-f_[fj_elem()-1].x() , a_[fj_elem()-1]));
1555 ret->push_back(safeDiv(f_[fj_elem()-1].y() , a_[fj_elem()-1]));
1556 ret->push_back(tauC((safeDiv(-f_[fj_elem()-1].x() , a_[fj_elem()-1])),(bmode_[fj_elem()-1]==3)));
1557#ifdef THREED
1558 ret->push_back(fj_na());
1559#endif
1560 ret->push_back(safeMag(DVect2(theta(),thetaM())));
1561 ret->push_back(safeMag(getRelElemPos(con,fj_elem()-1)));
1562 ret->push_back(orientProps_ ? true : false);
1563 ret->push_back(userArea_);
1564 ret->push_back(fj_cohres());
1565 ret->push_back(fj_resmode());
1566 FP_S;
1567 }
1568
1569} // namespace itascaxd
1570
1571// EoF
Was this helpful? ... | Itasca Software © 2024, Itasca | Updated: Jun 07, 2025 |