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        // Destructor, called when contact is deleted: free allocated memory, etc.
 22        BURGER_EXPORT virtual ~ContactModelBurger();
 23        // Contact model name (used as keyword for commands and FISH).
 24        virtual QString  getName() const { return "burger"; }
 25        // The index provides a quick way to determine the type of contact model.
 26        // Each type of contact model in PFC must have a unique index; this is assigned
 27        // by PFC when the contact model is loaded. This index should be set to -1
 28        virtual void     setIndex(int i) { index_=i;}
 29        virtual int      getIndex() const {return index_;}
 30        // Contact model version number (e.g., MyModel05_1). The version number can be
 31        // accessed during the save-restore operation (within the archive method,
 32        // testing {stream.getRestoreVersion() == getMinorVersion()} to allow for 
 33        // future modifications to the contact model data structure.
 34        virtual uint32     getMinorVersion() const;
 35        // Copy the state information to a newly created contact model.
 36        // Provide access to state information, for use by copy method.
 37        virtual void     copy(const ContactModel *c) override;
 38        // Provide save-restore capability for the state information.
 39        virtual void     archive(ArchiveStream &); 
 40        // Enumerator for the properties.
 41        enum PropertyKeys { 
 42              kwKnK=1
 43            , kwCnK                            
 44            , kwKnM
 45            , kwCnM                            
 46            , kwKsK                            
 47            , kwCsK                            
 48            , kwKsM
 49            , kwCsM                            
 50            , kwMode
 51            , kwFric   
 52            , kwF
 53            , kwS
 54        };
 55        // Contact model property names in a comma separated list. The order corresponds with
 56        // the order of the PropertyKeys enumerator above. One can visualize any of these 
 57        // properties in PFC automatically. 
 58        virtual QString  getProperties() const { 
 59            return "bur_knk"
 60                   ",bur_cnk"
 61                   ",bur_knm"
 62                   ",bur_cnm"
 63                   ",bur_ksk"
 64                   ",bur_csk"
 65                   ",bur_ksm"
 66                   ",bur_csm"
 67                   ",bur_mode"
 68                   ",bur_fric"
 69                   ",bur_force"
 70                   ",bur_slip";
 71        }
 72        // Enumerator for contact model related FISH callback events. 
 73        enum FishCallEvents {
 74            fActivated=0
 75            ,fSlipChange
 76        };
 77        // Contact model FISH callback event names in a comma separated list. The order corresponds with
 78        // the order of the FishCallEvents enumerator above. 
 79        virtual QString  getFishCallEvents() const { 
 80            return 
 81                "contact_activated"
 82                ",slip_change"; 
 83        }
 84
 85        // Return the specified contact model property.
 86        virtual QVariant getProperty(uint32 i,const IContact *) const;
 87        // The return value denotes whether or not the property corresponds to the global
 88        // or local coordinate system (TRUE: global system, FALSE: local system). The
 89        // local system is the contact-plane system (nst) defined as follows.
 90        // If a vector V is expressed in the local system as (Vn, Vs, Vt), then V is
 91        // expressed in the global system as {Vn*nc + Vs*sc + Vt*tc} where where nc, sc
 92        // and tc are unit vectors in directions of the nst axes.
 93        // This is used when rendering contact model properties that are vectors.
 94        virtual bool     getPropertyGlobal(uint32 i) const;
 95        // Set the specified contact model property, ensuring that it is of the correct type
 96        // and within the correct range --- if not, then throw an exception.
 97        // The return value denotes whether or not the update has affected the timestep
 98        // computation (by having modified the translational or rotational tangent stiffnesses).
 99        // If true is returned, then the timestep will be recomputed.
100        virtual bool     setProperty(uint32 i,const QVariant &v,IContact *);
101        // The return value denotes whether or not the property is read-only
102        // (TRUE: read-only, FALSE: read-write).
103        virtual bool     getPropertyReadOnly(uint32 i) const;
104
105        // Prepare for entry into ForceDispLaw. The validate function is called when:
106        // (1) the contact is created, (2) a property of the contact that returns a true via
107        // the setProperty method has been modified and (3) when a set of cycles is executed
108        // via the {cycle N} command.
109        // Return value indicates contact activity (TRUE: active, FALSE: inactive).
110        virtual bool    validate(ContactModelMechanicalState *state,const double &timestep);
111        // The forceDisplacementLaw function is called during each cycle. Given the relative
112        // motion of the two contacting pieces (via
113        //   state->relativeTranslationalIncrement_ (Ddn, Ddss, Ddst)
114        //   state->relativeAngularIncrement_       (Dtt, Dtbs, Dtbt)
115        //     Ddn  : relative normal-displacement increment, Ddn > 0 is opening
116        //     Ddss : relative  shear-displacement increment (s-axis component)
117        //     Ddst : relative  shear-displacement increment (t-axis component)
118        //     Dtt  : relative twist-rotation increment
119        //     Dtbs : relative  bend-rotation increment (s-axis component)
120        //     Dtbt : relative  bend-rotation increment (t-axis component)
121        //       The relative displacement and rotation increments:
122        //         Dd = Ddn*nc + Ddss*sc + Ddst*tc
123        //         Dt = Dtt*nc + Dtbs*sc + Dtbt*tc
124        //       where nc, sc and tc are unit vectors in direc. of the nst axes, respectively.
125        //       [see {Table 1: Contact State Variables} in PFC Model Components:
126        //       Contacts and Contact Models: Contact Resolution]
127        // ) and the contact properties, this function must update the contact force and
128        // moment.
129        //   The force_ is acting on piece 2, and is expressed in the local coordinate system
130        //   (defined in getPropertyGlobal) such that the first component positive denotes
131        //   compression. If we define the moment acting on piece 2 by Mc, and Mc is expressed
132        //   in the local coordinate system (defined in getPropertyGlobal), then we must use the getMechanicalContact()->updateResultingTorquesLocal(...) method to 
133        //   get the total moment. 
134        // The return value indicates the contact activity status (TRUE: active, FALSE:
135        // inactive) during the next cycle.
136        // Additional information:
137        //   * If state->activated() is true, then the contact has just become active (it was
138        //     inactive during the previous time step).
139        //   * Fully elastic behavior is enforced during the SOLVE ELASTIC command by having
140        //     the forceDispLaw handle the case of {state->canFail_ == true}.
141        virtual bool    forceDisplacementLaw(ContactModelMechanicalState *state,const double &timestep);
142        // The getEffectiveXStiffness functions return the translational and rotational
143        // tangent stiffnesses used to compute a stable time step. When a contact is sliding,
144        // the translational tangent shear stiffness is zero (but this stiffness reduction
145        // is typically ignored when computing a stable time step). If the contact model
146        // includes a dashpot, then the translational stiffnesses must be increased (see
147        // Potyondy (2009)).
148        //   [Potyondy, D. 'Stiffness Matrix at a Contact Between Two Clumps,' Itasca
149        //   Consulting Group, Inc., Minneapolis, MN, Technical Memorandum ICG6863-L,
150        //   December 7, 2009.]
151        virtual DVect2  getEffectiveTranslationalStiffness() const { return DVect2(knk_,ksk_); }
152
153        // Return a new instance of the contact model. This is used in the CMAT
154        // when a new contact is created. 
155        virtual ContactModelBurger *clone() const override { return NEWC(ContactModelBurger()); }
156        // The getActivityDistance function is called by the contact-resolution logic when
157        // the CMAT is modified. Return value is the activity distance used by the
158        // checkActivity function.
159        virtual double              getActivityDistance() const {return 0.0;}
160        // The isOKToDelete function is called by the contact-resolution logic when...
161        // Return value indicates whether or not the contact may be deleted.
162        // If TRUE, then the contact may be deleted when it is inactive.
163        // If FALSE, then the contact may not be deleted (under any condition).
164        virtual bool                isOKToDelete() const { return !isBonded(); }
165        // Zero the forces and moments stored in the contact model. This function is called
166        // when the contact becomes inactive.
167        virtual void                resetForcesAndMoments() { force_.fill(0.0);}
168        virtual void                setForce(const DVect &v,IContact *) { force_ = v; }
169        virtual void                setArea(const double &) { throw Exception("The setArea method cannot be used with this contact model."); }
170        virtual double              getArea() const { return 0.0; }
171        // The checkActivity function is called by the contact-resolution logic when...
172        // Return value indicates contact activity (TRUE: active, FALSE: inactive).
173        virtual bool     checkActivity(const double &gap) { return  gap <= 0.0; }
174
175        // Returns the sliding state (FALSE is returned if not implemented).
176        virtual bool     isSliding() const { return s_; }
177        // Returns the bonding state (FALSE is returned if not implemented).
178        virtual bool     isBonded() const { return false; }
179
180        virtual bool    endPropertyUpdated(const QString &,const IContactMechanical *) {return false;}
181       // Both of these methods are called only for contacts with facets where the wall 
182        // resolution scheme is set the full. In such cases one might wish to propagate 
183        // contact state information (e.g., shear force) from one active contact to another. 
184        // See the Faceted Wall section in the documentation. 
185        virtual void     propagateStateInformation(IContactModelMechanical* oldCm,const CAxes &oldSystem=CAxes(),const CAxes &newSystem=CAxes());
186        virtual void     setNonForcePropsFrom(IContactModel *oldCM);
187
188        /// Return the total force that the contact model holds.
189        virtual DVect    getForce(const IContactMechanical *) const;
190
191        /// Return the total moment on 1 that the contact model holds
192        virtual DAVect   getMomentOn1(const IContactMechanical *) const;
193
194        /// Return the total moment on 1 that the contact model holds
195        virtual DAVect   getMomentOn2(const IContactMechanical *) const;
196
197   
198        // Methods to get and set properties. 
199        const double & knk() const {return knk_;}
200        void           knk(const double &d) {knk_=d;}
201        const double & cnk() const {return cnk_;}
202        void           cnk(const double &d) {cnk_=d;}
203        const double & knm() const {return knm_;}
204        void           knm(const double &d) {knm_=d;}
205        const double & cnm() const {return cnm_;}
206        void           cnm(const double &d) {cnm_=d;}
207        const double & ksk() const {return ksk_;}
208        void           ksk(const double &d) {ksk_=d;}
209        const double & csk() const {return csk_;}
210        void           csk(const double &d) {csk_=d;}
211        const double & ksm() const {return ksm_;}
212        void           ksm(const double &d) {ksm_=d;}
213        const double & csm() const {return csm_;}
214        void           csm(const double &d) {csm_=d;}
215
216        const double & fric() const { return fric_;}
217        void           fric(const double &d) {fric_=d;}
218        uint32           bmode() const {return bmode_;}
219        void           bmode(uint32 b) {bmode_= b;}
220
221        const double & fn0() const { return fn0_;}
222        void           fn0(const double &d) {fn0_=d;}
223        const double & u_n0() const { return u_n0_;}
224        void           u_n0(const double &d) {u_n0_=d;}
225        const double & u_nk0() const { return u_nk0_;}
226        void           u_nk0(const double &d) {u_nk0_=d;}
227        const DVect &  u_sk() const { return u_sk_;}
228        void           u_sk(const DVect &v) {u_sk_=v;}
229
230        const double & conAn() const { return conAn_;}
231        void           conAn(const double &d) {conAn_=d;}
232        const double & conB_An() const { return conB_An_;}
233        void           conB_An(const double &d) {conB_An_=d;}
234        const double & conCn() const { return conCn_;}
235        void           conCn(const double &d) {conCn_=d;}
236        const double & conDn() const { return conDn_;}
237        void           conDn(const double &d) {conDn_=d;}
238
239        const double & conAs() const { return conAs_;}
240        void           conAs(const double &d) {conAs_=d;}
241        const double & conB_As() const { return conB_As_;}
242        void           conB_As(const double &d) {conB_As_=d;}
243        const double & conCs() const { return conCs_;}
244        void           conCs(const double &d) {conCs_=d;}
245        const double & conDs() const { return conDs_;}
246        void           conDs(const double &d) {conDs_=d;}
247
248        const double & tdel() const { return tdel_;}
249        void           tdel(const double &d) {tdel_=d;}
250        const DVect &  force() const { return force_;}
251        void           force(const DVect &v) {force_=v;}
252        bool           s() const {return s_;}
253        void           s(bool b) {s_= b;}
254
255    private:
256        // Index - used internally by PFC. Should be set to -1 in the cpp file. 
257        static int index_;
258
259        // Burger model properties
260        double  knk_;     // normal stiffness for Kelvin section  (bur_knk)
261        double  cnk_;     // normal viscosity for Kelvin section  (bur_cnk)
262        double  knm_;     // normal stiffness for Maxwell section (bur_knm)
263        double  cnm_;     // normal viscosity for Maxwell section (bur_cnm)
264        double  ksk_;     // shear stiffness for Kelvin section   (bur_ksk)
265        double  csk_;     // shear viscosity for Kelvin section   (bur_csk)
266        double  ksm_;     // shear stiffness for Maxwell section  (bur_ksm)
267        double  csm_;     // shear viscosity for Maxwell section  (bur_csm)
268        double  fric_;    // friction coefficient                 (bur_fric)
269        uint32    bmode_;   // FDLaw option, with or without tensile force, default false (with tensile)
270        double  fn0_;     // normal contact force 1 step before
271        double  u_n0_;    // normal total overlap 1 step before
272        double  u_nk0_;   // normal overlap of Kelvin part 1step before
273        DVect   u_sk_;    // shear relative displacement of Kelvin part 1step before
274        double  conAn_;   // constant A in eq.(), normal
275        double  conB_An_; // constant B/A in eq.(), normal
276        double  conCn_;   // constant C in eq.(), normal
277        double  conDn_;   // constant D in eq.(), normal
278        double  conAs_;   // constant A in eq.(), shear
279        double  conB_As_; // constant B/A in eq.(), shear
280        double  conCs_;   // constant C in eq.(), shear
281        double  conDs_;   // constant D in eq.(), shear
282        double  tdel_;    // current timestep
283        DVect   force_;   // current total force
284        bool    s_;       // current sliding state
285
286        // Constants
287        inline double A(const double k_k, const double c_k) {    return(1.0 + k_k*tdel_/(2.0*c_k)); }
288        inline double B(const double k_k, const double c_k) { return(1.0 - k_k*tdel_/(2.0*c_k)); }
289        inline double B_A(const double k_k, const double c_k) { return(B(k_k,c_k)/A(k_k,c_k)); }
290        inline double C(const double k_k, const double c_k, const double k_m, const double c_m) {
291          return(tdel_/(2.0*c_k*A(k_k,c_k)) + 1.0/k_m + tdel_/(2.0*c_m)); }
292        inline double D(const double k_k, const double c_k, const double k_m, const double c_m) {
293          return(tdel_/(2.0*c_k*A(k_k,c_k)) - 1.0/k_m + tdel_/(2.0*c_m)); }
294
295    };
296} // namespace cmodelsxd
297// 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/ipiecemechanical.h"
  7#include "module/interface/ipiece.h"
  8#include "module/interface/ifishcalllist.h"
  9#include "fish/src/parameter.h"
 10
 11#include "../version.txt"
 12
 13#include "utility/src/tptr.h"
 14#include "shared/src/mathutil.h"
 15
 16#include "kernel/interface/iprogram.h"
 17#include "module/interface/icontactthermal.h"
 18#include "contactmodel/src/contactmodelthermal.h"
 19
 20#ifdef BURGER_LIB
 21#ifdef _WIN32
 22    int __stdcall DllMain(void *,unsigned, void *) {
 23        return 1;
 24    }
 25#endif
 26
 27    extern "C" EXPORT_TAG const char *getName() {
 28#if DIM==3
 29        return "contactmodelmechanical3dburger";
 30#else
 31        return "contactmodelmechanical2dburger";
 32#endif
 33    }
 34
 35    extern "C" EXPORT_TAG unsigned getMajorVersion() {
 36        return MAJOR_VERSION;
 37    }
 38
 39    extern "C" EXPORT_TAG unsigned getMinorVersion() {
 40        return MINOR_VERSION;
 41    }
 42
 43    extern "C" EXPORT_TAG void *createInstance() {
 44        cmodelsxd::ContactModelBurger *m = NEWC(cmodelsxd::ContactModelBurger());
 45        return (void *)m;
 46    }
 47#endif 
 48
 49namespace cmodelsxd {
 50    using namespace itasca;
 51
 52    int ContactModelBurger::index_ = -1;
 53    uint32 ContactModelBurger::getMinorVersion() const { return MINOR_VERSION;}
 54
 55    ContactModelBurger::ContactModelBurger() :knk_(0.0)      
 56                                             ,cnk_(0.0)      
 57                                             ,knm_(0.0)     
 58                                             ,cnm_(0.0)     
 59                                             ,ksk_(0.0)      
 60                                             ,csk_(0.0)   
 61                                             ,ksm_(0.0)  
 62                                             ,csm_(0.0)  
 63                                             ,fric_(0.0)  
 64                                             ,bmode_(0)  
 65                                             ,fn0_(0.0)  
 66                                             ,u_n0_(0.0)  
 67                                             ,u_nk0_(0.0)  
 68                                             ,u_sk_(0.0) 
 69                                             ,conAn_(0.0) 
 70                                             ,conB_An_(0.0)
 71                                             ,conCn_(0.0)   
 72                                             ,conDn_(0.0)   
 73                                             ,conAs_(0.0) 
 74                                             ,conB_As_(0.0)
 75                                             ,conCs_(0.0)  
 76                                             ,conDs_(0.0) 
 77                                             ,tdel_(0.0) 
 78                                             ,force_(0.0) 
 79                                             ,s_(false) 
 80    {  
 81
 82    }
 83
 84    ContactModelBurger::~ContactModelBurger() {
 85    }
 86
 87    void ContactModelBurger::archive(ArchiveStream &stream) {
 88        // The stream allows one to archive the values of the contact model
 89        // so that it can be saved and restored. The minor version can be
 90        // used here to allow for incremental changes to the contact model too. 
 91        stream & knk_;     
 92        stream & cnk_;     
 93        stream & knm_;     
 94        stream & cnm_;     
 95        stream & ksk_;     
 96        stream & csk_;     
 97        stream & ksm_;     
 98        stream & csm_;       
 99        stream & fric_;    
100        stream & bmode_;   
101        stream & fn0_;     
102        stream & u_n0_;    
103        stream & u_nk0_;   
104        stream & u_sk_;    
105        stream & conAn_;   
106        stream & conB_An_; 
107        stream & conCn_;   
108        stream & conDn_;   
109        stream & conAs_;   
110        stream & conB_As_; 
111        stream & conCs_;   
112        stream & conDs_;   
113        stream & tdel_;    
114        stream & force_;    
115        stream & s_;    
116    }
117
118    void ContactModelBurger::copy(const ContactModel *cm) {
119        // Copy all of the contact model properties. Used in the CMAT 
120        // when a new contact is created. 
121        ContactModelMechanical::copy(cm);
122        const ContactModelBurger *in = dynamic_cast<const ContactModelBurger*>(cm);
123        if (!in) throw std::runtime_error("Internal error: contact model dynamic cast failed.");
124        
125        knk(in->knk());     
126        cnk(in->cnk());     
127        knm(in->knm());     
128        cnm(in->cnm());     
129        ksk(in->ksk());     
130        csk(in->csk());     
131        ksm(in->ksm());     
132        csm(in->csm());     
133        fric(in->fric());    
134        bmode(in->bmode());   
135        fn0(in->fn0());     
136        u_n0(in->u_n0());    
137        u_nk0(in->u_nk0());   
138        u_sk(in->u_sk());    
139        conAn(in->conAn());   
140        conB_An(in->conB_An()); 
141        conCn(in->conCn());   
142        conDn(in->conDn());   
143        conAs(in->conAs());   
144        conB_As(in->conB_As()); 
145        conCs(in->conCs());   
146        conDs(in->conDs());   
147        tdel(in->tdel()); 
148        force(in->force());
149        s(in->s());
150    }
151
152
153    QVariant ContactModelBurger::getProperty(uint32 i,const IContact *) const {
154        // Return the property. The IContact pointer is provided so that 
155        // more complicated properties, depending on contact characteristics,
156        // can be calculated. Not used with the Burger model.
157        QVariant var;
158        switch (i) {
159        case kwKnK   : return knk_;
160        case kwCnK   : return cnk_;
161        case kwKnM   : return knm_;
162        case kwCnM   : return cnm_;
163        case kwKsK   : return ksk_;
164        case kwCsK   : return csk_;
165        case kwKsM   : return ksm_;
166        case kwCsM   : return csm_;
167        case kwMode  : return bmode_;
168        case kwFric  : return fric_;
169        case kwF     : var.setValue(force_); return var;
170        case kwS     : return s_;
171        }
172        assert(0);
173        return QVariant();
174    }
175
176    bool ContactModelBurger::getPropertyGlobal(uint32 i) const {
177        // Returns whether or not a property is held in the global axis system (TRUE)
178        // or the local system (FALSE). Used by the plotting logic.
179        switch (i) {
180        case kwF:   
181            return false;
182        }
183        return true;
184    }
185
186    bool ContactModelBurger::setProperty(uint32 i,const QVariant &v,IContact *) {
187        // Set a contact model property. Return value indicates that the timestep
188        // should be recalculated. 
189        switch (i) {
190        case kwKnK: {
191                if (!v.canConvert<double>())
192                    throw Exception("bur_knk must be a double.");
193                double val(v.toDouble());
194                if (val<0.0)
195                    throw Exception("Negative bur_knk not allowed.");
196                knk_ = val;
197                return true;
198            }
199        case kwCnK: {
200                if (!v.canConvert<double>())
201                    throw Exception("bur_cnk must be a double.");
202                double val(v.toDouble());
203                if (val<0.0)
204                    throw Exception("Negative bur_cnk not allowed.");
205                cnk_ = val;
206                return true;
207            }
208        case kwKnM: {
209                if (!v.canConvert<double>())
210                    throw Exception("bur_knm must be a double.");
211                double val(v.toDouble());
212                if (val<0.0)
213                    throw Exception("Negative bur_knm not allowed.");
214                knm_ = val;
215                return true;
216            }
217        case kwCnM: {
218                if (!v.canConvert<double>())
219                    throw Exception("bur_cnm must be a double.");
220                double val(v.toDouble());
221                if (val<0.0)
222                    throw Exception("Negative bur_cnm not allowed.");
223                cnm_ = val;
224                return true;
225            }
226        case kwKsK: {
227                if (!v.canConvert<double>())
228                    throw Exception("bur_ksk must be a double.");
229                double val(v.toDouble());
230                if (val<0.0)
231                    throw Exception("Negative bur_ksk not allowed.");
232                ksk_ = val;
233                return true;
234            }
235        case kwCsK: {
236                if (!v.canConvert<double>())
237                    throw Exception("bur_csk must be a double.");
238                double val(v.toDouble());
239                if (val<0.0)
240                    throw Exception("Negative bur_csk not allowed.");
241                csk_ = val;
242                return true;
243            }
244        case kwKsM: {
245                if (!v.canConvert<double>())
246                    throw Exception("bur_ksm must be a double.");
247                double val(v.toDouble());
248                if (val<0.0)
249                    throw Exception("Negative bur_ksm not allowed.");
250                ksm_ = val;
251                return true;
252            }
253        case kwCsM: {
254                if (!v.canConvert<double>())
255                    throw Exception("bur_csm must be a double.");
256                double val(v.toDouble());
257                if (val<0.0)
258                    throw Exception("Negative bur_csm not allowed.");
259                csm_ = val;
260                return true;
261            }
262        case kwMode: {
263                if (!v.canConvert<uint32>())
264                    throw Exception("bur_mode must be 0 (tensile) or 1 (no-tension).");
265                uint32 val(v.toUInt());
266                if (val >1)
267                    throw Exception("bur_mode must be 0 (tensile) or 1 (no-tension).");
268                bmode_ = val;
269                return false;
270            }
271        case kwFric: {
272                if (!v.canConvert<double>())
273                    throw Exception("bur_fric must be a double.");
274                double val(v.toDouble());
275                if (val<0.0)
276                    throw Exception("Negative bur_fric not allowed.");
277                fric_ = val;  
278                return false;
279            }
280        }
281        return false;
282    }
283
284    bool ContactModelBurger::getPropertyReadOnly(uint32 i) const {
285        // Returns TRUE if a property is read only or FALSE otherwise. 
286        switch (i) {
287        case kwF:
288        case kwS:
289            return true;
290        default:
291            break;
292        }
293        return false;
294    }
295
296    bool ContactModelBurger::validate(ContactModelMechanicalState *state,const double &) {
297        // Validate the / Prepare for entry into ForceDispLaw. The validate function is called when:
298        // (1) the contact is created, (2) a property of the contact that returns a true via
299        // the setProperty method has been modified and (3) when a set of cycles is executed
300        // via the {cycle N} command.
301        // Return value indicates contact activity (TRUE: active, FALSE: inactive).
302        return checkActivity(state->gap_);
303    }
304     
305    bool ContactModelBurger::forceDisplacementLaw(ContactModelMechanicalState *state,const double &timestep) {
306        assert(state);
307
308        // Current overlap
309        double overlap = - 1.0*state->gap_;
310        // Relative translational increment
311        DVect trans = state->relativeTranslationalIncrement_;
312        // Correction factor to account for when the contact becomes newly active.
313        // We estimate the time of activity during the timestep when the contact has first 
314        // become active and scale the forces accordingly.
315        double correction = 1.0;
316        // The contact was just activated from an inactive state
317        if (state->activated()) {
318            // Trigger the FISH callback if one is hooked up to the 
319            // contact_activated event.
320            if (cmEvents_[fActivated] >= 0) {
321                // An FArray of QVariant is returned and these will be passed
322                // to the FISH function as an array of FISH symbols as the second
323                // argument to the FISH callback function. 
324                auto c = state->getContact();
325                std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()) };
326                IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
327                fi->setCMFishCallArguments(c,arg,cmEvents_[fActivated]);
328            }
329            // Calculate the correction factor.
330            if (trans.x()) {
331                correction = -1.0*overlap / trans.x();
332                if (correction < 0)
333                    correction = 1.0;
334            }
335        }
336
337        trans*=correction;
338
339        if (timestep!=tdel_) { // re-calculated constants.
340            tdel_ = timestep;
341            // need some protection for divided by zero (k_k c_k k_m c_m = zero)
342            conAn_ = A(knk_, cnk_);
343            double conBn = B(knk_, cnk_);
344            conB_An_ = conBn / conAn_;
345            conCn_ = C(knk_, cnk_, knm_, cnm_);
346            conDn_ = D(knk_, cnk_, knm_, cnm_);
347            conAs_ = A(ksk_, csk_);
348            double conBs = B(ksk_, csk_);
349            conB_As_ = conBs / conAs_;
350            conCs_ = C(ksk_, csk_, ksm_, csm_);
351            conDs_ = D(ksk_, csk_, ksm_, csm_);
352        }
353
354
355        // normal force 
356        force_.rx() = 1.0/conCn_*(overlap-u_n0_+(1.0-conB_An_)*u_nk0_-conDn_*fn0_);
357        if (bmode_ && force_.x()<0.0) force_.rx() = 0.0;
358        u_nk0_ = conB_An_*u_nk0_+timestep/(2.0*cnk_*conAn_)*(force_.x()+fn0_);
359        u_n0_  = overlap;
360        fn0_   = force_.x();
361
362        // Calculate the shear force.
363        DVect sforce(0.0);
364        DVect sforce_old = force_;
365        sforce_old.rx()=0.0;
366        DVect v1 = trans;
367        DVect v2 = u_sk_ * (1.0-conB_As_);
368        DVect v3 = sforce_old * conDs_;
369        sforce = (v1+v2+v3) / conCs_ * (-1.0);
370
371        double d1 = timestep / (2.0*csk_*conAs_);
372        sforce.rx() = 0.0;
373        v1 = sforce + sforce_old;
374        u_sk_ = u_sk_*conB_As_-v1*d1;
375
376        // The canFail flag corresponds to whether or not the contact can undergo non-linear
377        // force-displacement response. If the SOLVE ELASTIC command is given then the 
378        // canFail state is set to FALSE. Otherwise it is always TRUE. 
379        if (state->canFail_) {
380            // Resolve sliding. This is the normal force multiplied by the coefficient of friction.
381            double crit = force_.x() * fric_;
382            crit = max(0.0,crit);
383            // This is the magnitude of the shear force.
384            double sfmag = sforce.mag();
385            // Sliding occurs when the magnitude of the shear force is greater than the 
386            // critical value.
387            if (sfmag > crit) {
388                // Lower the shear force to the critical value for sliding.
389                double rat = crit / sfmag;
390                sforce *= rat;
391                // Handle the slip_change event if one has been hooked up. Sliding has commenced.  
392                if (!s_ && cmEvents_[fSlipChange] >= 0) {
393                    auto c = state->getContact();
394                    std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
395                                                         fish::Parameter()                  };
396                    IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
397                    fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
398                }
399                s_ = true;
400            } else {
401                // Handle the slip_change event if one has been hooked up and
402                // the contact was previously sliding. Sliding has ceased.  
403                if (s_) {
404                    if (cmEvents_[fSlipChange] >= 0) {
405                        auto c = state->getContact();
406                        std::vector<fish::Parameter> arg = { fish::Parameter(c->getIThing()),
407                                                             fish::Parameter((qint64)1)      };
408                        IFishCallList *fi = const_cast<IFishCallList*>(state->getProgram()->findInterface<IFishCallList>());
409                        fi->setCMFishCallArguments(c,arg,cmEvents_[fSlipChange]);
410                    }
411                    s_ = false;
412                }
413            }
414        }
415        
416        // Set the shear components of the total force.
417        for (int i=1; i<dim; ++i)
418            force_.rdof(i) = sforce.dof(i);
419        // This is just a sanity check to ensure, in debug mode, that the force isn't wonky. 
420        assert(force_ == force_);
421        return true;
422    }
423
424    void ContactModelBurger::propagateStateInformation(IContactModelMechanical* old,const CAxes &oldSystem,const CAxes &newSystem) {
425        // Only called for contacts with wall facets when the wall resolution scheme
426        // is set to full!
427        // Only do something if the contact model is of the same type
428        if (old->getContactModel()->getName().compare("burger",Qt::CaseInsensitive) == 0 && !isBonded()) {
429            ContactModelBurger *oldCm = (ContactModelBurger *)old;
430#ifdef THREED
431            // Need to rotate just the shear component from oldSystem to newSystem
432
433            // Step 1 - rotate oldSystem so that the normal is the same as the normal of newSystem
434            DVect axis = oldSystem.e1() & newSystem.e1();
435            double c, ang, s;
436            DVect re2;
437            if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
438                axis = axis.unit();
439                c = oldSystem.e1()|newSystem.e1();
440                if (c > 0)
441                    c = std::min(c,1.0);
442                else
443                    c = std::max(c,-1.0);
444                ang = acos(c);
445                s = sin(ang);
446                double t = 1. - c;
447                DMatrix<3,3> rm;
448                rm.get(0,0) = t*axis.x()*axis.x() + c;
449                rm.get(0,1) = t*axis.x()*axis.y() - axis.z()*s;
450                rm.get(0,2) = t*axis.x()*axis.z() + axis.y()*s;
451                rm.get(1,0) = t*axis.x()*axis.y() + axis.z()*s;
452                rm.get(1,1) = t*axis.y()*axis.y() + c;
453                rm.get(1,2) = t*axis.y()*axis.z() - axis.x()*s;
454                rm.get(2,0) = t*axis.x()*axis.z() - axis.y()*s;
455                rm.get(2,1) = t*axis.y()*axis.z() + axis.x()*s;
456                rm.get(2,2) = t*axis.z()*axis.z() + c;
457                re2 = rm*oldSystem.e2();
458            }
459            else
460                re2 = oldSystem.e2();
461            // Step 2 - get the angle between the oldSystem rotated shear and newSystem shear
462            axis = re2 & newSystem.e2();
463            DVect2 tpf;
464            DMatrix<2,2> m;
465            if (!checktol(axis.abs().maxComp(),0.0,1.0,1000)) {
466                axis = axis.unit();
467                c = re2|newSystem.e2();
468                if (c > 0)
469                    c = std::min(c,1.0);
470                else
471                    c = std::max(c,-1.0);
472                ang = acos(c);
473                if (!checktol(axis.x(),newSystem.e1().x(),1.0,100))
474                    ang *= -1;
475                s = sin(ang);
476                m.get(0,0) = c;
477                m.get(1,0) = s;
478                m.get(0,1) = -m.get(1,0);
479                m.get(1,1) = m.get(0,0);
480                tpf = m*DVect2(oldCm->force_.y(),oldCm->force_.z());
481            } else {
482                m.get(0,0) = 1.;
483                m.get(0,1) = 0.;
484                m.get(1,0) = 0.;
485                m.get(1,1) = 1.;
486                tpf = DVect2(oldCm->force_.y(),oldCm->force_.z());
487            }
488            DVect pforce = DVect(0,tpf.x(),tpf.y());
489#else
490            oldSystem;
491            newSystem;
492            DVect pforce = DVect(0,oldCm->force_.y());
493#endif
494            for (int i=1; i<dim; ++i)
495                force_.rdof(i) += pforce.dof(i);
496            oldCm->force_ = DVect(0.0);
497        }
498        assert(force_ == force_);
499    }
500
501    void ContactModelBurger::setNonForcePropsFrom(IContactModel *old) {
502        // Only called for contacts with wall facets when the wall resolution scheme
503        // is set to full!
504        // Only do something if the contact model is of the same type
505        if (old->getName().compare("burger",Qt::CaseInsensitive)) {
506            ContactModelBurger *oldCm = (ContactModelBurger *)old;
507            knk_ = oldCm->knk_;
508            cnk_ = oldCm->cnk_;
509            knm_ = oldCm->knm_;
510            cnm_ = oldCm->cnm_;
511            ksk_ = oldCm->ksk_;
512            csk_ = oldCm->csk_;
513            ksm_ = oldCm->ksm_;
514            csm_ = oldCm->csm_;
515            fric_ = oldCm->fric_;
516            bmode_ = oldCm->bmode_;
517        }
518    }
519
520    DVect ContactModelBurger::getForce(const IContactMechanical *) const {
521        DVect ret(force_);
522        return ret;
523    }
524
525    DAVect ContactModelBurger::getMomentOn1(const IContactMechanical *c) const {
526        DVect force = getForce(c);
527        DAVect ret(0.0);
528        c->updateResultingTorqueOn1Local(force,&ret);
529        return ret;
530    }
531
532    DAVect ContactModelBurger::getMomentOn2(const IContactMechanical *c) const {
533        DVect force = getForce(c);
534        DAVect ret(0.0);
535        c->updateResultingTorqueOn2Local(force,&ret);
536        return ret;
537    }
538
539} // namespace cmodelsxd
540// EoF

Top