void _VectorAssemblyTerm_NA__Fn_AssembleElement( void* forceTerm, ForceVector* forceVector, Element_LocalIndex lElement_I, double* elForceVec ) {
   VectorAssemblyTerm_NA__Fn* self = Stg_CheckType( forceTerm, VectorAssemblyTerm_NA__Fn );
   IntegrationPointsSwarm*    swarm = (IntegrationPointsSwarm*)self->integrationSwarm;
   Dimension_Index            dim = forceVector->dim;
   IntegrationPoint*          particle;
   FeMesh*                    mesh;
   double*                    xi;
   Particle_InCellIndex       cParticle_I;
   Particle_InCellIndex       cellParticleCount;
   Element_NodeIndex          nodesPerEl;
   Node_ElementLocalIndex     A;
   ElementType*               elementType;
   Dof_Index                  dofsPerNode, i;
   Cell_Index                 cell_I;
   double                     detJac;
   double                     factor;
   double                     N[27];

   /* Since we are integrating over the velocity mesh - we want the velocity mesh here and not the temperature mesh */
   mesh = forceVector->feVariable->feMesh;

   VectorAssemblyTerm_NA__Fn_cppdata* cppdata = (VectorAssemblyTerm_NA__Fn_cppdata*)self->cppdata;
    
   debug_dynamic_cast<ParticleInCellCoordinate*>(cppdata->input->localCoord())->index() = lElement_I;  // set the elementId as the owning cell for the particleCoord
   cppdata->input->index()   = lElement_I;  // set the elementId for the fem coordinate

   /* Set the element type */
   elementType = FeMesh_GetElementType( mesh, lElement_I );
   nodesPerEl  = elementType->nodeCount;
   

   /* assumes constant number of dofs per element */
   dofsPerNode = forceVector->feVariable->fieldComponentCount;

   cell_I = CellLayout_MapElementIdToCellId( swarm->cellLayout, lElement_I );
   cellParticleCount = swarm->cellParticleCountTbl[ cell_I ];

   for ( cParticle_I = 0 ; cParticle_I < cellParticleCount ; cParticle_I++ ) {
      debug_dynamic_cast<ParticleInCellCoordinate*>(cppdata->input->localCoord())->particle_cellId(cParticle_I);  // set the particleCoord cellId
      particle = (IntegrationPoint*) Swarm_ParticleInCellAt( swarm, cell_I, cParticle_I );
      xi       = particle->xi;

      /* Calculate Determinant of Jacobian and Shape Functions */
      if (self->geometryMesh)
         detJac = ElementType_JacobianDeterminant( FeMesh_GetElementType( self->geometryMesh, lElement_I ), self->geometryMesh, lElement_I, xi, dim );
      else
         detJac = ElementType_JacobianDeterminant( elementType, mesh, lElement_I, xi, dim );

      ElementType_EvaluateShapeFunctionsAt( elementType, xi, N );

      /* evaluate function */
      const FunctionIO* funcout = debug_dynamic_cast<const FunctionIO*>(cppdata->func(cppdata->input.get()));

      factor = detJac * particle->weight;
      for( A = 0 ; A < nodesPerEl ; A++ )
         for( i = 0 ; i < dofsPerNode ; i++ )
            elForceVec[A * dofsPerNode + i ] += factor * funcout->at<double>(i) * N[A] ;

   }
}
Ejemplo n.º 2
0
double IntegrateField( FeVariable* tempField, IntegrationPointsSwarm* swarm ) {
	FeMesh*			mesh	= tempField->feMesh;
	unsigned		el_i;
	unsigned		cell_i;
	unsigned		point_i;
	double			lTemp	= 0.0;
	double			gTemp;
	double			temp;
	double			detJac;
	IntegrationPoint*	point;
	ElementType*		elType;
	unsigned		dim	= Mesh_GetDimSize( mesh );
	
	for( el_i = 0; el_i < Mesh_GetLocalSize( mesh, dim ); el_i++ ) {
		cell_i = CellLayout_MapElementIdToCellId( swarm->cellLayout, el_i );
		elType = FeMesh_GetElementType( mesh, el_i );
		
		for( point_i = 0; point_i < swarm->cellParticleCountTbl[cell_i]; point_i++ ) {
			point = (IntegrationPoint*)Swarm_ParticleInCellAt( swarm, cell_i, point_i );

			FeVariable_InterpolateWithinElement( tempField, el_i, point->xi, &temp );
			detJac = ElementType_JacobianDeterminant( elType, mesh, el_i, point->xi, dim );

			lTemp += detJac * point->weight * temp;
		}
	}

	MPI_Allreduce( &lTemp, &gTemp, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );

	return gTemp;
}
void _BuoyancyForceTermPpc_AssembleElement( void* _self, ForceVector* forceVector, Element_LocalIndex lElement_I, double* elForceVec ) {
    BuoyancyForceTermPpc* self = (BuoyancyForceTermPpc*) _self;
    IntegrationPoint* particle;
    Particle_InCellIndex cParticle_I;
    Particle_InCellIndex cellParticleCount;
    Element_NodeIndex elementNodeCount;
    Dimension_Index dim = forceVector->dim;
    IntegrationPointsSwarm* swarm = (IntegrationPointsSwarm*)self->integrationSwarm;
    FeMesh* mesh = forceVector->feVariable->feMesh;
    Node_ElementLocalIndex eNode_I;
    unsigned int dim_I;
    Cell_Index cell_I;
    ElementType* elementType;
    Dof_Index nodeDofCount;
    double gravity[3], factor, density;
    double detJac = 0.0;
    double Ni[27];
    double* xi;
    int err;

    elementType = FeMesh_GetElementType( mesh, lElement_I );
    elementNodeCount = elementType->nodeCount;
    nodeDofCount = dim;
    cell_I = CellLayout_MapElementIdToCellId( swarm->cellLayout, lElement_I );
    cellParticleCount = swarm->cellParticleCountTbl[cell_I];

    for( cParticle_I = 0 ; cParticle_I < cellParticleCount ; cParticle_I++ ) {
        particle = (IntegrationPoint*) Swarm_ParticleInCellAt( swarm, cell_I, cParticle_I );
        xi = particle->xi;

        detJac = ElementType_JacobianDeterminant( elementType, mesh, lElement_I, xi, dim );
        ElementType_EvaluateShapeFunctionsAt( elementType, xi, Ni );

        /* Density */
        err = PpcManager_Get( self->manager, lElement_I, particle, self->density_id, &density );

        Journal_Firewall( !err,
                          Journal_Register( Error_Type, (Name)BuoyancyForceTermPpc_Type  ),
                          "%d not found at the PpcManager\n", self->density_id );

        Journal_Firewall( !isnan( density ),
                          Journal_Register( Error_Type, (Name)BuoyancyForceTermPpc_Type  ),
                          "Density at integration point %i of element %i is nan\n", cParticle_I, lElement_I );

        /* Gravity */
        PpcManager_GetGravity( self->manager, lElement_I, particle, gravity );

        /* Apply force in the correct direction */
        for( eNode_I = 0 ; eNode_I < elementNodeCount; eNode_I++ ) {
            for( dim_I = 0 ; dim_I < dim ; dim_I++ ) {
                factor = detJac * particle->weight * density * gravity[dim_I];
                elForceVec[ eNode_I * nodeDofCount + dim_I ] += -1.0 * factor * Ni[ eNode_I ] ;
            }
        }
    }
}
void _GALEDivergenceForce_AssembleElement( void* forceTerm,
                                       ForceVector* forceVector, 
                                       Element_LocalIndex lElement_I, 
                                       double* elForceVec ) {
  GALEDivergenceForce* self=(GALEDivergenceForce*) forceTerm;
  FeMesh* mesh=forceVector->feVariable->feMesh;
  Node_ElementLocalIndex           eNode_I;
  Element_NodeIndex                elementNodeCount;
  Node_DomainIndex *elementNodes=NULL;

  double xi[3], force, factor;
  ElementType* geometryElementType;
  
  IArray *incidence;

  xi[0]=0;
  xi[1]=0;
  xi[2]=0;
  geometryElementType=FeMesh_GetElementType(self->geometryMesh,lElement_I);
  factor=ElementType_JacobianDeterminant( geometryElementType,
                                          self->geometryMesh,
                                          lElement_I,
                                          xi, forceVector->dim );
  incidence=IArray_New();
  Mesh_GetIncidence(mesh, Mesh_GetDimSize(mesh), lElement_I,
                    MT_VERTEX,incidence);
  elementNodeCount=IArray_GetSize(incidence);
  elementNodes=IArray_GetPtr(incidence);
  
  for( eNode_I = 0 ; eNode_I < elementNodeCount; eNode_I++ ) {
    if(Stg_Shape_IsCoordInside(self->domainShape,
                               Mesh_GetVertex(mesh,elementNodes[eNode_I])))
      {
        switch(self->force.type)
          {
          case GALEStressBC_Double:
            force=self->force.DoubleValue;
            break;
          case GALEStressBC_ConditionFunction:
            
            /* We use a variable number of zero "0", because
               we don't use the variable number and that one
               is always going to exist. */
            ConditionFunction_Apply
              (condFunc_Register->_cf[self->force.CFIndex],
               elementNodes[eNode_I],0,self->context,&force);
            break;
          }
        elForceVec[ eNode_I] += force*factor;
      }
  }
  Stg_Class_Delete(incidence);
}
double SemiLagrangianIntegratorSuite_EvaluateError( FeVariable* phiField, FeVariable* phiOldField, Swarm* gaussSwarm ) {
   FeMesh*			feMesh		= phiField->feMesh;
   GaussParticleLayout*	particleLayout 	= (GaussParticleLayout*)gaussSwarm->particleLayout;
   Index			lElement_I, lCell_I;
   unsigned		nDims		= Mesh_GetDimSize( feMesh );
   unsigned		numMeshElements	= Mesh_GetLocalSize( feMesh, nDims );
   double			elementError;
   double			lErrorSq	= 0.0;
   double			lAnalyticSq 	= 0.0;
   double			gErrorSq, gAnalyticSq, gErrorNorm;
   IntegrationPoint*	gaussPoint;
   unsigned		gaussPoint_I, numGaussPoints;
   double			initialValue, finalValue;
   double			elErrorSq, elAnalyticSq;
   ElementType*		elementType;
   double			detJac;

   for( lElement_I = 0; lElement_I < numMeshElements; lElement_I++ ) {
      lCell_I = CellLayout_MapElementIdToCellId( gaussSwarm->cellLayout, lElement_I );
      numGaussPoints = _GaussParticleLayout_InitialCount( particleLayout, NULL, lCell_I );

      elementType = FeMesh_GetElementType( feMesh, lElement_I );

      elErrorSq = 0.0;
      elAnalyticSq = 0.0;

      for( gaussPoint_I = 0; gaussPoint_I < numGaussPoints; gaussPoint_I++ ) {
         gaussPoint = (IntegrationPoint*) Swarm_ParticleInCellAt( gaussSwarm, lCell_I, gaussPoint_I );
         FeVariable_InterpolateWithinElement( phiOldField, lElement_I, gaussPoint->xi, &initialValue );
         FeVariable_InterpolateWithinElement( phiField, lElement_I, gaussPoint->xi, &finalValue );

         detJac = ElementType_JacobianDeterminant( elementType, feMesh, lElement_I, gaussPoint->xi, nDims );

         elErrorSq += ( finalValue - initialValue ) * ( finalValue - initialValue ) * gaussPoint->weight * detJac;
         elAnalyticSq += ( initialValue * initialValue ) * gaussPoint->weight * detJac;
      }

      elementError = sqrt( elErrorSq ) / sqrt( elAnalyticSq );

      lErrorSq += elErrorSq;
      lAnalyticSq += elAnalyticSq;
   }

   MPI_Allreduce( &lErrorSq, &gErrorSq, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );
   MPI_Allreduce( &lAnalyticSq, &gAnalyticSq, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD );

   gErrorNorm = sqrt( gErrorSq ) / sqrt( gAnalyticSq );

   return gErrorNorm;
}
Ejemplo n.º 6
0
void lecode_tools_Isostasy_AverageBody(lecode_tools_Isostasy *self,
                                       double** _avg_density, double** _rho_zero_density,
                                       double** _phi)
{
   FeMesh *mesh;
   ElementType *el_type;
   IntegrationPointsSwarm *swarm;
   double *local_density, *global_density;
   double *local_vol, *global_vol;
   double *local_rho_zero_vol, *global_rho_zero_vol;
   double *local_rho_zero_density, *global_rho_zero_density;
   double *local_phi, *global_phi, temp, tempDot;
   int cell, num_particles, num_dims, num_els;
   IntegrationPoint *particle;
   double jac_det;
   double density, alpha, densityFinal;
   Material *mat;
   Bool oneToMany;
   Grid* elGrid;
   int elInds[3], arraySize, arrayPos;
   int ii, jj;

   mesh = self->mesh;
   elGrid = *Mesh_GetExtension( mesh, Grid**,  mesh->elGridId );
   num_dims = Mesh_GetDimSize(mesh);
   swarm = self->swarm;
   num_els = FeMesh_GetElementLocalSize(mesh);

   arraySize=0;
   if ( num_dims == 2 ) arraySize = elGrid->sizes[0];
   else if ( num_dims == 3 ) arraySize = elGrid->sizes[0]*elGrid->sizes[self->zontalAxis];
   else assert(0);

   /* Allocate for the column values. */
   local_vol = (double*)malloc( arraySize*sizeof(double) );
   memset( local_vol, 0, arraySize*sizeof(double) );
   local_density = (double*)malloc( arraySize*sizeof(double) );
   memset( local_density, 0, arraySize*sizeof(double) );
   local_rho_zero_vol = (double*)malloc( arraySize*sizeof(double) );
   memset( local_rho_zero_vol, 0, arraySize*sizeof(double) );
   local_rho_zero_density = (double*)malloc( arraySize*sizeof(double) );
   memset( local_rho_zero_density, 0, arraySize*sizeof(double) );
   local_phi = (double*)malloc( arraySize*sizeof(double) );
   memset( local_phi, 0, arraySize*sizeof(double) );

   /* Initialise temperature. */
   temp = 0.0;

   oneToMany = Stg_Class_IsInstance(swarm->mapper, OneToManyMapper_Type);

   for (ii = 0; ii < num_els; ii++)
   {

      /* Make sure the element is beneath the surface. */
      Grid_Lift( elGrid, FeMesh_ElementDomainToGlobal( mesh, ii ), elInds );
      if ( self->surfaceIdx != -1 && elInds[self->vertAxis] >= self->surfaceIdx )
         continue;

      el_type = FeMesh_GetElementType(mesh, ii);
      cell = CellLayout_MapElementIdToCellId(swarm->cellLayout, ii);
      num_particles = swarm->cellParticleCountTbl[cell];

      for (jj = 0; jj < num_particles; jj++)
      {

         particle = (IntegrationPoint*)Swarm_ParticleInCellAt(swarm, cell, jj);
         jac_det = ElementType_JacobianDeterminant(el_type, mesh, ii, particle->xi, num_dims);

         if(!self->ppcManager){
            density = IntegrationPointMapper_GetDoubleFromMaterial(
                         swarm->mapper, particle, self->buoyancy->materialExtHandle,
                         offsetof(BuoyancyForceTerm_MaterialExt, density) );
            alpha = IntegrationPointMapper_GetDoubleFromMaterial(
                       swarm->mapper, particle, self->buoyancy->materialExtHandle,
                       offsetof(BuoyancyForceTerm_MaterialExt, alpha) );

            if (self->tempField)
            {
               FeVariable_InterpolateFromMeshLocalCoord(self->tempField, self->tempField->feMesh,
                     ii, particle->xi, &temp);
               FeVariable_InterpolateFromMeshLocalCoord(self->tempDotField, self->tempDotField->feMesh,
                     ii, particle->xi, &tempDot);
            }

            densityFinal = density*(1.0 - alpha*temp);

         } else {
            int err;
            /* Density */
            err = PpcManager_Get( self->ppcManager, ii, particle, self->densityID, &densityFinal );
            assert(!err);
         }

         arrayPos = elInds[0];
         if ( num_dims == 3 ) arrayPos += elInds[self->zontalAxis]*elGrid->sizes[0];

         local_vol[arrayPos] += particle->weight*jac_det;
         local_density[arrayPos] += particle->weight*jac_det*densityFinal;

         if (!oneToMany)
         {
            mat = IntegrationPointsSwarm_GetMaterialOn(swarm, particle);
            if (mat->index == self->rho_zero_mat->index)
            {
               local_rho_zero_vol[arrayPos] += particle->weight*jac_det;
               local_rho_zero_density[arrayPos] += particle->weight*jac_det*densityFinal;
            }
         }
         else
         {
            OneToManyRef *ref;
            int cnt;
            int kk;

            ref = OneToManyMapper_GetMaterialRef(swarm->mapper, particle);
            cnt = 0;
            for (kk = 0; kk < ref->numParticles; kk++)
            {
               mat = MaterialPointsSwarm_GetMaterialAt(((OneToManyMapper*)swarm->mapper)->materialSwarm, ref->particleInds[kk]);
               if (mat->index == self->rho_zero_mat->index)
                  cnt++;
            }

            if (2*cnt > ref->numParticles)
            {
               local_rho_zero_vol[arrayPos] += particle->weight*jac_det;
               local_rho_zero_density[arrayPos] += particle->weight*jac_det*densityFinal;
            }
         }

         if (_phi)
         {
            local_phi[arrayPos] += particle->weight*jac_det*(-density*alpha*tempDot);
         }
      }
   }

   /* Allocate for the global column values. */
   global_vol = (double*)malloc( arraySize*sizeof(double) );
   global_density = (double*)malloc( arraySize*sizeof(double) );
   global_rho_zero_vol = (double*)malloc( arraySize*sizeof(double) );
   global_rho_zero_density = (double*)malloc( arraySize*sizeof(double) );
   global_phi = (double*)malloc( arraySize*sizeof(double) );

   MPI_Allreduce(local_vol, global_vol, arraySize, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
   MPI_Allreduce(local_density, global_density, arraySize, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
   MPI_Allreduce(local_rho_zero_vol, global_rho_zero_vol, arraySize, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
   MPI_Allreduce(local_rho_zero_density, global_rho_zero_density, arraySize, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
   if (_phi)
      MPI_Allreduce(local_phi, global_phi, arraySize, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);

   free( local_vol );
   free( local_density );
   free( local_rho_zero_vol );
   free( local_rho_zero_density );
   free( local_phi );

   if ( self->avg )
   {
      for ( ii = 1; ii < arraySize; ii++ )
      {
         global_vol[0] += global_vol[ii];
         global_density[0] += global_density[ii];
         global_rho_zero_vol[0] += global_rho_zero_vol[ii];
         global_rho_zero_density[0] += global_rho_zero_density[ii];
         if ( _phi )
            global_phi[0] += global_phi[ii];
      }
   }

   /* Calculate results. */
   *_avg_density = (double*)malloc( arraySize*sizeof(double) );
   *_rho_zero_density = (double*)malloc( arraySize*sizeof(double) );
   if (_phi)
      *_phi = (double*)malloc( arraySize*sizeof(double) );
   for ( ii = 0; ii < arraySize; ii++ )
   {
      (*_avg_density)[ii] = (global_vol[ii] > 1e-7) ? global_density[ii]/global_vol[ii] : 0.0;
      (*_rho_zero_density)[ii] = (global_rho_zero_vol[ii] > 1e-7) ? global_rho_zero_density[ii]/global_rho_zero_vol[ii] : 0.0;
      if (_phi)
         (*_phi)[ii] = (global_vol[ii] > 1e-7) ? global_phi[ii]/global_vol[ii] : 0.0;
      if ( self->avg )
         break;
   }

   /*
       printf("Global mean density: %g\n", (*_avg_density)[0]);
       printf("Global mean rho_0 density: %g\n", (*_rho_zero_density)[0]);
       printf("Global phi/vol: %g\n", (*_phi)[0]);
   */

   free( global_vol );
   free( global_density );
   free( global_rho_zero_vol );
   free( global_rho_zero_density );
   free( global_phi );
}
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] ;
            }
         }
      }
   }
}
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] );
}
void _MatrixAssemblyTerm_NA__NB__Fn_AssembleElement(
   void*                                              matrixTerm,
   StiffnessMatrix*                                   stiffnessMatrix,
   Element_LocalIndex                                 lElement_I,
   SystemLinearEquations*                             sle,
   FiniteElementContext*                              context,
   double**                                           elStiffMat )
{
   MatrixAssemblyTerm_NA__NB__Fn* self = (MatrixAssemblyTerm_NA__NB__Fn*)matrixTerm;
   Swarm*                              swarm        = self->integrationSwarm;
   FeVariable*                         variable_row = stiffnessMatrix->rowVariable;
   FeVariable*                         variable_col = stiffnessMatrix->columnVariable;
   Dimension_Index                     dim          = stiffnessMatrix->dim;
   Particle_InCellIndex                cParticle_I, cellParticleCount;
   Node_ElementLocalIndex              nodesPerEl_row, nodesPerEl_col;

   Dof_Index                           dofPerNode_col;
   Index                               row, col; /* Indices into the stiffness matrix */
   Node_ElementLocalIndex              rowNode_I, colNode_I;
   Dof_Index                           colDof_I;
   double                              *xi, *Ni, *Mi;
   double                              detJac, weight, F, factor;
   IntegrationPoint*                   intPoint;
   Cell_Index                          cell_I;
   ElementType*                        elementType_row;
   ElementType*                        elementType_col;


   MatrixAssemblyTerm_NA__NB__Fn_cppdata* cppdata = (MatrixAssemblyTerm_NA__NB__Fn_cppdata*)self->cppdata;
   debug_dynamic_cast<ParticleInCellCoordinate*>(cppdata->input->localCoord())->index() = lElement_I;  // set the elementId as the owning cell for the particleCoord
   cppdata->input->index() = lElement_I;

   FeMesh*                 geometryMesh = ( self->geometryMesh ? self->geometryMesh : variable_row->feMesh );
   ElementType*            geometryElementType;

   /* Set the element type */
   geometryElementType = FeMesh_GetElementType( geometryMesh, lElement_I );

   elementType_row = FeMesh_GetElementType( variable_row->feMesh, lElement_I );
   nodesPerEl_row = elementType_row->nodeCount;
   elementType_col = FeMesh_GetElementType( variable_col->feMesh, lElement_I );
   nodesPerEl_col = elementType_col->nodeCount;

   dofPerNode_col = variable_col->fieldComponentCount;

   // allocate shape function array, Mi and Ni
   if( nodesPerEl_row > self->max_nElNodes_row ) {
      /* reallocate */
      if (self->Mi) free(self->Mi);
      self->Mi = (double*)AllocArray( double, nodesPerEl_row );
      self->max_nElNodes_row = nodesPerEl_row;
   }

   if( nodesPerEl_col > self->max_nElNodes_col ) {
      if( self->Ni) free(self->Ni);
      self->Ni = (double*)AllocArray(double, nodesPerEl_col );
      self->max_nElNodes_col = nodesPerEl_col;
   }
   Ni = self->Ni;
   if (elementType_row == elementType_col)
      Mi = Ni;

   cell_I = CellLayout_MapElementIdToCellId( swarm->cellLayout, lElement_I );
   cellParticleCount = swarm->cellParticleCountTbl[ cell_I ];

   for ( cParticle_I = 0 ; cParticle_I < cellParticleCount ; cParticle_I++ ) {
      debug_dynamic_cast<ParticleInCellCoordinate*>(cppdata->input->localCoord())->particle_cellId(cParticle_I);  // set the particleCoord cellId
      /* get integration point information */
      intPoint = (IntegrationPoint*)Swarm_ParticleInCellAt( swarm, cell_I, cParticle_I );
      xi = intPoint->xi;
      weight = intPoint->weight;

      /* evaluate shape function and jacobian determinant */
      detJac = ElementType_JacobianDeterminant( geometryElementType, geometryMesh, lElement_I, xi, dim );
      ElementType_EvaluateShapeFunctionsAt( elementType_col, xi, Ni );
      if (elementType_row != elementType_col)
         ElementType_EvaluateShapeFunctionsAt( elementType_row, xi, Mi );

      // /* evaluate function */
      const IO_double* funcout = debug_dynamic_cast<const IO_double*>(cppdata->func(cppdata->input.get()));
      F = funcout->at();

      factor = weight*detJac*F;
      /* build stiffness matrix */
      for ( rowNode_I = 0; rowNode_I < nodesPerEl_row ; rowNode_I++) {
         for (colNode_I = 0; colNode_I < nodesPerEl_col; colNode_I++ ) {
            for( colDof_I=0; colDof_I<dofPerNode_col; colDof_I++) {
                  /* note that we use the row dof count here too */
                  row = rowNode_I*dofPerNode_col + colDof_I;
                  col = colNode_I*dofPerNode_col + colDof_I;
                  elStiffMat[row][col] += factor * ( Ni[rowNode_I] * Mi[colNode_I] );
            }
         }
      }
   }
}
void _ThermalBuoyancyForceTerm_AssembleElement( void* forceTerm, ForceVector* forceVector, Element_LocalIndex lElement_I, double* elForceVec ) {
	ThermalBuoyancyForceTerm*	self = Stg_CheckType( forceTerm, ThermalBuoyancyForceTerm );
	Swarm*							swarm = self->integrationSwarm;
	Dimension_Index				dim = forceVector->dim;
	IntegrationPoint*				particle;
	FeVariable*						temperatureField;
	FeMesh*							mesh;
	FeMesh*							temperatureMesh;
	double*							xi;
	Particle_InCellIndex			cParticle_I;
	Particle_InCellIndex			cellParticleCount;
	Element_NodeIndex				elementNodeCount;
	Node_ElementLocalIndex		node_I;
	ElementType*					elementType;
	Dof_Index						dofsPerNode;
	Cell_Index						cell_I;
	double							detJac;
	double							factor;
	/*double							Ni[8];*/
	double							Ni[27];
	double							force;
	double							rayleighNumber;
	double							temperature;

	/* Get context extension */
	rayleighNumber   = self->rayleighNumber;
	temperatureField = self->temperatureField;
	temperatureMesh  = temperatureField->feMesh;

	/* Since we are integrating over the velocity mesh - we want the velocity mesh here and not the temperature mesh */
	mesh             = forceVector->feVariable->feMesh;
	
	/* Set the element type */
	elementType      = FeMesh_GetElementType( mesh, lElement_I ); 
	elementNodeCount = elementType->nodeCount;

	/* assumes constant number of dofs per element */
	dofsPerNode = dim;
	
	cell_I = CellLayout_MapElementIdToCellId( swarm->cellLayout, lElement_I );
	cellParticleCount = swarm->cellParticleCountTbl[ cell_I ];
	
	for ( cParticle_I = 0 ; cParticle_I < cellParticleCount ; cParticle_I++ ) {
		particle = (IntegrationPoint*) Swarm_ParticleInCellAt( swarm, cell_I, cParticle_I );
		xi       = particle->xi;
		
		/* Calculate Determinant of Jacobian and Shape Functions */
		detJac = ElementType_JacobianDeterminant( elementType, mesh, lElement_I, xi, dim );
		ElementType_EvaluateShapeFunctionsAt( elementType, xi, Ni );

		/* Field Get Temperature from Field Variable */
		FeVariable_InterpolateFromMeshLocalCoord( temperatureField, mesh, lElement_I, xi, &temperature );

		force = rayleighNumber * temperature;

		factor = detJac * particle->weight * force;
		for( node_I = 0 ; node_I < elementNodeCount ; node_I++ ) 
			elForceVec[node_I * dofsPerNode + J_AXIS ] += factor * Ni[ node_I ] ;
		
	}
}