// 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(); } }
// Update particle position, velocity, temp, and conc // throws CommonException() void UpdateParticlesTask::Execute(void) { CommonException *upErr = NULL; #ifdef CONST_ARRAYS int ndsArray[MAX_SHAPE_NODES]; double fn[MAX_SHAPE_NODES]; #else int ndsArray[maxShapeNodes]; double fn[maxShapeNodes]; #endif // Damping terms on the grid or on the particles // particleAlpha = (1-beta)/dt + pdamping(t) // gridAlpha = -m*(1-beta)/dt + damping(t) double particleAlpha = bodyFrc.GetParticleDamping(mtime); double gridAlpha = bodyFrc.GetDamping(mtime); // nonPICGridAlpha = damping(t) // globalPIC = (1-beta)/dt double nonPICGridAlpha = bodyFrc.GetNonPICDamping(mtime); double globalPIC = bodyFrc.GetPICDamping(); // Update particle position, velocity, temp, and conc #pragma omp parallel for private(ndsArray,fn) for(int p=0;p<nmpmsNR;p++) { MPMBase *mpmptr = mpm[p]; try { // get shape functions const ElementBase *elemRef = theElements[mpmptr->ElemID()]; int *nds = ndsArray; elemRef->GetShapeFunctions(fn,&nds,mpmptr); int numnds = nds[0]; // Update particle position and velocity const MaterialBase *matRef=theMaterials[mpmptr->MatID()]; int matfld=matRef->GetField(); // Allow material to override global settings double localParticleAlpha = particleAlpha; double localGridAlpha = gridAlpha; matRef->GetMaterialDamping(localParticleAlpha,localGridAlpha,nonPICGridAlpha,globalPIC); // data structure for extrapolations GridToParticleExtrap *gp = new GridToParticleExtrap; // acceleration on the particle gp->acc = mpmptr->GetAcc(); ZeroVector(gp->acc); // extrapolate nodal velocity from grid to particle ZeroVector(&gp->vgpnp1); // only two possible transport tasks double rate[2]; rate[0] = rate[1] = 0.; int task; TransportTask *nextTransport; // Loop over nodes for(int i=1;i<=numnds;i++) { // increment velocity and acceleraton const NodalPoint *ndptr = nd[nds[i]]; short vfld = (short)mpmptr->vfld[i]; // increment ndptr->IncrementDelvaTask5(vfld,matfld,fn[i],gp); #ifdef CHECK_NAN // conditionally compiled check for nan velocities if(gp->vgpnp1.x!=gp->vgpnp1.x || gp->vgpnp1.y!=gp->vgpnp1.y || gp->vgpnp1.z!=gp->vgpnp1.z) { #pragma omp critical (output) { cout << "\n# UpdateParticlesTask::Execute: bad material velocity field for vfld=" << vfld << "matfld=" << matfld << " fn[i]=" << fn[i] << endl;; PrintVector("# Particle velocity vgpn1 = ",&gp->vgpnp1); cout << endl; ndptr->Describe(); } } #endif // increment transport rates nextTransport=transportTasks; task=0; while(nextTransport!=NULL) nextTransport=nextTransport->IncrementTransportRate(ndptr,fn[i],rate[task++]); } // Find grid damping acceleration parts = ag*Vgp(n) = ag*(Vgp(n+1) - Agp(n)*dt) Vector accExtra = gp->vgpnp1; AddScaledVector(&accExtra, gp->acc, -timestep); ScaleVector(&accExtra,localGridAlpha); // update position, and must be before velocity update because updates need initial velocity // This section does second order update mpmptr->MovePosition(timestep,&gp->vgpnp1,&accExtra,localParticleAlpha); // update velocity in mm/sec mpmptr->MoveVelocity(timestep,&accExtra); // update transport values nextTransport=transportTasks; task=0; while(nextTransport!=NULL) nextTransport=nextTransport->MoveTransportValue(mpmptr,timestep,rate[task++]); // energy coupling here adds adiabtic temperature rise if(ConductionTask::adiabatic) { double dTad = mpmptr->GetBufferClear_dTad(); // in K mpmptr->pTemperature += dTad; // in K } // delete grid to particle extrap data delete gp; } catch(CommonException& err) { if(upErr==NULL) { #pragma omp critical (error) upErr = new CommonException(err); } } catch(std::bad_alloc&) { if(upErr==NULL) { #pragma omp critical (error) upErr = new CommonException("Memory error","UpdateParticlesTask::Execute"); } } catch(...) { if(upErr==NULL) { #pragma omp critical (error) upErr = new CommonException("Unexpected error","UpdateParticlesTask::Execute"); } } } // throw any errors if(upErr!=NULL) throw *upErr; // rigid materials move at their current velocity for(int p=nmpmsNR;p<nmpms;p++) { mpm[p]->MovePosition(timestep); } }
// increment external load on a particle // input is analysis time in seconds // (only called when diffusion is active) MatPtFluxBC *MatPtFluxBC::AddMPFlux(double bctime) { // condition value is g/(mm^2-sec), Divide by rho*csat to get potential flux in mm/sec // find this flux and then add (times area) to get mm^3-potential/sec MPMBase *mpmptr = mpm[ptNum-1]; MaterialBase *matptr = theMaterials[mpmptr->MatID()]; // Flux is a scalar and we need int_(face) F Ni(x) dA // Since F is constant, only need integral which is done by CPDI methods // which has be generalized to work for GIMP too // We use X_DIRECTION for bcDIR for efficiency. For Silent BC, change to // Normal direction to all caculation of n Vector fluxMag; ZeroVector(&fluxMag); int bcDir=X_DIRECTION; if(style==SILENT) { TransportProperties t; matptr->GetTransportProps(mpmptr,fmobj->np,&t); Tensor *D = &(t.diffusionTensor); // D in mm^2/sec, Dc in 1/mm if(fmobj->IsThreeD()) { fluxMag.x = D->xx*mpmptr->pDiffusion[gGRADx] + D->xy*mpmptr->pDiffusion[gGRADy] + D->xz*mpmptr->pDiffusion[gGRADz]; fluxMag.y = D->xy*mpmptr->pDiffusion[gGRADx] + D->yy*mpmptr->pDiffusion[gGRADy] + D->yz*mpmptr->pDiffusion[gGRADz]; fluxMag.z = D->xz*mpmptr->pDiffusion[gGRADx] + D->yz*mpmptr->pDiffusion[gGRADy] + D->zz*mpmptr->pDiffusion[gGRADz]; } else { fluxMag.x = D->xx*mpmptr->pDiffusion[gGRADx] + D->xy*mpmptr->pDiffusion[gGRADy]; fluxMag.y = D->xy*mpmptr->pDiffusion[gGRADx] + D->yy*mpmptr->pDiffusion[gGRADy]; } bcDir = N_DIRECTION; } else if(direction==EXTERNAL_FLUX) { // csatrho = rho0 V0 csat/V (units g/mm^3) double csatrho = mpmptr->GetRho()*mpmptr->GetConcSaturation()/mpmptr->GetRelativeVolume(); fluxMag.x = BCValue(bctime)/csatrho; } else { // coupled surface flux and ftime is bath concentration // time variable (t) is replaced by c-cbath, where c is the particle potential and cbath is bath potential varTime = mpmptr->pPreviousConcentration-GetBCFirstTime(); GetPosition(&varXValue,&varYValue,&varZValue,&varRotValue); double currentValue = fabs(scale*function->Val()); if(varTime>0.) currentValue=-currentValue; // csatrho = rho0 V0 csat/V (units g/mm^3) double csatrho = mpmptr->GetRho()*mpmptr->GetConcSaturation()/mpmptr->GetRelativeVolume(); fluxMag.x = currentValue/csatrho; } // get corners and direction from material point int cElem[4],numDnds; Vector corners[4],tscaled; double ratio = mpmptr->GetTractionInfo(face,bcDir,cElem,corners,&tscaled,&numDnds); // compact CPDI nodes into list of nodes (nds) and final shape function term (fn) // May need up to 8 (in 3D) for each of the numDnds (2 in 2D or 4 in 3D) int nds[8*numDnds+1]; double fn[8*numDnds+1]; int numnds = CompactCornerNodes(numDnds,corners,cElem,ratio,nds,fn); // add force to each node int i; for(i=1;i<=numnds;i++) diffusion->AddFluxCondition(nd[nds[i]],DotVectors(&fluxMag,&tscaled)*fn[i],false); return (MatPtFluxBC *)GetNextObject(); }
// 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); }
// 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 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); }
// 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); }
// Update particle position, velocity, temp, and conc void UpdateParticlesTask::Execute(void) { CommonException *upErr = NULL; int numnds,nds[maxShapeNodes]; double fn[maxShapeNodes]; Vector vgpnp1; // Damping terms on the grid or on the particles // particleAlpha = alpha(PIC)/dt + pdamping(t) // gridAlpha = -alpha(PIC)/dt + damping(t) double particleAlpha = bodyFrc.GetParticleDamping(mtime); double gridAlpha = bodyFrc.GetDamping(mtime); // copy to local values (OSParticulas uses to implement material damping) double localParticleAlpha = particleAlpha; double localGridAlpha = gridAlpha; // Update particle position, velocity, temp, and conc #pragma omp parallel for private(numnds,nds,fn,vgpnp1) for(int p=0;p<nmpmsNR;p++) { MPMBase *mpmptr = mpm[p]; try { // get shape functions const ElementBase *elemRef = theElements[mpmptr->ElemID()]; elemRef->GetShapeFunctions(&numnds,fn,nds,mpmptr); // Update particle position and velocity const MaterialBase *matRef=theMaterials[mpmptr->MatID()]; int matfld=matRef->GetField(); Vector *acc=mpmptr->GetAcc(); ZeroVector(acc); ZeroVector(&vgpnp1); double rate[2]; // only two possible transport tasks rate[0] = rate[1] = 0.; int task; TransportTask *nextTransport; short vfld; // Loop over nodes for(int i=1;i<=numnds;i++) { // increment velocity and acceleraton const NodalPoint *ndptr = nd[nds[i]]; vfld = (short)mpmptr->vfld[i]; ndptr->IncrementDelvaTask5(vfld,matfld,fn[i],&vgpnp1,acc); #ifdef CHECK_NAN if(vgpnp1.x!=vgpnp1.x || vgpnp1.y!=vgpnp1.y || vgpnp1.z!=vgpnp1.z) { cout << "\n# UpdateParticlesTask::Execute: bad material velocity field for vfld = " << vfld << endl; ndptr->Describe(); } #endif // increment transport rates nextTransport=transportTasks; task=0; while(nextTransport!=NULL) nextTransport=nextTransport->IncrementTransportRate(ndptr,fn[i],rate[task++]); } // Find vgpn Vector vgpn = vgpnp1; AddScaledVector(&vgpn,acc,-timestep); // find effective grid acceleration and velocity AddScaledVector(acc,&vgpn,-localGridAlpha); AddScaledVector(&vgpnp1,&vgpn,-timestep*localGridAlpha); // update position, and must be before velocity update because updates need initial velocity // This section does second order update mpmptr->MovePosition(timestep,&vgpnp1,0.5*timestep,localParticleAlpha); // update velocity in mm/sec mpmptr->MoveVelocity(timestep,localParticleAlpha); // update transport values nextTransport=transportTasks; task=0; while(nextTransport!=NULL) nextTransport=nextTransport->MoveTransportValue(mpmptr,timestep,rate[task++]); // thermal ramp thermal.UpdateParticleTemperature(&mpmptr->pTemperature,timestep); // energy coupling here if conduction not doing it if(!ConductionTask::active) { if(ConductionTask::adiabatic) { double energy = mpmptr->GetDispEnergy(); // in nJ/g double Cv = matRef->GetHeatCapacity(mpmptr); // in nJ/(g-K) mpmptr->pTemperature += energy/Cv; // in K } mpmptr->SetDispEnergy(0.); } } catch(CommonException err) { if(upErr==NULL) { #pragma omp critical upErr = new CommonException(err); } } } // throw any errors if(upErr!=NULL) throw *upErr; // rigid materials move at their current velocity for(int p=nmpmsNR;p<nmpms;p++) { mpm[p]->MovePosition(timestep,&mpm[p]->vel,0.,0.); } }
// 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(); } }