// calculate tractions on one side of crack for this segment // add forces to material velocity fields on one side of the crack double CrackSegment::AddTractionForceSegSide(CrackHeader *theCrack,int side,double sign) { int numnds,nds[maxShapeNodes]; double fn[maxShapeNodes]; short vfld; double fnorm = 0.; NodalPoint *ndi; int cnum=theCrack->GetNumber(); Vector cspos = MakeVector(surfx[side-1], surfy[side-1], 0.); const ElementBase *elref = theElements[surfInElem[side-1]]; elref->GetShapeFunctionsForCracks(&numnds,fn,nds,&cspos); // loop over all nodes seen by this crack surface particle for(int i=1;i<=numnds;i++) { // Get velocity field to use ndi = nd[nds[i]]; vfld = ndi->GetFieldForSurfaceParticle(side,cnum,this); // if has particles (and they see cracks), add force and track normalization if(vfld>=0) { ndi->AddFtotSpreadTask3(vfld,FTract(sign*fn[i])); fnorm += fn[i]; } } // return amount used return fnorm; }
// Get mass matrix, find dimensionless particle locations, // and find grid momenta void PostForcesTask::Execute(void) { // Add traction BCs on particles MatPtTractionBC::SetParticleSurfaceTractions(mtime); // Add traction law forces to velocity fields if(fmobj->hasTractionCracks) { CrackHeader *nextCrack=firstCrack; while(nextCrack!=NULL) { nextCrack->AddTractionForce(); nextCrack=(CrackHeader *)nextCrack->GetNextObject(); } } // Add crack tip heating adds to conduction force if(conduction) conduction->AddCrackTipHeating(); // Add interface forces to velocity fields and track total interface energy NodalPoint::interfaceEnergy=0.; CrackNode::CrackInterfaceOnKnownNodes(); MaterialInterfaceNode::MaterialInterfaceOnKnownNodes(); // Add gravity and body forces (if any are present) // Note: If ever need to implement body force that depend on particle state (stress, strain, etc.) // then move the body force addition into GridForcesTask loop where gravity is commented out // When used to keep Fext, this section would all add fint and fext to get ftot (and it was always needed) Vector gridBodyForce; if(bodyFrc.gravity || bodyFrc.hasGridBodyForce) { for(int i=1;i<=nnodes;i++) { NodalPoint *ndptr = nd[i]; bodyFrc.GetGridBodyForce(&gridBodyForce,ndptr,mtime); ndptr->AddGravityAndBodyForceTask3(&gridBodyForce); } } // Impose BCs on ftot to get correct grid BCs for velocity NodalVelBC::ConsistentGridForces(); // Do similar to transport property BCs (not parallel because small and possible use of function/global variables) TransportTask *nextTransport=transportTasks; while(nextTransport!=NULL) nextTransport=nextTransport->SetTransportForceBCs(timestep); }
// Update grid momenta and transport rates void UpdateMomentaTask::Execute(void) { CommonException *umErr = NULL; #pragma omp parallel for for(int i=1;i<=nnodes;i++) { NodalPoint *ndptr = nd[i]; ndptr->UpdateMomentaOnNode(timestep); // get grid transport rates (update transport properties when particle state updated) // do first so both material and crack contact will have actual rates TransportTask *nextTransport=transportTasks; while(nextTransport!=NULL) nextTransport=nextTransport->TransportRates(ndptr,timestep); // material contact if(fmobj->multiMaterialMode) { try { ndptr->MaterialContactOnNode(timestep,UPDATE_MOMENTUM_CALL,NULL,NULL); } catch(CommonException err) { if(umErr==NULL) { #pragma omp critical umErr = new CommonException(err); } } } } // throw error now if(umErr!=NULL) throw *umErr; // adjust momenta and forces for crack contact on known nodes CrackNode::CrackContactTask4(timestep); }
// allocate crack and material velocity fields needed for time step on real nodes // tried critical sections when nodes changed, but it was slower // can't use ghost nodes, because need to test all on real nodes // // This task only used if have cracks or in multimaterial mode void InitVelocityFieldsTask::Execute(void) { CommonException *initErr = NULL; int tp = fmobj->GetTotalNumberOfPatches(); #pragma omp parallel { int nds[maxShapeNodes]; double fn[maxShapeNodes]; int pn = GetPatchNumber(); // do non-rigid and rigid contact materials in patch pn for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_CONTACT;block++) { // get material point (only in this patch) MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(block); while(mpmptr!=NULL) { const MaterialBase *matID = theMaterials[mpmptr->MatID()]; // material object for this particle const int matfld = matID->GetField(); // material velocity field // get nodes and shape function for material point p const ElementBase *elref = theElements[mpmptr->ElemID()]; // element containing this particle // don't actually need shape functions, but need to screen out zero shape function // like done in subsequent tasks, otherwise node numbers will not align correctly // only thing used from return are numnds and nds int numnds; elref->GetShapeFunctions(&numnds,fn,nds,mpmptr); // Only need to decipher crack velocity field if has cracks (firstCrack!=NULL) // and if this material allows cracks. #ifdef COMBINE_RIGID_MATERIALS bool decipherCVF = firstCrack!=NULL && block!=FIRST_RIGID_CONTACT; #else bool decipherCVF = firstCrack!=NULL; #endif // Check each node for(int i=1;i<=numnds;i++) { // use real node in this loop NodalPoint *ndptr = nd[nds[i]]; // always zero when no cracks (or when ignoring cracks) short vfld = 0; // If need, find vlocity field and for each field set location // (above or below crack) and crack number (1 based) or 0 for NO_CRACK if(decipherCVF) { // in CRAMP, find crack crossing and appropriate velocity field CrackField cfld[2]; cfld[0].loc = NO_CRACK; // NO_CRACK=0, ABOVE_CRACK=1, or BELOW_CRACK=2 cfld[1].loc = NO_CRACK; int cfound=0; Vector norm; // track normal vector for crack plane CrackHeader *nextCrack = firstCrack; while(nextCrack!=NULL) { vfld = nextCrack->CrackCross(mpmptr->pos.x,mpmptr->pos.y,ndptr->x,ndptr->y,&norm); if(vfld!=NO_CRACK) { cfld[cfound].loc=vfld; cfld[cfound].norm=norm; #ifdef IGNORE_CRACK_INTERACTIONS // appears to always be same crack, and stop when found one cfld[cfound].crackNum=1; break; #endif // Get crack number (default code does not ignore interactions) cfld[cfound].crackNum=nextCrack->GetNumber(); cfound++; // stop if found two because code can only handle two interacting cracks // It exits loop now to go ahead with the first two found, by physics may be off if(cfound>1) break; } nextCrack=(CrackHeader *)nextCrack->GetNextObject(); } // find (and allocate if needed) the velocity field // Use vfld=0 if no cracks found if(cfound>0) { // In parallel, this is critical code #pragma omp critical { try { vfld = ndptr->AddCrackVelocityField(matfld,cfld); } catch(CommonException err) { if(initErr==NULL) initErr = new CommonException(err); } } } // set material point velocity field for this node mpmptr->vfld[i] = vfld; } // make sure material velocity field is created too // (Note: when maxMaterialFields==1 (Singe Mat Mode), mvf[0] is always there // so no need to create it here) if(maxMaterialFields>1 && ndptr->NeedsMatVelocityField(vfld,matfld)) { // If parallel, this is critical code #pragma omp critical { try { ndptr->AddMatVelocityField(vfld,matfld); } catch(CommonException err) { if(initErr==NULL) initErr = new CommonException(err); } } } } // next material point mpmptr = (MPMBase *)mpmptr->GetNextObject(); } } } // was there an error? if(initErr!=NULL) throw *initErr; // copy crack and material fields on real nodes to ghost nodes if(tp>1) { for(int pn=0;pn<tp;pn++) patches[pn]->InitializationReduction(); } }
// Get mass matrix, find dimensionless particle locations, // and find grid momenta void InitializationTask::Execute(void) { CommonException *initErr = NULL; // Zero Mass Matrix and vectors warnings.BeginStep(); int tp = fmobj->GetTotalNumberOfPatches(); #pragma omp parallel { // zero all nodal variables on real nodes #pragma omp for for(int i=1;i<=nnodes;i++) nd[i]->InitializeForTimeStep(); // zero ghost nodes in patch for this thread int pn = GetPatchNumber(); patches[pn]->InitializeForTimeStep(); // particle calculations get xipos for particles and if doing CPDI // precalculate CPDI info needed for subsequent shape functions #pragma omp for nowait for(int p=0;p<nmpmsRC;p++) { MPMBase *mpmptr = mpm[p]; // pointer const ElementBase *elref = theElements[mpmptr->ElemID()]; // element containing this particle try { elref->GetShapeFunctionData(mpmptr); } catch(CommonException err) { if(initErr==NULL) { #pragma omp critical initErr = new CommonException(err); } } } } // was there an error? if(initErr!=NULL) throw *initErr; // allocate crack and material velocity fields needed for time step on real nodes // tried critical sections when nodes changed, but it was slower // can't use ghost nodes, because need to test all on real nodes if(firstCrack!=NULL || maxMaterialFields>1) { #pragma omp parallel { int nds[maxShapeNodes]; double fn[maxShapeNodes]; //for(int pn=0;pn<tp;pn++) { int pn = GetPatchNumber(); // do non-rigid and rigid contact materials in patch pn for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_CONTACT;block++) { // get material point (only in this patch) MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(block); while(mpmptr!=NULL) { const MaterialBase *matID = theMaterials[mpmptr->MatID()]; // material object for this particle const int matfld = matID->GetField(); // material velocity field // get nodes and shape function for material point p const ElementBase *elref = theElements[mpmptr->ElemID()]; // element containing this particle // don't actually need shape functions, but need to screen out zero shape function // like done in subsequent tasks, otherwise node numbers will not align correctly // only think used from return are numnds and nds int numnds; elref->GetShapeFunctions(&numnds,fn,nds,mpmptr); // Add particle property to each node in the element for(int i=1;i<=numnds;i++) { // use real node in this loop NodalPoint *ndptr = nd[nds[i]]; // always zero when no cracks short vfld = 0; #ifdef COMBINE_RIGID_MATERIALS // when combining rigid particles, extrapolate all to field 0 and later // copy to other active fields if(firstCrack!=NULL && block!=FIRST_RIGID_CONTACT) #else if(firstCrack!=NULL) #endif { // in CRAMP, find crack crossing and appropriate velocity field CrackField cfld[2]; cfld[0].loc = NO_CRACK; // NO_CRACK, ABOVE_CRACK, or BELOW_CRACK cfld[1].loc = NO_CRACK; int cfound=0; Vector norm; CrackHeader *nextCrack = firstCrack; while(nextCrack!=NULL) { vfld = nextCrack->CrackCross(mpmptr->pos.x,mpmptr->pos.y,ndptr->x,ndptr->y,&norm); if(vfld!=NO_CRACK) { cfld[cfound].loc=vfld; cfld[cfound].norm=norm; #ifdef IGNORE_CRACK_INTERACTIONS cfld[cfound].crackNum=1; // appears to always be same crack, and stop when found one break; #else cfld[cfound].crackNum=nextCrack->GetNumber(); cfound++; if(cfound>1) break; // stop if found two, if there are more then two, physics will be off #endif } nextCrack=(CrackHeader *)nextCrack->GetNextObject(); } // find (and allocate if needed) the velocity field // Use vfld=0 if no cracks found if(cfound>0) { // In parallel, this is critical code #pragma omp critical { try { vfld = ndptr->AddCrackVelocityField(matfld,cfld); } catch(CommonException err) { if(initErr==NULL) initErr = new CommonException(err); } } } // set material point velocity field for this node mpmptr->vfld[i] = vfld; } // make sure material velocity field is created too if(maxMaterialFields>1 && ndptr->NeedsMatVelocityField(vfld,matfld)) { // If parallel, this is critical code #pragma omp critical { try { ndptr->AddMatVelocityField(vfld,matfld); } catch(CommonException err) { if(initErr==NULL) initErr = new CommonException(err); } } } } // next material point mpmptr = (MPMBase *)mpmptr->GetNextObject(); } } //} // end for loop when not in parallel } // was there an error? if(initErr!=NULL) throw *initErr; // copy crack and material fields on real nodes to ghost nodes if(tp>1) { for(int pn=0;pn<tp;pn++) patches[pn]->InitializationReduction(); } } // Update forces applied to particles MatPtLoadBC::SetParticleFext(mtime); // remove contact conditions CrackNode::RemoveCrackNodes(); MaterialInterfaceNode::RemoveInterfaceNodes(); // turn off isothermal ramp when done and ramp step initialization thermal.CheckDone(mtime); }
// Get mass matrix, find dimensionless particle locations, // and find grid momenta void ExtrapolateRigidBCsTask::Execute(void) { double fn[maxShapeNodes]; // undo dynamic velocity, temp, and conc BCs from rigid materials // and get pointer to first empty one in reuseRigid...BC ProjectRigidBCsTask::UnsetRigidBCs((BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC, (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC); ProjectRigidBCsTask::UnsetRigidBCs((BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC, (BoundaryCondition **)&firstRigidTempBC,(BoundaryCondition **)&reuseRigidTempBC); ProjectRigidBCsTask::UnsetRigidBCs((BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC, (BoundaryCondition **)&firstRigidConcBC,(BoundaryCondition **)&reuseRigidConcBC); int i,numnds,setFlags; Vector rvel; bool hasDir[3]; double tempValue,concValue; // this loop not parallel because of possible function in getting rigid settings // also will usually be small loop for(int p=nmpmsRC;p<nmpms;p++) { // bet material point and the rigid material MPMBase *mpmptr = mpm[p]; const RigidMaterial *rigid = (RigidMaterial *)theMaterials[mpmptr->MatID()]; // material object for this particle // get rigid particle velocity // Get directions set, others will be zero setFlags = rigid->SetDirection(); ZeroVector(&rvel); if(rigid->GetVectorSetting(&rvel,hasDir,mtime,&mpmptr->pos)) { if(hasDir[0]) mpmptr->vel.x = rvel.x; if(hasDir[1]) mpmptr->vel.y = rvel.y; if(hasDir[2]) mpmptr->vel.z = rvel.z; } else { if(setFlags&CONTROL_X_DIRECTION) rvel.x = mpmptr->vel.x; if(setFlags&CONTROL_Y_DIRECTION) rvel.y = mpmptr->vel.y; if(setFlags&CONTROL_Z_DIRECTION) rvel.z = mpmptr->vel.z; } // get rigid particle temperature if(rigid->RigidTemperature()) { setFlags += CONTROL_TEMPERATURE; if(rigid->GetValueSetting(&tempValue,mtime,&mpmptr->pos)) mpmptr->pTemperature = tempValue; } // concentration if(rigid->RigidConcentration()) { setFlags += CONTROL_CONCENTRATION; if(rigid->GetValueSetting(&concValue,mtime,&mpmptr->pos)) mpmptr->pConcentration = concValue; } // get nodes and shape function for material point p const ElementBase *elref = theElements[mpmptr->ElemID()]; // element containing this particle elref->ShapeFunction(mpmptr->GetNcpos(),FALSE,&fn[1],NULL,NULL,NULL); numnds=elref->NumberNodes(); // Add particle property to each node in the element for(i=1;i<=numnds;i++) { // get node pointer and set values int mi=elref->nodes[i-1]; // 1 based node // it might possible need a velocity field (does nothing in single material mode or if already there) nd[mi]->AddMatVelocityField(0,0); // add BC info nd[mi]->AddRigidBCInfo(mpmptr,fn[i],setFlags,&rvel); } } // read nodal settings, rezero their used values, and set boundary conditions for(int i=1;i<=nnodes;i++) { NodalPoint *ndptr = nd[i]; setFlags = ndptr->ReadAndZeroRigidBCInfo(&rvel,&tempValue,&concValue); if(setFlags&CONTROL_X_DIRECTION) { ProjectRigidBCsTask::SetRigidBCs(i,-40,X_DIRECTION,rvel.x,0.,0, (BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC, (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC); } if(setFlags&CONTROL_X_DIRECTION) { ProjectRigidBCsTask::SetRigidBCs(i,-40,Y_DIRECTION,rvel.y,0.,0, (BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC, (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC); } if(setFlags&CONTROL_X_DIRECTION) { ProjectRigidBCsTask::SetRigidBCs(i,-40,Z_DIRECTION,rvel.z,0.,0, (BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC, (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC); } if(setFlags&CONTROL_TEMPERATURE) { ProjectRigidBCsTask::SetRigidBCs(i,0,TEMP_DIRECTION,tempValue,0.,0, (BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC, (BoundaryCondition **)&firstRigidTempBC,(BoundaryCondition **)&reuseRigidTempBC); } if(setFlags&CONTROL_CONCENTRATION) { ProjectRigidBCsTask::SetRigidBCs(i,0,CONC_DIRECTION,concValue,0.,0, (BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC, (BoundaryCondition **)&firstRigidConcBC,(BoundaryCondition **)&reuseRigidConcBC); } } // if any left over rigid BCs, delete them now ProjectRigidBCsTask::RemoveRigidBCs((BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,(BoundaryCondition **)&firstRigidVelocityBC); ProjectRigidBCsTask::RemoveRigidBCs((BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC,(BoundaryCondition **)&firstRigidTempBC); ProjectRigidBCsTask::RemoveRigidBCs((BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC,(BoundaryCondition **)&firstRigidConcBC); }
// Calculate J and K at crack tips CustomTask *CalcJKTask::StepCalculation(void) { // skip if not needed if(!getJKThisStep) return nextTask; int nds[maxShapeNodes]; double fn[maxShapeNodes]; //double xDeriv[maxShapeNodes],yDeriv[maxShapeNodes],zDeriv[maxShapeNodes]; // set up strain fields for crack extrapolations //#pragma omp parallel private(nds,fn,xDeriv,yDeriv,zDeriv) #pragma omp parallel private(nds,fn) { // in case 2D planar //for(int i=0;i<maxShapeNodes;i++) zDeriv[i] = 0.; #pragma omp for for(int i=1;i<=nnodes;i++) nd[i]->ZeroDisp(); // zero displacement fields on ghost nodes int pn = MPMTask::GetPatchNumber(); patches[pn]->ZeroDisp(); // loop over only non-rigid particles in patch that do not ignore cracks MPMBase *mpnt = patches[pn]->GetFirstBlockPointer(FIRST_NONRIGID); while(mpnt!=NULL) { // material reference const MaterialBase *matref = theMaterials[mpnt->MatID()]; // find shape functions and derviatives int numnds; const ElementBase *elref = theElements[mpnt->ElemID()]; //elref->GetShapeGradients(&numnds,fn,nds,xDeriv,yDeriv,zDeriv,mpnt); elref->GetShapeFunctions(&numnds,fn,nds,mpnt); // Add particle property to each node in the element NodalPoint *ndmi; short vfld; double fnmp; for(int i=1;i<=numnds;i++) { // global mass matrix vfld=(short)mpnt->vfld[i]; // velocity field to use fnmp=fn[i]*mpnt->mp; // get node pointer ndmi = MPMTask::GetNodePointer(pn,nds[i]); // get 2D gradient terms (dimensionless) and track material (if needed) int activeMatField = matref->GetActiveField(); Matrix3 gradU = mpnt->GetDisplacementGradientMatrix(); ndmi->AddUGradient(vfld,fnmp,gradU(0,0),gradU(0,1),gradU(1,0),gradU(1,1),activeMatField,mpnt->mp); // GRID_JTERMS double rho = matref->GetRho(NULL); if(JGridEnergy) { // Add velocity (scaled by sqrt(rho) such that v^2 is 2 X grid kinetic energy in nJ/mm^3) // In axisymmetric, kinetic energy density is 2 pi (0.5 m v^2)/(2 pi rp Ap), but since m = rho rp Ap // kinetic energy density is still 0.5 rho v^2 ndmi->AddGridVelocity(vfld,fnmp*sqrt(rho),mpnt->vel.x,mpnt->vel.y); // scale by rho to get actual stress fnmp *= rho; } else { // scale by rho to get specific energy and actual stress fnmp *= rho; // get energy and rho*energy has units nJ/mm^3 // In axisymmetric, energy density is 2 pi m U/(2 pi rp Ap), but since m = rho rp Ap // energy density is still rho*energy ndmi->AddEnergy(vfld,fnmp,mpnt->vel.x,mpnt->vel.y,mpnt->GetWorkEnergy()); } // get a nodal stress (rho*stress has units N/m^2 = uN/mm^2) Tensor sp = mpnt->ReadStressTensor(); ndmi->AddStress(vfld,fnmp,&sp); } // next non-rigid material point mpnt = (MPMBase *)mpnt->GetNextObject(); } } // copy ghost to real nodes int totalPatches = fmobj->GetTotalNumberOfPatches(); if(totalPatches>1) { for(int j=0;j<totalPatches;j++) patches[j]->JKTaskReduction(); } // finish strain fields #pragma omp parallel for for(int i=1;i<=nnodes;i++) nd[i]->CalcStrainField(); // No Do the J Integral calculations int inMat; Vector d,C; CrackSegment *crkTip; CrackHeader *nextCrack=firstCrack; while(nextCrack!=NULL) { nextCrack->JIntegral(); // crack-axis components of J-integral // if material known, find KI and KII for crack tips if(getJKThisStep & NEED_K) { for(int i=START_OF_CRACK;i<=END_OF_CRACK;i++) { crkTip=nextCrack->GetCrackTip(i); inMat=crkTip->tipMatnum; if(inMat>0) { //C=crkTip->C; // will be crack segment property C.x=0.0; C.y=0.0; ; C.z=0.; // find normal and shear COD nextCrack->GetCOD(crkTip,d,true); d.z=0.; // convert to K crkTip->sif=theMaterials[inMat-1]->ConvertJToK(d,C,crkTip->Jint,fmobj->np); } else { crkTip->sif.x=0; crkTip->sif.y=0; } } } // next crack nextCrack=(CrackHeader *)nextCrack->GetNextObject(); } return nextTask; }
// Get mass matrix, find dimensionless particle locations, // and find grid momenta void MassAndMomentumTask::Execute(void) { CommonException *massErr = NULL; double fn[maxShapeNodes],xDeriv[maxShapeNodes],yDeriv[maxShapeNodes],zDeriv[maxShapeNodes]; int nds[maxShapeNodes]; #pragma mark ... UPDATE RIGID CONTACT PARTICLES // Set rigid BC contact material velocities first (so loop can be parallel) // GetVectorSetting() uses globals and therefore can't be parallel if(nmpmsRC>nmpmsNR) { Vector newvel; bool hasDir[3]; for(int p=nmpmsNR;p<nmpmsRC;p++) { MPMBase *mpmptr = mpm[p]; const RigidMaterial *matID = (RigidMaterial *)theMaterials[mpm[p]->MatID()]; if(matID->GetVectorSetting(&newvel,hasDir,mtime,&mpmptr->pos)) { // change velocity if functions being used, otherwise keep velocity constant if(hasDir[0]) mpmptr->vel.x = newvel.x; if(hasDir[1]) mpmptr->vel.y = newvel.y; if(hasDir[2]) mpmptr->vel.z = newvel.z; } } } // loop over non-rigid and rigid contact particles - this parallel part changes only particle p // mass, momenta, etc are stored on ghost nodes, which are sent to real nodes in next non-parallel loop //for(int pn=0;pn<4;pn++) #pragma omp parallel private(fn,xDeriv,yDeriv,zDeriv,nds) { // thread for patch pn int pn = GetPatchNumber(); // in case 2D planar for(int i=0;i<maxShapeNodes;i++) zDeriv[i] = 0.; #pragma mark ... EXTRAPOLATE NONRIGID PARTICLES try { for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_CONTACT;block++) { MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(block); while(mpmptr!=NULL) { const MaterialBase *matID = theMaterials[mpmptr->MatID()]; // material object for this particle int matfld = matID->GetField(); // material velocity field // get nodes and shape function for material point p int i,numnds; const ElementBase *elref = theElements[mpmptr->ElemID()]; // element containing this particle if(fmobj->multiMaterialMode) elref->GetShapeGradients(&numnds,fn,nds,xDeriv,yDeriv,zDeriv,mpmptr); else elref->GetShapeFunctions(&numnds,fn,nds,mpmptr); // Add particle property to each node in the element short vfld; NodalPoint *ndptr; for(i=1;i<=numnds;i++) { // get node pointer ndptr = GetNodePointer(pn,nds[i]); // momentum vector (and allocate velocity field if needed) vfld = mpmptr->vfld[i]; ndptr->AddMassMomentum(mpmptr,vfld,matfld,fn[i],xDeriv[i],yDeriv[i],zDeriv[i], 1,block==FIRST_NONRIGID); } // next material point mpmptr = (MPMBase *)mpmptr->GetNextObject(); } } } catch(CommonException err) { if(massErr==NULL) { #pragma omp critical massErr = new CommonException(err); } } catch(...) { cout << "Unknown exception in MassAndMomentumTask()" << endl; } } // throw now - only possible error if too many CPDI nodes in 3D if(massErr!=NULL) throw *massErr; // reduction of ghost node forces to real nodes int totalPatches = fmobj->GetTotalNumberOfPatches(); if(totalPatches>1) { for(int pn=0;pn<totalPatches;pn++) patches[pn]->MassAndMomentumReduction(); } #pragma mark ... RIGID BOUNDARY CONDITIONS // undo dynamic velocity, temp, and conc BCs from rigid materials // and get pointer to first empty one in reuseRigid...BC UnsetRigidBCs((BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC, (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC); UnsetRigidBCs((BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC, (BoundaryCondition **)&firstRigidTempBC,(BoundaryCondition **)&reuseRigidTempBC); UnsetRigidBCs((BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC, (BoundaryCondition **)&firstRigidConcBC,(BoundaryCondition **)&reuseRigidConcBC); // For Rigid BC materials create velocity BC on each node in the element for(int p=nmpmsRC;p<nmpms;p++) { MPMBase *mpmptr = mpm[p]; // pointer int matid0 = mpmptr->MatID(); const MaterialBase *matID = theMaterials[matid0]; // material object for this particle RigidMaterial *rigid=(RigidMaterial *)matID; const ElementBase *elref = theElements[mpmptr->ElemID()]; // element containing this particle int numnds=elref->NumberNodes(); double rvalue; for(int i=1;i<=numnds;i++) { int mi=elref->nodes[i-1]; // 1 based node // look for setting function in one to three directions // GetVectorSetting() returns true if function has set the velocity, otherwise it return FALSE bool hasDir[3]; Vector rvel; if(rigid->GetVectorSetting(&rvel,hasDir,mtime,&mpmptr->pos)) { // velocity set by 1 to 3 functions as determined by hasDir[i] if(hasDir[0]) { mpmptr->vel.x = rvel.x; SetRigidBCs(mi,matid0,X_DIRECTION,rvel.x,0.,rigid->mirrored, (BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC, (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC); } if(hasDir[1]) { mpmptr->vel.y = rvel.y; SetRigidBCs(mi,matid0,Y_DIRECTION,rvel.y,0.,rigid->mirrored, (BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC, (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC); } if(hasDir[2]) { mpmptr->vel.z = rvel.z; SetRigidBCs(mi,matid0,Z_DIRECTION,rvel.z,0.,rigid->mirrored, (BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC, (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC); } } else { // velocity set by particle velocity in selected directions if(rigid->RigidDirection(X_DIRECTION)) { SetRigidBCs(mi,matid0,X_DIRECTION,mpmptr->vel.x,0.,rigid->mirrored, (BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC, (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC); } if(rigid->RigidDirection(Y_DIRECTION)) { SetRigidBCs(mi,matid0,Y_DIRECTION,mpmptr->vel.y,0.,rigid->mirrored, (BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC, (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC); } if(rigid->RigidDirection(Z_DIRECTION)) { SetRigidBCs(mi,matid0,Z_DIRECTION,mpmptr->vel.z,0.,rigid->mirrored, (BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC, (BoundaryCondition **)&firstRigidVelocityBC,(BoundaryCondition **)&reuseRigidVelocityBC); } } // temperature if(rigid->RigidTemperature()) { if(rigid->GetValueSetting(&rvalue,mtime,&mpmptr->pos)) mpmptr->pTemperature=rvalue; SetRigidBCs(mi,matid0,TEMP_DIRECTION,mpmptr->pTemperature,0.,0, (BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC, (BoundaryCondition **)&firstRigidTempBC,(BoundaryCondition **)&reuseRigidTempBC); } // concentration if(rigid->RigidConcentration()) { if(rigid->GetValueSetting(&rvalue,mtime,&mpmptr->pos)) mpmptr->pConcentration=rvalue; SetRigidBCs(mi,matid0,CONC_DIRECTION,mpmptr->pConcentration,0.,0, (BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC, (BoundaryCondition **)&firstRigidConcBC,(BoundaryCondition **)&reuseRigidConcBC); } } } // if any left over rigid BCs, delete them now RemoveRigidBCs((BoundaryCondition **)&firstVelocityBC,(BoundaryCondition **)&lastVelocityBC,(BoundaryCondition **)&firstRigidVelocityBC); RemoveRigidBCs((BoundaryCondition **)&firstTempBC,(BoundaryCondition **)&lastTempBC,(BoundaryCondition **)&firstRigidTempBC); RemoveRigidBCs((BoundaryCondition **)&firstConcBC,(BoundaryCondition **)&lastConcBC,(BoundaryCondition **)&firstRigidConcBC); #ifdef COMBINE_RIGID_MATERIALS bool combineRigid = firstCrack!=NULL && fmobj->multiMaterialMode && fmobj->hasRigidContactParticles; #endif #pragma mark ... POST EXTRAPOLATION TASKS // Post mass and momentum extrapolation calculations on nodes #pragma omp parallel { // variables for each thread CrackNode *firstCrackNode=NULL,*lastCrackNode=NULL; MaterialInterfaceNode *firstInterfaceNode=NULL,*lastInterfaceNode=NULL; // Each pass in this loop should be independent #pragma omp for nowait for(int i=1;i<=nnodes;i++) { // node reference NodalPoint *ndptr = nd[i]; try { #ifdef COMBINE_RIGID_MATERIALS // combine rigid fields if necessary if(combineRigid) ndptr->CopyRigidParticleField(); #endif // Get total nodal masses and count materials if multimaterial mode ndptr->CalcTotalMassAndCount(); // multimaterial contact if(fmobj->multiMaterialMode) ndptr->MaterialContactOnNode(timestep,MASS_MOMENTUM_CALL,&firstInterfaceNode,&lastInterfaceNode); // crack contact if(firstCrack!=NULL) ndptr->CrackContact(FALSE,0.,&firstCrackNode,&lastCrackNode); // get transport values on nodes TransportTask *nextTransport=transportTasks; while(nextTransport!=NULL) nextTransport = nextTransport->GetNodalValue(ndptr); } catch(CommonException err) { if(massErr==NULL) { #pragma omp critical massErr = new CommonException(err); } } } #pragma omp critical { // link up crack nodes if(lastCrackNode != NULL) { if(CrackNode::currentCNode != NULL) firstCrackNode->SetPrevBC(CrackNode::currentCNode); CrackNode::currentCNode = lastCrackNode; } // link up interface nodes if(lastInterfaceNode != NULL) { if(MaterialInterfaceNode::currentIntNode != NULL) firstInterfaceNode->SetPrevBC(MaterialInterfaceNode::currentIntNode); MaterialInterfaceNode::currentIntNode = lastInterfaceNode; } } } // throw any errors if(massErr!=NULL) throw *massErr; #pragma mark ... IMPOSE BOUNDARY CONDITIONS // Impose transport BCs and extrapolate gradients to the particles TransportTask *nextTransport=transportTasks; while(nextTransport!=NULL) { nextTransport->ImposeValueBCs(mtime); nextTransport = nextTransport->GetGradients(mtime); } // locate BCs with reflected nodes if(firstRigidVelocityBC!=NULL) { NodalVelBC *nextBC=firstRigidVelocityBC; double mstime=1000.*mtime; //cout << "# Find Reflected Nodes" << endl; while(nextBC!=NULL) nextBC = nextBC->SetMirroredVelBC(mstime); } // used to call class methods for material contact and crack contact here // Impose velocity BCs NodalVelBC::GridMomentumConditions(TRUE); }
// Get total grid point forces (except external forces) // throws CommonException() void GridForcesTask::Execute(void) { CommonException *forceErr = NULL; // need to be private in threads #ifdef CONST_ARRAYS double fn[MAX_SHAPE_NODES],xDeriv[MAX_SHAPE_NODES],yDeriv[MAX_SHAPE_NODES],zDeriv[MAX_SHAPE_NODES]; int ndsArray[MAX_SHAPE_NODES]; #else double fn[maxShapeNodes],xDeriv[maxShapeNodes],yDeriv[maxShapeNodes],zDeriv[maxShapeNodes]; int ndsArray[maxShapeNodes]; #endif // loop over non-rigid particles - this parallel part changes only particle p // forces are stored on ghost nodes, which are sent to real nodes in next non-parallel loop #pragma omp parallel private(ndsArray,fn,xDeriv,yDeriv,zDeriv) { // in case 2D planar for(int i=0;i<maxShapeNodes;i++) zDeriv[i] = 0.; // patch for this thread int pn = GetPatchNumber(); try { MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(FIRST_NONRIGID); while(mpmptr!=NULL) { const MaterialBase *matref = theMaterials[mpmptr->MatID()]; // material class (read only) int matfld = matref->GetField(); // get transport tensors (if needed) TransportProperties t; if(transportTasks!=NULL) matref->GetTransportProps(mpmptr,fmobj->np,&t); // find shape functions and derviatives const ElementBase *elemref = theElements[mpmptr->ElemID()]; int *nds = ndsArray; elemref->GetShapeGradients(fn,&nds,xDeriv,yDeriv,zDeriv,mpmptr); int numnds = nds[0]; // Add particle property to buffer on the material point (needed to allow parallel code) short vfld; NodalPoint *ndptr; for(int i=1;i<=numnds;i++) { vfld = (short)mpmptr->vfld[i]; // crack velocity field to use // total force vector = internal + external forces // (in g mm/sec^2 or micro N) Vector theFrc; mpmptr->GetFintPlusFext(&theFrc,fn[i],xDeriv[i],yDeriv[i],zDeriv[i]); // add body forces (do in outside loop now) // add the total force to nodal point ndptr = GetNodePointer(pn,nds[i]); ndptr->AddFtotTask3(vfld,matfld,&theFrc); #ifdef CHECK_NAN if(theFrc.x!=theFrc.x || theFrc.y!=theFrc.y || theFrc.z!=theFrc.z) { #pragma omp critical (output) { cout << "\n# GridForcesTask::Execute: bad nodal force vfld = " << vfld << ", matfld = " << matfld; PrintVector(" theFrc = ",&theFrc); cout << endl; ndptr->Describe(); } } #endif // transport forces TransportTask *nextTransport=transportTasks; while(nextTransport!=NULL) nextTransport=nextTransport->AddForces(ndptr,mpmptr,fn[i],xDeriv[i],yDeriv[i],zDeriv[i],&t); } // next material point mpmptr = (MPMBase *)mpmptr->GetNextObject(); } } catch(CommonException& err) { if(forceErr==NULL) { #pragma omp critical (error) forceErr = new CommonException(err); } } catch(std::bad_alloc&) { if(forceErr==NULL) { #pragma omp critical (error) forceErr = new CommonException("Memory error","GridForcesTask::Execute"); } } catch(...) { if(forceErr==NULL) { #pragma omp critical (error) forceErr = new CommonException("Unexpected error","GridForcesTask::Execute"); } } } // throw errors now if(forceErr!=NULL) throw *forceErr; // reduction of ghost node forces to real nodes int totalPatches = fmobj->GetTotalNumberOfPatches(); if(totalPatches>1) { for(int pn=0;pn<totalPatches;pn++) patches[pn]->GridForcesReduction(); } }
// Get total grid point forces (except external forces) void UpdateStrainsLastContactTask::Execute(void) { CommonException *uslErr = NULL; int nds[maxShapeNodes]; double fn[maxShapeNodes],xDeriv[maxShapeNodes],yDeriv[maxShapeNodes],zDeriv[maxShapeNodes]; #pragma omp parallel private(nds,fn,xDeriv,yDeriv,zDeriv) { // in case 2D planar for(int i=0;i<maxShapeNodes;i++) zDeriv[i] = 0.; try { #pragma omp for // zero again (which finds new positions for contact rigid particle data on the nodes) for(int i=1;i<=nnodes;i++) nd[i]->RezeroNodeTask6(timestep); // zero ghost nodes on this patch int pn = GetPatchNumber(); patches[pn]->RezeroNodeTask6(timestep); // loop over non-rigid particles only - this parallel part changes only particle p // mass, momenta, etc are stored on ghost nodes, which are sent to real nodes in next non-parallel loop MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(FIRST_NONRIGID); while(mpmptr!=NULL) { const MaterialBase *matref = theMaterials[mpmptr->MatID()]; int matfld = matref->GetField(); // find shape functions (why ever need gradients?) const ElementBase *elref = theElements[mpmptr->ElemID()]; int numnds; if(fmobj->multiMaterialMode) { // Need gradients for volume gradient elref->GetShapeGradients(&numnds,fn,nds,xDeriv,yDeriv,zDeriv,mpmptr); } else elref->GetShapeFunctions(&numnds,fn,nds,mpmptr); short vfld; NodalPoint *ndptr; for(int i=1;i<=numnds;i++) { // get node pointer ndptr = GetNodePointer(pn,nds[i]); // add mass and momentum this task vfld = (short)mpmptr->vfld[i]; ndptr->AddMassMomentumLast(mpmptr,vfld,matfld,fn[i],xDeriv[i],yDeriv[i],zDeriv[i]); } // next non-rigid material point mpmptr = (MPMBase *)mpmptr->GetNextObject(); } } catch(CommonException err) { if(uslErr==NULL) { #pragma omp critical uslErr = new CommonException(err); } } } // throw errors now if(uslErr!=NULL) throw *uslErr; // reduction of ghost node forces to real nodes int totalPatches = fmobj->GetTotalNumberOfPatches(); if(totalPatches>1) { for(int pn=0;pn<totalPatches;pn++) patches[pn]->MassAndMomentumReductionLast(); } // grid temperature is never updated unless needed here // update nodal values for transport properties (when coupled to strain) TransportTask *nextTransport=transportTasks; while(nextTransport!=NULL) nextTransport=nextTransport->UpdateNodalValues(timestep); // adjust momenta for multimaterial contact if(fmobj->multiMaterialMode) { for(int i=1;i<=nnodes;i++) nd[i]->MaterialContactOnNode(timestep,UPDATE_STRAINS_LAST_CALL,NULL,NULL); } // adjust momenta for crack contact if(firstCrack!=NULL) CrackNode::ContactOnKnownNodes(); // impose grid boundary conditions NodalVelBC::GridMomentumConditions(FALSE); // update strains based on current velocities UpdateStrainsFirstTask::FullStrainUpdate(strainTimestep,(fmobj->mpmApproach==USAVG_METHOD),fmobj->np); }
// Get mass matrix, find dimensionless particle locations, // and find grid momenta void MassAndMomentumTask::Execute(void) { CommonException *massErr = NULL; double fn[maxShapeNodes],xDeriv[maxShapeNodes],yDeriv[maxShapeNodes],zDeriv[maxShapeNodes]; int nds[maxShapeNodes]; #pragma mark ... UPDATE RIGID CONTACT PARTICLES // Set rigid BC contact material velocities first (so loop can be parallel) // GetVectorSetting() uses globals and therefore can't be parallel if(nmpmsRC>nmpmsNR) { Vector newvel; bool hasDir[3]; for(int p=nmpmsNR;p<nmpmsRC;p++) { MPMBase *mpmptr = mpm[p]; const RigidMaterial *matID = (RigidMaterial *)theMaterials[mpm[p]->MatID()]; if(matID->GetVectorSetting(&newvel,hasDir,mtime,&mpmptr->pos)) { // change velocity if functions being used, otherwise keep velocity constant if(hasDir[0]) mpmptr->vel.x = newvel.x; if(hasDir[1]) mpmptr->vel.y = newvel.y; if(hasDir[2]) mpmptr->vel.z = newvel.z; } } } // loop over non-rigid and rigid contact particles - this parallel part changes only particle p // mass, momenta, etc are stored on ghost nodes, which are sent to real nodes in next non-parallel loop //for(int pn=0;pn<4;pn++) #pragma omp parallel private(fn,xDeriv,yDeriv,zDeriv,nds) { // thread for patch pn int pn = GetPatchNumber(); // in case 2D planar for(int i=0;i<maxShapeNodes;i++) zDeriv[i] = 0.; #pragma mark ... EXTRAPOLATE NONRIGID AND RIGID CONTACT PARTICLES try { for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_CONTACT;block++) { MPMBase *mpmptr = patches[pn]->GetFirstBlockPointer(block); while(mpmptr!=NULL) { const MaterialBase *matID = theMaterials[mpmptr->MatID()]; // material object for this particle int matfld = matID->GetField(); // material velocity field // get nodes and shape function for material point p int i,numnds; const ElementBase *elref = theElements[mpmptr->ElemID()]; // element containing this particle if(fmobj->multiMaterialMode) elref->GetShapeGradients(&numnds,fn,nds,xDeriv,yDeriv,zDeriv,mpmptr); else elref->GetShapeFunctions(&numnds,fn,nds,mpmptr); // Add particle property to each node in the element short vfld; NodalPoint *ndptr; for(i=1;i<=numnds;i++) { // get node pointer ndptr = GetNodePointer(pn,nds[i]); // add mass and momentum (and maybe contact stuff) to this node vfld = mpmptr->vfld[i]; ndptr->AddMassMomentum(mpmptr,vfld,matfld,fn[i],xDeriv[i],yDeriv[i],zDeriv[i], 1,block==FIRST_NONRIGID); } // next material point mpmptr = (MPMBase *)mpmptr->GetNextObject(); } } } catch(CommonException err) { if(massErr==NULL) { #pragma omp critical massErr = new CommonException(err); } } catch(...) { cout << "Unknown exception in MassAndMomentumTask()" << endl; } } // throw now - only possible error if too many CPDI nodes in 3D if(massErr!=NULL) throw *massErr; // reduction of ghost node forces to real nodes int totalPatches = fmobj->GetTotalNumberOfPatches(); if(totalPatches>1) { for(int pn=0;pn<totalPatches;pn++) patches[pn]->MassAndMomentumReduction(); } }
// Get mass matrix, find dimensionless particle locations, // and find grid momenta // throws CommonException() void PostExtrapolationTask::Execute(void) { CommonException *massErr = NULL; bool combineRigid = firstCrack!=NULL && fmobj->multiMaterialMode && fmobj->hasRigidContactParticles; // Post mass and momentum extrapolation calculations on nodes #pragma omp parallel { // variables for each thread CrackNode *firstCrackNode=NULL,*lastCrackNode=NULL; MaterialInterfaceNode *firstInterfaceNode=NULL,*lastInterfaceNode=NULL; // Each pass in this loop should be independent #pragma omp for nowait for(int i=1;i<=nnodes;i++) { // node reference NodalPoint *ndptr = nd[i]; try { // combine rigid fields if necessary if(combineRigid) ndptr->CopyRigidParticleField(); // Get total nodal masses and count materials if multimaterial mode ndptr->CalcTotalMassAndCount(); // multimaterial contact if(fmobj->multiMaterialMode) ndptr->MaterialContactOnNode(timestep,MASS_MOMENTUM_CALL,&firstInterfaceNode,&lastInterfaceNode); // crack contact if(firstCrack!=NULL) ndptr->CrackContact(FALSE,0.,&firstCrackNode,&lastCrackNode); // get transport values on nodes TransportTask *nextTransport=transportTasks; while(nextTransport!=NULL) nextTransport = nextTransport->GetNodalValue(ndptr); } catch(std::bad_alloc&) { if(massErr==NULL) { #pragma omp critical (error) massErr = new CommonException("Memory error","PostExtrapolationTask::Execute"); } } catch(...) { if(massErr==NULL) { #pragma omp critical (error) massErr = new CommonException("Unexpected error","PostExtrapolationTask::Execute"); } } } #pragma omp critical (linknodes) { // link up crack nodes if(lastCrackNode != NULL) { if(CrackNode::currentCNode != NULL) firstCrackNode->SetPrevBC(CrackNode::currentCNode); CrackNode::currentCNode = lastCrackNode; } // link up interface nodes if(lastInterfaceNode != NULL) { if(MaterialInterfaceNode::currentIntNode != NULL) firstInterfaceNode->SetPrevBC(MaterialInterfaceNode::currentIntNode); MaterialInterfaceNode::currentIntNode = lastInterfaceNode; } } } // throw any errors if(massErr!=NULL) throw *massErr; #pragma mark ... IMPOSE BOUNDARY CONDITIONS // Impose transport BCs and extrapolate gradients to the particles TransportTask *nextTransport=transportTasks; while(nextTransport!=NULL) { nextTransport->ImposeValueBCs(mtime); nextTransport = nextTransport->GetGradients(mtime); } // locate BCs with reflected nodes if(firstRigidVelocityBC!=NULL) { NodalVelBC *nextBC=firstRigidVelocityBC; //cout << "# Find Reflected Nodes" << endl; while(nextBC!=NULL) nextBC = nextBC->SetMirroredVelBC(mtime); } // used to call class methods for material contact and crack contact here // Impose velocity BCs NodalVelBC::GridMomentumConditions(TRUE); }