//-------------------------------------------------------------- // Name: CGEOMIPMAPPING::Init - public // Description: Initiate the geomipmapping system // Arguments: - iPatchSize: the size of the patch (in vertices) // a good size is usually around 17 (17x17 verts) // Return Value: A boolean value: -true: successful initiation // -false: unsuccessful initiation //-------------------------------------------------------------- bool CGEOMIPMAPPING::Init( int iPatchSize ) { int x, z; int iLOD; int iDivisor; int iPatch; if( m_iSize==0 ) return false; if( m_pPatches ) Shutdown( ); //initiate the patch information m_iPatchSize= iPatchSize; m_iNumPatchesPerSide= m_iSize/m_iPatchSize; m_pPatches= new SGEOMM_PATCH [SQUARE( m_iNumPatchesPerSide )]; if( m_pPatches==NULL ) { Shutdown( ); g_log.Write( LOG_SUCCESS, "Could not allocate memory for geomipmapping patch system" ); return false; } //figure out the maximum level of detail for a patch iDivisor= m_iPatchSize-1; iLOD= 0; while( iDivisor>2 ) { iDivisor= iDivisor>>1; iLOD++; } //the max amount of detail m_iMaxLOD= iLOD; //initialize the patch values for( z=0; z<m_iNumPatchesPerSide; z++ ) { for( x=0; x<m_iNumPatchesPerSide; x++ ) { iPatch= GetPatchNumber( x, z ); //initialize the patches to the lowest level of detail m_pPatches[iPatch].m_iLOD= m_iMaxLOD; m_pPatches[iPatch].m_bVisible= true; } } g_log.Write( LOG_SUCCESS, "Geomipmapping system successfully initialized" ); return true; }
//-------------------------------------------------------------- // Name: CGEOMIPMAPPING::Update - public // Description: Update the geomipmapping system // Arguments: -camera: the camera object your demo is using // Return Value: None //-------------------------------------------------------------- void CGEOMIPMAPPING::Update( CCAMERA camera ) { float fX, fY, fZ; float fScaledSize; int x, z; int iPatch; fScaledSize= m_iPatchSize*m_vecScale[0]; for( z=0; z<m_iNumPatchesPerSide; z++ ) { for( x=0; x<m_iNumPatchesPerSide; x++ ) { iPatch= GetPatchNumber( x, z ); //compute patch center (used for distance determination fX= ( x*m_iPatchSize )+( m_iPatchSize/2.0f ); fZ= ( z*m_iPatchSize )+( m_iPatchSize/2.0f ); fY= GetScaledHeightAtPoint( ( int )fX, ( int )fZ ); //only scale the X and Z values, the Y value has already been scaled fX*= m_vecScale[0]; fZ*= m_vecScale[2]; //get the distance from the camera to the patch m_pPatches[iPatch].m_fDistance= sqrtf( SQR( ( fX-camera.m_vecEyePos[0] ) )+ SQR( ( fY-camera.m_vecEyePos[1] ) )+ SQR( ( fZ-camera.m_vecEyePos[2] ) ) ); //BAD way to determine patch LOD if( m_pPatches[iPatch].m_fDistance<500 ) m_pPatches[iPatch].m_iLOD= 0; else if( m_pPatches[iPatch].m_fDistance<1000 ) m_pPatches[iPatch].m_iLOD= 1; else if( m_pPatches[iPatch].m_fDistance<2500 ) m_pPatches[iPatch].m_iLOD= 2; else if( m_pPatches[iPatch].m_fDistance>=2500 ) m_pPatches[iPatch].m_iLOD= 3; } } }
//根据patch大小初始化 bool GeoMipMapping::Init(int iPatchSize) { if (m_iSize == 0) return false; //释放资源 if (m_pPatches) ShutDown(); m_iPatchSize = iPatchSize; //patch数量 m_iNumPatchesPerSide = m_iSize / iPatchSize; //分配内存 m_pPatches = new SGEOMM_PATCH[m_iNumPatchesPerSide * m_iNumPatchesPerSide]; if (m_pPatches == 0) { ShutDown(); return false; } //求patch能被最小分割的度 int iDivision = m_iPatchSize - 1; int iLOD = 0; while (iDivision > 2) //应该可以为1 { iDivision >>= 1; iLOD++; } m_iMaxLOD = iLOD; //初始化每个patch for (int z = 0; z < m_iNumPatchesPerSide; z++) { for (int x = 0; x < m_iNumPatchesPerSide; x++) { m_pPatches[GetPatchNumber(x, z)].m_iLOD = m_iMaxLOD; //最详细 } } return true; }
//根据摄像机的位置更新LOD void GeoMipMapping::Update(Camera *camera) { float fCenterX, fCenterY, fCenterZ; D3DXVECTOR3 camPos = camera->getPosition(); float dMax = 0; //遍历每个patch,计算其到摄像机的距离 for (int z = 0; z < m_iNumPatchesPerSide; z ++) { for (int x = 0; x < m_iNumPatchesPerSide; x++) { int iPatch = GetPatchNumber(x, z); fCenterX = (x * m_iPatchSize) + m_iPatchSize / 2.0f; fCenterZ = (z * m_iPatchSize) + m_iPatchSize / 2.0f; fCenterY = GetHeight(fCenterX, fCenterZ); //求摄像机到patch的距离 m_pPatches[iPatch].m_fDistance = sqrt(Math::SQR(camPos.x - fCenterX) + Math::SQR(camPos.y - fCenterY) + Math::SQR(camPos.z - fCenterZ)); if (m_pPatches[iPatch].m_fDistance > dMax) dMax = m_pPatches[iPatch].m_fDistance; if (m_pPatches[iPatch].m_fDistance < 20) m_pPatches[iPatch].m_iLOD = 0; else if (m_pPatches[iPatch].m_fDistance < 50) m_pPatches[iPatch].m_iLOD = 1; else if (m_pPatches[iPatch].m_fDistance < 100) m_pPatches[iPatch].m_iLOD = 2; else if (m_pPatches[iPatch].m_fDistance >= 120) m_pPatches[iPatch].m_iLOD = 3; } } }
// 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(); } }
//-------------------------------------------------------------- // Name: CGEOMIPMAPPING::RenderPatch - private // Description: Render a patch of terrain // Arguments: -PX, PZ: the patch location // -bMultitex: use multitexturing or not // -bDetail: render with a detail map or not // Return Value: None //-------------------------------------------------------------- void CGEOMIPMAPPING::RenderPatch( int PX, int PZ, bool bMultiTex, bool bDetail ) { SGEOMM_NEIGHBOR patchNeighbor; SGEOMM_NEIGHBOR fanNeighbor; float fSize; float fHalfSize; float x, z; int iPatch= GetPatchNumber( PX, PZ ); int iDivisor; int iLOD; //find out information about the patch to the current patch's left, if the patch is of a //greater detail or there is no patch to the left, we can render the mid-left vertex if( m_pPatches[GetPatchNumber( PX-1, PZ )].m_iLOD<=m_pPatches[iPatch].m_iLOD || PX==0 ) patchNeighbor.m_bLeft= true; else patchNeighbor.m_bLeft= false; //find out about the upper patch if( m_pPatches[GetPatchNumber( PX, PZ+1 )].m_iLOD<=m_pPatches[iPatch].m_iLOD || PZ==m_iNumPatchesPerSide ) patchNeighbor.m_bUp= true; else patchNeighbor.m_bUp= false; //find out about the right patch if( m_pPatches[GetPatchNumber( PX+1, PZ )].m_iLOD<=m_pPatches[iPatch].m_iLOD || PX==m_iNumPatchesPerSide ) patchNeighbor.m_bRight= true; else patchNeighbor.m_bRight= false; //find out about the lower patch if( m_pPatches[GetPatchNumber( PX, PZ-1 )].m_iLOD<=m_pPatches[iPatch].m_iLOD || PZ==0 ) patchNeighbor.m_bDown= true; else patchNeighbor.m_bDown= false; //we need to determine the distance between each triangle-fan that //we will be rendering iLOD = m_pPatches[GetPatchNumber( PX, PZ )].m_iLOD+1; fSize = ( float )m_iPatchSize; iDivisor= m_iPatchSize-1; //find out how many fan divisions we are going to have while( --iLOD>-1 ) iDivisor= iDivisor>>1; //the size between the center of each triangle fan fSize/= iDivisor; //half the size between the center of each triangle fan (this will be //the size between each vertex) fHalfSize= fSize/2.0f; for( z=fHalfSize; ( ( int )( z+fHalfSize ) )<m_iPatchSize+1; z+=fSize ) { for( x=fHalfSize; ( ( int )( x+fHalfSize ))<m_iPatchSize+1; x+=fSize ) { //if this fan is in the left row, we may need to adjust it's rendering to //prevent cracks if( x==fHalfSize ) fanNeighbor.m_bLeft= patchNeighbor.m_bLeft; else fanNeighbor.m_bLeft= true; //if this fan is in the bottom row, we may need to adjust it's rendering to //prevent cracks if( z==fHalfSize ) fanNeighbor.m_bDown= patchNeighbor.m_bDown; else fanNeighbor.m_bDown= true; //if this fan is in the right row, we may need to adjust it's rendering to //prevent cracks if( x>=( m_iPatchSize-fHalfSize ) ) fanNeighbor.m_bRight= patchNeighbor.m_bRight; else fanNeighbor.m_bRight= true; //if this fan is in the top row, we may need to adjust it's rendering to //prevent cracks if( z>=( m_iPatchSize-fHalfSize ) ) fanNeighbor.m_bUp= patchNeighbor.m_bUp; else fanNeighbor.m_bUp= true; //render the triangle fan RenderFan( ( PX*m_iPatchSize )+x, ( PZ*m_iPatchSize )+z, fSize, fanNeighbor, bMultiTex, bDetail ); } } }
//-------------------------------------------------------------- // Name: CGEOMIPMAPPING::Render - public // Description: Render the geomipmapping system // Arguments: None // Return Value: None //-------------------------------------------------------------- void CGEOMIPMAPPING::Render( void ) { int x, z; //reset the counting variables m_iPatchesPerFrame = 0; m_iVertsPerFrame= 0; m_iTrisPerFrame = 0; //enable back-face culling glEnable( GL_CULL_FACE ); //render the multitexturing terrain if( m_bMultitexture && m_bDetailMapping && m_bTextureMapping ) { glDisable( GL_BLEND ); //bind the primary color texture to the first texture unit glActiveTextureARB( GL_TEXTURE0_ARB ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, m_texture.GetID( ) ); //bind the detail color texture to the second texture unit glActiveTextureARB( GL_TEXTURE1_ARB ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, m_detailMap.GetID( ) ); glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB ); glTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2 ); //render the patches for( z=0; z<m_iNumPatchesPerSide; z++ ) { for( x=0; x<m_iNumPatchesPerSide; x++ ) { if( m_pPatches[GetPatchNumber( x, z )].m_bVisible ) { RenderPatch( x, z, true, true ); m_iPatchesPerFrame++; } } } } //no hardware multitexturing available, or the user only wants to render //the detail texture or the color texture else { if( m_bTextureMapping ) { //bind the primary color texture (FOR THE PRIMARY TEXTURE PASS) glActiveTextureARB( GL_TEXTURE0_ARB ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, m_texture.GetID( ) ); //render the color texture for( z=0; z<m_iNumPatchesPerSide; z++ ) { for( x=0; x<m_iNumPatchesPerSide; x++ ) { if( m_pPatches[GetPatchNumber( x, z )].m_bVisible ) { RenderPatch( x, z, true, true ); m_iPatchesPerFrame++; } } } } if( !( m_bTextureMapping && !m_bDetailMapping ) ) { //if the user wants detail mapping, we need to set some things up if( m_bDetailMapping ) { //bind the detail texture glActiveTextureARB( GL_TEXTURE0_ARB ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, m_detailMap.GetID( ) ); //only use blending if a texture pass was made if( m_bTextureMapping ) { glEnable( GL_BLEND ); glBlendFunc( GL_ZERO, GL_SRC_COLOR ); } } //render either the detail map on top of the texture, //only the detail map, or neither for( z=0; z<m_iNumPatchesPerSide; z++ ) { for( x=0; x<m_iNumPatchesPerSide; x++ ) { if( m_pPatches[GetPatchNumber( x, z )].m_bVisible ) { RenderPatch( x, z, true, true ); m_iPatchesPerFrame++; } } } } } glDisable( GL_BLEND ); //unbind the texture occupying the second texture unit glActiveTextureARB( GL_TEXTURE1_ARB ); glDisable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, 0 ); //unbind the texture occupying the first texture unit glActiveTextureARB( GL_TEXTURE0_ARB ); glDisable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, 0 ); }
//-------------------------------------------------------------- // Name: CGEOMIPMAPPING::Update - public // Description: Update the geomipmapping system // Arguments: -camera: the camera object your demo is using // -bCullPatches: cull unseen patches (true by default) // Return Value: None //-------------------------------------------------------------- void CGEOMIPMAPPING::Update( CCAMERA camera, bool bCullPatches ) { float fX, fY, fZ; float fScaledSize; int x, z; int iPatch; fScaledSize= m_iPatchSize*m_vecScale[0]; for( z=0; z<m_iNumPatchesPerSide; z++ ) { for( x=0; x<m_iNumPatchesPerSide; x++ ) { iPatch= GetPatchNumber( x, z ); //compute patch center (used for distance determination fX= ( x*m_iPatchSize )+( m_iPatchSize/2.0f ); fZ= ( z*m_iPatchSize )+( m_iPatchSize/2.0f ); fY= GetScaledHeightAtPoint( ( int )fX, ( int )fZ ); //only scale the X and Z values, the Y value has already been scaled fX*= m_vecScale[0]; fZ*= m_vecScale[2]; //check to see if the user wanted to cull the non-visible patches if( bCullPatches ) { //do a frustum test against the patch if( camera.CubeFrustumTest( fX, fY, fZ, m_iPatchSize*m_vecScale[0] ) ) m_pPatches[iPatch].m_bVisible= true; //the patch is not visible else m_pPatches[iPatch].m_bVisible= false; } //make all patches visible else m_pPatches[iPatch].m_bVisible= true; //only finish updating if the patch is visible if( m_pPatches[iPatch].m_bVisible ) { //get the distance from the camera to the patch m_pPatches[iPatch].m_fDistance= sqrtf( SQUARE( ( fX-camera.m_vecEyePos[0] ) )+ SQUARE( ( fY-camera.m_vecEyePos[1] ) )+ SQUARE( ( fZ-camera.m_vecEyePos[2] ) ) ); //BAD way to determine patch LOD, we will be fixing this code a bit later in the chapter if( m_pPatches[iPatch].m_fDistance<500 ) m_pPatches[iPatch].m_iLOD= 0; else if( m_pPatches[iPatch].m_fDistance<1000 ) m_pPatches[iPatch].m_iLOD= 1; else if( m_pPatches[iPatch].m_fDistance<2500 ) m_pPatches[iPatch].m_iLOD= 2; else if( m_pPatches[iPatch].m_fDistance>=2500 ) m_pPatches[iPatch].m_iLOD= 3; } } } }
// 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); }
// See if any particles have changed elements // Stop if off the grid // throws CommonException() void ResetElementsTask::Execute(void) { // update feedback damping now if needed bodyFrc.UpdateAlpha(timestep,mtime); // how many patches? int totalPatches = fmobj->GetTotalNumberOfPatches(); #ifdef PARALLEL_RESET // initialize error CommonException *resetErr = NULL; // parallel over patches #pragma omp parallel { // thread for patch pn int pn = GetPatchNumber(); try { // resetting all element types for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_BC;block++) { // get first material point in this block MPMBase *mptr = patches[pn]->GetFirstBlockPointer(block); MPMBase *prevMptr = NULL; // previous one of this type in current patch while(mptr!=NULL) { int status = ResetElement(mptr); if(status==LEFT_GRID) { // particle has left the grid mptr->IncrementElementCrossings(); // enter warning only if this particle did not leave the grid before if(!mptr->HasLeftTheGridBefore()) { int result = warnings.Issue(fmobj->warnParticleLeftGrid,-1); if(result==REACHED_MAX_WARNINGS || result==GAVE_WARNING) { #pragma omp critical (output) { mptr->Describe(); } // abort if needed if(result==REACHED_MAX_WARNINGS) { char errMsg[100]; sprintf(errMsg,"Too many particles have left the grid\n (plot x displacement to see last one)."); mptr->origpos.x=-1.e6; throw CommonException(errMsg,"ResetElementsTask::Execute"); } } // set this particle has left the grid once mptr->SetHasLeftTheGridBefore(TRUE); } // bring back to the previous element ReturnToElement(mptr); } else if(status==NEW_ELEMENT && totalPatches>1) { // did it also move to a new patch? int newpn = mpmgrid.GetPatchForElement(mptr->ElemID()); if(pn != newpn) { if(!patches[pn]->AddMovingParticle(mptr,patches[newpn],prevMptr)) { throw CommonException("Out of memory storing data for particle changing patches","ResetElementsTask::Execute"); } } } else if(status==LEFT_GRID_NAN) { #pragma omp critical (output) { cout << "# Particle has left the grid and position is nan" << endl; mptr->Describe(); } throw CommonException("Particle has left the grid and position is nan","ResetElementsTask::Execute"); } // next material point and update previous particle prevMptr = mptr; mptr = (MPMBase *)mptr->GetNextObject(); } } } catch(CommonException& err) { if(resetErr==NULL) { #pragma omp critical (error) resetErr = new CommonException(err); } } catch(std::bad_alloc&) { if(resetErr==NULL) { #pragma omp critical (error) resetErr = new CommonException("Memory error","ResetElementsTask::Execute"); } } catch(...) { if(resetErr==NULL) { #pragma omp critical (error) resetErr = new CommonException("Unexepected error","ResetElementsTask::Execute"); } } } // throw now if was an error if(resetErr!=NULL) throw *resetErr; // reduction phase moves the particles for(int pn=0;pn<totalPatches;pn++) patches[pn]->MoveParticlesToNewPatches(); #else int status; MPMBase *mptr,*prevMptr,*nextMptr; for(int pn=0;pn<totalPatches;pn++) { for(int block=FIRST_NONRIGID;block<=FIRST_RIGID_BC;block++) { // get first material point in this block mptr = patches[pn]->GetFirstBlockPointer(block); prevMptr = NULL; // previous one of this type in current patch while(mptr!=NULL) { status = ResetElement(mptr); if(status==LEFT_GRID) { // particle has left the grid mptr->IncrementElementCrossings(); // enter warning only if this particle did not leave the grid before if(!mptr->HasLeftTheGridBefore()) { int result = warnings.Issue(fmobj->warnParticleLeftGrid,-1); if(result==REACHED_MAX_WARNINGS || result==GAVE_WARNING) { mptr->Describe(); // abort if needed if(result==REACHED_MAX_WARNINGS) { char errMsg[100]; sprintf(errMsg,"Too many particles have left the grid\n (plot x displacement to see last one)."); mptr->origpos.x=-1.e6; throw CommonException(errMsg,"ResetElementsTask::Execute"); } } // set this particle has left the grid once mptr->SetHasLeftTheGridBefore(TRUE); } // bring back to the previous element ReturnToElement(mptr); } else if(status==NEW_ELEMENT && totalPatches>1) { int newpn = mpmgrid.GetPatchForElement(mptr->ElemID()); if(pn != newpn) { // next material point read before move this particle nextMptr = (MPMBase *)mptr->GetNextObject(); // move particle mptr patches[pn]->RemoveParticleAfter(mptr,prevMptr); patches[newpn]->AddParticle(mptr); // next material point is now after the prevMptr, which stays the same, which may be NULL mptr = nextMptr; continue; } } else if(status==LEFT_GRID_NAN) { cout << "# Particle has left the grid and position is nan" << endl; mptr->Describe(); throw CommonException("Particle has left the grid and position is nan","ResetElementsTask::Execute"); } // next material point and update previous particle prevMptr = mptr; mptr = (MPMBase *)mptr->GetNextObject(); } } } #endif }
void GeoMipMapping::RenderPatch(int px, int pz) { SGEOMM_NEIGHBOR patchNeighbor; SGEOMM_NEIGHBOR fanNeighbor; float fSize = 0.0f; float fHalfSize = 0.0f; float z, x; int iPatch = GetPatchNumber(px, pz); int iDivisor = 0; int iLOD = 0; //左边的比较精细,所以不用管,直接可以绘制 if (m_pPatches[GetPatchNumber(px - 1, pz)].m_iLOD <= m_pPatches[iPatch].m_iLOD || px == 0) patchNeighbor.m_bLeft = true; //可以绘制 else patchNeighbor.m_bLeft = false; //不能绘制 if (m_pPatches[GetPatchNumber(px, pz + 1)].m_iLOD <= m_pPatches[iPatch].m_iLOD || pz == m_iNumPatchesPerSide) patchNeighbor.m_bUp = true; else patchNeighbor.m_bUp = false; if (m_pPatches[GetPatchNumber(px + 1, pz)].m_iLOD <= m_pPatches[iPatch].m_iLOD || px == m_iNumPatchesPerSide) patchNeighbor.m_bRight = true; else patchNeighbor.m_bRight = false; if (m_pPatches[GetPatchNumber(px, pz - 1)].m_iLOD <= m_pPatches[iPatch].m_iLOD || pz == 0) patchNeighbor.m_bBottom = true; else patchNeighbor.m_bBottom = false; fSize = (float)m_iPatchSize; iDivisor = m_iPatchSize - 1; iLOD = m_pPatches[iPatch].m_iLOD; while (iLOD-- >= 0) iDivisor >>= 1; fSize /= iDivisor; fHalfSize = fSize / 2.0f; for (z = fHalfSize; ((int)z + fHalfSize ) < m_iPatchSize + 1; z += fSize) { for (x = fHalfSize; ((int)x + fHalfSize) < m_iPatchSize + 1; x += fSize) { if (x == fHalfSize) fanNeighbor.m_bLeft = patchNeighbor.m_bLeft; else fanNeighbor.m_bLeft = true; if (z == fHalfSize) fanNeighbor.m_bBottom = patchNeighbor.m_bBottom; else fanNeighbor.m_bBottom = true; if (x >= (m_iPatchSize - fHalfSize)) fanNeighbor.m_bRight = patchNeighbor.m_bRight; else fanNeighbor.m_bRight = true; if (z >= (m_iPatchSize - fHalfSize)) fanNeighbor.m_bUp = patchNeighbor.m_bUp; else fanNeighbor.m_bUp = true; RenderFan((px * m_iPatchSize) + x, (pz * m_iPatchSize) + z, fSize, fanNeighbor); } } }
// 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(); } }