Esempio n. 1
0
template <int dim, typename T> void update(grid<dim,T>& oldGrid, int steps)
{
	int rank=0;
    #ifdef MPI_VERSION
    rank = MPI::COMM_WORLD.Get_rank();
    #endif

	ghostswap(oldGrid);

	grid<dim,T> newGrid(oldGrid);

	T r = 1.0;
	T u = 1.0;
	T K = 1.0;
	T M = 1.0;
	T dt = 0.01;
	T kT = 0.01;
	T dV = 1.0;

	for (int step=0; step<steps; step++) {
		if (rank==0)
			print_progress(step, steps);

		for (int i=0; i<nodes(oldGrid); i++) {
			T phi = oldGrid(i);
			T noise = gaussian(0.0,sqrt(2.0*kT/(dt*dV)));
			newGrid(i) = phi-dt*M*(-r*phi+u*pow(phi,3)-K*laplacian(oldGrid,i)+noise);
		}
		swap(oldGrid,newGrid);
		ghostswap(oldGrid);
	}
}
Esempio n. 2
0
template <int dim> void update(MMSP::grid<dim,vector<double> >& grid, int steps)
{
	MMSP::grid<dim,vector<double> > update(grid);

	double dt = 0.01;

	for (int step=0; step<steps; step++) {
		for (int i=0; i<nodes(grid); i++) {
			// compute laplacians
			vector<double> lap = laplacian(grid,i);

			// compute sums of squares
			double sum = 0.0;
			for (int j=0; j<fields(grid); j++) {
				double phi = grid(i)[j];
				sum += phi*phi;
			}

			// compute update values
			for (int j=0; j<fields(grid); j++) {
				double phi = grid(i)[j];
				// particles have zero mobility
				if (j==0) update(i)[j] = phi;
				else update(i)[j] = phi-dt*(-phi-pow(phi,3)+2.0*(phi*sum-lap[j]));
			}
		}
		swap(grid,update);
		ghostswap(grid);
	}
}
Esempio n. 3
0
template <int dim> void update(MMSP::grid<dim,sparse<double> >& grid, int steps)
{
	double dt = 0.01;
	double epsilon = 1.0e-8;

	for (int step=0; step<steps; step++) {
		// update grid must be overwritten each time
		MMSP::grid<dim,sparse<double> > update(grid);

		for (int i=0; i<nodes(grid); i++) {
			vector<int> x = position(grid,i);

			// determine nonzero fields within
			// the neighborhood of this node
			sparse<bool> neighbors;
			for (int j=0; j<dim; j++)
				for (int k=-1; k<=1; k++) {
					x[j] += k;
					for (int h=0; h<length(grid(x)); h++) {
						int index = MMSP::index(grid(x),h);
						set(neighbors,index) = 1;
					}
					x[j] -= k;
				}

			// if there is only one nonzero field,
			// then it remains the same 
			if (length(neighbors)<2)
				update(i) = grid(i);

			else {
				// compute laplacians
				sparse<double> lap = laplacian(grid,i);

				// compute sums of squares
				double sum = 0.0;
				for (int j=0; j<length(grid(i)); j++) {
					double phi = MMSP::value(grid(i),j);
					sum += phi*phi;
				}

				// compute update values
				for (int j=0; j<length(neighbors); j++) {
					int index = MMSP::index(neighbors,j);
					double phi = grid(i)[index];
					// particles have zero mobility
					if (index==0) set(update(i),index) = phi;
					else {
						double value = phi-dt*(-phi-pow(phi,3)+2.0*(phi*sum-lap[index]));
						if (value>epsilon) set(update(i),index) = value;
					}
				}
			}
		}
		swap(grid,update);
		ghostswap(grid);
	}
}
Esempio n. 4
0
void update(MMSP::grid<3,int>& grid, int steps)
{
	const double kT = 0.75;
	int gss = int(sqrt(nodes(grid)));

	for (int step=0; step<steps; step++) {
		for (int h=0; h<nodes(grid); h++) {
			// choose a random node 
			int p = rand()%nodes(grid);
			vector<int> x = position(grid,p);
			int spin1 = grid(p);

			if (spin1!=0) {
				// determine neighboring spins
				sparse<bool> neighbors;
				for (int i=-1; i<=1; i++)
					for (int j=-1; j<=1; j++)
						for (int k=-1; k<=1; k++) {
							int spin = grid[x[0]+i][x[1]+j][x[2]+k];
							set(neighbors,spin) = true;
						}

				// choose a random neighbor spin
				int spin2 = index(neighbors,rand()%length(neighbors));

				if (spin1!=spin2 and spin2!=0) {
					// compute energy change
					double dE = -energy(spin1,spin2);
					for (int i=-1; i<=1; i++)
						for (int j=-1; j<=1; j++)
							for (int k=-1; k<=1; k++) {
								int spin = grid[x[0]+i][x[1]+j][x[2]+k];
								dE += energy(spin,spin2)-energy(spin,spin1);
							}

					// compute boundary energy, mobility
					double E = energy(spin1,spin2);
					double M = mobility(spin1,spin2);

					// attempt a spin flip
					double r = double(rand())/double(RAND_MAX);
					if (dE<=0.0 and r<M*E) grid(p) = spin2;
					if (dE>0.0 and r<M*E*exp(-dE/(E*kT))) grid(p) = spin2;
				}
			}
			if (h%gss==0) ghostswap(grid);
		}
	}
}
Esempio n. 5
0
void update(MMSP::grid<2,int>& grid, int steps)
{
	const double kT = 0.50;
	int gss = int(sqrt(nodes(grid)));

	for (int step=0; step<steps; step++) {
		for (int h=0; h<nodes(grid); h++) {
			// choose a random node
			int p = rand()%nodes(grid);
			vector<int> x = position(grid,p);
			int spin1 = grid(p);

			if (spin1!=0) {
				// determine neighboring spins
				sparse<bool> neighbors;
				for (int i=-1; i<=1; i++)
					for (int j=-1; j<=1; j++) {
						int spin = grid[x[0]+i][x[1]+j];
						set(neighbors,spin) = true;
					}

				// choose a random neighbor spin
				int spin2 = index(neighbors,rand()%length(neighbors));

				if (spin1!=spin2 and spin2!=0) {
					// compute energy change
					double dE = -1.0;
					for (int i=-1; i<=1; i++)
						for (int j=-1; j<=1; j++) {
							int spin = grid[x[0]+i][x[1]+j];
							dE += (spin!=spin2)-(spin!=spin1);
						}

					// attempt a spin flip
					double r = double(rand())/double(RAND_MAX);
					if (dE<=0.0) grid(p) = spin2;
					else if (r<exp(-dE/kT)) grid(p) = spin2;
				}
			}
			if (h%gss==0) ghostswap(grid);
		}
	}
}
Esempio n. 6
0
void update(grid<3,vector<double> >& grid, int steps)
{
    double J = 1.0;
    double kT = 0.75;
    double pi = acos(-1.0);

    int gss = int(sqrt(nodes(grid)));

    for (int step=0; step<steps; step++) {
        for (int h=0; h<nodes(grid); h++) {
            // choose a random site
            int p = rand()%nodes(grid);
            vector<int> x = position(grid,p);
            vector<double>& s1 = grid(p);

            // choose a random unit vector
            vector<double> s2(3);
            double psi = 2.0*pi*double(rand())/double(RAND_MAX);
            double theta = acos(1.0-2.0*double(rand())/double(RAND_MAX));
            s2[0] = cos(psi)*sin(theta);
            s2[1] = sin(psi)*sin(theta);
            s2[2] = cos(theta);

            // compute energy change
            double sum = -1.0;
            for (int i=-1; i<=1; i++)
                for (int j=-1; j<=1; j++)
                    for (int k=-1; k<=1; k++) {
                        vector<double>& s = grid[x[0]+i][x[1]+j][x[2]+k];
                        sum += s[0]*(s1[0]-s2[0])+s[1]*(s1[1]-s2[1])+s[2]*(s1[2]-s2[2]);
                    }
            double dE = -J*sum;

            // attempt a spin flip
            double r = double(rand())/double(RAND_MAX);
            if (dE<=0.0) grid(p) = s2;
            else if (r<exp(-dE/kT)) grid(p) = s2;

            if (h%gss==0) ghostswap(grid);
        }
    }
}
Esempio n. 7
0
template <int dim> void update(MMSP::grid<dim,double>& grid, int steps)
{
	MMSP::grid<dim,double> update(grid);

	double r = 1.0;
	double u = 1.0;
	double K = 1.0;
	double M = 1.0;
	double dt = 0.01;
	double kT = 0.01;
	double dV = 1.0;

	for (int step=0; step<steps; step++) {
		for (int i=0; i<nodes(grid); i++) {
			double phi = grid(i);
			double noise = gaussian(0.0,sqrt(2.0*kT/(dt*dV)));
			update(i) = phi-dt*M*(-r*phi+u*pow(phi,3)-K*laplacian(grid,i)+noise);
		}
		swap(grid,update);
		ghostswap(grid);
	}
}
Esempio n. 8
0
template <int dim> void update(grid<dim, sparse<phi_type> >& oldGrid, int steps)
{
	int rank=0;
	#ifdef MPI_VERSION
	rank=MPI::COMM_WORLD.Get_rank();
	#endif
	const phi_type dt = 0.01;
	const phi_type width = 14.5;
	const phi_type epsilon = 1.0e-8;
	const double mu_hi = 1.00;
	const double mu_lo = 0.01;
	const double mu_x = 0.6422;
	const double mu_s = 0.0175;

	std::ofstream vfile;
	if (rank==0)
		vfile.open("v.log",std::ofstream::out | std::ofstream::app);

	for (int step = 0; step < steps; step++) {
		if (rank==0) print_progress(step, steps);
		// newGrid grid must be overwritten each time
		ghostswap(oldGrid);
		grid<dim, sparse<phi_type> > newGrid(oldGrid);

		for (int d=0; d<dim; d++) {
			if (x0(oldGrid, d) == g0(oldGrid,d)) {
				b0(oldGrid,d) = Dirichlet;
				b0(newGrid,d) = Dirichlet;
			} else if (x1(oldGrid,d) == g1(oldGrid,d)) {
				b1(oldGrid,d) = Dirichlet;
				b1(newGrid,d) = Dirichlet;
			}
		}

		for (int i = 0; i < nodes(oldGrid); i++) {
			vector<int> x = position(oldGrid, i);

			// determine nonzero fields within
			// the neighborhood of this node
			// (2 adjacent voxels along each cardinal direction)
			sparse<int> s;
			for (int j = 0; j < dim; j++)
				for (int k = -1; k <= 1; k++) {
					x[j] += k;
					for (int h = 0; h < length(oldGrid(x)); h++) {
						int pindex = index(oldGrid(x), h);
						set(s, pindex) = 1;
					}
					x[j] -= k;
				}
			phi_type S = phi_type(length(s));

			// if only one field is nonzero,
			// then copy this node to newGrid
			if (S < 2.0) newGrid(i) = oldGrid(i);
			else {
				// compute laplacian of each field
				sparse<phi_type> lap = laplacian(oldGrid, i);

				// compute variational derivatives
				sparse<phi_type> dFdp;
				for (int h = 0; h < length(s); h++) {
					int hindex = index(s, h);
					for (int j = h + 1; j < length(s); j++) {
						int jindex = index(s, j);
						phi_type gamma = energy(hindex, jindex);
						phi_type eps = 4.0 / acos(-1.0) * sqrt(0.5 * gamma * width);
						phi_type w = 4.0 * gamma / width;
						// Update dFdp_h and dFdp_j, so the inner loop can be over j>h instead of j≠h
						set(dFdp, hindex) += 0.5 * eps * eps * lap[jindex] + w * oldGrid(i)[jindex];
						set(dFdp, jindex) += 0.5 * eps * eps * lap[hindex] + w * oldGrid(i)[hindex];
					}
				}

				// compute time derivatives
				sparse<phi_type> dpdt;
				phi_type mu = mobility(mu_lo, mu_hi, mu_x, mu_s, oldGrid(x).getMagPhi());

				for (int h = 0; h < length(s); h++) {
					int hindex = index(s, h);
					for (int j = h + 1; j < length(s); j++) {
						int jindex = index(s, j);
						set(dpdt, hindex) -= mu * (dFdp[hindex] - dFdp[jindex]);
						set(dpdt, jindex) -= mu * (dFdp[jindex] - dFdp[hindex]);
					}
				}

				// compute update values
				phi_type sum = 0.0;
				for (int h = 0; h < length(s); h++) {
					int pindex = index(s, h);
					phi_type value = oldGrid(i)[pindex] + dt * (2.0 / S) * dpdt[pindex]; // Extraneous factor of 2?
					if (value > 1.0) value = 1.0;
					if (value < 0.0) value = 0.0;
					if (value > epsilon) set(newGrid(i), pindex) = value;
					sum += newGrid(i)[pindex];
				}

				// project onto Gibbs simplex (enforce Σφ=1)
				phi_type rsum = 0.0;
				if (fabs(sum) > 0.0) rsum = 1.0 / sum;
				for (int h = 0; h < length(newGrid(i)); h++) {
					int pindex = index(newGrid(i), h);
					set(newGrid(i), pindex) *= rsum;
				}
			}

		} // Loop over nodes(oldGrid)

		if ((step+1) % 10 == 0) {
			// Scan along just above the mid-line for the grain boundary.
			// When found, determine its angle.
			vector<int> x(dim, 0);
			const int offset = 2;

			const phi_type vert_mag = 1.0/std::sqrt(3.0);
			const phi_type edge_mag = 1.0/std::sqrt(2.0);
			const phi_type bulk_mag = 1.0;

			const phi_type edge_contour = edge_mag + 0.125*(bulk_mag - edge_mag);
			const phi_type vert_contour = vert_mag + 0.125*(edge_mag - vert_mag);

			x[0] = x0(newGrid,0);
			x[1] = (g1(newGrid,1) - g0(newGrid,1))/2;
			while (x[0]<x1(newGrid) && x[1]>=y0(newGrid) && x[1]<y1(newGrid) && newGrid(x).getMagPhi()>vert_contour)
				x[0]++;
			if (x[0] == x1(newGrid))
				x[0] = g0(newGrid,0);
			int v0 = x[0];
			#ifdef MPI_VERSION
			MPI::COMM_WORLD.Allreduce(&x[0], &v0, 1, MPI_INT, MPI_MAX);
			#endif

			x[1] += offset;
			while (x[0]>= x0(newGrid) && x[0]<x1(newGrid) && x[1]>=y0(newGrid) && x[1]<y1(newGrid) && newGrid(x).getMagPhi()>edge_contour)
				x[0]++;
			if (x[0] == x1(newGrid))
				x[0] = g0(newGrid,0);
			int v1 = x[0];
			#ifdef MPI_VERSION
			MPI::COMM_WORLD.Allreduce(&x[0], &v1, 1, MPI_INT, MPI_MAX);
			#endif

			x[1] += offset;
			while (x[0]>= x0(newGrid) && x[0]<x1(newGrid) && x[1]>=y0(newGrid) && x[1]<y1(newGrid) && newGrid(x).getMagPhi()>edge_contour)
				x[0]++;
			if (x[0] == x1(newGrid))
				x[0] = g0(newGrid,0);
			int v2 = x[0];
			#ifdef MPI_VERSION
			MPI::COMM_WORLD.Allreduce(&x[0], &v2, 1, MPI_INT, MPI_MAX);
			#endif

			// Second-order right-sided difference to approximate slope
			double diffX = 3.0*v0 - 4.0*v1 + 1.0*v2;
			double theta = 180.0/M_PI * std::atan2(2.0*offset*dx(newGrid,1), dx(newGrid,0)*diffX);

			if (rank==0)
				vfile << dx(newGrid,0)*v0 << '\t' << dx(newGrid,0)*v1 << '\t' << dx(newGrid,0)*v2 << '\t' << diffX << '\t' << theta << '\n';
		}

		swap(oldGrid, newGrid);
	} // Loop over steps
	ghostswap(oldGrid);

	if (rank==0)
		vfile.close();
}
Esempio n. 9
0
unsigned long update_old(MMSP::grid<dim, sparse<float> >& grid, int steps, int nthreads)
{
#if (!defined MPI_VERSION) && ((defined CCNI) || (defined BGQ))
    std::cerr<<"Error: MPI is required for CCNI."<<std::endl;
    exit(1);
#endif
    unsigned long timer=0;
    int rank=0;
#ifdef MPI_VERSION
    rank=MPI::COMM_WORLD.Get_rank();
#endif
    const float dt = 0.01;
    const float width = 10.0;
    const float gamma = 1.0;
    const float eps = 4.0 / acos(-1.0) * sqrt(0.5 * gamma * width);
    const float w = 4.0 * gamma / width;
    const float mu = 1.0;
    const float epsilon = 1.0e-8;

#ifndef SILENT
    static int iterations = 1;
#ifdef DEBUG
    if (iterations==1 && rank==0)
        printf("CFL condition Co=%2.2f.\n", mu*eps*eps*dt/(dx(grid, 0)*dx(grid,0)));
#endif
#endif

#ifndef SILENT
    if (rank==0) print_progress(0, steps, iterations);
#endif

    for (int step = 0; step < steps; step++) {
        // update grid must be overwritten each time
        MMSP::grid<dim, sparse<float> > update(grid);
        ghostswap(grid);

        unsigned long comp_time=rdtsc();
        for (int i = 0; i < nodes(grid); i++) {
            vector<int> x = position(grid, i);

            // determine nonzero fields within
            // the neighborhood of this node
            // (2 adjacent voxels along each cardinal direction)
            sparse<int> s;
            for (int j = 0; j < dim; j++)
                for (int k = -1; k <= 1; k++) {
                    x[j] += k;
                    for (int h = 0; h < length(grid(x)); h++) {
                        int index = MMSP::index(grid(x), h);
                        set(s, index) = 1;
                    }
                    x[j] -= k;
                }
            float S = float(length(s));

            // if only one field is nonzero,
            // then copy this node to update
            if (S < 2.0) update(i) = grid(i);
            else {
                // compute laplacian of each field
                sparse<float> lap = laplacian(grid, i);

                // compute variational derivatives
                sparse<float> dFdp;
                for (int h = 0; h < length(s); h++) {
                    int hindex = MMSP::index(s, h);
                    for (int j = h + 1; j < length(s); j++) {
                        int jindex = MMSP::index(s, j);
                        // Update dFdp_h and dFdp_j, so the inner loop can be over j>h instead of j≠h
                        set(dFdp, hindex) += 0.5 * eps * eps * lap[jindex] + w * grid(i)[jindex];
                        set(dFdp, jindex) += 0.5 * eps * eps * lap[hindex] + w * grid(i)[hindex];
                    }
                }

                // compute time derivatives
                sparse<float> dpdt;
                for (int h = 0; h < length(s); h++) {
                    int hindex = MMSP::index(s, h);
                    for (int j = h + 1; j < length(s); j++) {
                        int jindex = MMSP::index(s, j);
                        set(dpdt, hindex) -= mu * (dFdp[hindex] - dFdp[jindex]);
                        set(dpdt, jindex) -= mu * (dFdp[jindex] - dFdp[hindex]);
                    }
                }

                // compute update values
                float sum = 0.0;
                for (int h = 0; h < length(s); h++) {
                    int index = MMSP::index(s, h);
                    float value = grid(i)[index] + dt * (2.0 / S) * dpdt[index]; // Extraneous factor of 2?
                    if (value > 1.0) value = 1.0;
                    if (value < 0.0) value = 0.0;
                    if (value > epsilon) set(update(i), index) = value;
                    sum += update(i)[index];
                }

                // project onto Gibbs simplex (enforce Σφ=1)
                float rsum = 0.0;
                if (fabs(sum) > 0.0) rsum = 1.0 / sum;
                for (int h = 0; h < length(update(i)); h++) {
                    int index = MMSP::index(update(i), h);
                    set(update(i), index) *= rsum;
                }
            }
        } // Loop over nodes(grid)
        swap(grid, update);
        comp_time=rdtsc()-comp_time;
        timer+=comp_time;
#ifndef SILENT
        if (rank==0) print_progress(step+1, steps, iterations);
#endif
    } // Loop over steps
    ghostswap(grid);
#ifndef SILENT
    ++iterations;
#endif
    return timer;
}
Esempio n. 10
0
unsigned long update(MMSP::grid<dim, sparse<float> >& grid, int steps, int nthreads)
{

#if (!defined MPI_VERSION) && ((defined CCNI) || (defined BGQ))
    std::cerr<<"Error: MPI is required for CCNI."<<std::endl;
    exit(1);
#endif
    int rank=0;
    unsigned int np=0;
#ifdef MPI_VERSION
    rank=MPI::COMM_WORLD.Get_rank();
    np=MPI::COMM_WORLD.Get_size();
#endif

#ifndef SILENT
    static int iterations = 1;
    if (rank==0) print_progress(0, steps, iterations);
#endif

    unsigned long timer = 0;
    for (int step = 0; step < steps; step++) {
        unsigned long comptime=rdtsc();
        // update grid must be overwritten each time
        MMSP::grid<dim, sparse<float> > update(grid);
        ghostswap(grid);

        pthread_t * p_threads = new pthread_t[ nthreads];
        update_thread_para<dim>* update_para = new update_thread_para<dim>[nthreads];
        pthread_attr_t attr;
        pthread_attr_init (&attr);
        unsigned long nincr = nodes(grid)/nthreads;
        unsigned long ns = 0;

        for(int i=0; i<nthreads; i++) {
            update_para[i].nstart=ns;
            ns+=nincr;
            update_para[i].nend=ns;

            update_para[i].grid= &grid;
            update_para[i].update= &update;

            pthread_create(&p_threads[i], &attr, update_threads_helper<dim>, (void *) &update_para[i] );
        }

        for(int i=0; i!= nthreads ; i++) {
            pthread_join(p_threads[i], NULL);
        }

        delete [] p_threads ;
        delete [] update_para ;

#ifndef SILENT
        if (rank==0) print_progress(step+1, steps, iterations);
#endif
        swap(grid, update);
        timer += rdtsc() - comptime;
    } // Loop over steps
    ghostswap(grid);
#ifndef SILENT
    ++iterations;
#endif

    unsigned long total_update_time=timer;
#ifdef MPI_VERSION
    MPI::COMM_WORLD.Allreduce(&timer, &total_update_time, 1, MPI_UNSIGNED_LONG, MPI_SUM);
#endif
    return total_update_time/np; // average update time
}
Esempio n. 11
0
template <int dim> void update(grid<dim, sparse<phi_type> >& oldGrid, int steps)
{
	#if (!defined MPI_VERSION) && (defined BGQ)
	std::cerr<<"Error: Blue Gene requires MPI."<<std::endl;
	exit(-1);
	#endif
	int rank=0;
	#ifdef MPI_VERSION
	rank = MPI::COMM_WORLD.Get_rank();
	#endif
	const phi_type dt = 0.01;
	const phi_type width = 14.5;
	const phi_type epsilon = 1.0e-8;

	for (int step = 0; step < steps; step++) {
		if (rank==0) print_progress(step, steps);
		// newGrid must be overwritten each time
		ghostswap(oldGrid);
		grid<dim, sparse<phi_type> > newGrid(oldGrid);

		for (int i = 0; i < nodes(oldGrid); i++) {
			vector<int> x = position(oldGrid, i);

			// determine nonzero fields within
			// the neighborhood of this node
			// (2 adjacent voxels along each cardinal direction)
			sparse<int> s;
			for (int j = 0; j < dim; j++)
				for (int k = -1; k <= 1; k++) {
					x[j] += k;
					for (int h = 0; h < length(oldGrid(x)); h++) {
						int sindex = index(oldGrid(x), h);
						set(s, sindex) = 1;
					}
					x[j] -= k;
				}
			phi_type S = phi_type(length(s));

			// if only one field is nonzero,
			// then copy this node to newGrid
			if (S < 2.0) newGrid(i) = oldGrid(i);
			else {
				// compute laplacian of each field
				sparse<phi_type> lap = laplacian(oldGrid, i);

				// compute variational derivatives
				sparse<phi_type> dFdp;
				for (int h = 0; h < length(s); h++) {
					int hindex = index(s, h);
					for (int j = h + 1; j < length(s); j++) {
						int jindex = index(s, j);
						phi_type gamma = energy(hindex, jindex);
						phi_type eps = 4.0 / acos(-1.0) * sqrt(0.5 * gamma * width);
						phi_type w = 4.0 * gamma / width;
						// Update dFdp_h and dFdp_j, so the inner loop can be over j>h instead of j≠h
						set(dFdp, hindex) += 0.5 * eps * eps * lap[jindex] + w * oldGrid(i)[jindex];
						set(dFdp, jindex) += 0.5 * eps * eps * lap[hindex] + w * oldGrid(i)[hindex];
					}
				}

				// compute time derivatives
				sparse<phi_type> dpdt;
				for (int h = 0; h < length(s); h++) {
					int hindex = index(s, h);
					for (int j = h + 1; j < length(s); j++) {
						int jindex = index(s, j);
						phi_type mu = mobility(hindex, jindex);
						set(dpdt, hindex) -= mu * (dFdp[hindex] - dFdp[jindex]);
						set(dpdt, jindex) -= mu * (dFdp[jindex] - dFdp[hindex]);
					}
				}

				// compute new values
				phi_type sum = 0.0;
				for (int h = 0; h < length(s); h++) {
					int sindex = index(s, h);
					phi_type value = oldGrid(i)[sindex] + dt * (2.0 / S) * dpdt[sindex]; // Extraneous factor of 2?
					if (value > 1.0) value = 1.0;
					if (value < 0.0) value = 0.0;
					if (value > epsilon) set(newGrid(i), sindex) = value;
					sum += newGrid(i)[sindex];
				}

				// project onto Gibbs simplex (enforce Σφ=1)
				phi_type rsum = 0.0;
				if (fabs(sum) > 0.0) rsum = 1.0 / sum;
				for (int h = 0; h < length(newGrid(i)); h++) {
					int sindex = index(newGrid(i), h);
					set(newGrid(i), sindex) *= rsum;
				}
			}
		} // Loop over nodes(oldGrid)
		swap(oldGrid, newGrid);
	} // Loop over steps
	ghostswap(oldGrid);
}
template <int dim> void update(MMSP::grid<dim,sparse<double> >& grid, int steps)
{
	double dt = 0.01;
	double width = 8.0;

	for (int step=0; step<steps; step++) {
		print_progress(step, steps);
		// update grid must be overwritten each time
		MMSP::grid<dim,sparse<double> > update(grid);

		#ifndef MPI_VERSION
		#pragma omp parallel for
		#endif
		for (int n=0; n<nodes(grid); n++) {
			vector<int> x = position(grid,n);

			// compute laplacian of each field
			sparse<double> lapPhi = laplacian(grid,n);

			double S = double(length(lapPhi));

			// if only one field is nonzero,
			// then copy this node to update
			if (S<2.0) update(x) = grid(n);

			else {

				// compute variational derivatives
				sparse<double> dFdp;
				for (int h=0; h<length(lapPhi); h++) {
					int hindex = MMSP::index(lapPhi,h);
					double phii = grid(n)[hindex];
					for (int j=h+1; j<length(lapPhi); j++) {
						int jindex = MMSP::index(lapPhi,j);
						double phij = grid(n)[jindex];
						double gamma = energy(hindex,jindex);
						double eps = 4.0/acos(-1.0)*sqrt(0.5*gamma*width);
						double w = 4.0*gamma/width;
						set(dFdp,hindex) += 0.5*eps*eps*lapPhi[jindex]+w*phij;
						set(dFdp,jindex) += 0.5*eps*eps*lapPhi[hindex]+w*phii;
						for (int k=j+1; k<length(lapPhi); k++) {
							int kindex = MMSP::index(lapPhi,k);
							double phik = grid(n)[kindex];
							set(dFdp,hindex) += 3.0*phij*phik;
							set(dFdp,jindex) += 3.0*phii*phik;
							set(dFdp,kindex) += 3.0*phii*phij;
						}
					}
				}

				// compute time derivatives
				sparse<double> dpdt;
				for (int h=0; h<length(lapPhi); h++) {
					int hindex = MMSP::index(lapPhi,h);
					for (int j=h+1; j<length(lapPhi); j++) {
						int jindex = MMSP::index(lapPhi,j);
						double mu = mobility(hindex,jindex);
						set(dpdt,hindex) -= mu*(dFdp[hindex]-dFdp[jindex]);
						set(dpdt,jindex) -= mu*(dFdp[jindex]-dFdp[hindex]);
					}
				}

				// compute update values
				double sum = 0.0;
				for (int h=0; h<length(dpdt); h++) {
					int index = MMSP::index(dpdt,h);
					double value = grid(n)[index]+dt*(2.0/S)*dpdt[index];
					if (value>1.0) value = 1.0;
					if (value<0.0) value = 0.0;
					if (value>machine_epsilon) set(update(x),index) = value;
					sum += update(x)[index];
				}

				// project onto Gibbs simplex
				double rsum = (fabs(sum)>machine_epsilon)?1.0/sum:0.0;
				for (int h=0; h<length(update(x)); h++) {
					int index = MMSP::index(update(x),h);
					set(update(x),index) *= rsum;
				}
			}
		}
		swap(grid,update);
		ghostswap(grid);
	}
	MMSP::sparse<double> mass;
	for (int n=0; n<nodes(grid); n++)
		for (int l=0; l<length(grid(n)); l++) {
			int index = grid(n).index(l);
			set(mass,index) += grid(n)[index];
		}
	for (int l=0; l<length(mass); l++)
		std::cout<<mass.value(l)<<'\t';
	std::cout<<std::endl;
}
Esempio n. 13
0
template <int dim> void update(MMSP::grid<dim,vector<double> >& grid, int steps)
{
	MMSP::grid<dim,vector<double> > update(grid);

	double dt = 0.01;
	double width = 8.0;

	for (int step=0; step<steps; step++) {
		for (int i=0; i<nodes(grid); i++) {
			vector<int> x = position(grid,i);

			// determine nonzero fields within 
			// the neighborhood of this node
			double S = 0.0;
			vector<int> s(fields(grid),0);
			for (int h=0; h<fields(grid); h++) {
				for (int j=0; j<dim; j++)
					for (int k=-1; k<=1; k++) {
						x[j] += k;
						if (grid(x)[h]>0.0) {
							s[h] = 1;
							x[j] -= k;
							goto next;
						}
						x[j] -= k;
					}
				next: S += s[h];
			}

			// if only one field is nonzero,
			// then copy this node to update
			if (S<2.0) update(i) = grid(i);

			else {
				// compute laplacian of each field
				vector<double> lap = laplacian(grid,i);

				// compute variational derivatives
				vector<double> dFdp(fields(grid),0.0);
				for (int h=0; h<fields(grid); h++)
					if (s[h]>0.0)
						for (int j=h+1; j<fields(grid); j++)
							if (s[j]>0.0) {
								double gamma = energy(h,j);
								double eps = 4.0/acos(-1.0)*sqrt(0.5*gamma*width);
								double w = 4.0*gamma/width;
								dFdp[h] += 0.5*eps*eps*lap[j]+w*grid(i)[j];
								dFdp[j] += 0.5*eps*eps*lap[h]+w*grid(i)[h];
								for (int k=j+1; k<fields(grid); k++)
									if (s[k]>0.0) {
										dFdp[h] += 3.0*grid(i)[j]*grid(i)[k];
										dFdp[j] += 3.0*grid(i)[k]*grid(i)[h];
										dFdp[k] += 3.0*grid(i)[h]*grid(i)[j];
									}
							}

				// compute time derivatives
				vector<double> dpdt(fields(grid),0.0);
				for (int h=0; h<fields(grid); h++)
					if (s[h]>0.0)
						for (int j=h+1; j<fields(grid); j++)
							if (s[j]>0.0) {
								double mu = mobility(h,j);
								dpdt[h] -= mu*(dFdp[h]-dFdp[j]);
								dpdt[j] -= mu*(dFdp[j]-dFdp[h]);
							}

				// compute update values
				double sum = 0.0;
				for (int h=0; h<fields(grid); h++) {
					double value = grid(i)[h]+dt*(2.0/S)*dpdt[h];
					if (value>1.0) value = 1.0;
					if (value<0.0) value = 0.0;
					update(i)[h] = value;
					sum += value;
				}

				// project onto Gibbs simplex
				double rsum = 0.0;
				if (fabs(sum)>0.0) rsum = 1.0/sum;
				for (int h=0; h<fields(grid); h++)
					update(i)[h] *= rsum;
			}
		}
		swap(grid,update);
		ghostswap(grid);
	}
}
Esempio n. 14
0
template <int dim, typename T> void update(grid<dim,vector<T> >& spinGrid, int steps)
{
	int rank=0;
    #ifdef MPI_VERSION
    rank = MPI::COMM_WORLD.Get_rank();
    #endif

	ghostswap(spinGrid);

	double J = 1.0;
	double kT = (dim==3)?0.75:0.50;
	double pi = acos(-1.0);

	int gss = (dim==1)?nodes(spinGrid):int(sqrt(nodes(spinGrid)));
	// srand() is called exactly once in MMSP.main.hpp. Do not call it here.

	for (int step=0; step<steps; step++) {
		if (rank==0)
			print_progress(step, steps);

		for (int h=0; h<nodes(spinGrid); h++) {
			// choose a random site
			int p = rand()%nodes(spinGrid);
			vector<int> x = position(spinGrid,p);
			vector<T>& s1 = spinGrid(p);

			// choose a random unit vector
			vector<T> s2(3);
			double psi = 2.0*pi*double(rand())/double(RAND_MAX);
			double theta = acos(1.0-2.0*double(rand())/double(RAND_MAX));
			s2[0] = cos(psi)*sin(theta);
			s2[1] = sin(psi)*sin(theta);
			s2[2] = cos(theta);

			// compute energy change
			double sum = -1.0;
			if (dim==1) {
				for (int i=-1; i<2; i++) {
					x[0] += i;
					vector<T>& s = spinGrid(x);
					sum += s[0]*(s1[0]-s2[0])+s[1]*(s1[1]-s2[1])+s[2]*(s1[2]-s2[2]);
					x[0] -= i;
				}
			} else if (dim==2) {
				for (int i=-1; i<2; i++) {
					x[0] += i;
					for (int j=-1; j<2; j++) {
						x[1] += j;
						vector<T>& s = spinGrid(x);
						sum += s[0]*(s1[0]-s2[0])+s[1]*(s1[1]-s2[1])+s[2]*(s1[2]-s2[2]);
						x[1] -= j;
					}
					x[0] -= i;
				}
			} else if (dim==3) {
				for (int i=-1; i<2; i++) {
					x[0] += i;
					for (int j=-1; j<2; j++) {
						x[1] += j;
						for (int k=-1; k<2; k++) {
							x[2] += k;
							vector<T>& s = spinGrid(x);
							sum += s[0]*(s1[0]-s2[0])+s[1]*(s1[1]-s2[1])+s[2]*(s1[2]-s2[2]);
							x[2] -= k;
						}
						x[1] -= j;
					}
					x[0] -= i;
				}
			}
			double dE = -J*sum;

			// attempt a spin flip
			double r = double(rand())/double(RAND_MAX);
			if (dE<=0.0)
				spinGrid(p) = s2;
			else if (r<exp(-dE/kT))
				spinGrid(p) = s2;

			if (h%gss==0)
				ghostswap(spinGrid);
		}
	}
}
Esempio n. 15
0
void update(MMSP::grid<2,MMSP::vector<double> >& grid, int steps)
{
	int rank=0;
	#ifdef MPI_VERSION
	rank = MPI::COMM_WORLD.Get_rank();
	#endif

  for (int d=0; d<2; d++) {
    dx(grid,d) = deltaX;
		if (MMSP::x0(grid,d)==MMSP::g0(grid,d))
        MMSP::b0(grid,d) = Neumann; // enumerated in MMSP.utility.hpp
    else if (MMSP::x1(grid,d)==MMSP::g1(grid,d))
        MMSP::b1(grid,d) = Neumann; // enumerated in MMSP.utility.hpp
	}

	ghostswap(grid);

	MMSP::grid<2,MMSP::vector<double> > update(grid);
  for (int d=0; d<2; d++) {
    dx(update,d) = deltaX;
		if (MMSP::x0(update,d)==MMSP::g0(update,d))
        MMSP::b0(update,d) = Neumann; // enumerated in MMSP.utility.hpp
    else if (MMSP::x1(update,d)==MMSP::g1(update,d))
        MMSP::b1(update,d) = Neumann; // enumerated in MMSP.utility.hpp
	}

	MMSP::grid<2,double> wspace(grid,1);
  for (int d=0; d<2; d++) {
    dx(wspace,d) = deltaX;
		if (MMSP::x0(wspace,d)==MMSP::g0(wspace,d))
        MMSP::b0(wspace,d) = Neumann; // enumerated in MMSP.utility.hpp
    else if (MMSP::x1(wspace,d)==MMSP::g1(wspace,d))
        MMSP::b1(wspace,d) = Neumann; // enumerated in MMSP.utility.hpp
	}


	for (int step=0; step<steps; step++) {
		for (int n=0; n<nodes(grid); n++) {
			MMSP::vector<int> x=position(grid,n);
			double sum = 0.0;
			for (int i=1; i<fields(grid); i++)
				sum += std::pow(grid(x)[i],2);

			double C = grid(x)[0];
			double lap = onelap(grid, x, 0);

			wspace(x) = -A*(C-Cm) + B*std::pow(C-Cm,3) + Da*std::pow(C-Ca,3) + Db*std::pow(C-Cb,3) - g*(C-Ca)*sum - kappa*lap;
		}
		ghostswap(wspace);

		double energy = 0.0;
		double mass = 0.0;
		for (int n=0; n<nodes(grid); n++) {
            MMSP::vector<int> x=position(grid,n);
            double lap = laplacian(wspace, x);
            double C = grid(x)[0];

            update(x)[0] = C + dt*D*lap;

            double sum = 0.0;
            for (int i=1; i<fields(grid); i++)
                sum += std::pow(grid(x)[i],2);

            for (int i=1; i<fields(grid); i++) {
                double phase = grid(x)[i];
                lap = onelap(grid, x, i);

                update(x)[i] = phase - dt*L*(df2deta(C,phase) + df3deta(phase,sum) - kappa*lap);
            }

            mass += dx(grid)*dy(grid)*update(x)[0];
            energy += dx(grid)*dy(grid)*energydensity(update(x));
        }
        #ifdef MPI_VERSION
        double myEnergy=energy;
        double myMass=mass;
        MPI::COMM_WORLD.Reduce(&myEnergy,&energy,1,MPI_DOUBLE,MPI_SUM,0);
        MPI::COMM_WORLD.Reduce(&myMass,&mass,1,MPI_DOUBLE,MPI_SUM,0);
        #endif
        #ifndef DEBUG
        if (rank==0)
            std::cout<<energy<<'\t'<<mass<<'\n';
        #endif

		swap(grid,update);
		ghostswap(grid);
	}
    #ifndef DEBUG
    if (rank==0)
        std::cout<<std::flush;
    #endif
}
Esempio n. 16
0
void update(MMSP::grid<dim,T>& grid, int steps)
{
	int rank=0;
	#ifdef MPI_VERSION
	rank = MPI::COMM_WORLD.Get_rank();
	#endif

	// Make sure the grid spacing is correct
	for (int d=0; d<dim; d++) {
		dx(grid,d) = deltaX;
		if (MMSP::x0(grid,d)==MMSP::g0(grid,d))
		    MMSP::b0(grid,d) = Neumann; // enumerated in MMSP.utility.hpp
		else if (MMSP::x1(grid,d)==MMSP::g1(grid,d))
		    MMSP::b1(grid,d) = Neumann; // enumerated in MMSP.utility.hpp
  }

  ghostswap(grid);

    // Let's be absolutely explicit about BCs here.
	MMSP::grid<dim,T> update(grid);
	for (int d=0; d<dim; d++) {
		dx(update,d) = deltaX;
		if (MMSP::x0(update,d)==MMSP::g0(update,d))
		    MMSP::b0(update,d) = Neumann; // enumerated in MMSP.utility.hpp
		else if (MMSP::x1(update,d)==MMSP::g1(update,d))
		    MMSP::b1(update,d) = Neumann; // enumerated in MMSP.utility.hpp
  }

	MMSP::grid<dim,T> temp(grid);
	for (int d=0; d<dim; d++) {
		dx(temp,d) = deltaX;
		if (MMSP::x0(temp,d)==MMSP::g0(temp,d))
		    MMSP::b0(temp,d) = Neumann; // enumerated in MMSP.utility.hpp
		else if (MMSP::x1(temp,d)==MMSP::g1(temp,d))
		    MMSP::b1(temp,d) = Neumann; // enumerated in MMSP.utility.hpp
  }


	for (int step=0; step<steps; step++) {
		for (int n=0; n<nodes(grid); n++) {
			MMSP::vector<int> x = position(grid,n);
			if (isOutside(x)) {
				temp(x) = 0.0;
			} else {
	    		double c = grid(x);
    			temp(x) = dfdc(c) - K*zfLaplacian(grid,x);
			}
		}
		#ifdef MPI_VERSION
		MPI::COMM_WORLD.Barrier();
		#endif
		ghostswap(temp);

		double energy = 0.0;
		double mass = 0.0;
		for (int n=0; n<nodes(grid); n++) {
			MMSP::vector<int> x = position(grid,n);
			if (isOutside(x)) {
				update(x) = 0.0;
			} else {
		    	update(x) = grid(x) + dt*D*zfLaplacian(temp,x);
	    		energy += dx(grid)*dy(grid)*energydensity(update(x));
    			mass += dx(grid)*dy(grid)*update(x);
		    }
		}
		#ifdef MPI_VERSION
		MPI::COMM_WORLD.Barrier();
		double myEnergy = energy;
		double myMass = mass;
		MPI::COMM_WORLD.Reduce(&myEnergy, &energy, 1, MPI_DOUBLE, MPI_SUM, 0);
        MPI::COMM_WORLD.Reduce(&myMass, &mass, 1, MPI_DOUBLE, MPI_SUM, 0);
        #endif
		if (rank==0)
		    std::cout<<energy<<'\t'<<mass<<'\n';

		swap(grid,update);
		ghostswap(grid);
	}
    #ifndef DEBUG
	if (rank==0)
	    std::cout<<std::flush;
	#endif
}