PyLiq1.cpp

Go to the documentation of this file.
00001 /* *********************************************************************
00002 **    Module:   PyLiq1.cpp 
00003 **
00004 **    Purpose:  Provide a p-y material that gets pore pressure from a
00005 **                              specified element that contains a PorousFluidSolid.
00006 **
00007 **    Developed by Ross W. Boulanger
00008 **    (C) Copyright 2002, All Rights Reserved.
00009 **
00010 ** ****************************************************************** */
00011 
00012 // $Revision: 1.0
00013 // $Date: 2002/5/15
00014 // $Source: /OpenSees/SRC/material/uniaxial/PyLiq1.cpp
00015 
00016 // Written: RWB
00017 // Created: May 2002
00018 // Revision: A
00019 //
00020 // Description: This file contains the class implementation for PyLiq1
00021 
00022 #include <PyLiq1.h>
00023 #include <NDMaterial.h>
00024 #include <Vector.h>
00025 #include <Channel.h>
00026 #include <math.h>
00027 
00028 // Controls on internal iteration between spring components
00029 const int PYmaxIterations = 20;
00030 const double PYtolerance = 1.0e-12;
00031 
00032 int PyLiq1::loadStage = 0;
00033 Vector PyLiq1::stressV3(3);
00034 
00036 //      Constructor with data
00037 
00038 PyLiq1::PyLiq1(int tag, int classtag, int soil, double p_ult, double y_50,
00039                 double dragratio, double dash_pot, double p_res, 
00040                 int solid_elem1, int solid_elem2, Domain *the_Domain)
00041 :PySimple1(tag, classtag, soil, p_ult, y_50, dragratio, dash_pot),
00042 pRes(p_res), solidElem1(solid_elem1), solidElem2(solid_elem2), theDomain(the_Domain)
00043 {
00044         // Initialize PySimple variables and history variables
00045         //
00046         this->revertToStart();
00047     initialTangent = Tangent;
00048 }
00049 
00051 //      Default constructor
00052 
00053 PyLiq1::PyLiq1()
00054 :PySimple1(), pRes(0.0), solidElem1(0), solidElem2(0), theDomain(0)
00055 {
00056 }
00058 //      Default destructor
00059 PyLiq1::~PyLiq1()
00060 {
00061   // Call PySimple1 destructor even though it does nothing.
00062   //
00063   // PySimple1::~PySimple1();
00064 }
00065 
00067 int 
00068 PyLiq1::setTrialStrain (double newy, double yRate)
00069 {
00070         // Call the base class PySimple1 to take care of the basic p-y behavior.
00071         //
00072         Ty = newy;
00073         PySimple1::setTrialStrain(Ty, yRate);
00074 
00075         // Reset mean consolidation stress if loadStage switched from 0 to 1
00076         //              Note: currently assuming y-axis is vertical, and that the
00077         //              out-of-plane normal stress equals sigma-xx.
00078         //
00079         if(lastLoadStage ==0 && loadStage ==1){
00080 
00081                 meanConsolStress = getEffectiveStress();
00082                 if(meanConsolStress == 0.0){
00083                         opserr << "WARNING meanConsolStress is 0 in solid elements, ru will divide by zero";
00084                         opserr << "PyLiq1: " << endln;
00085                         opserr << "Adjacent solidElems: " << solidElem1 << ", " << solidElem2 << endln;
00086                         exit(-1);
00087                 }
00088         }
00089         lastLoadStage = loadStage;
00090 
00091         // Obtain the mean effective stress from the adjacent solid elements,
00092         //    and calculate ru for scaling of p-y base relation.
00093         //
00094         if(loadStage == 1) {
00095                 double meanStress = getEffectiveStress();
00096                 Tru = 1.0 - meanStress/meanConsolStress;
00097                 if(Tru > 1.0-pRes/PySimple1::pult) Tru = 1.0-pRes/PySimple1::pult;
00098         }
00099         else {
00100                 Tru = 0.0;
00101         }
00102 
00103 
00104         // Call the base class PySimple1 to get basic p-y response,
00105         //
00106         double baseP = PySimple1::getStress();
00107         double baseTangent = PySimple1::getTangent();
00108 
00109         // Check: Only update Hru if not yet converged (avoiding small changes in Tru).
00110         //
00111         Hru = Tru;
00112         if(Ty==Cy && Tp==Cp) { Hru = Cru;}
00113 
00114         // During dilation of the soil (ru dropping), provide a stiff transition
00115         //   between the old and new scaled p-y relations. This avoids illogical
00116         //   hardening of the p-y relation (i.e., negative stiffnesses).
00117         //
00118         if (Hru < Cru){
00119 
00120                 maxTangent = (PySimple1::pult/PySimple1::y50)*(1.0-Cru);
00121 
00122                 //  If unloading, follow the old scaled p-y relation until p=0.
00123                 //
00124                 if(Cy>0.0 && Ty<Cy && baseP>0.0){
00125                         Hru = Cru;
00126                 }
00127                 if(Cy<0.0 && Ty>Cy && baseP<0.0){
00128                         Hru = Cru;
00129                 }
00130                 
00131                 //  If above the stiff transition line (between Tru & Cru scaled surfaces)
00132                 //
00133                 double yref = Cy + baseP*(Cru-Hru)/maxTangent;
00134                 if(Cy>0.0 && Ty>Cy && Ty<yref){
00135                         Hru = 1.0 - (Cp + (Ty-Cy)*maxTangent)/baseP;
00136                 }
00137                 if(Cy<0.0 && Ty<Cy && Ty>yref){
00138                         Hru = 1.0 - (Cp + (Ty-Cy)*maxTangent)/baseP;
00139                 }
00140                 if(Hru > Cru) Hru = Cru;
00141                 if(Hru < Tru) Hru = Tru;
00142 
00143         }
00144 
00145         //  Now set the tangent and Tp values accordingly
00146         //
00147 
00148         Tp = baseP*(1.0-Hru);
00149 //      Tangent = (1.0-Hru)*baseTangent;
00150         if(Hru==Cru || Hru==Tru){
00151                 Tangent = (1.0-Hru)*baseTangent;
00152         }
00153         else {
00154                 Tangent = maxTangent;
00155         }
00156 
00157         return 0;
00158 }
00160 double 
00161 PyLiq1::getStress(void)
00162 {
00163         double dashForce = getStrainRate()*this->getDampTangent();
00164 
00165         // Limit the combined force to pult*(1-ru).
00166         //
00167         double pmax = (1.0-PYtolerance)*PySimple1::pult*(1.0-Hru);
00168 //      double pmax = (1.0-PYtolerance)*PySimple1::pult;
00169         if(fabs(Tp + dashForce) >= pmax)
00170                 return pmax*(Tp+dashForce)/fabs(Tp+dashForce);
00171         else return Tp + dashForce;
00172 
00173 }
00175 double 
00176 PyLiq1::getTangent(void)
00177 {
00178         return this->Tangent;
00179 }
00181 double 
00182 PyLiq1::getInitialTangent(void)
00183 {
00184     return this->initialTangent;
00185 }
00187 double 
00188 PyLiq1::getDampTangent(void)
00189 {
00190         // Call the base class PySimple1 to get basic p-y response,
00191         //    and then scale by (1-ru).
00192         //
00193         double dampTangent = PySimple1::getDampTangent();
00194         return dampTangent*(1.0-Hru);
00195 }
00197 double 
00198 PyLiq1::getStrain(void)
00199 {
00200         double strain = PySimple1::getStrain();
00201     return strain;
00202 }
00204 double 
00205 PyLiq1::getStrainRate(void)
00206 {
00207     double strainrate = PySimple1::getStrainRate();
00208         return strainrate;
00209 }
00211 int 
00212 PyLiq1::commitState(void)
00213 {
00214         // Call the PySimple1 base function to take care of details.
00215         //
00216         PySimple1::commitState();
00217         Cy = Ty;
00218         Cp = Tp;
00219         Cru= Hru;
00220         
00221     return 0;
00222 }
00223 
00225 int 
00226 PyLiq1::revertToLastCommit(void)
00227 {
00228         // reset to committed values
00229     //
00230         PySimple1::revertToLastCommit();
00231         Ty = Cy;
00232         Tp = Cp;
00233         Hru= Cru;
00234 
00235         return 0;
00236 }
00237 
00239 int 
00240 PyLiq1::revertToStart(void)
00241 {
00242         // Call the PySimple1 base function to take care of most details.
00243         //
00244         PySimple1::revertToStart();
00245         Ty = 0.0;
00246         Tp = 0.0;
00247         maxTangent = (PySimple1::pult/PySimple1::y50);
00248         
00249         // Excess pore pressure ratio and pointers
00250         //
00251         Tru = 0.0;
00252         Hru = 0.0;
00253         meanConsolStress = -PySimple1::pult;
00254         lastLoadStage = 0;
00255         loadStage = 0;
00256         if(pRes <= 0.0) pRes = 0.01*PySimple1::pult;
00257         if(pRes > PySimple1::pult) pRes = PySimple1::pult;
00258         elemFlag.assign("NONE");
00259 
00260         // Now get all the committed variables initiated
00261         //
00262         commitState();
00263 
00264     return 0;
00265 }
00266 
00268 double 
00269 PyLiq1::getEffectiveStress(void)
00270 {
00271         // Default value for meanStress
00272         double meanStress = meanConsolStress;
00273         
00274         // if the elemFlag has not been set yet, then set it
00275         //
00276         if(elemFlag.compare("NONE") == 0) {     //string.compare returns zero if equal
00277 
00278                 // if theDomain pointer is nonzero, then set pointers to attached soil elements.
00279                 //
00280                 if(theDomain != 0)
00281                 {       
00282                         Element *theElement1 = theDomain->getElement(solidElem1);
00283                         Element *theElement2 = theDomain->getElement(solidElem2);
00284                         if (theElement1 == 0 || theElement2 == 0) {
00285                                 opserr << "WARNING solid element not found in getEffectiveStress" << endln;
00286                                 opserr << "PyLiq1: " << endln;
00287                                 opserr << "Adjacent solidElems: " << solidElem1 << ", " << solidElem2 << endln;
00288                                 exit(-1);
00289                         }
00290 
00291                         // Check each of the allowable element types, starting with 4NodeQuads
00292                         theQuad1 = dynamic_cast<FourNodeQuad*>(theElement1);
00293                         theQuad2 = dynamic_cast<FourNodeQuad*>(theElement2);
00294                         if(theQuad1 != 0 && theQuad2 != 0) {
00295                                 elemFlag.assign("4NodeQuad");
00296                         }
00297 
00298                         // Check on each other type of allowable element types, only if no successful yet.
00299                         if(elemFlag.compare("NONE") == 0) {     //string.compare returns zero if equal
00300 
00301                                 // try other elements like, 4NodeQuadUP
00302                                 elemFlag.assign("NONE");
00303                         }
00304                         
00305                         // Check on acceptable soil materials
00306                         //
00307                         if(elemFlag.compare("4NodeQuad") == 0) {
00308                                 NDMaterial *theNDM1[4];
00309                                 NDMaterial *theNDM2[4];
00310                                 FluidSolidPorousMaterial *theFSPM1[4];
00311                                 FluidSolidPorousMaterial *theFSPM2[4];
00312                                 int dummy = 0;
00313                                 for (int i=0; i<4; i++) {
00314                                   theNDM1[i] = theQuad1->theMaterial[i];
00315                                   theNDM2[i] = theQuad2->theMaterial[i];
00316                                   theFSPM1[i] = dynamic_cast<FluidSolidPorousMaterial*>(theNDM1[i]);
00317                                   theFSPM2[i] = dynamic_cast<FluidSolidPorousMaterial*>(theNDM2[i]);
00318                                   if(theFSPM1 == 0 || theFSPM2 == 0) dummy = dummy + 1;
00319                                 }
00320                                 if(dummy == 0) elemFlag.append("-FSPM");
00321 
00322                                 // Check other acceptable soil types.
00323                         }
00324 
00325                         if(elemFlag.compare("NONE") == 0) {     // Never obtained a valid pointer set
00326                                 opserr << "WARNING: Adjoining solid elements did not return valid pointers";
00327                                 opserr << "PyLiq1: " << endln;
00328                                 opserr << "Adjacent solidElems: " << solidElem1 << ", " << solidElem2 << endln;
00329                                 exit(-1);
00330                                 return meanStress;
00331                         }
00332         
00333                 }
00334         }
00335         
00336         // Get effective stresses using appropriate pointers in elemFlag not "NONE"
00337         //
00338         if(elemFlag.compare("NONE") != 0) {
00339 
00340                 if(elemFlag.compare("4NodeQuad-FSPM") == 0) {
00341                         meanStress = 0.0;
00342                         Vector *theStressVector = &stressV3;
00343                         double excessPorePressure = 0.0;
00344                         NDMaterial *theNDM;
00345                         FluidSolidPorousMaterial *theFSPM;
00346 
00347                         for(int i=0; i < 4; i++) { 
00348                                 *theStressVector = theQuad1->theMaterial[i]->getStress();
00349                                 meanStress += 2.0*(*theStressVector)[0] + (*theStressVector)[1];
00350                                 *theStressVector = theQuad2->theMaterial[i]->getStress();
00351                                 meanStress += 2.0*(*theStressVector)[0] + (*theStressVector)[1];
00352 
00353                                 theNDM = theQuad1->theMaterial[i];
00354                                 theFSPM= dynamic_cast<FluidSolidPorousMaterial*>(theNDM);
00355                                 excessPorePressure += (theFSPM->trialExcessPressure);
00356                                 theNDM = theQuad2->theMaterial[i];
00357                                 theFSPM= dynamic_cast<FluidSolidPorousMaterial*>(theNDM);
00358                                 excessPorePressure += (theFSPM->trialExcessPressure);
00359                         }
00360                         meanStress = meanStress/(2.0*4.0*3.0);
00361                         excessPorePressure = excessPorePressure/(2.0*4.0);
00362                         meanStress = meanStress - excessPorePressure;
00363 
00364                         return meanStress;
00365                 }
00366 
00367                 else if(elemFlag.compare("4NodeQuadUP-FSPM") == 0) {
00368                         
00369                         // expect to later have UP option on quads
00370 
00371                         return meanStress;
00372                 }
00373                 
00374                 else {  // Never found a matching flag
00375                         opserr << "WARNING: Something wrong with specification of elemFlag in getEffectiveStress";
00376                         opserr << "PyLiq1: " << endln;
00377                         opserr << "Adjacent solidElems: " << solidElem1 << ", " << solidElem2 << endln;
00378                         exit(-1);
00379                         return meanStress;
00380                 }
00381         }
00382 
00383         return meanStress;
00384 }
00385 
00387 int 
00388 PyLiq1::updateParameter(int snum,Information &eleInformation)
00389 {
00390         // TclUpdateMaterialStageCommand will call this routine with the
00391         // command:
00392         //
00393         //      updateMaterialStage - material tag -stage snum
00394         //
00395         // If snum = 0; running linear elastic for soil elements,
00396         //              so excess pore pressure should be zero.
00397         // If snum = 1; running plastic soil element behavior,
00398         //              so this marks the end of the "consol" gravity loading.
00399 
00400         if(snum !=0 && snum !=1){
00401                 opserr << "WARNING updateMaterialStage for PyLiq1 material must be 0 or 1";
00402                 opserr << endln;
00403                 exit(-1);
00404         }
00405         loadStage = snum;
00406 
00407         return 0;
00408 }
00409 
00411 UniaxialMaterial *
00412 PyLiq1::getCopy(void)
00413 {
00414         // Make a new instance of this class and then assign it "this" to make a copy.
00415         //
00416         PyLiq1 *clone;                  // pointer to a PyLiq1 class
00417         clone = new PyLiq1();   // pointer gets a new instance of PyLiq1
00418         *clone = *this;                 // the clone (dereferenced pointer) = dereferenced this.
00419         
00420         return clone;
00421 }
00422 
00424 int 
00425 PyLiq1::sendSelf(int cTag, Channel &theChannel)
00426 {
00427         // I'm following an example by Frank here.
00428         //
00429         int res =0;
00430 
00431         static Vector data(16);
00432 
00433         PySimple1::sendSelf(cTag, theChannel);
00434 
00435         data(0)  = this->getTag();
00436         data(1)  = Ty;
00437         data(2)  = Cy;
00438         data(3)  = Tp;
00439         data(4)  = Cp;
00440         data(5)  = Tangent;
00441         data(6)  = maxTangent;
00442         data(7)  = Tru;
00443         data(8)  = Cru;
00444         data(9)  = Hru;
00445         data(10) = (int)solidElem1;
00446         data(11) = (int)solidElem2;
00447         data(12) = meanConsolStress;
00448         data(13) = (int)loadStage;
00449         data(14) = (int)lastLoadStage;
00450         data(15) = initialTangent;
00451         
00452   res = theChannel.sendVector(this->getDbTag(), cTag, data);
00453   if (res < 0) 
00454     opserr << "PyLiq1::sendSelf() - failed to send data\n";
00455 
00456   return res;
00457 }
00458 
00460 int 
00461 PyLiq1::recvSelf(int cTag, Channel &theChannel, 
00462                                FEM_ObjectBroker &theBroker)
00463 {
00464   int res = 0;
00465 
00466   static Vector data(16);
00467   res = theChannel.recvVector(this->getDbTag(), cTag, data);
00468   
00469   if (res < 0) {
00470       opserr << "PyLiq1::recvSelf() - failed to receive data\n";
00471       this->setTag(0);      
00472   }
00473   else {
00474     this->setTag((int)data(0));
00475 
00476         PySimple1::recvSelf(cTag, theChannel, theBroker);
00477 
00478         Ty    = data(1);
00479         Cy    = data(2);
00480         Tp    = data(3);
00481         Cp    = data(4);
00482         Tangent    = data(5);
00483         maxTangent =data(6);
00484         Tru        = data(7);
00485         Cru        = data(8);
00486         Hru        = data(9);
00487         solidElem1        = (int)data(10);
00488         solidElem2        = (int)data(11);
00489         meanConsolStress  = data(12);
00490         loadStage         = (int)data(13);
00491         lastLoadStage     = (int)data(14);
00492         initialTangent    = data(15);
00493 
00494         // set the trial quantities
00495         this->revertToLastCommit();
00496   }
00497 
00498   return res;
00499 }
00500 
00502 void 
00503 PyLiq1::Print(OPS_Stream &s, int flag)
00504 {
00505     s << "PyLiq1, tag: " << this->getTag() << endln;
00506     s << "  soilType: " << soilType << endln;
00507     s << "  pult: " << pult << endln;
00508     s << "  y50: " << y50 << endln;
00509     s << "  drag: " << drag << endln;
00510         s << "  pResidual: " << pRes << endln;
00511         s << "  dashpot: " << dashpot << endln;
00512         s << "  solidElem1: " << solidElem1 << endln;
00513         s << "  solidElem2: " << solidElem2 << endln;
00514 }
00515 

Generated on Mon Oct 23 15:05:21 2006 for OpenSees by doxygen 1.5.0