void StokesContinuityResid<EvalT, Traits>::
evaluateFields(typename Traits::EvalData workset)
{
  typedef Intrepid::FunctionSpaceTools FST;

  for (std::size_t cell=0; cell < workset.numCells; ++cell) {
    for (std::size_t qp=0; qp < numQPs; ++qp) {
      divergence(cell,qp) = 0.0;
      for (std::size_t i=0; i < numDims; ++i) {
        divergence(cell,qp) += VGrad(cell,qp,i,i);
      }
    }
  }
  FST::integrate<ScalarT>(CResidual, divergence, wBF, Intrepid::COMP_CPP,  
                          false); // "false" overwrites

  contractDataFieldScalar<ScalarT>(CResidual, divergence, wBF,false); // "false" overwrites



  if (havePSPG) {
    for (std::size_t cell=0; cell < workset.numCells; ++cell) {
      for (std::size_t node=0; node < numNodes; ++node) {          
	for (std::size_t qp=0; qp < numQPs; ++qp) {               
	  for (std::size_t j=0; j < numDims; ++j) { 
	    CResidual(cell,node) += 
	      TauM(cell,qp)*Rm(cell,qp,j)*wGradBF(cell,node,qp,j);
	  }  
	}    
      }
    }
  }

}
Ejemplo n.º 2
0
void lpaggreg::DQualities::computeQualities()
{
    if (values==0){
        return;
    }
    unsigned hsize=metaData.getHsize();
    unsigned osize=values->getOsize();
    unsigned vsize=values->getVsize();
    qualities=dqualities(new vector<shared_ptr<UpperTriangularMatrix<shared_ptr<lpaggreg::Quality> > > >(hsize));
    for (int h = 0; h < hsize; h++){
        (*qualities)[h]=oqualities(new UpperTriangularMatrix<shared_ptr<lpaggreg::Quality> >(osize));
    }
    for (int k=0; k < vsize; k++){
        int i=0;
        int h;
        vector<UpperTriangularMatrix<lp_quality_type> > sum;
        vector<UpperTriangularMatrix<lp_quality_type> > info;
        for (h=0; h<hsize; h++){
            sum.push_back(UpperTriangularMatrix<lp_quality_type>(osize));
            info.push_back(UpperTriangularMatrix<lp_quality_type>(osize));
        }
        for (h = (metaData.getPath())[i]; i < metaData.getLeaveSize(); h = (metaData.getPath())[++i]){
            for (int i = osize-1; i >=0; i--) {
                (sum[h])(i,i,(*values)[h][k][i]);
                (info[h])(i,i,entropyReduction((*values)[h][k][i], 0));
                (sum[(metaData.getParents())[h]])(i,i,(sum[(metaData.getParents())[h]])(i,i)+(sum[h])(i,i));
                (info[(metaData.getParents())[h]])(i,i,(info[(metaData.getParents())[h]])(i,i)+(info[h])(i,i));
                for (int j = i+1; j < osize; j++) {
                    (sum[h])(i,j,(sum[h])(i+1,j)+(sum[h])(i,i));
                    (info[h])(i,j,(info[h])(i+1,j)+(info[h])(i,i));
                    (*(*qualities)[h])(i,j)->addToGain(entropyReduction((sum[h])(i,j), (info[h])(i,j)));
                    (*(*qualities)[h])(i,j)->addToLoss(divergence(j-i+1, (sum[h])(i,j), (info[h])(i,j)));
                    (sum[(metaData.getParents())[h]])(i,j,(sum[(metaData.getParents())[h]])(i,j)+(sum[h])(i,j));
                    (info[(metaData.getParents())[h]])(i,j,(info[(metaData.getParents())[h]])(i,j)+(info[h])(i,j));
                }
            }
        }
        for (h = (metaData.getPath())[i]; i < hsize-1; h = (metaData.getPath())[++i]){
            for (int i = osize-1; i >=0; i--) {
                for (int j = i; j < osize; j++) {
                    (*(*qualities)[h])(i,j)->addToGain(entropyReduction((sum[h])(i,j), (info[h])(i,j)));
                    (*(*qualities)[h])(i,j)->addToLoss(divergence((j-i+1)*(metaData.getSize())[h], (sum[h])(i,j), (info[h])(i,j)));
                    (sum[(metaData.getParents())[h]])(i,j,(sum[(metaData.getParents())[h]])(i,j)+(sum[h])(i,j));
                    (info[(metaData.getParents())[h]])(i,j,(info[(metaData.getParents())[h]])(i,j)+(info[h])(i,j));
                }
            }
        }
        for (int i = osize-1; i >=0; i--) {
            for (int j = i; j < osize; j++) {
                (*(*qualities)[h])(i,j)->addToGain(entropyReduction((sum[h])(i,j), (info[h])(i,j)));
                (*(*qualities)[h])(i,j)->addToLoss(divergence((j-i+1)*(metaData.getSize())[h], (sum[h])(i,j), (info[h])(i,j)));
            }
        }
    }
}
void FluidSystem::project(VelocityField &velocity) const {
    Grid pressure(fullDim);
    Grid divergence(fullDim);
    div(divergence, velocity, dim);
    divergence = -1 * divergence;
    setContinuityBoundaries(divergence, dim);
    setContinuityBoundaries(pressure, dim);
    linearSolve(pressure, divergence, 1, 6, dim, std::bind(&setContinuityBoundaries,
                                                           std::placeholders::_1, dim));
    VelocityField gradient(fullStaggeredDim);
    gradient.clear();
    grad(gradient, pressure, dim);
    velocity -= gradient;
    if (horizontalNeumann) {
        setHorizontalNeumannBoundaries(velocity[0], dim);
    } else {
        setContinuityBoundaries(velocity[0], dim);
    }
    if (verticalNeumann) {
        setVerticalNeumannBoundaries(velocity[1], dim);
    } else {
        setContinuityBoundaries(velocity[1], dim);
    }
    setDepthNeumannBoundaries(velocity[2], dim);
}
Ejemplo n.º 4
0
/*
	Function for setting up and running the fluid simulation kernels
*/
void solveFluid(struct Configuration* config) { 
	// Jacobi settings
	float alpha = -1.0f;
	// Should use alpha -1 here, but this gives nicer results
	//float alpha = -(1.0f/invhalfgridscale);
	float rbeta = 0.25;
	int iterations = 100;

	// grid scaling. this is currently not used
    if(rank == 0){
        float gridscale = 1.0f;
        float invgridscale = 1.0f/gridscale;
        float invhalfgridscale = 0.5f/gridscale; 

        // Timstep value
        float timestep = 0.05f;

        // Emitter settings
        float amount = 2.0f;
        float radius = 0.5*config->N/10.0f;
        float emitterposx = config->N/2;
        float emitterposy = config->N/3;

        // buoyancy settings
        float bdiry = 1.0f;
        float bdirx = 0.0f;
        float bstrength = 0.1f;

        // advection settings
        float veldamp = 0.01f;	


        // Velocity advection
        float *tmp = config->velx0; config->velx0 = config->velx; config->velx = tmp;
        float *tmp1 = config->vely0; config->vely0 = config->vely; config->vely = tmp1;
        advect(config->N, config->velx, config->velx0, config->velx0, config->vely0, timestep, veldamp, 1);
        advect(config->N, config->vely, config->vely0, config->velx0, config->vely0, timestep, veldamp, 2);

        // Density advection
        float *tmp2 = config->dens0; config->dens0 = config->dens; config->dens = tmp2;
        advect(config->N, config->dens, config->dens0, config->velx, config->vely, timestep, 0.0f, 0);

        // Add density and density buoyancy
        addDensity(config->N, config->dens, timestep, emitterposx, emitterposy, radius, amount);
        addDensityBuoyancy(config->N, config->velx, config->vely, config->dens, bdirx, bdiry, bstrength, timestep);

        // Divergence calculation
        divergence(config->N, config->velx, config->vely, config->div);	

        // Pressure jacobi calculation. First set pres array to zero as initial guess
        setMem(config->N, config->pres);
    }

	jacobi(iterations);
	
    if(rank == 0){
        // Calculate projection
        projection(config->N, config->velx, config->vely, config->pres);	
    }
}
Ejemplo n.º 5
0
int main(int argc, char **argv)
{

  int NX,NY,NZ;
  MPI_Init (&argc, &argv);
  int nprocs, procid;
  MPI_Comm_rank(MPI_COMM_WORLD, &procid);
  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

  /* Parsing Inputs  */
  if(argc==1){
    NX=256;NY=256;NZ=256;
  }
  else{
    NX=atoi(argv[1]); NY=atoi(argv[2]); NZ=atoi(argv[3]);
  }
  int N[3]={NX,NY,NZ};

  int nthreads=1;
  grad(N,nthreads);

  laplace(N,nthreads);

  divergence(N,nthreads);

  biharmonic(N,nthreads);

  MPI_Finalize();
  return 0;
} // end main
Ejemplo n.º 6
0
void divergence(EBCellFAB&                a_divF,
                const EBFluxFAB&          a_flux,
                const EBISBox&            a_ebisBox,
                const Box&                a_box,
                const RealVect&           a_fluxVal,
                const Real&               a_dx)
{
  IntVectSet ivs(a_box);
  for (VoFIterator vofit(ivs, a_ebisBox.getEBGraph()); vofit.ok(); ++vofit)
    {
      Real divval = divergence(a_flux, a_fluxVal, a_ebisBox, vofit(), a_dx);
      a_divF(vofit(), 0) = divval;
    }

}
Ejemplo n.º 7
0
// w component of velocity source term
double eval_q_w(double x, double y, double z)
{
  typedef DualNumber<Scalar, NumberArray<NDIM, Scalar> > FirstDerivType;
  typedef DualNumber<FirstDerivType, NumberArray<NDIM, FirstDerivType> > SecondDerivType;
  typedef DualNumber<SecondDerivType, NumberArray<NDIM, SecondDerivType> > ThirdDerivType;
  typedef ThirdDerivType ADScalar;

  // Treat velocity as a vector
  NumberArray<NDIM, ADScalar> U;

  ADScalar x = ADScalar(x1,NumberArrayUnitVector<NDIM, 0, Scalar>::value());
  ADScalar y = ADScalar(y1,NumberArrayUnitVector<NDIM, 1, Scalar>::value());
  ADScalar z = ADScalar(z1,NumberArrayUnitVector<NDIM, 2, Scalar>::value());

  // Arbitrary manufactured solutions
  U[0]       = a * helper_f(x)                  + helper_g(y).derivatives()[1] + helper_h(z).derivatives()[2];
  U[1]       = b * helper_f(x).derivatives()[0] + helper_g(y)                  + helper_h(z).derivatives()[2];
  U[2]       = c * helper_f(x).derivatives()[0] + helper_g(y).derivatives()[1] + helper_h(z);
  ADScalar P = d * helper_f(x)                  + helper_gt(y)                 + helper_h(z);

  // NS equation residuals
  NumberArray<NDIM, Scalar> Q_u = 
    raw_value(

	      // convective term
	      divergence(U.outerproduct(U))

	      // pressure
	      - P.derivatives()

	      // dissipation
	      + nu * divergence(gradient(U)));

  return Q_u[2];

}
Ejemplo n.º 8
0
void PCM::propagateCavityGradients(const ScalarField& A_shape, ScalarField& A_nCavity, ScalarFieldTilde& A_rhoExplicitTilde, bool electricOnly) const
{   if(fsp.pcmVariant == PCM_SGA13)
    {   //Propagate gradient w.r.t expanded cavities to nCavity:
        ((PCM*)this)->A_nc = 0;
        const ScalarField* A_shapeEx[2] = { &A_shape, &Acavity_shapeVdw };
        for(int i=0; i<2; i++)
        {   //First compute derivative w.r.t expanded electron density:
            ScalarField A_nCavityEx;
            ShapeFunction::propagateGradient(nCavityEx[i], *(A_shapeEx[i]), A_nCavityEx, fsp.nc, fsp.sigma);
            ((PCM*)this)->A_nc += (-1./fsp.nc) * integral(A_nCavityEx*nCavityEx[i]);
            //then propagate to original electron density:
            ScalarField nCavityExUnused; //unused return value below
            ShapeFunction::expandDensity(wExpand[i], Rex[i], nCavity, nCavityExUnused, &A_nCavityEx, &A_nCavity);
        }
    }
    else if(fsp.pcmVariant == PCM_CANDLE)
    {   ScalarField A_nCavityEx;
        ScalarFieldTilde A_phiExt;
        double A_pCavity=0.;
        ShapeFunction::propagateGradient(nCavityEx[0], coulomb(Sf[0]*rhoExplicitTilde), I(wExpand[0]*J(A_shape)) + Acavity_shapeVdw,
                                         A_nCavityEx, A_phiExt, A_pCavity, fsp.nc, fsp.sigma, fsp.pCavity);
        A_nCavity += fsp.Ztot * I(Sf[0] * J(A_nCavityEx));
        if(!electricOnly) A_rhoExplicitTilde += coulomb(Sf[0]*A_phiExt);
        ((PCM*)this)->A_nc = (-1./fsp.nc) * integral(A_nCavityEx*nCavityEx[0]);
        ((PCM*)this)->A_eta_wDiel = integral(A_shape * I(wExpand[1]*J(shapeVdw)));
        ((PCM*)this)->A_pCavity = A_pCavity;
    }
    else if(isPCM_SCCS(fsp.pcmVariant))
    {   //Electrostatic and volumetric combinations via shape:
        ShapeFunctionSCCS::propagateGradient(nCavity, A_shape - fsp.cavityPressure, A_nCavity, fsp.rhoMin, fsp.rhoMax, epsBulk);
        //Add surface contributions:
        ScalarField shapePlus, shapeMinus;
        ShapeFunctionSCCS::compute(nCavity+(0.5*fsp.rhoDelta), shapePlus, fsp.rhoMin, fsp.rhoMax, epsBulk);
        ShapeFunctionSCCS::compute(nCavity-(0.5*fsp.rhoDelta), shapeMinus, fsp.rhoMin, fsp.rhoMax, epsBulk);
        VectorField Dn = gradient(nCavity);
        ScalarField DnLength = sqrt(lengthSquared(Dn));
        ScalarField A_shapeMinus = (fsp.cavityTension/fsp.rhoDelta) * DnLength;
        ScalarField A_DnLength = (fsp.cavityTension/fsp.rhoDelta) * (shapeMinus - shapePlus);
        A_nCavity -= divergence(Dn * (inv(DnLength) * A_DnLength));
        ShapeFunctionSCCS::propagateGradient(nCavity+(0.5*fsp.rhoDelta), -A_shapeMinus, A_nCavity, fsp.rhoMin, fsp.rhoMax, epsBulk);
        ShapeFunctionSCCS::propagateGradient(nCavity-(0.5*fsp.rhoDelta),  A_shapeMinus, A_nCavity, fsp.rhoMin, fsp.rhoMax, epsBulk);
    }
    else //All gradients are w.r.t the same shape function - propagate them to nCavity (which is defined as a density product for SaLSA)
    {   ShapeFunction::propagateGradient(nCavity, A_shape + Acavity_shape, A_nCavity, fsp.nc, fsp.sigma);
        ((PCM*)this)->A_nc = (-1./fsp.nc) * integral(A_nCavity*nCavity);
    }
}
Ejemplo n.º 9
0
/*
 * This routine is in charge of the Temperature equation.  Virtually all
 * of the terms can be enabled or disabled by parameters read in through the
 * configuration file.  This equation has the form:
 * 
 * dT/dt = div(uT) + w hat z + del^2 T 
 */
void calcTemp()
{
    complex PRECISION * forces = T->force1;
    
    if(tDiff)
    {
        laplacian(T->spectral, forces, 0, 1.0);
    }
    else
    {
        memset(forces, 0, spectralCount * sizeof(complex PRECISION));
    }

    if(tempAdvection)
    {
        //advect the background profile (as long as it is enabled)
        if(tempBackground)
        {
            plusEq(forces, u->vec->z->spectral);
        }

        //advect the perturbations
        p_vector flux = temp1;
        multiply(u->vec->x->spatial, T->spatial, flux->x->spatial);
        multiply(u->vec->y->spatial, T->spatial, flux->y->spatial);
        multiply(u->vec->z->spatial, T->spatial, flux->z->spatial);

        fftForward(flux->x);
        fftForward(flux->y);
        fftForward(flux->z);

        p_field advect = temp2->x;
        divergence(flux, advect);

        minusEq(forces, advect->spectral);

    }
    
    //Apply hyper diffusion to the boundaries
    if(sanitize)
    {
        killBoundaries(T->spatial, forces, 1, 100);
    }
}
Ejemplo n.º 10
0
void NS(void)
{
	//surface_tension_geo();
	//surface_tension();
//	if(iteration%ioutput==0)
//	{
//		print_2D_array("GeoSurfx.dat",iteration,"GeoSurfx",surfx[0],l-1,m-1,dx);
//		print_2D_array("GeoSurfy.dat",iteration,"GeoSurfy",surfy[0],l-1,m-1,dx);
//	}
/*	surface_tension();
	if(iteration%ioutput==0)
	{
		print_2D_array("FreeSurfx.dat",iteration,"FreeSurfx",surfx[0],l-1,m-1,dx);
		print_2D_array("FreeSurfy.dat",iteration,"FreeSurfy",surfy[0],l-1,m-1,dx);
	}
	*/
	momentum();
	divergence();
//	print_2D_array("surfx",iteration,"surfx",surfx[0],l-1,m-1,dx);
//	print_2D_array("surfy",iteration,"surfy",surfy[0],l-1,m-1,dx);
//	print_2D_array("sigma",iteration,"sigma",sigma[0],l+1,m+1,dx);
}
Ejemplo n.º 11
0
int main (int argc, char** argv)
{
	int i;
	int iterations = 100;
	// prepare grids
	// declare_grids -->
	float *  u_0_0_out;
	float *  u_0_0;
	float *  ux_1_0;
	float *  uy_2_0;
	float *  uz_3_0;
	float *  u_0_0_out_cpu;
	float *  u_0_0_cpu;
	float *  ux_1_0_cpu;
	float *  uy_2_0_cpu;
	float *  uz_3_0_cpu;
	if ((argc<4))
	{
		printf("Wrong number of parameters. Syntax:\n%s <x_max> <y_max> <z_max> <# of iterations>\n", argv[0]);
		exit(-1);
	}
	int x_max = atoi(argv[1]);
	int y_max = atoi(argv[2]);
	int z_max = atoi(argv[3]);
	if(argc==5)
	  iterations = atoi(argv[4]);
	// <--
	
	// allocate_grids -->
	u_0_0=((float * )malloc((((x_max*y_max)*z_max)*sizeof (float))));
	ux_1_0=((float * )malloc(((((x_max+2)*y_max)*z_max)*sizeof (float))));
	uy_2_0=((float * )malloc((((x_max*(y_max+2))*z_max)*sizeof (float))));
	uz_3_0=((float * )malloc((((x_max*y_max)*(z_max+2))*sizeof (float))));
	u_0_0_cpu=((float * )malloc((((x_max*y_max)*z_max)*sizeof (float))));
	ux_1_0_cpu=((float * )malloc(((((x_max+2)*y_max)*z_max)*sizeof (float))));
	uy_2_0_cpu=((float * )malloc((((x_max*(y_max+2))*z_max)*sizeof (float))));
	uz_3_0_cpu=((float * )malloc((((x_max*y_max)*(z_max+2))*sizeof (float))));
	// <--
	
	
	// initialize
	// initialize_grids -->
	initialize(u_0_0, ux_1_0, uy_2_0, uz_3_0, 0.1, 0.2, 0.30000000000000004, x_max, y_max, z_max);
	initialize(u_0_0_cpu, ux_1_0_cpu, uy_2_0_cpu, uz_3_0_cpu, 0.1, 0.2, 0.30000000000000004, x_max, y_max, z_max);
	// <--
	
	long nFlopsPerStencil = 8;
	long nGridPointsCount = iterations * ((x_max*y_max)*z_max);
	long nBytesTransferred = iterations * (((((((x_max+2)*y_max)*z_max)*sizeof (float))+(((x_max*(y_max+2))*z_max)*sizeof (float)))+(((x_max*y_max)*(z_max+2))*sizeof (float)))+(((x_max*y_max)*z_max)*sizeof (float)));
	

	/* *************************** PGI GPU-acc benchmark ********************* */

	
	// warm up
	
	{
		// compute_stencil -->
	  divergence(( & u_0_0_out), u_0_0, ux_1_0, uy_2_0, uz_3_0, 0.4, 0.5, 0.6, x_max, y_max, z_max,iterations);
		// <--
	}
	
	// run the benchmark
	tic ();
	{
		// compute_stencil -->
	  divergence(( & u_0_0_out), u_0_0, ux_1_0, uy_2_0, uz_3_0, 0.7, 0.7999999999999999, 0.8999999999999999, x_max, y_max, z_max,iterations);
		// <--	
	}
	toc (nFlopsPerStencil, nGridPointsCount, nBytesTransferred);

	
	/* *************************** ******************** ********************* */	

	/* *************************** Naive CPU Comparison ********************* */
	
	// warm up cpu comparison

	{
		// compute_stencil -->
	  divergence(( & u_0_0_out_cpu), u_0_0_cpu, ux_1_0_cpu, uy_2_0_cpu, uz_3_0_cpu, 0.4, 0.5, 0.6, x_max, y_max, z_max,iterations);
		// <--
	}
	
	// run the benchmark
	tic ();
	{
		// compute_stencil -->
	  divergence_cpu(( & u_0_0_out_cpu), u_0_0_cpu, ux_1_0_cpu, uy_2_0_cpu, uz_3_0_cpu, 0.7, 0.7999999999999999, 0.8999999999999999, x_max, y_max, z_max,iterations);
		// <--	
	}
	toc (nFlopsPerStencil, nGridPointsCount, nBytesTransferred);

	// checking "correctness" (assuming cpu version is correct)
	int error_count=0;
	int halo = 0;
	int x,y,z;
	for(y=0;y<x_max;y++) {
	  for(x=0;x<x_max;x++) {
	    for(z=0;z<y_max;z++) {
	      i = x + (x_max+halo)*y + (x_max+halo)*(y_max+halo)*z;
	      if(fabs(u_0_0_out[i] - u_0_0_out_cpu[i])>0.001) {
		error_count++;
		printf("%dth error encountered at u[%d]: |%f-%f|=%5.16f\n",error_count,i,u_0_0_out[i],u_0_0_out_cpu[i],fabs(u_0_0_out[i] - u_0_0_out_cpu[i]));
		if(error_count>30) {
		  printf("too many errors\n"); printf("print some solutions\n");
		  for(x=0;x<100;x++) {
		    printf("u_pgi[%d]=%2.2f ?? u_cpu[%d]=%2.2f\n",x,u_0_0_out[x],x,u_0_0_out_cpu[x]);
		  }
		  exit(1);
		}
	      }
	    }
	  }
	}
	if(error_count==0) {
	  printf("Error Check Successful. No errors encountered.\n");	  
	}
			  
	
	
	// free memory
	// deallocate_grids -->
	free(u_0_0);
	free(ux_1_0);
	free(uy_2_0);
	free(uz_3_0);
	// <--
	
	
	return EXIT_SUCCESS;
}
Ejemplo n.º 12
0
//Source term depending on cell
void sources(struct CSRMat *Mat, struct RHS *Rhs)
{
   int icell, ivar, idir;
   double *CelldblPnt, *phi, *dep, Src[nvar];
   double tau[ndir][ndir], div, CmuOm;
   int i, j, k;
   double beta, Sij[ndir][ndir], Omij[ndir][ndir], xiw, fb;
   double SAa, SAb, SAc;

   for (icell=0;icell<ncell;icell++) {
      phi = setvar(icell);
      dep = setdep(icell);
      CelldblPnt = setdblcell(icell);

      memset(Src, 0.0, nvar * sizeof(double));

      // Momentum Sources ----------------------------------------------------
      if (eos != ICOUPLED) {
         for (idir=0;idir<ndir;idir++)
            Src[Uvar+idir] = - dep[PGrd+idir];
      }

      // Turbulence production --------------
      if (Kvar!=-1) {
         for (idir=0;idir<ndir;idir++)
            Src[Uvar+idir]-= 2.0 / 3.0 * dep[Rdep] * dep[KGrd+idir];
            //Src[Uvar+idir]-= 2.0 / 3.0 * dep[MTdep] * divergence( dep);

         stress( phi, dep, tau);
         Src[Kvar] = prodk( dep, tau); 
      }

      // turbulence Sources --------------------------------------------------
      switch (turb) {
      //    Spalart Allmaras ----------------
      case SA:
         // NASA #################################
         /*SAa = cb1 * ( 1.0 - ft2( phi, dep)) * Shat( phi, dep) * phi[MTvar];

         SAb = ( cw1 * fw( phi, dep) - cb1 / (kappa * kappa) * ft2( phi, dep)) * \
                    ( phi[MTvar] * phi[MTvar]) / ( dep[Ddep] * dep[Ddep]);

         SAc = cb2 / sigma * scalarp( ndir, &dep[MTGrd], &dep[MTGrd]);*/
         // Deck #################################
         SAa = cb1 * Shat( phi, dep) * phi[MTvar];

         SAb = cw1 * fw( phi, dep) * \
             ( phi[MTvar] * phi[MTvar]) / ( dep[Ddep] * dep[Ddep]);

         SAc = 0.0; //cb2 / sigma * scalarp( ndir, &dep[MTGrd], &dep[MTGrd]);

         Src[MTvar] = dep[Rdep] * (SAa - SAb + SAc);
         break;
      //    Kw Wilcox 2006 ------------------
      case KW06:
         strain( dep, Sij);
         rotation( dep, Omij);
         div = divergence( dep);

         for (i=0;i<ndir;i++)
            Sij[i][i] -= 0.5 * div;

         xiw = 0.0;
         for (i=0;i<ndir;i++) {
         for (j=0;j<ndir;j++) {
         for (k=0;k<ndir;k++)
            xiw += Omij[i][j] * Omij[j][k] * Sij[k][i]; }}

         CmuOm = Cmu * phi[OMvar];
         xiw = fabs( xiw / (CmuOm * CmuOm * CmuOm));

         fb = ( 1.0 + 85.0*xiw) / ( 1.0 + 100.0*xiw);
         beta = beta0 * fb;

         Src[Kvar] -= Cmu   * dep[Rdep]  * phi[Kvar]  * phi[OMvar];
         Src[OMvar] = alpha * phi[OMvar] / phi[Kvar]  * prodk( dep, tau);
         Src[OMvar]-= beta  * dep[Rdep]  * phi[OMvar] * phi[OMvar];
         if ( scalarp( ndir, &dep[KGrd], &dep[OMGrd]) > 0.0)
            Src[OMvar]+= 0.125 * dep[Rdep] / phi[OMvar] * \
                                 scalarp( ndir, &dep[KGrd], &dep[OMGrd]);
         break;
      //    Menter KwSST --------------------
      case KWSST:
         strain( dep, Sij);
         rotation( dep, Omij);

         alpha = blend( F1(phi,dep), gamma1, gamma2);
         beta  = blend( F1(phi,dep), beta1, beta2);

         Src[Kvar] -= Cmu   * dep[Rdep]  * phi[Kvar]  * phi[OMvar];
         Src[OMvar] = alpha * dep[Rdep]  / dep[MTdep] * prodk( dep, tau);
         Src[OMvar]-= beta  * dep[Rdep]  * phi[OMvar] * phi[OMvar];
         Src[OMvar]+= 2.0 * (1.0-F1(phi,dep)) * sigw2 * dep[Rdep] / phi[OMvar] * \
                                 scalarp( ndir, &dep[KGrd], &dep[OMGrd]);
         break;
      }

      getrhs( Rhs, icell, CelldblPnt[CellVol], Src);
   }
}
double FluidMixture::operator()(const ScalarFieldArray& indep, ScalarFieldArray& Phi_indep, Outputs outputs) const
{	static StopWatch watch("FluidMixture::operator()"); watch.start();

	//logPrintf("indep.size: %d nIndep: %d\n",indep.size(),nIndep);
	myassert(indep.size()==get_nIndep());

	//---------- Compute site densities from the independent variables ---------
	ScalarFieldTildeArray Ntilde(nDensities); //site densities (in reciprocal space)
	std::vector< vector3<> > P0(component.size()); //polarization densities G=0
	for(unsigned ic=0; ic<component.size(); ic++)
	{	const FluidComponent& c = *component[ic];
		ScalarFieldArray N(c.molecule.sites.size());
		c.idealGas->getDensities(&indep[c.offsetIndep], &N[0], P0[ic]);
		for(unsigned i=0; i<c.molecule.sites.size(); i++)
		{	//Replace negative densities with 0:
			double Nmin, Nmax;
			callPref(eblas_capMinMax)(gInfo.nr, N[i]->dataPref(), Nmin, Nmax, 0.);
			//store site densities in fourier space
			Ntilde[c.offsetDensity+i] = J(N[i]);
			N[i] = 0; //Really skimp on memory!
		}
	}

	//----------- Handle density constraints ------------
	std::vector<double> Nscale(component.size(), 1.0); //density scale factor that satisfies the constraint
	std::vector<double> Ntot_c; //vector of total number of molecules for each component
	std::vector<double> Nscale_Qfixed(component.size(), 0.); //derivative of Nscale w.r.t the fixed charge
	std::vector<std::vector<double> > Nscale_N0(component.size(), std::vector<double>(component.size(),0.0)); //jacobian of Nscale w.r.t the uncorrected molecule counts
	std::vector<string> names; //list of molecule names
	
	//Find fixed N and charged species:
	double Qfixed = 0.0;
	if(rhoExternal) Qfixed += integral(rhoExternal);
	std::vector<std::pair<double,double> > N0Q;
	for(unsigned ic=0; ic<component.size(); ic++)
	{	const FluidComponent& c = *component[ic];
		double Qmolecule = c.molecule.getCharge();
		if(c.Nnorm>0 || Qmolecule)
		{	double N0 = integral(Ntilde[c.offsetDensity])/c.molecule.sites[0]->positions.size();
			if(c.Nnorm>0)
			{	Nscale[ic] = c.Nnorm/N0;
				Nscale_N0[ic][ic] = -c.Nnorm/pow(N0,2);
				Qfixed += Qmolecule*c.Nnorm;
			}
			else
			{	N0Q.push_back(std::make_pair(N0, Qmolecule));
				names.push_back(c.molecule.name);
			}
		}
	}
	//Find the betaV (see Qtot()) that makes the unit cell neutral
	if(N0Q.size()==0)
	{	if(fabs(Qfixed)>fabs(Qtol))
			die("Unit cell has a fixed net charge %le,"
				"and there are no free charged species to neutralize it.\n", Qfixed);
	}
	else
	{	double Qprime, Qcell, betaV=0.0;
		if(Qfixed+Qtot(-HUGE_VAL,Qprime,N0Q)<0)
			die("Unit cell will always have a net negative charge (no free positive charges).\n")
		if(Qfixed+Qtot(+HUGE_VAL,Qprime,N0Q)>0)
			die("Unit cell will always have a net positive charge (no free negative charges).\n")

		for(int iter=0; iter<10; iter++) //while(1)
		{	Qcell = Qfixed+Qtot(betaV,Qprime,N0Q,&names,&gInfo,verboseLog);
			if(verboseLog) logPrintf("betaV = %le, Qcell = %le, Qprime = %le\n", betaV, Qcell, Qprime);
			if(fabs(Qcell)<fabs(Qtol)) break;	
			if(std::isnan(Qcell)) 
			  { betaV=0.0; break;}
			betaV -= Qcell/Qprime; //Newton-Raphson update
			
		}
		for(unsigned ic=0; ic<component.size(); ic++)
		{	const FluidComponent& ci = *component[ic];
			double Qi = ci.molecule.getCharge();
			if(Qi && ci.Nnorm<=0)
			{	Nscale[ic] = exp(-Qi*betaV);
				Nscale_Qfixed[ic] = exp(-Qi*betaV) * Qi / Qprime;
				for(unsigned jc=0; jc<component.size(); jc++)
				{	const FluidComponent& cj = *component[jc];
					double Qj = cj.molecule.getCharge();
					if(Qj && cj.Nnorm<=0)
						Nscale_N0[ic][jc] += Qi*Qj*exp(-(Qi+Qj)*betaV)/Qprime;
				}
			}
		}
	}
	std::vector<double> Phi_Nscale(component.size(), 0.0); //accumulate explicit derivatives w.r.t Nscale here

	//Apply the scale factors to the site densities
	for(unsigned ic=0; ic<component.size(); ic++)
	{	const FluidComponent& c = *component[ic];
		for(unsigned i=0; i<c.molecule.sites.size(); i++)
			Ntilde[c.offsetDensity+i] *= Nscale[ic];
		P0[ic] *= Nscale[ic];
		Ntot_c.push_back(integral(Ntilde[c.offsetDensity]));
	}

	EnergyComponents Phi; //the grand free energy (with component information)
	ScalarFieldTildeArray Phi_Ntilde(nDensities); //gradients (functional derivative) w.r.t reciprocal space site densities
	nullToZero(Phi_Ntilde,gInfo);
	std::vector< vector3<> > Phi_P0(component.size()); //functional derivative w.r.t polarization density G=0
	VectorFieldTilde Phi_epsMF; //functional derivative w.r.t mean field electric field
	
	//G=0 fix for mismatch in fluid-fluid vs. fluid-electron charge kernels
	//We do this AFTER we have applied the appropriate scale factors
	if( N0Q.size() && (!useMFKernel)) //if we have charged species in our fluid, and are using mismatched charge kernels
	{
	  	for(unsigned ic=0; ic<component.size(); ic++)
		{	const FluidComponent& c = *component[ic];
		        for(unsigned i=0; i<c.molecule.sites.size(); i++)
			  { 
			    const Molecule::Site& s = *(c.molecule.sites[i]);
			    Phi["Gzero"] += Qfixed*(Ntot_c[ic]/gInfo.detR-c.idealGas->Nbulk)*s.positions.size()*s.deltaS;
			    Phi_Ntilde[c.offsetDensity+i]->data()[0] += (1.0/gInfo.dV) * (Qfixed*s.deltaS);
			  }
		}
	}

	//--------- Compute the (scaled) mean field coulomb interaction --------
	{	ScalarFieldTilde rho; //total charge density
		ScalarFieldTilde rhoMF; //effective charge density for mean-field term
		bool needRho = rhoExternal || outputs.Phi_rhoExternal;
		
		VectorFieldTilde epsMF = polarizable ? J(VectorField(&indep[nIndepIdgas])) : 0; //mean field electric field
		vector3<> P0tot;
		
		for(unsigned ic=0; ic<component.size(); ic++)
		{	const FluidComponent& c = *component[ic];
			for(unsigned i=0; i<c.molecule.sites.size(); i++)
			{	const Molecule::Site& s = *(c.molecule.sites[i]);
				if(s.chargeKernel)
				{	if(needRho) rho += s.chargeKernel * Ntilde[c.offsetDensity+i];
					rhoMF += s.chargeKernel(0) * (c.molecule.mfKernel * Ntilde[c.offsetDensity+i]);
				}
				//Polarization contributions:
				if(polarizable && s.polKernel)
				{	
					#define Polarization_Compute_Pi_Ni \
						VectorField Pi = (Cpol*s.alpha) * I(c.molecule.mfKernel*epsMF - (rhoExternal ? gradient(s.polKernel*coulomb(rhoExternal)) : 0)); \
						ScalarField Ni = I(Ntilde[c.offsetDensity+i]);
					Polarization_Compute_Pi_Ni
					
					ScalarField Phi_Ni = (0.5/(Cpol*s.alpha))*lengthSquared(Pi);
					Phi["Apol"] += gInfo.dV * dot(Ni, Phi_Ni);
					//Derivative contribution to site densities:
					Phi_Ntilde[c.offsetDensity+i] += Idag(Phi_Ni); Phi_Ni=0;
					//Update contributions to bound charge:
					VectorFieldTilde NPtilde = J(Ni * Pi); Pi=0; Ni=0;
					ScalarFieldTilde divNPbar;
					if(needRho) rho -= s.polKernel*divergence(NPtilde);
					VectorFieldTilde NPbarMF = c.molecule.mfKernel*NPtilde; NPtilde=0;
					rhoMF -= divergence(NPbarMF);
					Phi_epsMF += gInfo.nr * NPbarMF;
					P0tot += getGzero(NPbarMF);
				}
			}
			P0tot += P0[ic];
		}
		
		if(rhoMF)
		{	//External charge interaction:
			ScalarFieldTilde Phi_rho;
			ScalarFieldTilde Phi_rhoMF;
			if(needRho)
			{	if(rhoExternal)
				{	
				  ScalarFieldTilde OdExternal = O(coulomb(rhoExternal));
				  if (!useMFKernel)
				   {	
			  	       Phi["ExtCoulomb"] += dot(rho, OdExternal);
				       Phi_rho += OdExternal;
				   }
				   if (useMFKernel)
				   {
				       Phi["ExtCoulomb"] += dot(rhoMF, OdExternal);   
				       Phi_rhoMF += OdExternal; 
				   }
				}
				if(outputs.Phi_rhoExternal) 
				{
				  if (!useMFKernel) *outputs.Phi_rhoExternal = coulomb(rho);
				  if (useMFKernel) *outputs.Phi_rhoExternal = coulomb(rhoMF);
				}
			}
		
			//Mean field contributions:
			{	ScalarFieldTilde OdMF = O(coulomb(rhoMF)); //mean-field electrostatic potential
				Phi["Coulomb"] += 0.5*dot(rhoMF, OdMF);
				Phi_rhoMF += OdMF;
			}
			
			//Polarization density interactions:
			if(outputs.electricP) *outputs.electricP = P0tot * gInfo.detR;
			//--- corrections for net dipole in cell:
			vector3<> Phi_P0tot = (4*M_PI*gInfo.detR) * P0tot;
			Phi["PsqCell"] += 0.5 * dot(Phi_P0tot, P0tot); 
			//--- external electric field interactions:
			Phi["ExtCoulomb"] -= gInfo.detR * dot(Eexternal, P0tot);
			Phi_P0tot -= gInfo.detR * Eexternal;
			
			//Propagate gradients:
			for(unsigned ic=0; ic<component.size(); ic++)
			{	const FluidComponent& c = *component[ic];
				for(unsigned i=0; i<c.molecule.sites.size(); i++)
				{	const Molecule::Site& s = *(c.molecule.sites[i]);
					if(s.chargeKernel)
					{	if(Phi_rho) Phi_Ntilde[c.offsetDensity+i] += (1./gInfo.dV) * (s.chargeKernel * Phi_rho);
						Phi_Ntilde[c.offsetDensity+i] += (s.chargeKernel(0)/gInfo.dV) * (c.molecule.mfKernel * Phi_rhoMF);
					}
					//Polarization contributions:
					if(polarizable && s.polKernel)
					{	VectorFieldTilde Phi_NPtilde = gradient(c.molecule.mfKernel*Phi_rhoMF + (needRho ? s.polKernel*Phi_rho : 0));
						setGzero(Phi_NPtilde, getGzero(Phi_NPtilde) + Phi_P0tot);
						VectorField Phi_NP = Jdag(Phi_NPtilde); Phi_NPtilde=0;
						//propagate gradients from NP to N, epsMF and rhoExternal:
						Polarization_Compute_Pi_Ni
						#undef Polarization_Compute_Pi_Ni
						// --> via Ni
						ScalarField Phi_Ni; for(int k=0; k<3; k++) Phi_Ni += Phi_NP[k]*Pi[k];
						Phi_Ntilde[c.offsetDensity+i] += (1./gInfo.dV) * Idag(Phi_Ni); Phi_Ni=0;
						// --> via Pi
						VectorFieldTilde Phi_PiTilde = Idag(Phi_NP * Ni); Phi_NP=0;
						Phi_epsMF += (Cpol*s.alpha/gInfo.dV)*(c.molecule.mfKernel*Phi_PiTilde);
					}
				}
				Phi_P0[ic] += (1./gInfo.detR) * Phi_P0tot; //convert to functional derivative
			}
		}
	}
	
	//--------- Hard sphere mixture and bonding -------------
	{	//Compute the FMT weighted densities:
		ScalarFieldTilde n0tilde, n1tilde, n2tilde, n3tilde, n1vTilde, n2mTilde;
		std::vector<ScalarField> n0mol(component.size(), 0); //partial n0 for molecules that need bonding corrections
		std::vector<int> n0mult(component.size(), 0); //number of sites which contribute to n0 for each molecule
		std::vector<std::map<double,int> > bond(component.size()); //sets of bonds for each molecule
		bool bondsPresent = false; //whether bonds are present for any molecule
		for(unsigned ic=0; ic<component.size(); ic++)
		{	const FluidComponent& c = *component[ic];
			bond[ic] = c.molecule.getBonds();
			ScalarFieldTilde n0molTilde;
			for(unsigned i=0; i<c.molecule.sites.size(); i++)
			{	const Molecule::Site& s = *(c.molecule.sites[i]);
				if(s.Rhs)
				{	const ScalarFieldTilde& Nsite = Ntilde[c.offsetDensity+i];
					n0mult[ic] += s.positions.size();
					n0molTilde += s.w0  * Nsite;
					n1tilde    += s.w1  * Nsite;
					n2tilde    += s.w2  * Nsite;
					n3tilde    += s.w3  * Nsite;
					n1vTilde   += s.w1v * Nsite;
					n2mTilde   += s.w2m * Nsite;
				}
			}
			if(n0molTilde) n0tilde += n0molTilde;
			if(bond[ic].size())
			{	n0mol[ic] = I(n0molTilde);
				bondsPresent = true;
			}
		}
		if(n0tilde) //at least one sphere in the mixture
		{	ScalarField n0 = I(n0tilde); n0tilde=0;
			ScalarField n1 = I(n1tilde); n1tilde=0;
			ScalarField n2 = I(n2tilde); n2tilde=0;
			ScalarField Phi_n0, Phi_n1, Phi_n2; ScalarFieldTilde Phi_n3tilde, Phi_n1vTilde, Phi_n2mTilde;
			//Compute the sphere mixture free energy:
			Phi["MixedFMT"] += T * PhiFMT(n0, n1, n2, n3tilde, n1vTilde, n2mTilde,
				Phi_n0, Phi_n1, Phi_n2, Phi_n3tilde, Phi_n1vTilde, Phi_n2mTilde);
			//Bonding corrections if required
			if(bondsPresent)
			{	for(unsigned ic=0; ic<component.size(); ic++)
				{	const FluidComponent& c = *component[ic];
					ScalarField Phi_n0mol;
					for(const auto& b: bond[ic])
						Phi["Bonding"] += T * PhiBond(b.first, b.second*1./n0mult[ic],
							n0mol[ic], n2, n3tilde, Phi_n0mol, Phi_n2, Phi_n3tilde);
					if(Phi_n0mol)
					{	//Propagate gradient w.r.t n0mol[ic] to the site densities:
						ScalarFieldTilde Phi_n0molTilde = Idag(Phi_n0mol);
						for(unsigned i=0; i<c.molecule.sites.size(); i++)
						{	const Molecule::Site& s = *(c.molecule.sites[i]);
							if(s.Rhs)
								Phi_Ntilde[c.offsetDensity+i] += T * (s.w0  * Phi_n0molTilde);
						}
					}
				}
			}
			//Accumulate gradients w.r.t weighted densities to site densities:
			ScalarFieldTilde Phi_n0tilde = Idag(Phi_n0); Phi_n0=0;
			ScalarFieldTilde Phi_n1tilde = Idag(Phi_n1); Phi_n1=0;
			ScalarFieldTilde Phi_n2tilde = Idag(Phi_n2); Phi_n2=0;
			for(const FluidComponent* c: component)
			{	for(unsigned i=0; i<c->molecule.sites.size(); i++)
				{	const Molecule::Site& s = *(c->molecule.sites[i]);
					if(s.Rhs)
					{	ScalarFieldTilde& Phi_Nsite = Phi_Ntilde[c->offsetDensity+i];
						Phi_Nsite += T * (s.w0  * Phi_n0tilde);
						Phi_Nsite += T * (s.w1  * Phi_n1tilde);
						Phi_Nsite += T * (s.w2  * Phi_n2tilde);
						Phi_Nsite += T * (s.w3  * Phi_n3tilde);
						Phi_Nsite += T * (s.w1v * Phi_n1vTilde);
						Phi_Nsite += T * (s.w2m * Phi_n2mTilde);
					}
				}
			}
		}
	}

	//---------- Excess functionals --------------
	for(const FluidComponent* c: component) if(c->fex)
		Phi["Fex("+c->molecule.name+")"] += c->fex->compute(&Ntilde[c->offsetDensity], &Phi_Ntilde[c->offsetDensity]);

	//--------- Mixing functionals --------------
	for(const Fmix* fmix: fmixArr)
		Phi["Fmix("+fmix->getName()+")"] += fmix->compute(Ntilde, Phi_Ntilde);

	//--------- PhiNI ---------
	nullToZero(Phi_Ntilde, gInfo);
	if(outputs.N) outputs.N->resize(nDensities);
	//Put the site densities and gradients back in real space
	ScalarFieldArray N(nDensities);
	ScalarFieldArray Phi_N(nDensities);
	for(unsigned i=0; i<nDensities; i++)
	{	N[i] = I(Ntilde[i]); Ntilde[i]=0;
		Phi_N[i] = Jdag(Phi_Ntilde[i]); Phi_Ntilde[i] = 0;
		if(outputs.N) (*outputs.N)[i] = N[i]; //Link site-density to return pointer if necessary
	}
	//Estimate psiEff based on gradients, if requested
	if(outputs.psiEff)
	{	outputs.psiEff->resize(nDensities);
		for(const FluidComponent* c: component)
			for(unsigned i=0; i<c->molecule.sites.size(); i++)
			{	ScalarField& psiCur = outputs.psiEff->at(c->offsetDensity+i);
				psiCur = Phi_N[c->offsetDensity+i] + c->idealGas->V[i];
				if(i==0) psiCur -= c->idealGas->mu / c->molecule.sites[0]->positions.size();
				psiCur *= (-1./T);
			}
	}
	for(unsigned ic=0; ic<component.size(); ic++)
	{	const FluidComponent& c = *component[ic];
		Phi["PhiNI("+c.molecule.name+")"] +=
			c.idealGas->compute(&indep[c.offsetIndep], &N[c.offsetDensity], &Phi_N[c.offsetDensity], Nscale[ic], Phi_Nscale[ic]);

		//Fixed N correction to entropy:
		if(Nscale[ic]!=1.0)
		{	double deltaTs = T*log(Nscale[ic]) / c.molecule.sites[0]->positions.size();
			Phi_N[c.offsetDensity] += deltaTs;
			Phi["PhiNI("+c.molecule.name+")"] += integral(N[c.offsetDensity])*deltaTs;
		}
	}
	//Add in the implicit contributions to Phi_Nscale
	for(unsigned ic=0; ic<component.size(); ic++)
	{	const FluidComponent& ci = *component[ic];
		bool anyNonzero=false;
		for(unsigned jc=0; jc<component.size(); jc++)
			if(Nscale_N0[ic][jc])
				anyNonzero=true;
		if(anyNonzero)
		{	Phi_Nscale[ic] += gInfo.detR*dot(P0[ic], Phi_P0[ic])/ Nscale[ic];
			for(unsigned i=0; i<ci.molecule.sites.size(); i++)
				Phi_Nscale[ic] += gInfo.dV*dot(N[ci.offsetDensity+i], Phi_N[ci.offsetDensity+i])/ Nscale[ic];
		}
	}
	//Propagate gradients from Nscale to N:
	for(unsigned jc=0; jc<component.size(); jc++)
	{	const FluidComponent& cj = *component[jc];
		double Phi_Ncontrib = 0.0;
		for(unsigned ic=0; ic<component.size(); ic++)
			if(Nscale_N0[ic][jc])
				Phi_Ncontrib += Phi_Nscale[ic] * Nscale_N0[ic][jc];
		if(Phi_Ncontrib)
			Phi_N[cj.offsetDensity] += Phi_Ncontrib / (Nscale[jc] * cj.molecule.sites[0]->positions.size());
	}

	//Propagate gradients from Phi_N and Phi_P to Phi_indep
	Phi_indep.resize(get_nIndep());
	for(unsigned ic=0; ic<component.size(); ic++)
	{	const FluidComponent& c = *component[ic];
		c.idealGas->convertGradients(&indep[c.offsetIndep], &N[c.offsetDensity],
			&Phi_N[c.offsetDensity], Phi_P0[ic], &Phi_indep[c.offsetIndep], Nscale[ic]);
	}
	for(unsigned k=nIndepIdgas; k<get_nIndep(); k++) Phi_indep[k] = Jdag(Phi_epsMF[k-nIndepIdgas]);
	
	//Propagate gradients from Nscale to Qfixed / rhoExternal (Natural G=0 solution)
	if(outputs.Phi_rhoExternal)
	{	double Phi_Qfixed = 0.;
		for(unsigned ic=0; ic<component.size(); ic++)
		{
			Phi_Qfixed += Phi_Nscale[ic] * Nscale_Qfixed[ic];
			if (N0Q.size() && (!useMFKernel))
		        {
				const FluidComponent& c = *component[ic];
				for(unsigned i=0; i<c.molecule.sites.size(); i++)
				{ 
				 	//Correction to lambda from charge kernel mismatch
					  const Molecule::Site& s = *(c.molecule.sites[i]);
					  double lambda_s =  (Ntot_c[ic]/gInfo.detR-c.idealGas->Nbulk)*s.deltaS*s.positions.size();
					  if(verboseLog) logPrintf("Charge kernel mismatch correction for site %s of molecule %s: %lg\n",
					  s.name.c_str(),c.molecule.name.c_str(),lambda_s);
					  Phi_Qfixed += lambda_s;
				}
				 if(verboseLog) logPrintf("Total number of molecules of type %s: %lg\n",c.molecule.name.c_str(),Ntot_c[ic]);
		        }
		}
		nullToZero(*outputs.Phi_rhoExternal, gInfo);
		(*outputs.Phi_rhoExternal)->setGzero(Phi_Qfixed);
	}
	
	Phi["+pV"] += p * gInfo.detR; //background correction

	if(verboseLog) Phi.print(globalLog, true, "\t\t\t\t%15s = %25.16lf\n");
	if(outputs.Phi) *(outputs.Phi) = Phi;
	
	Phi_indep *= gInfo.dV; //convert functional derivative to partial derivative
	watch.stop();
	return Phi;
}
Ejemplo n.º 14
0
int checkCorrection(const Box& a_domain)
{
  int eekflag = 0;
  const EBIndexSpace* const ebisPtr = Chombo_EBIS::instance();
  CH_assert(ebisPtr->isDefined());
  //create a dbl of split up into 2^D boxes
  Vector<Box> vbox;
  Vector<int> proc;
  domainSplit(a_domain, vbox, a_domain.size(0)/2);
  LoadBalance(proc, vbox);
  DisjointBoxLayout dbl(vbox, proc);
  LayoutData<bool>  map1d(dbl);
  int ibox = 0;

  //make every other map 1d
  for (DataIterator dit = dbl.dataIterator(); dit.ok(); ++dit)
    {
      map1d[dit()] = (ibox%2 == 0);
      ibox++;
    }

  LevelData< BaseFab<int> > intmap(dbl, 1 , IntVect::Unit);
  Correct1D2D::makeIntMap(intmap, map1d, dbl);

  //this defines an ebisl with 2 ghost cells
  EBLevelGrid eblg(dbl, ProblemDomain(a_domain), 2, Chombo_EBIS::instance()) ;

  RealVect fluxVal = RealVect::Unit;
  Real dx = 1.0/a_domain.size(0);

  EBCellFactory fact(eblg.getEBISL());
  LevelData<EBCellFAB> divU(dbl, 1, IntVect::Zero, fact);
  Correct1D2D correctinator(eblg, map1d, 1);
  correctinator.setToZero(); //this is important
  for (DataIterator dit = dbl.dataIterator(); dit.ok(); ++dit)
    {
      //make a flux that is borked on the 1d side of box boundaries
      EBFluxFAB fluxFunc(     eblg.getEBISL()[dit()], dbl[dit()], 1);
      setBorkedFlux(fluxFunc, eblg.getEBISL()[dit()], dbl[dit()], fluxVal, intmap[dit()]);
      //increment 1d buffers in corrector
      for (int idir = 0; idir < SpaceDim; idir++)
        {
          correctinator.increment1D(fluxFunc[idir], 1./dx, dit());
          correctinator.increment2D(fluxFunc[idir], 1./dx, dit());
        }

      //now take the divergence of the flux.   it should be zero except
      //at box boundaries on the 1d side
      divergence(divU[dit()], fluxFunc, eblg.getEBISL()[dit()], dbl[dit()], fluxVal, dx);
    }
  //find max value of divergence before corrections

  Real max, min;
  EBLevelDataOps::getMaxMin(max, min, divU, 0);
  pout() << "before correction max divU = " << max << ", min divU = " << min << endl;

  //correct solution due to mismatch at 1d-2d boundaries
  correctinator.correctSolution(divU);

  //recalc max min
  EBLevelDataOps::getMaxMin(max, min, divU, 0);
  pout() << "after  correction max divU = " << max << ", min divU = " << min << endl;
  if (Abs(max-min) > 1.0e-3)
    {
      pout() << "corrector did not seem to correct" << endl;
      return -7;
    }
  return eekflag;
}
Ejemplo n.º 15
0
/**
 *
 * Function to compute the optical flow in one scale
 *
 **/
void Dual_TVL1_optic_flow(
		float *I0,           // source image
		float *I1,           // target image
		float *u1,           // x component of the optical flow
		float *u2,           // y component of the optical flow
		const int   nx,      // image width
		const int   ny,      // image height
		const float tau,     // time step
		const float lambda,  // weight parameter for the data term
		const float theta,   // weight parameter for (u - v)²
		const int   warps,   // number of warpings per scale
		const float epsilon, // tolerance for numerical convergence
		const bool  verbose  // enable/disable the verbose mode
		)
{
	const int   size = nx * ny;
	const float l_t = lambda * theta;

	size_t sf = sizeof(float);
	float *I1x    = malloc(size*sf);
	float *I1y    = xmalloc(size*sf);
	float *I1w    = xmalloc(size*sf);
	float *I1wx   = xmalloc(size*sf);
	float *I1wy   = xmalloc(size*sf);
	float *rho_c  = xmalloc(size*sf);
	float *v1     = xmalloc(size*sf);
	float *v2     = xmalloc(size*sf);
	float *p11    = xmalloc(size*sf);
	float *p12    = xmalloc(size*sf);
	float *p21    = xmalloc(size*sf);
	float *p22    = xmalloc(size*sf);
	float *div    = xmalloc(size*sf);
	float *grad   = xmalloc(size*sf);
	float *div_p1 = xmalloc(size*sf);
	float *div_p2 = xmalloc(size*sf);
	float *u1x    = xmalloc(size*sf);
	float *u1y    = xmalloc(size*sf);
	float *u2x    = xmalloc(size*sf);
	float *u2y    = xmalloc(size*sf);

	centered_gradient(I1, I1x, I1y, nx, ny);

	// initialization of p
	for (int i = 0; i < size; i++)
	{
		p11[i] = p12[i] = 0.0;
		p21[i] = p22[i] = 0.0;
	}

	for (int warpings = 0; warpings < warps; warpings++)
	{
		// compute the warping of the target image and its derivatives
		bicubic_interpolation_warp(I1,  u1, u2, I1w,  nx, ny, true);
		bicubic_interpolation_warp(I1x, u1, u2, I1wx, nx, ny, true);
		bicubic_interpolation_warp(I1y, u1, u2, I1wy, nx, ny, true);

#pragma omp parallel for
		for (int i = 0; i < size; i++)
		{
			const float Ix2 = I1wx[i] * I1wx[i];
			const float Iy2 = I1wy[i] * I1wy[i];

			// store the |Grad(I1)|^2
			grad[i] = (Ix2 + Iy2);

			// compute the constant part of the rho function
			rho_c[i] = (I1w[i] - I1wx[i] * u1[i]
						- I1wy[i] * u2[i] - I0[i]);
		}

		int n = 0;
		float error = INFINITY;
		while (error > epsilon * epsilon && n < MAX_ITERATIONS)
		{
			n++;
			// estimate the values of the variable (v1, v2)
			// (thresholding opterator TH)
#pragma omp parallel for
			for (int i = 0; i < size; i++)
			{
				const float rho = rho_c[i]
					+ (I1wx[i] * u1[i] + I1wy[i] * u2[i]);

				float d1, d2;

				if (rho < - l_t * grad[i])
				{
					d1 = l_t * I1wx[i];
					d2 = l_t * I1wy[i];
				}
				else
				{
					if (rho > l_t * grad[i])
					{
						d1 = -l_t * I1wx[i];
						d2 = -l_t * I1wy[i];
					}
					else
					{
						if (grad[i] < GRAD_IS_ZERO)
							d1 = d2 = 0;
						else
						{
							float fi = -rho/grad[i];
							d1 = fi * I1wx[i];
							d2 = fi * I1wy[i];
						}
					}
				}

				v1[i] = u1[i] + d1;
				v2[i] = u2[i] + d2;
			}

			// compute the divergence of the dual variable (p1, p2)
			divergence(p11, p12, div_p1, nx ,ny);
			divergence(p21, p22, div_p2, nx ,ny);

			// estimate the values of the optical flow (u1, u2)
			error = 0.0;
#pragma omp parallel for reduction(+:error)
			for (int i = 0; i < size; i++)
			{
				const float u1k = u1[i];
				const float u2k = u2[i];

				u1[i] = v1[i] + theta * div_p1[i];
				u2[i] = v2[i] + theta * div_p2[i];

				error += (u1[i] - u1k) * (u1[i] - u1k) +
					(u2[i] - u2k) * (u2[i] - u2k);
			}
			error /= size;

			// compute the gradient of the optical flow (Du1, Du2)
			forward_gradient(u1, u1x, u1y, nx ,ny);
			forward_gradient(u2, u2x, u2y, nx ,ny);

			// estimate the values of the dual variable (p1, p2)
#pragma omp parallel for
			for (int i = 0; i < size; i++)
			{
				const float taut = tau / theta;
				const float g1   = hypot(u1x[i], u1y[i]);
				const float g2   = hypot(u2x[i], u2y[i]);
				const float ng1  = 1.0 + taut * g1;
				const float ng2  = 1.0 + taut * g2;

				p11[i] = (p11[i] + taut * u1x[i]) / ng1;
				p12[i] = (p12[i] + taut * u1y[i]) / ng1;
				p21[i] = (p21[i] + taut * u2x[i]) / ng2;
				p22[i] = (p22[i] + taut * u2y[i]) / ng2;
			}
		}

		if (verbose)
			fprintf(stderr, "Warping: %d, "
					"Iterations: %d, "
					"Error: %f\n", warpings, n, error);
	}

	// delete allocated memory
	free(I1x);
	free(I1y);
	free(I1w);
	free(I1wx);
	free(I1wy);
	free(rho_c);
	free(v1);
	free(v2);
	free(p11);
	free(p12);
	free(p21);
	free(p22);
	free(div);
	free(grad);
	free(div_p1);
	free(div_p2);
	free(u1x);
	free(u1y);
	free(u2x);
	free(u2y);
}
Ejemplo n.º 16
0
void StableFluid3D::projectVelocity(double dt)
{
	setBoundary();

	Vector divergence(vel.Length());
	// fill in velocities
	double dx = width / (double)resX;
	double dy = height / (double)resY;
	double dz = depth / (double)resZ;
	for (int i = 0; i < resX; ++i)
	{
		for (int j = 0; j < resY; ++j)
		{
			for (int k = 0; k < resZ; ++k)
			{
				int index = makeIndex(i, j, k);

				double div = (tempVelocities[0][i + 1][j][k] - tempVelocities[0][i][j][k]) / dx + (tempVelocities[1][i][j + 1][k] - tempVelocities[1][i][j][k]) / dy + (tempVelocities[2][i][j][k + 1] - tempVelocities[2][i][j][k]) / dz;

				vel[index] = div;
				divergence[index] = div;
			}
		}
	}

	//	vel *= density / dt;
	bool useOldPCG = false;
	if (useOldPCG)
	{
		int k = 0;
		Vector laplacianTimesPressure(pressure.Length());
		laplacian.Multiply(pressure, laplacianTimesPressure);
		r[0] = vel - laplacianTimesPressure;
		double error = r[0].Magnitude2();
		while ((std::sqrt(error) > PCG_EPS) && (k < PCG_MAXITER))
		{
			//cerr << "PCG iteration " << k << ", error: " << std::sqrt(error) << endl;
			ConjugateGradient(preconditioner, z[k % 2], r[k % 2], 0.0001, 500.0);

			++k;
			int i1 = (k - 1) % 2;
			int i2 = k % 2;
			if (k == 1)
			{
				p = z[0];
			}
			else
			{
				double beta = (InnerProduct(r[i1], z[i1])) /
					(InnerProduct(r[i2], z[i2]));
				p *= beta;
				p += z[i1];
			}
			Vector laplacianTimesP(p.Length());
			laplacian.Multiply(p, laplacianTimesP);
			double alpha = (InnerProduct(r[i1], z[i1])) /
				(InnerProduct(p, laplacianTimesP));
			pressure += alpha * p;
			r[i2] = r[i1] - alpha * (laplacianTimesP);
			error = r[i2].Magnitude2();
		}
		if (std::sqrt(error) > PCG_EPS)
		{
			std::cout << "end preconditioned conj grad " << "error: " << error << std::endl;
		}
	}
	else
	{
		p = Vector(vel.Length());
		r[0] = divergence;
		//ApplyPreconditioner(r[0], z[0]);
		double sigma = InnerProduct(r[0], z[0]);

		int k = 0;
		double error = r[0].Magnitude2();
		while (k < PCG_MAXITER)
		{
			++k;
			Vector s(vel.Length());
			s = z[0];
			int k = 0;
			laplacian.Multiply(s, z[0]);
			double rho = 1.0;
			double alpha = rho / InnerProduct(s, z[0]);
			p += alpha * s;
			r[0] -= alpha * z[0];
			error = r[0].Magnitude2();
			if (error < PCG_EPS * PCG_EPS)
			{
				pressure = p;
				break;
			}
			//ApplyPreconditioner(r[0], z[0]);
			double sigmaNew = InnerProduct(r[0], z[0]);
			double beta = sigmaNew / rho;
			s = z[0] + beta * s;
			sigma = sigmaNew;
		}
		Vector laplacianTimesPressure(pressure.Length());
		laplacian.Multiply(pressure, laplacianTimesPressure);
		r[0] = vel - laplacianTimesPressure;
		error = r[0].Magnitude2();
		while ((std::sqrt(error) > PCG_EPS) && (k < PCG_MAXITER))
		{
			//cerr << "PCG iteration " << k << ", error: " << std::sqrt(error) << endl;
			ConjugateGradient(preconditioner, z[k % 2], r[k % 2], 0.0001, 500.0);

			++k;
			int i1 = (k - 1) % 2;
			int i2 = k % 2;
			if (k == 1)
			{
				p = z[0];
			}
			else
			{
				double beta = (InnerProduct(r[i1], z[i1])) /
					(InnerProduct(r[i2], z[i2]));
				p *= beta;
				p += z[i1];
			}
			Vector laplacianTimesP(p.Length());
			laplacian.Multiply(p, laplacianTimesP);
			double alpha = (InnerProduct(r[i1], z[i1])) /
				(InnerProduct(p, laplacianTimesP));
			pressure += alpha * p;
			r[i2] = r[i1] - alpha * (laplacianTimesP);
			error = r[i2].Magnitude2();
		}
		if (std::sqrt(error) > PCG_EPS)
		{
			std::cout << "end preconditioned conj grad " << "error: " << error << std::endl;
		}
	}

	/*
	mathlib::Vector PCGr, PCGd, PCGq, PCGs;
	PCGr.Resize(resX * resY * resZ);
	PCGd.Resize(resX * resY * resZ);
	PCGq.Resize(resX * resY * resZ);
	PCGs.Resize(resX * resY * resZ);

	int iter = 0;
	PCGr = vel - laplacian * pressure;
	mathlib::ConjugateGradient(preconditioner, PCGd, PCGr);
	double deltaNew = mathlib::InnerProduct(PCGr, PCGd);
	double errBound = PCG_EPS * PCG_EPS * deltaNew;

	while ((iter < PCG_MAXITER)  && (deltaNew > errBound))
	{
	if (!(iter % 3))
	cerr << "iteration " << iter << ", error: " << deltaNew << endl;
	PCGq = laplacian * PCGd;
	double alpha = deltaNew / (mathlib::InnerProduct(PCGd, PCGq));
	pressure += alpha * PCGd;
	if ((iter % 10) == 0)
	PCGr = vel - laplacian * pressure;
	else
	PCGr -= alpha * PCGq;

	mathlib::ConjugateGradient(preconditioner, PCGs, PCGr);
	double deltaOld = deltaNew;
	deltaNew = mathlib::InnerProduct(PCGr, PCGs);
	double beta = deltaNew / deltaOld;
	PCGd *= beta;
	PCGd += PCGs;
	++iter;
	}
	cout << "end preconditioned conj grad "<< "error: " << deltaNew << endl;
	*/
	std::cout << "dt:" << dt << "\t density:" << density << std::endl;
	//	dt = 1.0;
	for (int i = 0; i < resX; ++i)
	{
		for (int j = 0; j < resY; ++j)
		{
			for (int k = 0; k < resZ; ++k)
			{
				int i1 = makeIndex(i, j, k);
				int i2;

				double deltaPressure;
				i2 = (i == 0 ? i1 : i1 - 1);
				velocities[0][i][j][k] = tempVelocities[0][i][j][k] - dt* 0.5 * (pressure[i1] - pressure[i2]) / dx;
				deltaPressure = pressure[i1] - pressure[i2];

				i2 = (j == 0 ? i1 : i1 - resX);
				velocities[1][i][j][k] = tempVelocities[1][i][j][k] - dt *  0.5 * (pressure[i1] - pressure[i2]) / dy;
				deltaPressure = pressure[i1] - pressure[i2];

				i2 = (k == 0 ? i1 : i1 - resY * resX);
				velocities[2][i][j][k] = tempVelocities[2][i][j][k] - dt * 0.5 * (pressure[i1] - pressure[i2]) / dz;
				deltaPressure = pressure[i1] - pressure[i2];
			}
		}
	}
}
Ejemplo n.º 17
0
void PCM::updateCavity()
{
    //Cavities from expanded densities for SGA13 variant:
    if(fsp.pcmVariant == PCM_SGA13)
    {   ScalarField* shapeEx[2] = { &shape, &shapeVdw };
        for(int i=0; i<2; i++)
        {   ShapeFunction::expandDensity(wExpand[i], Rex[i], nCavity, nCavityEx[i]);
            ShapeFunction::compute(nCavityEx[i], *(shapeEx[i]), fsp.nc, fsp.sigma);
        }
    }
    else if(fsp.pcmVariant == PCM_CANDLE)
    {   nCavityEx[0] = fsp.Ztot * I(Sf[0] * J(nCavity));
        ShapeFunction::compute(nCavityEx[0], coulomb(Sf[0]*rhoExplicitTilde), shapeVdw,
                               fsp.nc, fsp.sigma, fsp.pCavity); //vdW cavity
        shape = I(wExpand[0] * J(shapeVdw)); //dielectric cavity
    }
    else if(isPCM_SCCS(fsp.pcmVariant))
        ShapeFunctionSCCS::compute(nCavity, shape, fsp.rhoMin, fsp.rhoMax, epsBulk);
    else //Compute directly from nCavity (which is a density product for SaLSA):
        ShapeFunction::compute(nCavity, shape, fsp.nc, fsp.sigma);

    //Compute and cache cavitation energy and gradients:
    const auto& solvent = fsp.solvents[0];
    switch(fsp.pcmVariant)
    {
    case PCM_SaLSA:
    case PCM_CANDLE:
    case PCM_SGA13:
    {   //Select relevant shape function:
        const ScalarFieldTilde sTilde = J(fsp.pcmVariant==PCM_SaLSA ? shape : shapeVdw);
        ScalarFieldTilde A_sTilde;
        //Cavitation:
        const double nlT = solvent->Nbulk * fsp.T;
        const double Gamma = log(nlT/solvent->Pvap) - 1.;
        const double Cp = 15. * (solvent->sigmaBulk/(2*solvent->Rvdw * nlT) - (1+Gamma)/6);
        const double coeff2 = 1. + Cp - 2.*Gamma;
        const double coeff3 = Gamma - 1. -2.*Cp;
        ScalarField sbar = I(wCavity*sTilde);
        Adiel["Cavitation"] = nlT * integral(sbar*(Gamma + sbar*(coeff2 + sbar*(coeff3 + sbar*Cp))));
        A_sTilde += wCavity*Idag(nlT * (Gamma + sbar*(2.*coeff2 + sbar*(3.*coeff3 + sbar*(4.*Cp)))));
        //Dispersion:
        ScalarFieldTildeArray Ntilde(Sf.size()), A_Ntilde(Sf.size()); //effective nuclear densities in spherical-averaged ansatz
        for(unsigned i=0; i<Sf.size(); i++)
            Ntilde[i] = solvent->Nbulk * (Sf[i] * sTilde);
        const double vdwScaleEff = (fsp.pcmVariant==PCM_CANDLE) ? fsp.sqrtC6eff : fsp.vdwScale;
        Adiel["Dispersion"] = e.vanDerWaals->energyAndGrad(atpos, Ntilde, atomicNumbers, vdwScaleEff, &A_Ntilde);
        A_vdwScale = Adiel["Dispersion"]/vdwScaleEff;
        for(unsigned i=0; i<Sf.size(); i++)
            if(A_Ntilde[i])
                A_sTilde += solvent->Nbulk * (Sf[i] * A_Ntilde[i]);
        //Propagate gradients to appropriate shape function:
        (fsp.pcmVariant==PCM_SaLSA ? Acavity_shape : Acavity_shapeVdw) = Jdag(A_sTilde);
        break;
    }
    case PCM_GLSSA13:
    {   VectorField Dshape = gradient(shape);
        ScalarField surfaceDensity = sqrt(lengthSquared(Dshape));
        ScalarField invSurfaceDensity = inv(surfaceDensity);
        A_tension = integral(surfaceDensity);
        Adiel["CavityTension"] = A_tension * fsp.cavityTension;
        Acavity_shape = (-fsp.cavityTension)*divergence(Dshape*invSurfaceDensity);
        break;
    }
    case PCM_LA12:
    case PCM_PRA05:
        break; //no contribution
case_PCM_SCCS_any:
        {   //Volume contribution:
            Adiel["CavityPressure"] = fsp.cavityPressure * (gInfo.detR - integral(shape));
            //Surface contribution:
            ScalarField shapePlus, shapeMinus;
            ShapeFunctionSCCS::compute(nCavity+(0.5*fsp.rhoDelta), shapePlus, fsp.rhoMin, fsp.rhoMax, epsBulk);
            ShapeFunctionSCCS::compute(nCavity-(0.5*fsp.rhoDelta), shapeMinus, fsp.rhoMin, fsp.rhoMax, epsBulk);
            ScalarField DnLength = sqrt(lengthSquared(gradient(nCavity)));
            Adiel["CavityTension"] = (fsp.cavityTension/fsp.rhoDelta) * integral(DnLength * (shapeMinus - shapePlus));
            break;
        }
    }
}