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); } }
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); } }
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); } }
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); } } }
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); } } }
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); } } }
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); } }
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(); }
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; }
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 }
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; }
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); } }
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); } } }
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 }
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 }