void _MeshParticleLayout_InitialiseParticlesOfCell( void* meshParticleLayout, void* _swarm, Cell_Index cell_I ) { MeshParticleLayout* self = (MeshParticleLayout*)meshParticleLayout; Swarm* swarm = (Swarm*)_swarm; Particle_InCellIndex particlesThisCell = swarm->cellParticleCountTbl[cell_I]; Particle_InCellIndex cParticle_I = 0; GlobalParticle* particle = NULL; double lCoord[3]; unsigned dim_i; unsigned nDims = Mesh_GetDimSize( self->mesh ); for( cParticle_I = 0; cParticle_I < particlesThisCell; cParticle_I++ ) { particle = (GlobalParticle*)Swarm_ParticleInCellAt( swarm, cell_I, cParticle_I ); particle->owningCell = cell_I; if (self->filltype == 0 ) { for( dim_i = 0; dim_i < nDims; dim_i++ ) lCoord[dim_i] = SobolGenerator_GetNextNumber_WithMinMax( self->sobolGenerator[dim_i], -1.0, +1.0 ); } else if (self->filltype == 1){ for( dim_i = 0; dim_i < nDims; dim_i++ ) lCoord[dim_i] = Swarm_Random_Random_WithMinMax( -1.0, +1.0 ); } else Journal_Firewall( NULL, NULL, "In func %s: Invalid fill type setting. Must be 0 (space filler), or 1 (random).", __func__ ); FeMesh_CoordLocalToGlobal( self->mesh, cell_I, lCoord, particle->coord ); } }
int _Ppc_VecDotVec_Get( void* _self, unsigned lElement_I, IntegrationPoint* particle, double* result ) { Ppc_VecDotVec* self = (Ppc_VecDotVec*) _self; double dot, vec1[3], vec2[3]; int err; memset(vec1, 0, sizeof(double)*3); memset(vec2, 0, sizeof(double)*3); err = PpcManager_Get( self->manager, lElement_I, particle, self->vec1, &(vec1[0]) ); err = PpcManager_Get( self->manager, lElement_I, particle, self->vec2, &(vec2[0]) ); if( self->transformv1 ) { double xyz[3], rtp[3]; memcpy( rtp, vec1, sizeof(double)*3 ); FeMesh_CoordLocalToGlobal( self->manager->mesh, lElement_I, particle->xi, xyz ); Spherical_VectorRTP2XYZ( rtp, xyz, self->manager->integrationSwarm->dim, vec1 ) ; } dot = vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2] ; *result = dot; return 0; }
int _Ppc_Auto_Thermal_Profile_Get( void* _self, unsigned lElement_I, IntegrationPoint* particle, double* result ) { Ppc_Auto_Thermal_Profile* self = (Ppc_Auto_Thermal_Profile*) _self; Coord coord; double start_coord, end_coord, min_temp, max_temp, temp; double rho, cp, alpha, radiogenic; double k, c1, z, term1; unsigned int vertaxis; int err; err = PpcManager_Get( self->manager, lElement_I, particle, self->cpTag, &cp ); assert(!err); err = PpcManager_Get( self->manager, lElement_I, particle, self->diffusivityTag, &alpha ); assert(!err); err = PpcManager_Get( self->manager, lElement_I, particle, self->radiogenicTag, &radiogenic ); assert(!err); err = PpcManager_Get( self->manager, lElement_I, particle, self->densityTag, &rho ); assert(!err); start_coord = self->start_coord; end_coord = self->end_coord; min_temp = self->min_temp; max_temp = self->max_temp; vertaxis = self->axis; FeMesh_CoordLocalToGlobal( self->manager->mesh, lElement_I, particle->xi, coord ); z = coord[vertaxis]; if( z > start_coord ) temp = min_temp; else if( z <= start_coord && z > end_coord ) { /* This is doing the steady-state conduction-advection geotherm */ k = rho*cp*alpha; term1 = (radiogenic/(2*k))*(z*z); c1 = (max_temp-min_temp+term1)/z; temp = -term1 + (c1*z) + min_temp; } else temp = max_temp; /* if( temp > max_temp ) temp = max_temp; if( temp < min_temp ) temp = min_temp; */ result[0] = temp; return 0; }
int _Ppc_IsInsideShape_Get( void* _self, Element_LocalIndex lElement_I, IntegrationPoint* particle, double* result ) { /*@ returns 1 if a particle is found within the specified shape @*/ Ppc_IsInsideShape* self = (Ppc_IsInsideShape*) _self; double globalCoord[3]; int err = 0; // get global coords FeMesh_CoordLocalToGlobal( self->manager->integrationSwarm->mesh, lElement_I, particle->xi, globalCoord ); if( Stg_Shape_IsCoordInside( self->shape, globalCoord ) ) { result[0] = 1; } else { result[0] = 0; } return err; }
int _Ppc_PointGravity_Get( void* _self, Element_LocalIndex lElement_I, IntegrationPoint* particle, double* result ) { Ppc_PointGravity* self = (Ppc_PointGravity*) _self; MaterialPointsSwarm *ms=NULL; double vector[3], gravity[3], global[3], mag, alpha; int err; // get global coord FeMesh_CoordLocalToGlobal( self->manager->integrationSwarm->mesh, lElement_I, particle->xi, global ); // calc vector to self->point vector[0] = self->point[0]-global[0]; vector[1] = self->point[1]-global[1]; vector[2] = self->point[2]-global[2]; if (self->manager->integrationSwarm->dim == 2) vector[2]=0; mag = StGermain_VectorMagnitude( vector, self->manager->integrationSwarm->dim ); // make a unit vector vector[0] = vector[0] / mag; vector[1] = vector[1] / mag; vector[2] = vector[2] / mag; assert( fabs(StGermain_VectorMagnitude( vector, self->manager->integrationSwarm->dim )-1) < 1e-8 ); /* get alpha */ err = PpcManager_Get( self->manager, lElement_I, particle, self->alphaTag, &alpha ); assert( !err ); /* TODO: Gravity doesn't need to be a static vector type now, this implementation should be changed so Gravity could be defined as a general ppc */ err = PpcManager_GetGravity( self->manager, lElement_I, particle, gravity ); assert( !err ); /* return unit vector */ result[0] = gravity[1] * alpha * vector[0]; result[1] = gravity[1] * alpha * vector[1]; result[2] = gravity[1] * alpha * vector[2]; return 0; }
double _Byerlee_GetYieldCriterion( void* rheology, ConstitutiveMatrix* constitutiveMatrix, MaterialPointsSwarm* materialPointsSwarm, Element_LocalIndex lElement_I, MaterialPoint* materialPoint, Coord xi ) { Byerlee* self = (Byerlee*) rheology; double depth = 0.0; double height; int err; Coord coord; /* stupid way to recover the integration point from the materialPoint * TODO: FIXCONSTITUTIVE use integration point only */ IntegrationPoint* integrationPoint = (IntegrationPoint*) Swarm_ParticleAt( constitutiveMatrix->integrationSwarm, constitutiveMatrix->currentParticleIndex ); /* Calculate Depth */ if( self->height_id != -1 ) { err = PpcManager_Get( self->mgr, lElement_I, integrationPoint, self->height_id, &height ); Journal_Firewall( !err, global_error_stream, "Error in file %s. Cannot get reference height for '%s'. Ensure you have passed in the correct input with a line like\n\t<param name=\"HeightReferenceInput\">someInputfunction</param>\n", __func__, self->name ); } else { double min[3], max[3]; Mesh_GetGlobalCoordRange( self->mesh, min, max ); height = max[ J_AXIS ]; } /* This rheology assumes particle is an integration points thats can be mapped to a particle * that has no meaningful coord. Best to re-calc the global from local */ FeMesh_CoordLocalToGlobal( self->mesh, lElement_I, xi, coord ); depth = height - coord[ J_AXIS ]; return self->cohesion + self->depthCoefficient * depth; }
void lucIsosurface_DrawWalls( lucIsosurface* self, Vertex ***vertex ) { int i, j, k; Vertex ** points; Vertex * midVertices; /* Allocate Memory */ points = Memory_Alloc_Array( Vertex* , 8, "array for marching squares"); midVertices = Memory_Alloc_Array( Vertex , 4, "array for marching squares"); points[LEFT] = &midVertices[0]; points[RIGHT] = &midVertices[1]; points[TOP] = &midVertices[2]; points[BOTTOM] = &midVertices[3]; /* Check boundaries of area this vertex array covers, * only draw walls if aligned to outer edges of global domain */ int min[3], max[3], range[3] = {self->nx-1, self->ny-1, self->nz-1}; int axis; if (self->sampleGlobal || self->isosurfaceField->dim == 2) { /* Array covers the entire domain, don't need to check */ for (axis=0; axis<3; axis++) { min[axis] = 0; max[axis] = range[axis]; if (range[axis] == 0) range[axis] = 1; } } else { /* Compare global min/max to min/max of our sample region and set ranges to process accordingly */ FeVariable* field = (FeVariable*)self->isosurfaceField; Coord posMin, posMax; FeMesh_CoordLocalToGlobal( field->feMesh, vertex[0][0][0].element_I, vertex[0][0][0].pos, posMin ); FeMesh_CoordLocalToGlobal( field->feMesh, vertex[self->nx-1][self->ny-1][self->nz-1].element_I, vertex[self->nx-1][self->ny-1][self->nz-1].pos, posMax ); for (axis=0; axis<3; axis++) { if (posMin[axis] == self->globalMin[axis]) min[axis] = 0; else min[axis] = range[axis]; if (posMax[axis] == self->globalMax[axis]) max[axis] = range[axis]; else max[axis] = 0; } } /* Generate front/back walls (Z=min/max, sample XY) */ if (range[K_AXIS] > 0) { for ( i = 0 ; i < self->nx - 1 ; i++ ) { for ( j = 0 ; j < self->ny - 1 ; j++ ) { for ( k = min[K_AXIS]; k <= max[K_AXIS]; k += range[K_AXIS]) { points[LEFT_BOTTOM] = &vertex[ i ][ j ][k]; points[RIGHT_BOTTOM] = &vertex[i+1][ j ][k]; points[LEFT_TOP] = &vertex[ i ][j+1][k]; points[RIGHT_TOP] = &vertex[i+1][j+1][k]; lucIsosurface_WallElement( self, points ); } } } } /* Generate left/right walls (X=min/max, sample YZ) */ if (self->isosurfaceField->dim == 3 && range[I_AXIS] > 0) { for ( k = 0 ; k < self->nz - 1 ; k++ ) { for ( j = 0 ; j < self->ny - 1 ; j++ ) { for ( i = min[I_AXIS]; i <= max[I_AXIS]; i += range[I_AXIS]) { points[LEFT_BOTTOM] = &vertex[i][ j ][ k ]; points[RIGHT_BOTTOM] = &vertex[i][j+1][ k ]; points[LEFT_TOP] = &vertex[i][ j ][k+1]; points[RIGHT_TOP] = &vertex[i][j+1][k+1]; lucIsosurface_WallElement( self, points ); } } } } /* Generate top/bottom walls (Y=min/max, sample XZ) */ if (self->isosurfaceField->dim == 3 && range[J_AXIS] > 0) { for ( i = 0 ; i < self->nx - 1 ; i++ ) { for ( k = 0 ; k < self->nz - 1 ; k++ ) { for ( j = min[J_AXIS]; j <= max[J_AXIS]; j += range[J_AXIS]) { points[LEFT_BOTTOM] = &vertex[ i ][j][ k ]; points[RIGHT_BOTTOM] = &vertex[i+1][j][ k ]; points[LEFT_TOP] = &vertex[ i ][j][k+1]; points[RIGHT_TOP] = &vertex[i+1][j][k+1]; lucIsosurface_WallElement( self, points ); } } } } Memory_Free( points ); Memory_Free( midVertices ); }
void CreateTriangle(lucIsosurface* self, Vertex* point1, Vertex* point2, Vertex* point3, Bool wall) { Vertex* points[3] = {point1, point2, point3}; int i; if (self->triangleCount >= self->trianglesAlloced) { self->trianglesAlloced += 100; self->triangleList = Memory_Realloc_Array( self->triangleList, Surface_Triangle, self->trianglesAlloced ); } /* Wall flag */ self->triangleList[self->triangleCount].wall = wall; for (i=0; i<3; i++) { double value = 0; float *pos = self->triangleList[self->triangleCount].pos[i]; if (self->sampleGlobal) { /* Check maskField values */ if ( self->maskField ) { double mvalue; FieldVariable_InterpolateValueAt( self->maskField, points[i]->pos, &mvalue); /* Don't bother calculating if vertex is masked */ if (lucDrawingObjectMask_Test( &self->mask, mvalue ) == False) return; } /* Get global coordinates */ pos[0] = points[i]->pos[0]; pos[1] = points[i]->pos[1]; pos[2] = points[i]->pos[2]; if (self->isosurfaceField->dim == 2) pos[2] = 0; /* Get colourField value */ if ( self->colourField && self->colourMap) FieldVariable_InterpolateValueAt( self->colourField, points[i]->pos, &value); } else { FeVariable* field = (FeVariable*)self->isosurfaceField; double dpos[3] = {0}; /* Check maskField values */ if ( self->maskField ) { double mvalue; FeVariable_InterpolateWithinElement( self->maskField, points[i]->element_I, points[i]->pos, &mvalue); /* Don't bother calculating if vertex is masked */ if (lucDrawingObjectMask_Test( &self->mask, mvalue ) == False) return; } /* Get global coordinates */ FeMesh_CoordLocalToGlobal( field->feMesh, points[i]->element_I, points[i]->pos, dpos ); pos[0] = dpos[0]; pos[1] = dpos[1]; pos[2] = dpos[2]; /* Get colourField value */ if ( self->colourField && self->colourMap) FeVariable_InterpolateWithinElement( self->colourField, points[i]->element_I, points[i]->pos, &value); } /* Copy value */ self->triangleList[self->triangleCount].value[i] = value; } self->triangleCount++; }
void _MatAssembly_NA__Fi__NB_AssembleElement( void* matrixTerm, StiffnessMatrix* stiffnessMatrix, Element_LocalIndex lElement_I, SystemLinearEquations* sle, FiniteElementContext* context, double** elStiffMat ) { MatAssembly_NA__Fi__NB* self = (MatAssembly_NA__Fi__NB*)matrixTerm; Swarm* swarm = self->integrationSwarm; FeVariable* rowFeVar = stiffnessMatrix->rowVariable; FeVariable* colFeVar = stiffnessMatrix->columnVariable; Dimension_Index dim = stiffnessMatrix->dim; int rowDofs = rowFeVar->fieldComponentCount; // number of dofs per row node int colDofs = colFeVar->fieldComponentCount; // number of dofs per row node IntegrationPoint* currIntegrationPoint; double* xi; double weight; Particle_InCellIndex cParticle_I, cellParticleCount; Index rowNodes; // number of row nodes per element Index colNodes; // number of col nodes per element Index A,B; Index i; double detJac; double gradRho_rtp[3], gradRho_xyz[3], rho, xyz[3]; Cell_Index cell_I; ElementType* rowElementType, *colElementType; double N[27], M[6]; /* Set the element type */ rowElementType = FeMesh_GetElementType( rowFeVar->feMesh, lElement_I ); rowNodes = rowElementType->nodeCount; colElementType = FeMesh_GetElementType( colFeVar->feMesh, lElement_I ); colNodes = colElementType->nodeCount; cell_I = CellLayout_MapElementIdToCellId( swarm->cellLayout, lElement_I ); cellParticleCount = swarm->cellParticleCountTbl[ cell_I ]; for( cParticle_I = 0 ; cParticle_I < cellParticleCount ; cParticle_I++ ) { currIntegrationPoint = (IntegrationPoint*)Swarm_ParticleInCellAt( swarm, cell_I, cParticle_I ); xi = currIntegrationPoint->xi; weight = currIntegrationPoint->weight; /* Calculate Determinant of Jacobian and Shape Functions */ detJac = ElementType_JacobianDeterminant( colElementType, colFeVar->feMesh, lElement_I, xi, dim ); ElementType_EvaluateShapeFunctionsAt( rowElementType, xi, M ); ElementType_EvaluateShapeFunctionsAt( colElementType, xi, N ); /* evaluate ppc function */ PpcManager_Get( self->ppcManager, lElement_I, currIntegrationPoint, self->rho, &rho ); // ASSUMES: gradRho_rtp[0] is the radial component of grad(rho) PpcManager_Get( self->ppcManager, lElement_I, currIntegrationPoint, self->grad_rho, &(gradRho_rtp[0]) ); gradRho_rtp[0]=-1*gradRho_rtp[0]/rho; gradRho_rtp[1]=0; gradRho_rtp[2]=0; // minus one because depth is the negative of radial-axis // This needs to be converted to an xyz basis vector FeMesh_CoordLocalToGlobal( colFeVar->feMesh, lElement_I, xi, xyz ); Spherical_VectorRTP2XYZ( gradRho_rtp, xyz, 2, gradRho_xyz ); for( A=0; A<rowNodes; A++ ) { for( B=0; B<colNodes; B++ ) { for ( i = 0; i < colDofs ; i++ ) { elStiffMat[rowDofs*A][colDofs*B+i] += detJac * weight * M[A] * gradRho_xyz[i] * N[B] ; } } } } }
double _GALEDruckerPrager_GetYieldCriterion( void* druckerPrager, ConstitutiveMatrix* constitutiveMatrix, MaterialPointsSwarm* materialPointsSwarm, Element_LocalIndex lElement_I, MaterialPoint* materialPoint, Coord xi ) { GALEDruckerPrager* self = (GALEDruckerPrager*) druckerPrager; Dimension_Index dim = constitutiveMatrix->dim; double cohesion; double cohesionAfterSoftening; double frictionCoefficient; double frictionCoefficientAfterSoftening; double minimumYieldStress; double minimumViscosity; double effectiveCohesion; double effectiveFrictionCoefficient; double frictionalStrength; double pressure; GALEDruckerPrager_Particle* particleExt; Cell_Index cell_I; Coord coord; Element_GlobalIndex element_gI = 0; unsigned inds[3]; Grid* elGrid; Bool inside_boundary; double factor; /* Get Parameters From Rheology */ cohesion = self->cohesion; cohesionAfterSoftening = self->cohesionAfterSoftening; frictionCoefficient = self->frictionCoefficient; frictionCoefficientAfterSoftening = self->frictionCoefficientAfterSoftening; minimumYieldStress = self->minimumYieldStress; minimumViscosity = self->minimumViscosity; particleExt = (GALEDruckerPrager_Particle*)ExtensionManager_Get( materialPointsSwarm->particleExtensionMgr, materialPoint, self->particleExtHandle ); if( self->pressureField ) FeVariable_InterpolateWithinElement( self->pressureField, lElement_I, xi, &pressure ); else { SwarmVariable_ValueAt( self->swarmPressure, constitutiveMatrix->currentParticleIndex, &pressure ); } cell_I=CellLayout_MapElementIdToCellId(materialPointsSwarm->cellLayout, lElement_I ); FeMesh_CoordLocalToGlobal(self->pressureField->feMesh, cell_I, xi, coord); if(self->hydrostaticTerm) { pressure+=HydrostaticTerm_Pressure(self->hydrostaticTerm,coord); } /* Normally we add the average of the trace of the stress. With compressible material, you have to do it. But with stabilized linear pressure elements, the non-zero trace is a numerical artifact. So we do not add it. */ /* pressure+=self->trace/dim; */ /* Calculate frictional strength. We modify the friction and cohesion because we have grouped terms from the normal stresses and moved it to the yield indicator. */ /* Big song and dance to see if we are at a boundary that we care about */ elGrid = *(Grid**)ExtensionManager_Get(self->pressureField->feMesh->info, self->pressureField->feMesh, self->pressureField->feMesh->elGridId ); element_gI = FeMesh_ElementDomainToGlobal( self->pressureField->feMesh, lElement_I ); RegularMeshUtils_Element_1DTo3D( self->pressureField->feMesh, element_gI, inds ); inside_boundary=(self->boundaryBottom && inds[1]==0) || (self->boundaryTop && inds[1]==elGrid->sizes[1]-1) || (self->boundaryLeft && inds[0]==0) || (self->boundaryRight && inds[0]==elGrid->sizes[0]-1) || (dim==3 && ((self->boundaryBack && inds[2]==0) || (self->boundaryFront && inds[2]==elGrid->sizes[2]-1))); effectiveFrictionCoefficient = _GALEDruckerPrager_EffectiveFrictionCoefficient( self, materialPoint, inside_boundary ); effectiveCohesion = _GALEDruckerPrager_EffectiveCohesion(self,materialPoint, inside_boundary); if(dim==2) { /* effectiveFrictionCoefficient=tan(phi). If factor=sin(atan(1/tan(phi))) => factor=cos(phi)=1/sqrt(1+tan(phi)**2) */ factor=1/sqrt(1 + effectiveFrictionCoefficient*effectiveFrictionCoefficient); frictionalStrength = effectiveFrictionCoefficient*pressure*factor + effectiveCohesion*factor; } else { double cos_phi, sin_phi; /* cos(phi)=1/sqrt(1+tan(phi)**2) */ cos_phi= 1/sqrt(1 + effectiveFrictionCoefficient*effectiveFrictionCoefficient); sin_phi=effectiveFrictionCoefficient*cos_phi; factor=2*cos_phi/(sqrt(3.0)*(3-sin_phi)); /* The full expression is sqrt(J2)=p*2*sin(phi)/(sqrt(3)*(3-sin(phi))) + C*6*cos(phi)/(sqrt(3)*(3-sin(phi))) Note the extra factor of 3 for cohesion */ frictionalStrength = effectiveFrictionCoefficient*factor*pressure + effectiveCohesion*3*factor; } /* If the minimumYieldStress is not set, then use the effective cohesion. Maybe it should be the modified effective cohesion, though that probably should not matter much. */ minimumYieldStress = self->minimumYieldStress; if(minimumYieldStress==0.0) minimumYieldStress=effectiveCohesion; /* Make sure frictionalStrength is above the minimum */ if ( frictionalStrength < minimumYieldStress*factor) frictionalStrength = minimumYieldStress*factor; self->yieldCriterion = frictionalStrength; self->curFrictionCoef = effectiveFrictionCoefficient*factor; return frictionalStrength; }
void _SPR_StrainRate_AssemblePatch( SPR_StrainRate* self, int node_I, double** AMatrix, double** bVector) { /* * Functiona Details: * This assembles the AMatrix and the bVectors, see eq. 14.31, REFERENCE. * First the elements around the patch node are found, then for each element the * cooordinate and the strain rate at the super convergent locations are stored. */ OperatorFeVariable* rawField = self->rawField; FeMesh* feMesh = (FeMesh*)rawField->feMesh; Index dofThatExist = rawField->fieldComponentCount; Index nbrEl_I, nbrElementID, nbrElCount; Index count_i, count_j, dof_I; double center[3] = {0.0,0.0,0.0}; int orderOfInterpolation = self->orderOfInterpolation; IArray* inc = self->inc; SymmetricTensor *scp_eps; double **globalCoord; double **pVec; int *nbrElList; /* 1) find the elements around the node and point to them via the nbrElList*/ FeMesh_GetNodeElements( feMesh, node_I, inc ); nbrElCount = IArray_GetSize( inc ); nbrElList = IArray_GetPtr( inc ); /* 2) Memory Allocations + Initialisations */ scp_eps = Memory_Alloc_Array( SymmetricTensor, nbrElCount, "StrainRate at superconvergent points" ); globalCoord = Memory_Alloc_2DArray( double, nbrElCount, self->dim, (Name)"Global Coords of superconvergent points" ); pVec = Memory_Alloc_2DArray( double, nbrElCount, orderOfInterpolation, (Name)"Holds transformed global coord polynomials" ); /* 3 ) Now collect information, to go find each elements contribution to the patch * So find the p vectors and strain-rate pseudo vectors for the Ax=b equation */ for( nbrEl_I = 0 ; nbrEl_I < nbrElCount ; nbrEl_I++ ) { nbrElementID = nbrElList[ nbrEl_I ]; FeMesh_CoordLocalToGlobal( feMesh, nbrElementID, center, globalCoord[nbrEl_I] ); self->_makePoly( globalCoord[nbrEl_I], pVec[nbrEl_I] ); _OperatorFeVariable_InterpolateWithinElement( rawField, nbrElList[nbrEl_I], center, scp_eps[nbrEl_I] ); } /* Construct A Matrix (Geometric based) and b Vectors (tensor based) */ for( nbrEl_I = 0 ; nbrEl_I < nbrElCount ; nbrEl_I++ ) { for( count_i = 0 ; count_i < orderOfInterpolation ; count_i++ ) { for( count_j = 0; count_j < orderOfInterpolation ; count_j++ ) { AMatrix[count_i][count_j] += ( pVec[nbrEl_I][count_i] * pVec[nbrEl_I][count_j] ); } } for(dof_I = 0 ; dof_I < dofThatExist ; dof_I++ ) { for( count_i = 0 ; count_i < orderOfInterpolation ; count_i++ ) { bVector[dof_I][ count_i ] += (scp_eps[nbrEl_I][dof_I] * pVec[nbrEl_I][count_i]); } } } Memory_Free( scp_eps ); Memory_Free( globalCoord ); Memory_Free( pVec ); }
void Spherical_CubedSphereNusselt_Output( UnderworldContext* context ) { Spherical_CubedSphereNusselt* self = NULL; Swarm* swarm = NULL; FeMesh* mesh = NULL; ElementType* elementType = NULL; Grid* grid = NULL; double avgT, vol; self = (Spherical_CubedSphereNusselt*)LiveComponentRegister_Get( context->CF->LCRegister, (Name)Spherical_CubedSphereNusselt_Type ); FeVariable *temperatureGradientsField = self->temperatureGradientsField; FeVariable *temperatureField = self->temperatureField; FeVariable *velocityField = self->velocityField; swarm = self->gaussSwarm; mesh = (FeMesh*)self->mesh; assert( self ); assert( mesh ); assert( swarm ); /* for each boundary element at the top integrate dT/dr & integrate T*v_r ASSUMPTIONS: * uses grid data structure for r,theta mesh (cartesian topology so i can) */ unsigned nEls, e_i, cell_i, nPoints, p_i, ijk[3]; IntegrationPoint* particle; double value[3], xyz[3], rtp[3], detJac, dT_dr, factor, vel[3], T, vel_rtp[3]; double gVolume[2], volume[2]; double J_Nu[2], gJ_Nu[2]; double rMin = ((RSGenerator*)mesh->generator)->crdMin[0]; double rMax = ((RSGenerator*)mesh->generator)->crdMin[1]; double dxdr[3], r; elementType = FeMesh_GetElementType( mesh, 0 ); // assuming all element are the same as el 0 memset( J_Nu, 0, 2*sizeof(double) ); memset( volume, 0, 2*sizeof(double) ); RegularMeshUtils_ErrorCheckAndGetDetails( (Mesh*)mesh, MT_VOLUME, &nEls, &grid ); for( e_i = 0; e_i < nEls; e_i++ ) { // use cartesian grid data structure - can improve later on to make more general RegularMeshUtils_Element_1DTo3D( mesh, Mesh_DomainToGlobal( (Mesh*)mesh, MT_VOLUME, e_i ), ijk ); // if element is on the outer radius boundary if( ijk[0] == grid->sizes[0] - 1 ) { // get integration number of integration points in cell cell_i = CellLayout_MapElementIdToCellId( swarm->cellLayout, e_i ); nPoints = swarm->cellParticleCountTbl[ cell_i ]; for( p_i = 0; p_i < nPoints; p_i++ ) { // get integration particle particle = (IntegrationPoint*) Swarm_ParticleInCellAt( swarm, cell_i, p_i ); // get temperatureDeriv and xyz FeVariable_InterpolateFromMeshLocalCoord( temperatureField, (FeMesh*)mesh, e_i, particle->xi, &T); FeVariable_InterpolateFromMeshLocalCoord( velocityField, (FeMesh*)mesh, e_i, particle->xi, vel); FeVariable_InterpolateFromMeshLocalCoord( temperatureGradientsField, (FeMesh*)mesh, e_i, particle->xi, value); FeMesh_CoordLocalToGlobal( mesh, e_i, particle->xi, xyz ); Spherical_XYZ2regionalSphere( xyz, rtp ); Spherical_VectorXYZ2regionalSphere( vel, xyz, vel_rtp ); detJac = ElementType_JacobianDeterminant( elementType, (FeMesh*)mesh, e_i, particle->xi, 3 ); r = sqrt( rtp[0]*rtp[0] + rtp[1]*rtp[1] + rtp[2]*rtp[2] ); dxdr[0] = r/xyz[0]; dxdr[1] = r/xyz[1]; dxdr[2] = r/xyz[2]; // calc dT_dr = dT_dx * dx_dr + dT_dy * dy_dr + dT_dz * dz_dr dT_dr = value[0]*dxdr[0] + value[1]*dxdr[1] + value[2]*dxdr[2]; // add to element integral J_Nu[0] += particle->weight * detJac * (dT_dr - T*vel_rtp[0]); volume[0] += detJac * particle->weight; } } // if element is on the inner radius boundary if( ijk[0] == 0 ) { // get integration number of integration points in cell cell_i = CellLayout_MapElementIdToCellId( swarm->cellLayout, e_i ); nPoints = swarm->cellParticleCountTbl[ cell_i ]; for( p_i = 0; p_i < nPoints; p_i++ ) { // get integration particle particle = (IntegrationPoint*) Swarm_ParticleInCellAt( swarm, cell_i, p_i ); // get temperatureDeriv and xyz FeVariable_InterpolateFromMeshLocalCoord( temperatureField, (FeMesh*)mesh, e_i, particle->xi, &T); FeVariable_InterpolateFromMeshLocalCoord( velocityField, (FeMesh*)mesh, e_i, particle->xi, vel); FeVariable_InterpolateFromMeshLocalCoord( temperatureGradientsField, (FeMesh*)mesh, e_i, particle->xi, value); FeMesh_CoordLocalToGlobal( mesh, e_i, particle->xi, xyz ); Spherical_XYZ2regionalSphere( xyz, rtp ); Spherical_VectorXYZ2regionalSphere( vel, xyz, vel_rtp ); detJac = ElementType_JacobianDeterminant( elementType, (FeMesh*)mesh, e_i, particle->xi, 3 ); r = sqrt( rtp[0]*rtp[0] + rtp[1]*rtp[1] + rtp[2]*rtp[2] ); dxdr[0] = r/xyz[0]; dxdr[1] = r/xyz[1]; dxdr[2] = r/xyz[2]; // calc dT_dr = dT_dx * dx_dr + dT_dy * dy_dr + dT_dz * dz_dr dT_dr = value[0]*dxdr[0] + value[1]*dxdr[1] + value[2]*dxdr[2]; J_Nu[1] += particle->weight * detJac * (dT_dr - T*vel_rtp[0]); volume[1] += detJac * particle->weight; } } } /* Sum of procs integral */ (void)MPI_Allreduce( J_Nu, gJ_Nu, 2, MPI_DOUBLE, MPI_SUM, context->communicator ); (void)MPI_Allreduce( volume, gVolume, 2, MPI_DOUBLE, MPI_SUM, context->communicator ); // to get horizontally averaged quantities we divide by volume gJ_Nu[0] /= gVolume[0]; gJ_Nu[1] /= gVolume[1]; // normalise CubedSphereNusselt upper condition - this is for scaling against published results // 1.22 and 2.22 are the inner and outer radii for those results factor = rMax * log(0.55); gJ_Nu[0] = factor * gJ_Nu[0]; // normalise CubedSphereNusselt lower condition factor = rMin * log(0.55); gJ_Nu[1] = factor * gJ_Nu[1]; avgT = PpcIntegral_Integrate( self->volAvgT ); vol = PpcIntegral_Integrate( self->vol ); StgFEM_FrequentOutput_PrintValue( context, avgT/vol ); StgFEM_FrequentOutput_PrintValue( context, gJ_Nu[0] ); StgFEM_FrequentOutput_PrintValue( context, gJ_Nu[1] ); }
unsigned GeneralSwarm_IntegrationPointMap( void* _self, void* _intSwarm, unsigned elementId, unsigned intPtCellId ){ GeneralSwarm* self = (GeneralSwarm*)_self; IntegrationPointsSwarm* intSwarm = (IntegrationPointsSwarm*)_intSwarm; Mesh* intMesh = (Mesh*)intSwarm->mesh; SwarmMap* map = NULL; // first, lets check if the int swarm is mirroring a general swarm if (intSwarm->mirroredSwarm == (Swarm*)self) { // ok, it is a mirrored swarm return Swarm_ParticleCellIDtoLocalID( self, CellLayout_MapElementIdToCellId( self->cellLayout, elementId ), intPtCellId ); } else if ( self->previousIntSwarmMap && self->previousIntSwarmMap->swarm==intSwarm ) { /* next check if previous swarmmap */ map = self->previousIntSwarmMap; } else { /* ok, previous is not our guy, check other existing: */ int ii; for (ii=0; ii<List_GetSize(self->intSwarmMapList); ii++) { map = *(SwarmMap**)List_GetItem(self->intSwarmMapList, ii); if ( map->swarm==intSwarm ){ self->previousIntSwarmMap = map; break; } } // if we've gotten to this point, there is no corresponding map.. let's create one */ map = SwarmMap_New( intSwarm ); // add to list List_Append( self->intSwarmMapList, (void*)&map ); self->previousIntSwarmMap = map; // also add to int swarm incase it moves List_Append( intSwarm->swarmsMappedTo, (void*)&map ); } unsigned matPointLocalIndex; if ( SwarmMap_Map(map,elementId,intPtCellId,&matPointLocalIndex) ) { /* ok, map found, return value */ return matPointLocalIndex; } else { /* not found... damn.. lets go ahead and find nearest neighbour */ /* lets check some things */ Journal_Firewall( Stg_Class_IsInstance( self->cellLayout, ElementCellLayout_Type ), NULL, "Error In func %s: %s expects a materialSwarm with cellLayout of type ElementCellLayout.", __func__, self->type ); Journal_Firewall( intSwarm->mesh==(FeMesh*)((ElementCellLayout*)self->cellLayout)->mesh, Journal_Register( Error_Type, (Name)self->type ), "Error - in %s(): Mapper requires both the MaterialSwarm and\n" "the IntegrationSwarm to live on the same mesh.\n" "Here the MaterialSwarm %s lives in the mesh %s\n" "and the IntegrationSwarm %s lives in the mesh %s.", self->name, ((ElementCellLayout*)self->cellLayout)->mesh->name, intSwarm->name, intSwarm->mesh->name ); Cell_Index cell_I = CellLayout_MapElementIdToCellId( intSwarm->cellLayout, elementId ); Cell_Index cell_M = CellLayout_MapElementIdToCellId( self->cellLayout, elementId ); IntegrationPoint* integrationPoint = (IntegrationPoint*)Swarm_ParticleInCellAt( intSwarm, cell_I, intPtCellId ); /* Convert integration point local to global coordinates */ Coord global; FeMesh_CoordLocalToGlobal( intMesh, elementId, integrationPoint->xi, (double*) &global ); /* now lets sweep material points to find our closest friend */ double distance2_min = DBL_MAX; double distance2; Particle_Index particle_M; unsigned cellPartCount = self->cellParticleCountTbl[ cell_M ]; Journal_Firewall( cellPartCount, Journal_Register( Error_Type, (Name)self->type ), "Error - in %s(): There doesn't appear to be any particles\n" "within the current cell (%u).\n", self->name, cell_M ); for ( particle_M = 0; particle_M < cellPartCount; particle_M++ ) { GlobalParticle* materialPoint = (GlobalParticle*)Swarm_ParticleInCellAt( self, cell_M, particle_M ); distance2 = pow( global[0] - materialPoint->coord[0], 2 ) + pow( global[1] - materialPoint->coord[1], 2 ); if( self->dim == 3 ) distance2 += pow( global[2] - materialPoint->coord[2], 2 ); if ( distance2 < distance2_min ){ distance2_min = distance2; matPointLocalIndex = Swarm_ParticleCellIDtoLocalID( self, cell_M, particle_M ); } } /* ok, we've found our nearest friend. record to mapping */ SwarmMap_Insert(map,elementId,intPtCellId,matPointLocalIndex); } return matPointLocalIndex; }
void _GeneralSwarm_Initialise( void* swarm, void* data ) { GeneralSwarm* self = (GeneralSwarm*) swarm; AbstractContext* context = (AbstractContext*)self->context; Index var_I = 0; _Swarm_Initialise( self, data ); if( self->escapedRoutine != NULL) Stg_Component_Initialise( self->escapedRoutine, data , False ); for( var_I = 0 ; var_I < self->nSwarmVars ; var_I++ ) { Stg_Component_Initialise( self->swarmVars[var_I], data , False ); } /** if loading from checkpoint, particle materials etc have already been loaded in Swarm_Build() - */ /** possibly need to check for empty cells (and populate) if performing a interpolation restart */ if ( context && True == context->loadFromCheckPoint ) { if ( (True == self->isSwarmTypeToCheckPointAndReload) && (True == context->interpolateRestart) ) { Particle_InCellIndex cParticle_I = 0; Particle_InCellIndex particle_I = 0; GlobalParticle* particle = NULL; double minDistance = HUGE_VAL; double distanceToParticle; Dimension_Index dim = self->dim; Cell_DomainIndex dCell_I; Cell_LocalIndex lCell_I; Cell_DomainIndex belongsToCell_I = 0; GlobalParticle* matNewParticle; GlobalParticle* matParticleToSplit; Particle_Index matNewParticle_IndexOnCPU; Coord xi; Coord coord; unsigned nEmptyCells = 0; Index* cellID = NULL; Index* particleCPUID = NULL; unsigned count; unsigned ii; /** first determine how many local cells are empty */ for( lCell_I = 0 ; lCell_I < self->cellLocalCount ; lCell_I++ ) if (self->cellParticleCountTbl[lCell_I] == 0) nEmptyCells++; /** create arrays which will be later used to populate cells */ cellID = Memory_Alloc_Array( Index, nEmptyCells, "Cell ID for cell to be populated" ); particleCPUID = Memory_Alloc_Array( Index, nEmptyCells, "particle ID for particle to populate cell" ); count = 0; for( lCell_I = 0 ; lCell_I < self->cellLocalCount ; lCell_I++ ) { minDistance = HUGE_VAL; if (self->cellParticleCountTbl[lCell_I] == 0) { /** select the centre of the current cell */ xi[0] = 0; xi[1] = 0; xi[2] = 0; Journal_Firewall( Stg_Class_IsInstance( self->cellLayout, ElementCellLayout_Type ), NULL, "Error In func %s: When performing interpolation restart, cellLayout must be of type ElementCellLayout.", __func__ ); /** get global coord */ FeMesh_CoordLocalToGlobal( ((ElementCellLayout*)self->cellLayout)->mesh, lCell_I, xi, coord ); for( dCell_I = 0 ; dCell_I < self->cellDomainCount ; dCell_I++ ) { /** Loop over particles find closest to cell centre */ for( cParticle_I = 0 ; cParticle_I < self->cellParticleCountTbl[dCell_I] ; cParticle_I++ ) { particle = (GlobalParticle*)Swarm_ParticleInCellAt( self, dCell_I, cParticle_I ); /** Calculate distance to particle */ distanceToParticle = (particle->coord[ I_AXIS ] - coord[ I_AXIS ]) * (particle->coord[ I_AXIS ] - coord[ I_AXIS ]) + (particle->coord[ J_AXIS ] - coord[ J_AXIS ]) * (particle->coord[ J_AXIS ] - coord[ J_AXIS ]) ; if (dim == 3) { distanceToParticle += (particle->coord[ K_AXIS ] - coord[ K_AXIS ]) * (particle->coord[ K_AXIS ] - coord[ K_AXIS ]) ; } /** Don't do square root here because it is unnessesary: i.e. a < b <=> sqrt(a) < sqrt(b) */ /** Check if this is the closest particle */ if (minDistance > distanceToParticle) { particle_I = cParticle_I; minDistance = distanceToParticle; belongsToCell_I = dCell_I; } } } /** create new particle which will be placed at centre of empty cell */ matNewParticle = (GlobalParticle*) Swarm_CreateNewParticle( self, &matNewParticle_IndexOnCPU ); /** grab closest particle, which we will copy */ matParticleToSplit = (GlobalParticle*) Swarm_ParticleInCellAt( self, belongsToCell_I, particle_I ); /** copy - even though self->particleExtensionMgr->finalSize maybe biger than sizeof(GlobalParticle) the addressing of the copy is the important part */ memcpy( matNewParticle, matParticleToSplit, self->particleExtensionMgr->finalSize ); /** set the owningCell to the cellDomainCount so that its owningCell will be reinitialised (not sure if necessary) */ matNewParticle->owningCell = self->cellDomainCount; /** Copy new global position (cell centre) to coord on new mat particle */ memcpy( matNewParticle->coord, coord, sizeof(Coord) ); /** we now store the required information to populate empty cells */ /** note that cells are not populated at this point, as this may interfere with the 0th order interpolation we are performing */ cellID[count] = lCell_I; particleCPUID[count] = matNewParticle_IndexOnCPU; count++; } } /** populate empty cells */ for(ii = 0 ; ii < count ; ii++) Swarm_AddParticleToCell( self, cellID[ii], particleCPUID[ii] ); Memory_Free( cellID ); Memory_Free( particleCPUID ); } /* TODO: print info / debug message */ } }