Пример #1
0
void solverloop(int start, int end){

  int       i, j;
  int       indx, indx_up, indx_lft;
  int       indx_rght, indx_up, indx_dwn;
  double    phi,dphi_dt,dmu_dt;
  double    drv_frce, alln_chn;
  double    Gamma, kai;
  double    dc_dx, dc_dy, V_gradC;

  #ifdef ANISO
    grad_phi(1, dphi_now);
  #endif

  for (i=start; i < end; i++) {

    #ifdef ANISO
      grad_phi(i+1, dphi_next);
    #endif

    for (j=1; j < (MESHX-1); j++){

      indx          =   i*MESHX + j;
      indx_lft      =   indx - 1;
      indx_rght     =   indx + 1;
      indx_up       =   indx - MESHX;
      indx_dwn      =   indx + MESHX;

      phi           =   phi_old[indx];

      #ifdef ISO
        Gamma       = 2*G*lap_phi[indx];
      #endif
      #ifdef ANISO
        Gamma       =     div_phi(j);
      #endif

      drv_frce      =     (mu_old[indx] - Mu)*(K-1)*(mu_old[indx])*6*phi*(1-phi);
      alln_chn      =     E*Gamma - (G/E)*18.0*(phi)*(1.0-phi)*(1.0-2.0*phi);
      dp_dt         =     (alln_chn + drv_frce)/(tau*E);

      phi_new[z]    =     phi + deltat*dphi_dt;

      #ifdef ANISO
        dc_dx       =     (conc[indx_rght] - conc[indx_lft])*0.5*inv_deltax;
        dc_dy       =     (conc[indx_dwn]  - conc[indx_up] )*0.5*inv_deltax;
        V_gradC     =     u_old[indx]*dc_dx + v_old[indx]*dc_dy;
      #endif
      #ifdef ISO
        V_gradC     =     0.0;
      #endif
      dmu_dt        =     Mob*lap_mu[indx] - V_gradC - (K-1)*mu_old[indx]*6*phi*(1-phi)*dphi_dt;
      kai           =     1+(K-1)*phi*phi*(3-2*phi);
      mu_new[indx]  =     mu_old[indx]  + deltat*dmu_dt/kai;
    }
    #ifdef ANISO
      fnupdate();
    #endif
  }
}
Пример #2
0
void solverloop(){

  int       i, j, z;
  double    p,dp_dt,dmu_dt;
  double    drv_frce, alln_chn;
  double    Gamma, kai;
  double    dc_dx, dc_dy, V_gradC = 0.0;

  #ifdef ANISO
  grad_phi(1, dphi_now);
  #endif

  for (i=start; i <= end; i++) {

    #ifdef ANISO
    grad_phi(i+1, dphi_next);
    #endif

    for (j=1; j < (MESHX-1); j++){

      z =   i*MESHX + j;
      p =   phi_old[z];

      #ifdef ISO
      Gamma = 2*G*lap_phi[z];
      #endif

      #ifdef ANISO
      Gamma         =     div_phi(j);
      #endif

      drv_frce      =     (mu_old[z] - Mu)*(K-1)*(mu_old[z])*6*p*(1-p);
      alln_chn      =     E*Gamma - (G/E)*18.0*(p)*(1.0-p)*(1.0-2.0*p);
      dp_dt         =     (alln_chn + drv_frce)/(tau*E);

      phi_new[z]    =     p + deltat*dp_dt;

      #ifdef FLUID
      dc_dx         =     (conc[z+1]-conc[z-1])*0.5*inv_deltax;
      dc_dy         =     (conc[z+MESHX]-conc[z-MESHX])*0.5*inv_deltax;
      V_gradC       =     u_old[z]*dc_dx + v_old[z]*dc_dy;
      #endif

      dmu_dt        =     Mob*lap_mu[z] - V_gradC - (K-1)*mu_old[z]*6*p*(1-p)*dp_dt;
      kai           =     1+(K-1)*p*p*(3-2*p);
      mu_new[z]     =     mu_old[z]  + deltat*dmu_dt/kai;
    }
    #ifdef ANISO
    fnupdate();
    #endif
  }
}
Пример #3
0
void solve_with_Cpp(MultiFab& soln, MultiFab& gphi, Real a, Real b, MultiFab& alpha, 
		    PArray<MultiFab>& beta, MultiFab& rhs, const BoxArray& bs, const Geometry& geom)
{
  BL_PROFILE("solve_with_Cpp()");
  BndryData bd(bs, 1, geom);
  set_boundary(bd, rhs, 0);

  ABecLaplacian abec_operator(bd, dx);
  abec_operator.setScalars(a, b);
  abec_operator.setCoefficients(alpha, beta);

  MultiGrid mg(abec_operator);
  mg.setVerbose(verbose);
  mg.solve(soln, rhs, tolerance_rel, tolerance_abs);

  PArray<MultiFab> grad_phi(BL_SPACEDIM, PArrayManage);
  for (int n = 0; n < BL_SPACEDIM; ++n)
      grad_phi.set(n, new MultiFab(BoxArray(soln.boxArray()).surroundingNodes(n), 1, 0));

#if (BL_SPACEDIM == 2)
  abec_operator.compFlux(grad_phi[0],grad_phi[1],soln);
#elif (BL_SPACEDIM == 3)
  abec_operator.compFlux(grad_phi[0],grad_phi[1],grad_phi[2],soln);
#endif

  // Average edge-centered gradients to cell centers.
  BoxLib::average_face_to_cellcenter(gphi, grad_phi, geom);
}
Пример #4
0
void solve_with_F90(MultiFab& soln, MultiFab& gphi, Real a, Real b, MultiFab& alpha, 
		    PArray<MultiFab>& beta, MultiFab& rhs, const BoxArray& bs, const Geometry& geom)
{
  BL_PROFILE("solve_with_F90()");

  FMultiGrid fmg(geom);

  int mg_bc[2*BL_SPACEDIM];
  if (bc_type == Periodic) {
    // Define the type of boundary conditions to be periodic
    for ( int n = 0; n < BL_SPACEDIM; ++n ) {
      mg_bc[2*n + 0] = MGT_BC_PER;
      mg_bc[2*n + 1] = MGT_BC_PER;
    }
  }
  else if (bc_type == Neumann) {
    // Define the type of boundary conditions to be Neumann
    for ( int n = 0; n < BL_SPACEDIM; ++n ) {
      mg_bc[2*n + 0] = MGT_BC_NEU;
      mg_bc[2*n + 1] = MGT_BC_NEU;
    }
  }
  else if (bc_type == Dirichlet) {
    // Define the type of boundary conditions to be Dirichlet
    for ( int n = 0; n < BL_SPACEDIM; ++n ) {
      mg_bc[2*n + 0] = MGT_BC_DIR;
      mg_bc[2*n + 1] = MGT_BC_DIR;
    }
  }

  fmg.set_bc(mg_bc);
  fmg.set_maxorder(maxorder);

  fmg.set_scalars(a, b);
  fmg.set_coefficients(alpha, beta);

  int always_use_bnorm = 0;
  int need_grad_phi = 1;
  fmg.solve(soln, rhs, tolerance_rel, tolerance_abs, always_use_bnorm, need_grad_phi);

  PArray<MultiFab> grad_phi(BL_SPACEDIM, PArrayManage);
  for (int n = 0; n < BL_SPACEDIM; ++n)
      grad_phi.set(n, new MultiFab(BoxArray(soln.boxArray()).surroundingNodes(n), 1, 0));

  fmg.get_fluxes(grad_phi);

  // Average edge-centered gradients to cell centers.
  BoxLib::average_face_to_cellcenter(gphi, grad_phi, geom);
}
KOKKOS_INLINE_FUNCTION
void FEInterpolation<EvalT, Traits>::operator () (const int i) const
{  
  for (PHX::index_size_type qp = 0; qp < num_qp; ++qp) {
    val_qp(i,qp) = 0.0;

    for (PHX::index_size_type dim = 0; dim < num_dim; ++dim)
      val_grad_qp(i,qp,dim) = 0.0;

    // Sum nodal contributions to qp
    for (PHX::index_size_type node = 0; node < num_nodes; ++node) {
      val_qp(i,qp) += phi(qp, node) * val_node(i,node);
      for (PHX::index_size_type dim = 0; dim < num_dim; ++dim)
	val_grad_qp(i,qp,dim) += grad_phi(qp, node, dim) * val_node(i,node);
    }
  }
}
//**********************************************************************
PHX_EVALUATE_FIELDS(FEInterpolation,cell_data)
{ 

  std::vector<Element_Linear2D>::iterator cell_it = cell_data.begin;

  // Loop over number of cells
  for (std::size_t cell = 0; cell < cell_data.num_cells; ++cell) {
    
    const shards::Array<double,shards::NaturalOrder,QuadPoint,Node>& phi = 
      cell_it->basisFunctions();

    const shards::Array<double,shards::NaturalOrder,QuadPoint,Node,Dim>& 
      grad_phi = cell_it->basisFunctionGradientsRealSpace();

    // Loop over quad points of cell
    for (int qp = 0; qp < num_qp; ++qp) {
      
      val_qp(cell,qp) = 0.0;

      for (int dim = 0; dim < num_dim; ++dim)
	val_grad_qp(cell,qp,dim) = 0.0;

      // Sum nodal contributions to qp
      for (int node = 0; node < num_nodes; ++node) {

	val_qp(cell,qp) += phi(qp,node) * val_node(cell,node);
	
	for (int dim = 0; dim < num_dim; ++dim)
	  val_grad_qp(cell,qp,dim) += 
	    grad_phi(qp,node,dim) * val_node(cell,node);
	
      }
    }
    
    ++cell_it;
 
  }
    
//   std::cout << "FEINterpolation: val_node" << std::endl;
//   val_node.print(std::cout,true);
//   std::cout << "FEINterpolation: val_qp" << std::endl;
//   val_qp.print(std::cout,true);
//   std::cout << "FEINterpolation: val_grad_qp" << std::endl;
//   val_grad_qp.print(std::cout,true);

}
Пример #7
0
void CellwiseDataGradient<DIM>::SetupGradients(AbstractCellPopulation<DIM>& rCellPopulation, const std::string& rItemName)
{
    MeshBasedCellPopulation<DIM>* pCellPopulation = static_cast<MeshBasedCellPopulation<DIM>*>(&(rCellPopulation));
    TetrahedralMesh<DIM,DIM>& r_mesh = pCellPopulation->rGetMesh();

    // Initialise gradients size
    unsigned num_nodes = pCellPopulation->GetNumNodes();
    mGradients.resize(num_nodes, zero_vector<double>(DIM));

    // The constant gradients at each element
    std::vector<c_vector<double, DIM> > gradients_on_elements;
    unsigned num_elements = r_mesh.GetNumElements();
    gradients_on_elements.resize(num_elements, zero_vector<double>(DIM));

    // The number of elements containing a given node (excl ghost elements)
    std::vector<unsigned> num_real_elems_for_node(num_nodes, 0);

    for (unsigned elem_index=0; elem_index<num_elements; elem_index++)
    {
        Element<DIM,DIM>& r_elem = *(r_mesh.GetElement(elem_index));

        // Calculate the basis functions at any point (eg zero) in the element
        c_matrix<double, DIM, DIM> jacobian, inverse_jacobian;
        double jacobian_det;
        r_mesh.GetInverseJacobianForElement(elem_index, jacobian, jacobian_det, inverse_jacobian);
        const ChastePoint<DIM> zero_point;
        c_matrix<double, DIM, DIM+1> grad_phi;
        LinearBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(zero_point, inverse_jacobian, grad_phi);

        bool is_ghost_element = false;

        for (unsigned node_index=0; node_index<DIM+1; node_index++)
        {
            unsigned node_global_index = r_elem.GetNodeGlobalIndex(node_index);

            // This code is commented because CellData can't deal with ghost nodes see #1975
            assert(pCellPopulation->IsGhostNode(node_global_index) == false);
            //// Check whether ghost element
            //if (pCellPopulation->IsGhostNode(node_global_index) == true)
            //{
            //    is_ghost_element = true;
            //    break;
            //}

            // If no ghost element, get PDE solution
            CellPtr p_cell = pCellPopulation->GetCellUsingLocationIndex(node_global_index);
            double pde_solution = p_cell->GetCellData()->GetItem(rItemName);

            // Interpolate gradient
            for (unsigned i=0; i<DIM; i++)
            {
                gradients_on_elements[elem_index](i) += pde_solution* grad_phi(i, node_index);
            }
        }

        // Add gradient at element to gradient at node
        if (!is_ghost_element)
        {
            for (unsigned node_index=0; node_index<DIM+1; node_index++)
            {
                unsigned node_global_index = r_elem.GetNodeGlobalIndex(node_index);
                mGradients[node_global_index] += gradients_on_elements[elem_index];
                num_real_elems_for_node[node_global_index]++;
            }
        }
    }

    // Divide to obtain average gradient
    for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = pCellPopulation->Begin();
         cell_iter != pCellPopulation->End();
         ++cell_iter)
    {
        unsigned node_global_index = pCellPopulation->GetLocationIndexUsingCell(*cell_iter);

        if (!num_real_elems_for_node[node_global_index] > 0)
        {
            NEVER_REACHED;
            // This code is commented because CellwiseData Can't deal with ghost nodes so won't ever come into this statement see #1975
            //// The node is a real node which is not in any real element
            //// but should be connected to some cells (if more than one cell in mesh)
            //Node<DIM>& this_node = *(pCellPopulation->GetNodeCorrespondingToCell(*cell_iter));
            //
            //mGradients[node_global_index] = zero_vector<double>(DIM);
            //unsigned num_real_adjacent_nodes = 0;
            //
            //// Get all the adjacent nodes which correspond to real cells
            //std::set<Node<DIM>*> real_adjacent_nodes;
            //real_adjacent_nodes.clear();
            //
            //// First loop over containing elements
            //for (typename Node<DIM>::ContainingElementIterator element_iter = this_node.ContainingElementsBegin();
            //     element_iter != this_node.ContainingElementsEnd();
            //     ++element_iter)
            //{
            //    // Then loop over nodes therein
            //    Element<DIM,DIM>& r_adjacent_elem = *(r_mesh.GetElement(*element_iter));
            //    for (unsigned local_node_index=0; local_node_index<DIM+1; local_node_index++)
            //    {
            //        unsigned adjacent_node_global_index = r_adjacent_elem.GetNodeGlobalIndex(local_node_index);
            //
            //        // If not a ghost node and not the node we started with
            //        if (    !(pCellPopulation->IsGhostNode(adjacent_node_global_index))
            //             && adjacent_node_global_index != node_global_index )
            //        {
            //
            //            // Calculate the contribution of gradient from this node
            //            Node<DIM>& adjacent_node = *(r_mesh.GetNode(adjacent_node_global_index));
            //
            //            double this_cell_concentration = CellwiseData<DIM>::Instance()->GetValue(*cell_iter, 0);
            //            CellPtr p_adjacent_cell = pCellPopulation->GetCellUsingLocationIndex(adjacent_node_global_index);
            //            double adjacent_cell_concentration = CellwiseData<DIM>::Instance()->GetValue(p_adjacent_cell, 0);
            //
            //            c_vector<double, DIM> gradient_contribution = zero_vector<double>(DIM);
            //
            //            if (fabs(this_cell_concentration-adjacent_cell_concentration) > 100*DBL_EPSILON)
            //            {
            //                c_vector<double, DIM> edge_vector = r_mesh.GetVectorFromAtoB(this_node.rGetLocation(), adjacent_node.rGetLocation());
            //                double norm_edge_vector = norm_2(edge_vector);
            //                gradient_contribution = edge_vector
            //                                            * (adjacent_cell_concentration - this_cell_concentration)
            //                                            / (norm_edge_vector * norm_edge_vector);
            //            }
            //
            //            mGradients[node_global_index] += gradient_contribution;
            //            num_real_adjacent_nodes++;
            //        }
            //    }
            //}
            //mGradients[node_global_index] /= num_real_adjacent_nodes;
        }
        else
        {
            mGradients[node_global_index] /= num_real_elems_for_node[node_global_index];
        }
    }
}
Пример #8
0
void solve_with_HPGMG(MultiFab& soln, MultiFab& gphi, Real a, Real b, MultiFab& alpha, PArray<MultiFab>& beta,
                      MultiFab& beta_cc, MultiFab& rhs, const BoxArray& bs, const Geometry& geom, int n_cell)
{
  BndryData bd(bs, 1, geom);
  set_boundary(bd, rhs, 0);

  ABecLaplacian abec_operator(bd, dx);
  abec_operator.setScalars(a, b);
  abec_operator.setCoefficients(alpha, beta);

  int minCoarseDim;
  if (domain_boundary_condition == BC_PERIODIC)
  {
    minCoarseDim = 2; // avoid problems with black box calculation of D^{-1} for poisson with periodic BC's on a 1^3 grid
  }
  else
  {
    minCoarseDim = 1; // assumes you can drop order on the boundaries
  }

  level_type level_h;
  mg_type MG_h;
  int numVectors = 12;

  int my_rank = 0, num_ranks = 1;

#ifdef BL_USE_MPI
  MPI_Comm_size (MPI_COMM_WORLD, &num_ranks);
  MPI_Comm_rank (MPI_COMM_WORLD, &my_rank);
#endif /* BL_USE_MPI */

  const double h0 = dx[0];
  // Create the geometric structure of the HPGMG grid using the RHS MultiFab as
  // a template. This doesn't copy any actual data.
  CreateHPGMGLevel(&level_h, rhs, n_cell, max_grid_size, my_rank, num_ranks, domain_boundary_condition, numVectors, h0);

  // Set up the coefficients for the linear operator L.
  SetupHPGMGCoefficients(a, b, alpha, beta_cc, &level_h);

  // Now that the HPGMG grid is built, populate it with RHS data.
  ConvertToHPGMGLevel(rhs, n_cell, max_grid_size, &level_h, VECTOR_F);

#ifdef USE_HELMHOLTZ
  if (ParallelDescriptor::IOProcessor()) {
    std::cout << "Creating Helmholtz (a=" << a << ", b=" << b << ") test problem" << std::endl;;
  }
#else
  if (ParallelDescriptor::IOProcessor()) {
    std::cout << "Creating Poisson (a=" << a << ", b=" << b << ") test problem" << std::endl;;
  }
#endif /* USE_HELMHOLTZ */

  if (level_h.boundary_condition.type == BC_PERIODIC)
  {
    double average_value_of_f = mean (&level_h, VECTOR_F);
    if (average_value_of_f != 0.0)
    {
      if (ParallelDescriptor::IOProcessor())
      {
        std::cerr << "WARNING: Periodic boundary conditions, but f does not sum to zero... mean(f)=" << average_value_of_f << std::endl;
      }
      //shift_vector(&level_h,VECTOR_F,VECTOR_F,-average_value_of_f);
    }
  }
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  rebuild_operator(&level_h,NULL,a,b);    // i.e. calculate Dinv and lambda_max
  MGBuild(&MG_h,&level_h,a,b,minCoarseDim,ParallelDescriptor::Communicator()); // build the Multigrid Hierarchy
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  if (ParallelDescriptor::IOProcessor())
      std::cout << std::endl << std::endl << "===== STARTING SOLVE =====" << std::endl << std::flush;

  MGResetTimers (&MG_h);
  zero_vector (MG_h.levels[0], VECTOR_U);
#ifdef USE_FCYCLES
  FMGSolve (&MG_h, 0, VECTOR_U, VECTOR_F, a, b, tolerance_abs, tolerance_rel);
#else
  MGSolve (&MG_h, 0, VECTOR_U, VECTOR_F, a, b, tolerance_abs, tolerance_rel);
#endif /* USE_FCYCLES */

  MGPrintTiming (&MG_h, 0);   // don't include the error check in the timing results
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  if (ParallelDescriptor::IOProcessor())
    std::cout << std::endl << std::endl << "===== Performing Richardson error analysis ==========================" << std::endl;
  // solve A^h u^h = f^h
  // solve A^2h u^2h = f^2h
  // solve A^4h u^4h = f^4h
  // error analysis...
  MGResetTimers(&MG_h);
  const double dtol = tolerance_abs;
  const double rtol = tolerance_rel;
  int l;for(l=0;l<3;l++){
    if(l>0)restriction(MG_h.levels[l],VECTOR_F,MG_h.levels[l-1],VECTOR_F,RESTRICT_CELL);
           zero_vector(MG_h.levels[l],VECTOR_U);
    #ifdef USE_FCYCLES
    FMGSolve(&MG_h,l,VECTOR_U,VECTOR_F,a,b,dtol,rtol);
    #else
     MGSolve(&MG_h,l,VECTOR_U,VECTOR_F,a,b,dtol,rtol);
    #endif
  }
  richardson_error(&MG_h,0,VECTOR_U);

  // Now convert solution from HPGMG back to rhs MultiFab.
  ConvertFromHPGMGLevel(soln, &level_h, VECTOR_U);

  const double norm_from_HPGMG = norm(&level_h, VECTOR_U);
  const double mean_from_HPGMG = mean(&level_h, VECTOR_U);
  const Real norm0 = soln.norm0();
  const Real norm2 = soln.norm2();
  if (ParallelDescriptor::IOProcessor()) {
    std::cout << "mean from HPGMG: " << mean_from_HPGMG << std::endl;
    std::cout << "norm from HPGMG: " << norm_from_HPGMG << std::endl;
    std::cout << "norm0 of RHS copied to MF: " << norm0 << std::endl;
    std::cout << "norm2 of RHS copied to MF: " << norm2 << std::endl;
  }

  // Write the MF to disk for comparison with the in-house solver
  if (plot_soln)
  {
    writePlotFile("SOLN-HPGMG", soln, geom);
  }

  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  MGDestroy(&MG_h);
  destroy_level(&level_h);
  //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  PArray<MultiFab> grad_phi(BL_SPACEDIM, PArrayManage);
  for (int n = 0; n < BL_SPACEDIM; ++n)
      grad_phi.set(n, new MultiFab(BoxArray(soln.boxArray()).surroundingNodes(n), 1, 0));

#if (BL_SPACEDIM == 2)
  abec_operator.compFlux(grad_phi[0],grad_phi[1],soln);
#elif (BL_SPACEDIM == 3)
  abec_operator.compFlux(grad_phi[0],grad_phi[1],grad_phi[2],soln);
#endif

  // Average edge-centered gradients to cell centers.
  BoxLib::average_face_to_cellcenter(gphi, grad_phi, geom);
}
double AbstractFunctionalCalculator<ELEMENT_DIM, SPACE_DIM, PROBLEM_DIM>::CalculateOnElement(Element<ELEMENT_DIM, SPACE_DIM>& rElement)
{
    double result_on_element = 0;

    // Third order quadrature.  Note that the functional may be non-polynomial (see documentation of class).
    GaussianQuadratureRule<ELEMENT_DIM> quad_rule(3);

    /// NOTE: This assumes that the Jacobian is constant on an element, ie
    /// no curvilinear bases were used for position
    double jacobian_determinant;
    c_matrix<double, SPACE_DIM, ELEMENT_DIM> jacobian;
    c_matrix<double, ELEMENT_DIM, SPACE_DIM> inverse_jacobian;
    rElement.CalculateInverseJacobian(jacobian, jacobian_determinant, inverse_jacobian);

    const unsigned num_nodes = rElement.GetNumNodes();

    // Loop over Gauss points
    for (unsigned quad_index=0; quad_index < quad_rule.GetNumQuadPoints(); quad_index++)
    {
        const ChastePoint<ELEMENT_DIM>& quad_point = quad_rule.rGetQuadPoint(quad_index);

        c_vector<double, ELEMENT_DIM+1> phi;
        LinearBasisFunction<ELEMENT_DIM>::ComputeBasisFunctions(quad_point, phi);
        c_matrix<double, ELEMENT_DIM, ELEMENT_DIM+1> grad_phi;
        LinearBasisFunction<ELEMENT_DIM>::ComputeTransformedBasisFunctionDerivatives(quad_point, inverse_jacobian, grad_phi);

        // Location of the Gauss point in the original element will be stored in x
        ChastePoint<SPACE_DIM> x(0,0,0);
        c_vector<double,PROBLEM_DIM> u = zero_vector<double>(PROBLEM_DIM);
        c_matrix<double,PROBLEM_DIM,SPACE_DIM> grad_u = zero_matrix<double>(PROBLEM_DIM,SPACE_DIM);

        for (unsigned i=0; i<num_nodes; i++)
        {
            const c_vector<double, SPACE_DIM>& r_node_loc = rElement.GetNode(i)->rGetLocation();

            // Interpolate x
            x.rGetLocation() += phi(i)*r_node_loc;

            // Interpolate u and grad u
            unsigned node_global_index = rElement.GetNodeGlobalIndex(i);
            for (unsigned index_of_unknown=0; index_of_unknown<PROBLEM_DIM; index_of_unknown++)
            {
                // NOTE - following assumes that, if say there are two unknowns u and v, they
                // are stored in the current solution vector as
                // [U1 V1 U2 V2 ... U_n V_n]
                unsigned index_into_vec = PROBLEM_DIM*node_global_index + index_of_unknown;

                double u_at_node = mSolutionReplicated[index_into_vec];
                u(index_of_unknown) += phi(i)*u_at_node;
                for (unsigned j=0; j<SPACE_DIM; j++)
                {
                    grad_u(index_of_unknown,j) += grad_phi(j,i)*u_at_node;
                }
            }
        }

        double wJ = jacobian_determinant * quad_rule.GetWeight(quad_index);
        result_on_element += GetIntegrand(x, u, grad_u) * wJ;
    }

    return result_on_element;
}