Burger’s Contact Model Implementation

See this page for the documentation of this contact model.

contactmodelburger.h

  1#pragma once
  2// contactmodelburger.h
  3
  4#include "contactmodel/src/contactmodelmechanical.h"
  5
  6#ifdef BURGER_LIB
  7#  define BURGER_EXPORT EXPORT_TAG
  8#elif defined(NO_MODEL_IMPORT)
  9#  define BURGER_EXPORT
 10#else
 11#  define BURGER_EXPORT IMPORT_TAG
 12#endif
 13
 14namespace cmodelsxd {
 15    using namespace itasca;
 16
 17    class ContactModelBurger : public ContactModelMechanical {
 18    public:
 19        // Constructor: Set default values for contact model properties.
 20        BURGER_EXPORT ContactModelBurger();
 21        BURGER_EXPORT ContactModelBurger(const ContactModelBurger &) noexcept;
 22        BURGER_EXPORT const ContactModelBurger & operator=(const ContactModelBurger &);
 23        BURGER_EXPORT void   addToStorage(poly::vector<ContactModelMechanical> *s,int ww = -1) override;
 24        // Destructor, called when contact is deleted: free allocated memory, etc.
 25        BURGER_EXPORT virtual ~ContactModelBurger();
 26        // Contact model name (used as keyword for commands and FISH).
 27        virtual QString  getName() const { return "burger"; }
 28        // The index provides a quick way to determine the type of contact model.
 29        // Each type of contact model in PFC must have a unique index; this is assigned
 30        // by PFC when the contact model is loaded. This index should be set to -1
 31        virtual void     setIndex(int i) { index_=i;}
 32        virtual int      getIndex() const {return index_;}
 33        // Contact model version number (e.g., MyModel05_1). The version number can be
 34        // accessed during the save-restore operation (within the archive method,
 35        // testing {stream.getRestoreVersion() == getMinorVersion()} to allow for 
 36        // future modifications to the contact model data structure.
 37        virtual uint32     getMinorVersion() const;
 38        // Copy the state information to a newly created contact model.
 39        // Provide access to state information, for use by copy method.
 40        virtual void     copy(const ContactModel *c) override;
 41        // Provide save-restore capability for the state information.
 42        virtual void     archive(ArchiveStream &); 
 43        // Enumerator for the properties.
 44        enum PropertyKeys { 
 45              kwKnK=1
 46            , kwCnK                            
 47            , kwKnM
 48            , kwCnM                            
 49            , kwKsK                            
 50            , kwCsK                            
 51            , kwKsM
 52            , kwCsM                            
 53            , kwMode
 54            , kwFric   
 55            , kwF
 56            , kwS
 57        };
 58        // Contact model property names in a comma separated list. The order corresponds with
 59        // the order of the PropertyKeys enumerator above. One can visualize any of these 
 60        // properties in PFC automatically. 
 61        virtual QString  getProperties() const { 
 62            return "bur_knk"
 63                   ",bur_cnk"
 64                   ",bur_knm"
 65                   ",bur_cnm"
 66                   ",bur_ksk"
 67                   ",bur_csk"
 68                   ",bur_ksm"
 69                   ",bur_csm"
 70                   ",bur_mode"
 71                   ",bur_fric"
 72                   ",bur_force"
 73                   ",bur_slip";
 74        }
 75        // Enumerator for contact model related FISH callback events. 
 76        enum FishCallEvents {
 77            fActivated=0
 78            ,fSlipChange
 79        };
 80        // Contact model FISH callback event names in a comma separated list. The order corresponds with
 81        // the order of the FishCallEvents enumerator above. 
 82        virtual QString  getFishCallEvents() const { 
 83            return 
 84                "contact_activated"
 85                ",slip_change"; 
 86        }
 87
 88        // Return the specified contact model property.
 89        virtual QVariant getProperty(uint32 i,const IContact *) const;
 90        // The return value denotes whether or not the property corresponds to the global
 91        // or local coordinate system (TRUE: global system, FALSE: local system). The
 92        // local system is the contact-plane system (nst) defined as follows.
 93        // If a vector V is expressed in the local system as (Vn, Vs, Vt), then V is
 94        // expressed in the global system as {Vn*nc + Vs*sc + Vt*tc} where where nc, sc
 95        // and tc are unit vectors in directions of the nst axes.
 96        // This is used when rendering contact model properties that are vectors.
 97        virtual bool     getPropertyGlobal(uint32 i) const;
 98        // Set the specified contact model property, ensuring that it is of the correct type
 99        // and within the correct range --- if not, then throw an exception.
100        // The return value denotes whether or not the update has affected the timestep
101        // computation (by having modified the translational or rotational tangent stiffnesses).
102        // If true is returned, then the timestep will be recomputed.
103        virtual bool     setProperty(uint32 i,const QVariant &v,IContact *);
104        // The return value denotes whether or not the property is read-only
105        // (TRUE: read-only, FALSE: read-write).
106        virtual bool     getPropertyReadOnly(uint32 i) const;
107
108        // Prepare for entry into ForceDispLaw. The validate function is called when:
109        // (1) the contact is created, (2) a property of the contact that returns a true via
110        // the setProperty method has been modified and (3) when a set of cycles is executed
111        // via the {cycle N} command.
112        // Return value indicates contact activity (TRUE: active, FALSE: inactive).
113        virtual bool    validate(ContactModelMechanicalState *state,const double &timestep);
114        // The forceDisplacementLaw function is called during each cycle. Given the relative
115        // motion of the two contacting pieces (via
116        //   state->relativeTranslationalIncrement_ (Ddn, Ddss, Ddst)
117        //   state->relativeAngularIncrement_       (Dtt, Dtbs, Dtbt)
118        //     Ddn  : relative normal-displacement increment, Ddn > 0 is opening
119        //     Ddss : relative  shear-displacement increment (s-axis component)
120        //     Ddst : relative  shear-displacement increment (t-axis component)
121        //     Dtt  : relative twist-rotation increment
122        //     Dtbs : relative  bend-rotation increment (s-axis component)
123        //     Dtbt : relative  bend-rotation increment (t-axis component)
124        //       The relative displacement and rotation increments:
125        //         Dd = Ddn*nc + Ddss*sc + Ddst*tc
126        //         Dt = Dtt*nc + Dtbs*sc + Dtbt*tc
127        //       where nc, sc and tc are unit vectors in direc. of the nst axes, respectively.
128        //       [see {Table 1: Contact State Variables} in PFC Model Components:
129        //       Contacts and Contact Models: Contact Resolution]
130        // ) and the contact properties, this function must update the contact force and
131        // moment.
132        //   The force_ is acting on piece 2, and is expressed in the local coordinate system
133        //   (defined in getPropertyGlobal) such that the first component positive denotes
134        //   compression. If we define the moment acting on piece 2 by Mc, and Mc is expressed
135        //   in the local coordinate system (defined in getPropertyGlobal), then we must use the getMechanicalContact()->updateResultingTorquesLocal(...) method to 
136        //   get the total moment. 
137        // The return value indicates the contact activity status (TRUE: active, FALSE:
138        // inactive) during the next cycle.
139        // Additional information:
140        //   * If state->activated() is true, then the contact has just become active (it was
141        //     inactive during the previous time step).
142        //   * Fully elastic behavior is enforced during the SOLVE ELASTIC command by having
143        //     the forceDispLaw handle the case of {state->canFail_ == true}.
144        virtual bool    forceDisplacementLaw(ContactModelMechanicalState *state,const double &timestep);
145        // The getEffectiveXStiffness functions return the translational and rotational
146        // tangent stiffnesses used to compute a stable time step. When a contact is sliding,
147        // the translational tangent shear stiffness is zero (but this stiffness reduction
148        // is typically ignored when computing a stable time step). If the contact model
149        // includes a dashpot, then the translational stiffnesses must be increased (see
150        // Potyondy (2009)).
151        //   [Potyondy, D. 'Stiffness Matrix at a Contact Between Two Clumps,' Itasca
152        //   Consulting Group, Inc., Minneapolis, MN, Technical Memorandum ICG6863-L,
153        //   December 7, 2009.]
154        virtual DVect2  getEffectiveTranslationalStiffness() const { return DVect2(knk_,ksk_); }
155
156        // Return a new instance of the contact model. This is used in the CMAT
157        // when a new contact is created. 
158        virtual ContactModelBurger *clone() const override { return NEW ContactModelBurger(); }
159        // The getActivityDistance function is called by the contact-resolution logic when
160        // the CMAT is modified. Return value is the activity distance used by the
161        // checkActivity function.
162        virtual double              getActivityDistance() const {return 0.0;}
163        // The isOKToDelete function is called by the contact-resolution logic when...
164        // Return value indicates whether or not the contact may be deleted.
165        // If TRUE, then the contact may be deleted when it is inactive.
166        // If FALSE, then the contact may not be deleted (under any condition).
167        virtual bool                isOKToDelete() const { return !isBonded(); }
168        // Zero the forces and moments stored in the contact model. This function is called
169        // when the contact becomes inactive.
170        virtual void                resetForcesAndMoments() { force_.fill(0.0);}
171        virtual void                setForce(const DVect &v,IContact *) { force_ = v; }
172        virtual void                setArea(const double &) { throw Exception("The setArea method cannot be used with this contact model."); }
173        virtual double              getArea() const { return 0.0; }
174        // The checkActivity function is called by the contact-resolution logic when...
175        // Return value indicates contact activity (TRUE: active, FALSE: inactive).
176        virtual bool     checkActivity(const double &gap) { return  gap <= 0.0; }
177
178        // Returns the sliding state (FALSE is returned if not implemented).
179        virtual bool     isSliding() const { return s_; }
180        // Returns the bonding state (FALSE is returned if not implemented).
181        virtual bool     isBonded() const { return false; }
182
183        virtual bool    endPropertyUpdated(const QString &,const IContactMechanical *) {return false;}
184       // Both of these methods are called only for contacts with facets where the wall 
185        // resolution scheme is set the full. In such cases one might wish to propagate 
186        // contact state information (e.g., shear force) from one active contact to another. 
187        // See the Faceted Wall section in the documentation. 
188        virtual void     propagateStateInformation(IContactModelMechanical* oldCm,const CAxes &oldSystem=CAxes(),const CAxes &newSystem=CAxes());
189        virtual void     setNonForcePropsFrom(IContactModel *oldCM);
190
191        /// Return the total force that the contact model holds.
192        virtual DVect    getForce() const;
193
194        /// Return the total moment on 1 that the contact model holds
195        virtual DAVect   getMomentOn1(const IContactMechanical *) const;
196
197        /// Return the total moment on 1 that the contact model holds
198        virtual DAVect   getMomentOn2(const IContactMechanical *) const;
199        
200        virtual DAVect getModelMomentOn1() const;
201        virtual DAVect getModelMomentOn2() const;
202
203        // Used to efficiently get properties from the contact model for the object pane.
204        // List of properties for the object pane, comma separated.
205        // All properties will be cast to doubles for comparison. No other comparisons
206        // are supported. This may not be the same as the entire property list.
207        // Return property name and type for plotting.
208        void objectPropsTypes(std::vector<std::pair<QString,InfoTypes>> *) const override;
209        // All properties cast to doubles - this is what can be compared. 
210        void objectPropValues(std::vector<double> *,const IContact *) const override;
211   
212        // Methods to get and set properties. 
213        const double & knk() const {return knk_;}
214        void           knk(const double &d) {knk_=d;}
215        const double & cnk() const {return cnk_;}
216        void           cnk(const double &d) {cnk_=d;}
217        const double & knm() const {return knm_;}
218        void           knm(const double &d) {knm_=d;}
219        const double & cnm() const {return cnm_;}
220        void           cnm(const double &d) {cnm_=d;}
221        const double & ksk() const {return ksk_;}
222        void           ksk(const double &d) {ksk_=d;}
223        const double & csk() const {return csk_;}
224        void           csk(const double &d) {csk_=d;}
225        const double & ksm() const {return ksm_;}
226        void           ksm(const double &d) {ksm_=d;}
227        const double & csm() const {return csm_;}
228        void           csm(const double &d) {csm_=d;}
229
230        const double & fric() const { return fric_;}
231        void           fric(const double &d) {fric_=d;}
232        uint32           bmode() const {return bmode_;}
233        void           bmode(uint32 b) {bmode_= b;}
234
235        const double & fn0() const { return fn0_;}
236        void           fn0(const double &d) {fn0_=d;}
237        const double & u_n0() const { return u_n0_;}
238        void           u_n0(const double &d) {u_n0_=d;}
239        const double & u_nk0() const { return u_nk0_;}
240        void           u_nk0(const double &d) {u_nk0_=d;}
241        const DVect &  u_sk() const { return u_sk_;}
242        void           u_sk(const DVect &v) {u_sk_=v;}
243
244        const double & conAn() const { return conAn_;}
245        void           conAn(const double &d) {conAn_=d;}
246        const double & conB_An() const { return conB_An_;}
247        void           conB_An(const double &d) {conB_An_=d;}
248        const double & conCn() const { return conCn_;}
249        void           conCn(const double &d) {conCn_=d;}
250        const double & conDn() const { return conDn_;}
251        void           conDn(const double &d) {conDn_=d;}
252
253        const double & conAs() const { return conAs_;}
254        void           conAs(const double &d) {conAs_=d;}
255        const double & conB_As() const { return conB_As_;}
256        void           conB_As(const double &d) {conB_As_=d;}
257        const double & conCs() const { return conCs_;}
258        void           conCs(const double &d) {conCs_=d;}
259        const double & conDs() const { return conDs_;}
260        void           conDs(const double &d) {conDs_=d;}
261
262        const double & tdel() const { return tdel_;}
263        void           tdel(const double &d) {tdel_=d;}
264        const DVect &  force() const { return force_;}
265        void           force(const DVect &v) {force_=v;}
266        bool           s() const {return s_;}
267        void           s(bool b) {s_= b;}
268
269    private:
270        // Index - used internally by PFC. Should be set to -1 in the cpp file. 
271        static int index_;
272
273        // Burger model properties
274        double  knk_ = 0.0;     // normal stiffness for Kelvin section  (bur_knk)
275        double  cnk_ = 0.0;     // normal viscosity for Kelvin section  (bur_cnk)
276        double  knm_ = 0.0;     // normal stiffness for Maxwell section (bur_knm)
277        double  cnm_ = 0.0;     // normal viscosity for Maxwell section (bur_cnm)
278        double  ksk_ = 0.0;     // shear stiffness for Kelvin section   (bur_ksk)
279        double  csk_ = 0.0;     // shear viscosity for Kelvin section   (bur_csk)
280        double  ksm_ = 0.0;     // shear stiffness for Maxwell section  (bur_ksm)
281        double  csm_ = 0.0;     // shear viscosity for Maxwell section  (bur_csm)
282        double  fric_ = 0.0;    // friction coefficient                 (bur_fric)
283        uint32    bmode_ = 0;   // FDLaw option, with or without tensile force, default false (with tensile)
284        double  fn0_ = 0.0;     // normal contact force 1 step before
285        double  u_n0_ = 0.0;    // normal total overlap 1 step before
286        double  u_nk0_ = 0.0;   // normal overlap of Kelvin part 1step before
287        DVect   u_sk_ = DVect(0.0);    // shear relative displacement of Kelvin part 1step before
288        double  conAn_ = 0.0;   // constant A in eq.(), normal
289        double  conB_An_ = 0.0; // constant B/A in eq.(), normal
290        double  conCn_ = 0.0;   // constant C in eq.(), normal
291        double  conDn_ = 0.0;   // constant D in eq.(), normal
292        double  conAs_ = 0.0;   // constant A in eq.(), shear
293        double  conB_As_ = 0.0; // constant B/A in eq.(), shear
294        double  conCs_ = 0.0;   // constant C in eq.(), shear
295        double  conDs_ = 0.0;   // constant D in eq.(), shear
296        double  tdel_ = 0.0;    // current timestep
297        DVect   force_ = DVect(0.0);   // current total force
298        bool    s_ = false;       // current sliding state
299
300        // Constants
301        inline double A(const double k_k, const double c_k) {    return(1.0 + k_k*tdel_/(2.0*c_k)); }
302        inline double B(const double k_k, const double c_k) { return(1.0 - k_k*tdel_/(2.0*c_k)); }
303        inline double B_A(const double k_k, const double c_k) { return(B(k_k,c_k)/A(k_k,c_k)); }
304        inline double C(const double k_k, const double c_k, const double k_m, const double c_m) {
305          return(tdel_/(2.0*c_k*A(k_k,c_k)) + 1.0/k_m + tdel_/(2.0*c_m)); }
306        inline double D(const double k_k, const double c_k, const double k_m, const double c_m) {
307          return(tdel_/(2.0*c_k*A(k_k,c_k)) - 1.0/k_m + tdel_/(2.0*c_m)); }
308
309    };
310} // namespace cmodelsxd
311// EoF

Top

contactmodelburger.cpp

  1// contactmodelburger.cpp
  2#include "contactmodelburger.h"
  3
  4#include "module/interface/icontactmechanical.h"
  5#include "module/interface/icontact.h"
  6#include "module/interface/ifishcalllist.h"
  7#include "fish/src/parameter.h"
  8
  9#include "../version.txt"
 10
 11#include "shared/src/mathutil.h"
 12
 13#include "kernel/interface/iprogram.h"
 14
 15#ifdef BURGER_LIB
 16#ifdef _WIN32
 17    int __stdcall DllMain(void *,unsigned, void *) {
 18        return 1;
 19    }
 20#endif
 21
 22    extern "C" EXPORT_TAG const char *getName() {
 23#if DIM==3
 24        return "contactmodelmechanical3dburger";
 25#else
 26        return "contactmodelmechanical2dburger";
 27#endif
 28    }
 29
 30    extern "C" EXPORT_TAG unsigned getMajorVersion() {
 31        return MAJOR_VERSION;
 32    }
 33
 34    extern "C" EXPORT_TAG unsigned getMinorVersion() {
 35        return MINOR_VERSION;
 36    }
 37
 38    extern "C" EXPORT_TAG void *createInstance() {
 39        cmodelsxd::ContactModelBurger *m = NEW cmodelsxd::ContactModelBurger();
 40        return (void *)m;
 41    }
 42#endif 
 43
 44namespace cmodelsxd {
 45    using namespace itasca;
 46
 47    int ContactModelBurger::index_ = -1;
 48    uint32 ContactModelBurger::getMinorVersion() const { return MINOR_VERSION; }
 49
 50    ContactModelBurger::ContactModelBurger() {  
 51    }
 52    
 53    ContactModelBurger::ContactModelBurger(const ContactModelBurger &m) noexcept {
 54        this->copy(&m);
 55    }
 56    
 57    const ContactModelBurger & ContactModelBurger::operator=(const ContactModelBurger &m) {
 58        this->copy(&m);
 59        return *this;
 60    }
 61    
 62    void ContactModelBurger::addToStorage(poly::vector<ContactModelMechanical> *s,int ww) { 
 63        s->addToStorage<ContactModelBurger>(*this,ww);
 64    }
 65
 66    ContactModelBurger::~ContactModelBurger() {
 67    }
 68
 69    void ContactModelBurger::archive(ArchiveStream &stream) {
 70        // The stream allows one to archive the values of the contact model
 71        // so that it can be saved and restored. The minor version can be
 72        // used here to allow for incremental changes to the contact model too. 
 73        stream & knk_;     
 74        stream & cnk_;     
 75        stream & knm_;     
 76        stream & cnm_;     
 77        stream & ksk_;     
 78        stream & csk_;     
 79        stream & ksm_;     
 80        stream & csm_;       
 81        stream & fric_;    
 82        stream & bmode_;   
 83        stream & fn0_;     
 84        stream & u_n0_;    
 85        stream & u_nk0_;   
 86        stream & u_sk_;    
 87        stream & conAn_;   
 88        stream & conB_An_; 
 89        stream & conCn_;   
 90        stream & conDn_;   
 91        stream & conAs_;   
 92        stream & conB_As_; 
 93        stream & conCs_;   
 94        stream & conDs_;   
 95        stream & tdel_;    
 96        stream & force_;    
 97        stream & s_;    
 98    }
 99
100    void ContactModelBurger::copy(const ContactModel *cm) {
101        // Copy all of the contact model properties. Used in the CMAT 
102        // when a new contact is created. 
103        ContactModelMechanical::copy(cm);
104        const ContactModelBurger *in = dynamic_cast<const ContactModelBurger*>(cm);
105        if (!in) throw std::runtime_error("Internal error: contact model dynamic cast failed.");
106        
107        knk(in->knk());     
108        cnk(in->cnk());     
109        knm(in->knm());     
110        cnm(in->cnm());     
111        ksk(in->ksk());     
112        csk(in->csk());     
113        ksm(in->ksm());     
114        csm(in->csm());     
115        fric(in->fric());    
116        bmode(in->bmode());   
117        fn0(in->fn0());     
118        u_n0(in->u_n0());    
119        u_nk0(in->u_nk0());   
120        u_sk(in->u_sk());    
121        conAn(in->conAn());   
122        conB_An(in->conB_An()); 
123        conCn(in->conCn());   
124        conDn(in->conDn());   
125        conAs(in->conAs());   
126        conB_As(in->conB_As()); 
127        conCs(in->conCs());   
128        conDs(in->conDs());   
129        tdel(in->tdel()); 
130        force(in->force());
131        s(in->s());
132    }
133
134
135    QVariant ContactModelBurger::getProperty(uint32 i,const IContact *) const {
136        // Return the property. The IContact pointer is provided so that 
137        // more complicated properties, depending on contact characteristics,
138        // can be calculated. Not used with the Burger model.  The IContact pointer may be a nullptr!
139        QVariant var;
140        switch (i) {
141        case kwKnK   : return knk_;
142        case kwCnK   : return cnk_;
143        case kwKnM   : return knm_;
144        case kwCnM   : return cnm_;
145        case kwKsK   : return ksk_;
146        case kwCsK   : return csk_;
147        case kwKsM   : return ksm_;
148        case kwCsM   : return csm_;
149        case kwMode  : return bmode_;
150        case kwFric  : return fric_;
151        case kwF     : var.setValue(force_); return var;
152        case kwS     : return s_;
153        }
154        assert(0);
155        return QVariant();
156    }
157
158    bool ContactModelBurger::getPropertyGlobal(uint32 i) const {
159        // Returns whether or not a property is held in the global axis system (TRUE)
160        // or the local system (FALSE). Used by the plotting logic.
161        switch (i) {
162        case kwF:   
163            return false;
164        }
165        return true;
166    }
167
168    bool ContactModelBurger::setProperty(uint32 i,const QVariant &v,IContact *) {
169        // Set a contact model property. Return value indicates that the timestep
170        // should be recalculated. 
171        switch (i) {
172        case kwKnK: {
173                if (!v.canConvert<double>())
174                    throw Exception("bur_knk must be a double.");
175                double val(v.toDouble());
176                if (val<0.0)
177                    throw Exception("Negative bur_knk not allowed.");
178                knk_ = val;
179                return true;
180            }
181        case kwCnK: {
182                if (!v.canConvert<double>())
183                    throw Exception("bur_cnk must be a double.");
184                double val(v.toDouble());
185                if (val<0.0)
186                    throw Exception("Negative bur_cnk not allowed.");
187                cnk_ = val;
188                return true;
189            }
190        case kwKnM: {
191                if (!v.canConvert<double>())
192                    throw Exception("bur_knm must be a double.");
193                double val(v.toDouble());
194                if (val<0.0)
195                    throw Exception("Negative bur_knm not allowed.");
196                knm_ = val;
197                return true;
198            }
199        case kwCnM: {
200                if (!v.canConvert<double>())
201                    throw Exception("bur_cnm must be a double.");
202                double val(v.toDouble());
203                if (val<0.0)
204                    throw Exception("Negative bur_cnm not allowed.");
205                cnm_ = val;
206                return true;
207            }
208        case kwKsK: {
209                if (!v.canConvert<double>())
210                    throw Exception("bur_ksk must be a double.");
211                double val(v.toDouble());
212                if (val<0.0)
213                    throw Exception("Negative bur_ksk not allowed.");
214                ksk_ = val;
215                return true;
216            }
217        case kwCsK: {
218                if (!v.canConvert<double>())
219                    throw Exception("bur_csk must be a double.");
220                double val(v.toDouble());
221                if (val<0.0)
222                    throw Exception("Negative bur_csk not allowed.");
223                csk_ = val;
224                return true;
225            }
226        case kwKsM: {
227                if (!v.canConvert<double>())
228                    throw Exception("bur_ksm must be a double.");
229                double val(v.toDouble());
230                if (val<0.0)
231                    throw Exception("Negative bur_ksm not allowed.");
232                ksm_ = val;
233                return true;
234            }
235        case kwCsM: {
236                if (!v.canConvert<double>())
237                    throw Exception("bur_csm must be a double.");
238                double val(v.toDouble());
239                if (val<0.0)
240                    throw Exception("Negative bur_csm not allowed.");
241                csm_ = val;
242                return true;
243            }
244        case kwMode: {
245                if (!v.canConvert<uint32>())
246                    throw Exception("bur_mode must be 0 (tensile) or 1 (no-tension).");
247                uint32 val(v.toUInt());
248                if (val >1)
249                    throw Exception("bur_mode must be 0 (tensile) or 1 (no-tension).");
250                bmode_ = val;
251                return false;
252            }
253        case kwFric: {
254                if (!v.canConvert<double>())
255                    throw Exception("bur_fric must be a double.");
256                double val(v.toDouble());
257                if (val<0.0)
258                    throw Exception("Negative bur_fric not allowed.");
259                fric_ = val;  
260                return false;
261            }
262        }
263        return false;
264    }
265
266    bool ContactModelBurger::getPropertyReadOnly(uint32 i) const {
267        // Returns TRUE if a property is read only or FALSE otherwise. 
268        switch (i) {
269        case kwF:
270        case kwS:
271            return true;
272        default:
273            break;
274        }
275        return false;
276    }
277
278    bool ContactModelBurger::validate(ContactModelMechanicalState *state,const double &) {
279        // Validate the / Prepare for entry into ForceDispLaw. The validate function is called when:
280        // (1) the contact is created, (2) a property of the contact that returns a true via
281        // the setProperty method has been modified and (3) when a set of cycles is executed
282        // via the {cycle N} command.
283        // Return value indicates contact activity (TRUE: active, FALSE: inactive).
284        return checkActivity(state->gap_);
285    }
286     
287    bool ContactModelBurger::forceDisplacementLaw(ContactModelMechanicalState *state,const double &timestep) {
288        assert(state);
289
290        // Current overlap
291        double overlap = - 1.0*state->gap_;
292        // Relative translational increment
293        DVect trans = state->relativeTranslationalIncrement_;
294        // Correction factor to account for when the contact becomes newly active.
295        // We estimate the time of activity during the timestep when the contact has first 
296        // become active and scale the forces accordingly.
297        double correction = 1.0;
298        // The contact was just activated from an inactive state
299        if (state->activated()) {
300            // Trigger the FISH callback if one is hooked up to the 
301            // contact_activated event.
302            if (cmEvents_[fActivated] >= 0) {
303                // An FArray of QVariant is returned and these will be passed
304                // to the FISH function as an array of FISH symbols as the second
305                // argument to the FISH callback function. 
306                auto c = state->getContact();
307                std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()) };
308                IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
309                fi->setCMFishCallArguments(c,arg,cmEvents_[fActivated]);
310            }
311            // Calculate the correction factor.
312            if (trans.x()) {
313                correction = -1.0*overlap / trans.x();
314                if (correction < 0)
315                    correction = 1.0;
316            }
317        }
318
319        trans*=correction;
320
321        if (timestep!=tdel_) { // re-calculated constants.
322            tdel_ = timestep;
323            // need some protection for divided by zero (k_k c_k k_m c_m = zero)
324            conAn_ = A(knk_, cnk_);
325            double conBn = B(knk_, cnk_);
326            conB_An_ = conBn / conAn_;
327            conCn_ = C(knk_, cnk_, knm_, cnm_);
328            conDn_ = D(knk_, cnk_, knm_, cnm_);
329            conAs_ = A(ksk_, csk_);
330            double conBs = B(ksk_, csk_);
331            conB_As_ = conBs / conAs_;
332            conCs_ = C(ksk_, csk_, ksm_, csm_);
333            conDs_ = D(ksk_, csk_, ksm_, csm_);
334        }
335
336
337        // normal force 
338        force_.rx() = 1.0/conCn_*(overlap-u_n0_+(1.0-conB_An_)*u_nk0_-conDn_*fn0_);
339        if (bmode_ && force_.x()<0.0) force_.rx() = 0.0;
340        u_nk0_ = conB_An_*u_nk0_+timestep/(2.0*cnk_*conAn_)*(force_.x()+fn0_);
341        u_n0_  = overlap;
342        fn0_   = force_.x();
343
344        // Calculate the shear force.
345        DVect sforce(0.0);
346        DVect sforce_old = force_;
347        sforce_old.rx()=0.0;
348        DVect v1 = trans;
349        DVect v2 = u_sk_ * (1.0-conB_As_);
350        DVect v3 = sforce_old * conDs_;
351        sforce = (v1+v2+v3) / conCs_ * (-1.0);
352
353        double d1 = timestep / (2.0*csk_*conAs_);
354        sforce.rx() = 0.0;
355        v1 = sforce + sforce_old;
356        u_sk_ = u_sk_*conB_As_-v1*d1;
357
358        // The canFail flag corresponds to whether or not the contact can undergo non-linear
359        // force-displacement response. If the SOLVE ELASTIC command is given then the 
360        // canFail state is set to FALSE. Otherwise it is always TRUE. 
361        if (state->canFail_) {
362            // Resolve sliding. This is the normal force multiplied by the coefficient of friction.
363            double crit = force_.x() * fric_;
364            crit = max(0.0,crit);
365            // This is the magnitude of the shear force.
366            double sfmag = sforce.mag();
367            // Sliding occurs when the magnitude of the shear force is greater than the 
368            // critical value.
369            if (sfmag > crit) {
370                // Lower the shear force to the critical value for sliding.
371                double rat = crit / sfmag;
372                sforce *= rat;
373                // Handle the slip_change event if one has been hooked up. Sliding has commenced.  
374                if (!s_ && cmEvents_[fSlipChange] >= 0) {
375                    auto c = state->getContact();
376                    std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
377                                                         fish::Parameter()                  };
378                    IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
379                    fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
380                }
381                s_ = true;
382            } else {
383                // Handle the slip_change event if one has been hooked up and
384                // the contact was previously sliding. Sliding has ceased.  
385                if (s_) {
386                    if (cmEvents_[fSlipChange] >= 0) {
387                        auto c = state->getContact();
388                        std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
389                                                             fish::Parameter((qint64)1)      };
390                        IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
391                        fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
392                    }
393                    s_ = false;
394                }
395            }
396        }
397        
398        // Set the shear components of the total force.
399        for (int i=1; i<dim; ++i)
400            force_.rdof(i) = sforce.dof(i);
401        // This is just a sanity check to ensure, in debug mode, that the force isn't wonky. 
402        assert(force_ == force_);
403        return true;
404    }
405
406    void ContactModelBurger::propagateStateInformation(IContactModelMechanical* old,const CAxes &oldSystem,const CAxes &newSystem) {
407        // Only called for contacts with wall facets when the wall resolution scheme
408        // is set to full!
409        // Only do something if the contact model is of the same type
410        if (old->getContactModel()->getName().compare("burger",Qt::CaseInsensitive) == 0 && !isBonded()) {
411            ContactModelBurger *oldCm = (ContactModelBurger *)old;
412#ifdef THREED
413            // Need to rotate just the shear component from oldSystem to newSystem
414
415            // Step 1 - rotate oldSystem so that the normal is the same as the normal of newSystem
416            DVect axis = oldSystem.e1() & newSystem.e1();
417            double c, ang, s;
418            DVect re2;
419            if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
420                axis = axis.unit();
421                c = oldSystem.e1()|newSystem.e1();
422                if (c > 0)
423                    c = std::min(c,1.0);
424                else
425                    c = std::max(c,-1.0);
426                ang = acos(c);
427                s = sin(ang);
428                double t = 1. - c;
429                DMatrix<3,3> rm;
430                rm.get(0,0) = t*axis.x()*axis.x() + c;
431                rm.get(0,1) = t*axis.x()*axis.y() - axis.z()*s;
432                rm.get(0,2) = t*axis.x()*axis.z() + axis.y()*s;
433                rm.get(1,0) = t*axis.x()*axis.y() + axis.z()*s;
434                rm.get(1,1) = t*axis.y()*axis.y() + c;
435                rm.get(1,2) = t*axis.y()*axis.z() - axis.x()*s;
436                rm.get(2,0) = t*axis.x()*axis.z() - axis.y()*s;
437                rm.get(2,1) = t*axis.y()*axis.z() + axis.x()*s;
438                rm.get(2,2) = t*axis.z()*axis.z() + c;
439                re2 = rm*oldSystem.e2();
440            }
441            else
442                re2 = oldSystem.e2();
443            // Step 2 - get the angle between the oldSystem rotated shear and newSystem shear
444            axis = re2 & newSystem.e2();
445            DVect2 tpf;
446            DMatrix<2,2> m;
447            if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
448                axis = axis.unit();
449                c = re2|newSystem.e2();
450                if (c > 0)
451                    c = std::min(c,1.0);
452                else
453                    c = std::max(c,-1.0);
454                ang = acos(c);
455                if (!checktol(axis.x(),newSystem.e1().x(),1.0,100))
456                    ang *= -1;
457                s = sin(ang);
458                m.get(0,0) = c;
459                m.get(1,0) = s;
460                m.get(0,1) = -m.get(1,0);
461                m.get(1,1) = m.get(0,0);
462                tpf = m*DVect2(oldCm->force_.y(),oldCm->force_.z());
463            } else {
464                m.get(0,0) = 1.;
465                m.get(0,1) = 0.;
466                m.get(1,0) = 0.;
467                m.get(1,1) = 1.;
468                tpf = DVect2(oldCm->force_.y(),oldCm->force_.z());
469            }
470            DVect pforce = DVect(0,tpf.x(),tpf.y());
471#else
472            oldSystem;
473            newSystem;
474            DVect pforce = DVect(0,oldCm->force_.y());
475#endif
476            for (int i=1; i<dim; ++i)
477                force_.rdof(i) += pforce.dof(i);
478            oldCm->force_ = DVect(0.0);
479        }
480        assert(force_ == force_);
481    }
482
483    void ContactModelBurger::setNonForcePropsFrom(IContactModel *old) {
484        // Only called for contacts with wall facets when the wall resolution scheme
485        // is set to full!
486        // Only do something if the contact model is of the same type
487        if (old->getName().compare("burger",Qt::CaseInsensitive)) {
488            ContactModelBurger *oldCm = (ContactModelBurger *)old;
489            knk_ = oldCm->knk_;
490            cnk_ = oldCm->cnk_;
491            knm_ = oldCm->knm_;
492            cnm_ = oldCm->cnm_;
493            ksk_ = oldCm->ksk_;
494            csk_ = oldCm->csk_;
495            ksm_ = oldCm->ksm_;
496            csm_ = oldCm->csm_;
497            fric_ = oldCm->fric_;
498            bmode_ = oldCm->bmode_;
499        }
500    }
501
502    DVect ContactModelBurger::getForce() const {
503        DVect ret(force_);
504        return ret;
505    }
506
507    DAVect ContactModelBurger::getMomentOn1(const IContactMechanical *c) const {
508        DVect force = getForce();
509        DAVect ret(0.0);
510        c->updateResultingTorqueOn1Local(force,&ret);
511        return ret;
512    }
513
514    DAVect ContactModelBurger::getMomentOn2(const IContactMechanical *c) const {
515        DVect force = getForce();
516        DAVect ret(0.0);
517        c->updateResultingTorqueOn2Local(force,&ret);
518        return ret;
519    }
520    
521    DAVect ContactModelBurger::getModelMomentOn1() const {
522        DAVect ret(0.0);
523        return ret;
524    }
525    
526    DAVect ContactModelBurger::getModelMomentOn2() const {
527        DAVect ret(0.0);
528        return ret;
529    }
530
531    void ContactModelBurger::objectPropsTypes(std::vector<std::pair<QString,InfoTypes>> *ret) const {
532        ret->clear();
533        ret->push_back({"bur_knk",ScalarInfo});
534        ret->push_back({"bur_cnk",ScalarInfo});
535        ret->push_back({"bur_knm",ScalarInfo});
536        ret->push_back({"bur_cnm",ScalarInfo});
537        ret->push_back({"bur_ksk",ScalarInfo});
538        ret->push_back({"bur_csk",ScalarInfo});
539        ret->push_back({"bur_ksm",ScalarInfo});
540        ret->push_back({"bur_csm",ScalarInfo});
541        ret->push_back({"bur_mode",ScalarInfo});
542        ret->push_back({"bur_fric",ScalarInfo});
543        ret->push_back({"bur_force",VectorInfo});
544        ret->push_back({"bur_slip",ScalarInfo});
545        
546    }
547    
548    void ContactModelBurger::objectPropValues(std::vector<double> *ret,const IContact *) const {
549        ret->clear();
550        ret->push_back(knk_);
551        ret->push_back(cnk_);
552        ret->push_back(knm_);
553        ret->push_back(cnm_);
554        ret->push_back(ksk_);
555        ret->push_back(csk_);
556        ret->push_back(ksm_);
557        ret->push_back(csm_);
558        ret->push_back(bmode_);
559        ret->push_back(fric_);
560        ret->push_back(force_.mag());
561        ret->push_back(s_);
562    }
563
564} // namespace cmodelsxd
565// EoF

Top