double run_soft_sphere(double reduced_density, double temp) { Functional f = SoftFluid(sigma, 1, 0); const double mu = find_chemical_potential(OfEffectivePotential(f), temp, reduced_density*pow(2,-5.0/2.0)); printf("mu is %g for reduced_density = %g at temperature %g\n", mu, reduced_density, temp); //printf("Filling fraction is %g with functional %s at temperature %g\n", reduced_density, teff); //fflush(stdout); temperature = temp; //if (kT == 0) kT = ;1 Lattice lat(Cartesian(xmax,0,0), Cartesian(0,ymax,0), Cartesian(0,0,zmax)); GridDescription gd(lat, dx); Grid softspherepotential(gd); softspherepotential.Set(soft_sphere_potential); f = SoftFluid(sigma, 1, mu); // compute approximate energy with chemical potential mu const double approx_energy = f(temperature, reduced_density*pow(2,-5.0/2.0))*xmax*ymax*zmax; const double precision = fabs(approx_energy*1e-9); f = OfEffectivePotential(SoftFluid(sigma, 1, mu) + ExternalPotential(softspherepotential)); static Grid *potential = 0; potential = new Grid(gd); *potential = softspherepotential - temperature*log(reduced_density*pow(2,-5.0/2.0)/(1.0*radius*radius*radius))*VectorXd::Ones(gd.NxNyNz); // Bad starting guess printf("\tMinimizing to %g absolute precision from %g from %g...\n", precision, approx_energy, temperature); fflush(stdout); Minimizer min = Precision(precision, PreconditionedConjugateGradient(f, gd, temperature, potential, QuadraticLineMinimizer)); took("Setting up the variables"); for (int i=0; min.improve_energy(true) && i<100; i++) { } took("Doing the minimization"); min.print_info(); Grid density(gd, EffectivePotentialToDensity()(temperature, gd, *potential)); //printf("# per area is %g at filling fraction %g\n", density.sum()*gd.dvolume/dw/dw, reduced_density); char *plotname = (char *)malloc(1024); sprintf(plotname, "papers/fuzzy-fmt/figs/radial-wca-%06.4f-%04.2f.dat", temp, reduced_density); z_plot(plotname, Grid(gd, pow(2,5.0/2.0)*density)); free(plotname); { //double peak = peak_memory()/1024.0/1024; //double current = current_memory()/1024.0/1024; //printf("Peak memory use is %g M (current is %g M)\n", peak, current); } took("Plotting stuff"); printf("density %g gives ff %g for reduced_density = %g and T = %g\n", density(0,0,gd.Nz/2), density(0,0,gd.Nz/2)*4*M_PI/3, reduced_density, temp); return density(0, 0, gd.Nz/2)*4*M_PI/3; // return bulk filling fraction }
int main(int argc, char **argv) { double reduced_density, temp; if (argc != 3) { printf("usage: %s reduced_density kT\n", argv[0]); return 1; } printf("git version: %s\n", version_identifier()); sscanf(argv[1], "%lg", &reduced_density); sscanf(argv[2], "%lg", &temp); HomogeneousWhiteBearFluid hf; printf("dx is %g\n", dx); double rad_bh = R_BH(temp); printf("rad is %g\n", rad_bh); hf.R() = rad_bh; hf.kT() = temp; hf.n() = reduced_density*pow(2,-5.0/2.0); printf("dividing by sigma = %g\n", sigma); printf("eta is %g\n", hf.n()*uipow(radius,3)*M_PI*4/3); hf.mu() = 0; hf.mu() = hf.d_by_dn(); // set mu based on derivative of hf printf("bulk energy is %g\n", hf.energy()); printf("cell energy should be %g\n", hf.energy()*dx*dx*dx); WhiteBearFluidVeff f(xmax, ymax, zmax, dx); f.R() = hf.R(); f.kT() = hf.kT(); f.mu() = hf.mu(); f.Vext() = 0; f.Veff() = -temp*log(hf.n()); { const int Ntot = f.Nx()*f.Ny()*f.Nz(); const Vector r = f.get_r(); const double Vmax = 100*temp; for (int i=0; i<Ntot; i++) { f.Vext()[i] = 4*epsilon*(uipow(sigma/r[i], 12) - uipow(sigma/r[i], 6)); if (!(f.Vext()[i] < Vmax)) f.Vext()[i] = Vmax; f.Veff()[i] += f.Vext()[i]*temp/10; // adjust uniform guess based on repulsive potential } } took("setting up the potential and Veff"); printf("initial energy is %g\n", f.energy()); took("Finding initial energy"); printf("Here is a new line!\n"); run_minimization(reduced_density, &f, temp); return 0; }
void run_sw_liquid(double ff, SW_liquidVeff *f, double kT) { Minimize min(f); min.set_relative_precision(0); min.set_maxiter(500); min.precondition(true); char *dumpname = new char[5000]; snprintf(dumpname, 5000, "papers/square-well-fluid/data/radial-sw-%.2f-%.2f-%.2f-X.dat", kT, f->lambda(), ff); { Vector rx = f->get_rx(); rx.dumpSliceZ(dumpname, f->Nx(), f->Ny(), f->Nz(), 0); } snprintf(dumpname, 5000, "papers/square-well-fluid/data/radial-sw-%.2f-%.2f-%.2f-Y.dat", kT, f->lambda(), ff); f->get_ry().dumpSliceZ(dumpname, f->Nx(), f->Ny(), f->Nz(), 0); snprintf(dumpname, 5000, "papers/square-well-fluid/data/radial-sw-%.2f-%.2f-%.2f-eta.dat", kT, f->lambda(), ff); char *fname = new char[5000]; //mkdir("papers/squre-well-fluid/figs/new-data", 0777); // make sure the directory exists snprintf(fname, 5000, "papers/square-well-fluid/data/radial-sw-%.2f-%.2f-%.2f.dat", kT, f->lambda(), ff); printf("=====================================================\n"); printf("| Working on ff = %4g, lambda = %4g and kT = %4g |\n", ff, f->lambda(), kT); printf("=====================================================\n"); while (min.improve_energy(gossipy)) { took("Doing the minimization step"); FILE *o = fopen(fname, "w"); if (!o) { fprintf(stderr, "error creating file %s\n", fname); exit(1); } const int Nz = f->Nz(); Vector Vext = f->Vext(); Vector r = f->get_r(); Vector n = f->get_n(); for (int i=0;i<Nz/2;i++) { fprintf(o, "%g\t%g\t%g\n", r[i]/sigma, n[i]*M_PI*uipow(sigma, 3)/6, Vext[i]); } fclose(o); n *= M_PI*uipow(sigma, 3)/6; n.dumpSliceZ(dumpname, f->Nx(), f->Ny(), f->Nz(), 0); took("Outputting to file"); } min.print_info(); delete[] fname; delete[] dumpname; }
double run_walls(double reduced_density, const char *name, Functional fhs, double teff) { double kT = teff; if (kT == 0) kT = 1; Functional f = OfEffectivePotential(fhs); const double zmax = width + 2*spacing; Lattice lat(Cartesian(dw,0,0), Cartesian(0,dw,0), Cartesian(0,0,zmax)); GridDescription gd(lat, dx); Grid constraint(gd); constraint.Set(notinwall); f = constrain(constraint, f); Grid potential(gd); potential = pow(2,-5.0/2.0)*(reduced_density*constraint + 1e-4*reduced_density*VectorXd::Ones(gd.NxNyNz)); potential = -kT*potential.cwise().log(); const double approx_energy = fhs(kT, reduced_density*pow(2,-5.0/2.0))*dw*dw*width; const double precision = fabs(approx_energy*1e-11); printf("\tMinimizing to %g absolute precision from %g from %g...\n", precision, approx_energy, kT); fflush(stdout); Minimizer min = Precision(precision, PreconditionedConjugateGradient(f, gd, kT, &potential, QuadraticLineMinimizer)); took("Setting up the variables"); if (strcmp(name, "hard") != 0 && false) { printf("For now, SoftFluid doesn't work properly, so we're skipping the\n"); printf("minimization at temperature %g.\n", teff); } else { for (int i=0;min.improve_energy(false) && i<100;i++) { } } took("Doing the minimization"); min.print_info(); Grid density(gd, EffectivePotentialToDensity()(kT, gd, potential)); //printf("# per area is %g at filling fraction %g\n", density.sum()*gd.dvolume/dw/dw, eta); char *plotname = (char *)malloc(1024); sprintf(plotname, "papers/fuzzy-fmt/figs/walls%s-%06.4f-%04.2f.dat", name, teff, reduced_density); z_plot(plotname, Grid(gd, density*pow(2,5.0/2.0))); free(plotname); took("Plotting stuff"); printf("density %g gives ff %g for reduced density = %g and T = %g\n", density(0,0,gd.Nz/2), density(0,0,gd.Nz/2)*4*M_PI/3, reduced_density, teff); return density(0, 0, gd.Nz/2)*4*M_PI/3; // return bulk filling fraction }
int main(){ long n, k; scanf("%ld %ld", &n, &k); std::vector<long> m(k); for(long p = 0; p < k; p++){scanf("%ld", &m[p]);} std::vector<std::vector<long> > pre(n + 1); for(long p = 1; p <= n; p++){ long w; scanf("%ld", &w); while(w--){long x; scanf("%ld", &x); pre[p].push_back(x);} } std::vector<long> courses; std::vector<bool> took(n + 1, 0); bool possible(true); for(int p = 0; p < k; p++){ printf("Main course: %ld\n", m[p]); std::vector<long> willtake; dfs(m[p], pre, willtake, took, m[p], possible); if(!possible){break;} for(long p = willtake.size() - 1; p >= 0; p--){ if(took[willtake[p]]){continue;} took[willtake[p]] = 1; courses.push_back(willtake[p]); } } if(!possible){puts("-1"); return 0;} printf("%ld\n", courses.size()); for(long p = 0; p < courses.size(); p++){printf("%ld ", courses[p]);} puts(""); return 0; }
int main(int, char **) { FILE *o = fopen("paper/figs/equation-of-state.dat", "w"); FILE *experiment = fopen("paper/figs/experimental-equation-of-state.dat", "w"); int imax=0; while (temperatures_kelvin[imax]) imax++; took("Counting the temperatures"); double mu = 0, nl = 0, nv = 0; Functional f = OfEffectivePotential(SaftFluid(water_prop.lengthscale, water_prop.epsilonAB, water_prop.kappaAB, water_prop.epsilon_dispersion, water_prop.lambda_dispersion, water_prop.length_scaling, 0)); for (int i=0; i<imax; i+=1) { //printf("Working on equation of state at %g Kelvin...\n", temperatures_kelvin[i]); double kT = kB*temperatures_kelvin[i]; saturated_liquid_vapor(f, kT, 1e-14, 0.0017, 0.0055, &nl, &nv, &mu, 1e-6); took("Finding coesisting liquid and vapor densities"); double pv = pressure(f, kT, nv); took("Finding pressure"); fprintf(o, "%g\t%g\t%g\t%g\n", temperatures_kelvin[i], pv, nl, nv); fflush(o); // FOR DEBUGGING fprintf(experiment, "%g\t%g\t%g\t%g\t%g\n", temperatures_kelvin[i], water_vapor_pressure[i], water_saturation_liquid[i], water_vapor_density[i], water_saturated_surface_tension[i]); fflush(experiment); } for (double T=650; T<=695; T += 1) { //printf("Working on bonus equation of state at %g Kelvin...\n", T); double kT = kB*T; saturated_liquid_vapor(f, kT, 0.0005, 0.0019, 0.003, &nl, &nv, &mu, 1e-6); took("Finding coesisting liquid and vapor densities"); double pv = pressure(f, kT, nv); took("Finding pressure"); fprintf(o, "%g\t%g\t%g\t%g\n", T, pv, nl, nv); fflush(o); // FOR DEBUGGING } fclose(o); fclose(experiment); }
void run_minimization(double reduced_density,WhiteBearFluidVeff *f, double kT) { Minimize min(f); min.set_relative_precision(0); min.set_maxiter(1000); min.set_miniter(9); min.precondition(true); char *fname = new char[5000]; mkdir("papers/fuzzy-fmt/figs/new-data", 0777); // make sure the directory exists snprintf(fname, 5000, "papers/fuzzy-fmt/figs/new-data/radial-bh-lj-%06.4f-%04.2f.dat", kT, reduced_density); printf("========================================\n"); printf("| Working on rho* = %4g and kT = %4g |\n", reduced_density, kT); printf("========================================\n"); do { //f->run_finite_difference_test("SFMT", 0, 100*min.recent_stepsize()); took("Doing the minimization step"); const int Nz = f->Nz(); Vector Vext = f->Vext(); Vector r = f->get_r(); Vector n = f->get_n(); f->get_Fideal(); // FIXME this is a hokey trick to make dV be defined Vector n3 = f->get_n3(); FILE *o = fopen(fname, "w"); if (!o) { fprintf(stderr, "error creating file %s\n", fname); exit(1); } for (int i=0;i<Nz/2;i++) { fprintf(o, "%g\t%g\t%g\t%g\n", r[i]/sigma, n[i]*uipow(sigma, 3), Vext[i], n3[i]); } fclose(o); took("Outputting to file"); } while (min.improve_energy(gossipy)); min.print_info(); delete[] fname; }
void run_with_eta(double eta, const char *name, Functional fhs) { // Generates a data file for the pair distribution function, for filling fraction eta // and distance of first sphere from wall of z0. Data saved in a table such that the // columns are x values and rows are z1 values. printf("Now starting run_with_eta with eta = %g name = %s\n", eta, name); Functional f = OfEffectivePotential(fhs + IdealGas()); double mu = find_chemical_potential(f, 1, eta/(4*M_PI/3)); f = OfEffectivePotential(fhs + IdealGas() + ChemicalPotential(mu)); Lattice lat(Cartesian(width,0,0), Cartesian(0,width,0), Cartesian(0,0,width)); GridDescription gd(lat, dx); Grid potential(gd); Grid constraint(gd); constraint.Set(notinsphere); f = constrain(constraint, f); potential = (eta*constraint + 1e-4*eta*VectorXd::Ones(gd.NxNyNz))/(4*M_PI/3); potential = -potential.cwise().log(); const double approx_energy = (fhs + IdealGas() + ChemicalPotential(mu))(1, eta/(4*M_PI/3))*uipow(width,3); const double precision = fabs(approx_energy*1e-10); //printf("Minimizing to %g absolute precision...\n", precision); { // Put mimizer in block so as to free it when we finish minimizing to save memory. Minimizer min = Precision(precision, PreconditionedConjugateGradient(f, gd, 1, &potential, QuadraticLineMinimizer)); for (int i=0;min.improve_energy(true) && i<100;i++) { double peak = peak_memory()/1024.0/1024; double current = current_memory()/1024.0/1024; printf("Peak memory use is %g M (current is %g M)\n", peak, current); fflush(stdout); } took("Doing the minimization"); } Grid density(gd, EffectivePotentialToDensity()(1, gd, potential)); Grid gsigma(gd, gSigmaA(1.0)(1, gd, density)); Grid nA(gd, ShellConvolve(2)(1, density)/(4*M_PI*4)); Grid n3(gd, StepConvolve(1)(1, density)); Grid nbar_sokolowski(gd, StepConvolve(1.6)(1, density)); nbar_sokolowski /= (4.0/3.0*M_PI*ipow(1.6, 3)); // Create the walls directory if it doesn't exist. if (mkdir("papers/pair-correlation/figs/walls", 0777) != 0 && errno != EEXIST) { // We failed to create the directory, and it doesn't exist. printf("Failed to create papers/pair-correlation/figs/walls: %s", strerror(errno)); exit(1); // fail immediately with error code } // here you choose the values of z0 to use // dx is the resolution at which we compute the density. char *plotname = new char[4096]; for (double z0 = 2.1; z0 < 4.5; z0 += 2.1) { // For each z0, we now pick one of our methods for computing the // pair distribution function: for (int version = 0; version < numplots; version++) { sprintf(plotname, "papers/pair-correlation/figs/triplet%s-%s-%04.2f-%1.2f.dat", name, fun[version], eta, z0); FILE *out = fopen(plotname,"w"); FILE *xfile = fopen("papers/pair-correlation/figs/triplet-x.dat","w"); FILE *zfile = fopen("papers/pair-correlation/figs/triplet-z.dat","w"); // the +1 for z0 and z1 are to shift the plot over, so that a sphere touching the wall // is at z = 0, to match with the monte carlo data const Cartesian r0(0,0,z0); for (double x = 0; x < 4; x += dx) { for (double z1 = -4; z1 <= 9; z1 += dx) { const Cartesian r1(x,0,z1); double g2 = pairdists[version](gsigma, density, nA, n3, nbar_sokolowski, r0, r1); double n_bulk = (3.0/4.0/M_PI)*eta; double g3 = g2*density(r0)*density(r1)/n_bulk/n_bulk; fprintf(out, "%g\t", g3); fprintf(xfile, "%g\t", x); fprintf(zfile, "%g\t", z1); } fprintf(out, "\n"); fprintf(xfile, "\n"); fprintf(zfile, "\n"); } fclose(out); fclose(xfile); fclose(zfile); } } delete[] plotname; took("Dumping the triplet dist plots"); const double ds = 0.01; // step size to use in path plots, FIXME increase for publication! const double delta = .1; //this is the value of radius of the //particle as it moves around the contact //sphere on its path char *plotname_path = new char[4096]; for (int version = 0; version < numplots; version++) { sprintf(plotname_path, "papers/pair-correlation/figs/triplet%s-path-%s-%04.2f.dat", name, fun[version], eta); FILE *out_path = fopen(plotname_path, "w"); if (!out_path) { fprintf(stderr, "Unable to create file %s!\n", plotname_path); return; } sprintf(plotname_path, "papers/pair-correlation/figs/triplet-back-contact-%s-%04.2f.dat", fun[version], eta); FILE *out_back = fopen(plotname_path, "w"); if (!out_back) { fprintf(stderr, "Unable to create file %s!\n", plotname_path); return; } fprintf(out_path, "# unused\tg3\tz\tx\n"); fprintf(out_back, "# unused\tg3\tz\tx\n"); const Cartesian r0(0,0, 2.0+delta); const double max_theta = M_PI*2.0/3; for (double z = 7; z >= 2*(2.0 + delta); z-=ds) { const Cartesian r1(0,0,z); double g2_path = pairdists[version](gsigma, density, nA, n3, nbar_sokolowski, r0, r1); double n_bulk = (3.0/4.0/M_PI)*eta; double g3 = g2_path*density(r0)*density(r1)/n_bulk/n_bulk; fprintf(out_path,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); } for (double z = -7; z <= -(2.0 + delta); z+=ds) { const Cartesian r1(0,0,z); double g2_path = pairdists[version](gsigma, density, nA, n3, nbar_sokolowski, r0, r1); double n_bulk = (3.0/4.0/M_PI)*eta; double g3 = g2_path*density(r0)*density(r1)/n_bulk/n_bulk; fprintf(out_back,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); } const double dtheta = ds/2; for (double theta = 0; theta <= max_theta; theta += dtheta){ const Cartesian r1((2.0+delta)*sin(theta), 0, (2.0+delta)*(1+cos(theta))); double g2_path = pairdists[version](gsigma, density, nA, n3, nbar_sokolowski, r0, r1); double n_bulk = (3.0/4.0/M_PI)*eta; double g3 = g2_path*density(r0)*density(r1)/n_bulk/n_bulk; fprintf(out_path,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); } for (double theta = 0; theta <= max_theta; theta += dtheta){ const Cartesian r1((2.0+delta)*sin(theta), 0,-(2.0+delta)*cos(theta)); double g2_path = pairdists[version](gsigma, density, nA, n3, nbar_sokolowski, r0, r1); double n_bulk = (3.0/4.0/M_PI)*eta; double g3 = g2_path*density(r0)*density(r1)/n_bulk/n_bulk; fprintf(out_back,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); } for (double x = (2.0+delta)*sqrt(3)/2; x<=6; x+=ds){ const Cartesian r1(x, 0, 1.0+delta/2); double g2_path = pairdists[version](gsigma, density, nA, n3, nbar_sokolowski, r0, r1); double n_bulk = (3.0/4.0/M_PI)*eta; double g3 = g2_path*density(r0)*density(r1)/n_bulk/n_bulk; fprintf(out_path,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); fprintf(out_back,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); } fclose(out_path); fclose(out_back); } for (int version = 0; version < numplots; version++) { sprintf(plotname_path, "papers/pair-correlation/figs/triplet-path-inbetween-%s-%04.2f.dat", fun[version], eta); FILE *out_path = fopen(plotname_path, "w"); if (!out_path) { fprintf(stderr, "Unable to create file %s!\n", plotname_path); return; } sprintf(plotname_path, "papers/pair-correlation/figs/triplet-back-inbetween-%s-%04.2f.dat", fun[version], eta); FILE *out_back = fopen(plotname_path, "w"); if (!out_back) { fprintf(stderr, "Unable to create file %s!\n", plotname_path); return; } fprintf(out_path, "# unused\tg3\tz\tx\n"); fprintf(out_back, "# unused\tg3\tz\tx\n"); const Cartesian r0(0,0, 4.0+2*delta); const double max_theta = M_PI; for (double z = 11; z >= 3*(2.0 + delta); z-=ds) { const Cartesian r1(0,0,z); double g2_path = pairdists[version](gsigma, density, nA, n3, nbar_sokolowski, r0, r1); double n_bulk = (3.0/4.0/M_PI)*eta; double g3 = g2_path*density(r0)*density(r1)/n_bulk/n_bulk; fprintf(out_path,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); } for (double z = -10; z <= -(2.0 + delta); z+=ds) { const Cartesian r1(0,0,z); double g2_path = pairdists[version](gsigma, density, nA, n3, nbar_sokolowski, r0, r1); double n_bulk = (3.0/4.0/M_PI)*eta; double g3 = g2_path*density(r0)*density(r1)/n_bulk/n_bulk; fprintf(out_back,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); } const double dtheta = ds/2; for (double theta = 0; theta <= max_theta; theta += dtheta){ const Cartesian r1((2.0+delta)*sin(theta), 0, (2.0+delta)*(2+cos(theta))); double g2_path = pairdists[version](gsigma, density, nA, n3, nbar_sokolowski, r0, r1); double n_bulk = (3.0/4.0/M_PI)*eta; double g3 = g2_path*density(r0)*density(r1)/n_bulk/n_bulk; fprintf(out_path,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); } for (double theta = 0; theta <= max_theta; theta += dtheta){ const Cartesian r1((2.0+delta)*sin(theta), 0, -(2.0+delta)*cos(theta)); double g2_path = pairdists[version](gsigma, density, nA, n3, nbar_sokolowski, r0, r1); double n_bulk = (3.0/4.0/M_PI)*eta; double g3 = g2_path*density(r0)*density(r1)/n_bulk/n_bulk; fprintf(out_back,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); } for (double x = 0; x>=-6; x-=ds){ const Cartesian r1(x, 0, 2.0+delta); double g2_path = pairdists[version](gsigma, density, nA, n3, nbar_sokolowski, r0, r1); double n_bulk = (3.0/4.0/M_PI)*eta; double g3 = g2_path*density(r0)*density(r1)/n_bulk/n_bulk; fprintf(out_path,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); fprintf(out_back,"0\t%g\t%g\t%g\n", g3, r1[2], r1[0]); } fclose(out_path); fclose(out_back); } delete[] plotname_path; }
double run_walls(double eta, const char *name, Functional fhs, double teff) { //printf("Filling fraction is %g with functional %s at temperature %g\n", eta, name, teff); //fflush(stdout); double kT = teff; if (kT == 0) kT = 1; Functional f = OfEffectivePotential(fhs); const double zmax = width + 2*spacing; Lattice lat(Cartesian(dw,0,0), Cartesian(0,dw,0), Cartesian(0,0,zmax)); GridDescription gd(lat, dx); Grid constraint(gd); constraint.Set(notinwall); f = constrain(constraint, f); // We reuse the potential, which should give us a better starting // guess on each calculation. static Grid *potential = 0; if (strcmp(name, "hard") == 0) { // start over for each potential delete potential; potential = 0; } if (!potential) { potential = new Grid(gd); *potential = (eta*constraint + 1e-4*eta*VectorXd::Ones(gd.NxNyNz))/(4*M_PI/3); *potential = -kT*potential->cwise().log(); } // FIXME below I use the HS energy because of issues with the actual // functional. const double approx_energy = fhs(kT, eta/(4*M_PI/3))*dw*dw*width; const double precision = fabs(approx_energy*1e-5); printf("\tMinimizing to %g absolute precision from %g from %g...\n", precision, approx_energy, kT); fflush(stdout); Minimizer min = Precision(precision, PreconditionedConjugateGradient(f, gd, kT, potential, QuadraticLineMinimizer)); took("Setting up the variables"); for (int i=0;min.improve_energy(false) && i<100;i++) { } took("Doing the minimization"); min.print_info(); Grid density(gd, EffectivePotentialToDensity()(kT, gd, *potential)); //printf("# per area is %g at filling fraction %g\n", density.sum()*gd.dvolume/dw/dw, eta); char *plotname = (char *)malloc(1024); sprintf(plotname, "papers/fuzzy-fmt/figs/walls%s-%06.4f-%04.2f.dat", name, teff, eta); z_plot(plotname, Grid(gd, 4*M_PI*density/3)); free(plotname); { GridDescription gdj = density.description(); double sep = gdj.dz*gdj.Lat.a3().norm(); int div = gdj.Nz; int mid = int (div/2.0); double Ntot_per_A = 0; double mydist = 0; for (int j=0; j<mid; j++){ Ntot_per_A += density(0,0,j)*sep; mydist += sep; } double Extra_per_A = Ntot_per_A - eta/(4.0/3.0*M_PI)*width/2; FILE *fout = fopen("papers/fuzzy-fmt/figs/wallsfillingfracInfo.txt", "a"); fprintf(fout, "walls%s-%04.2f.dat - If you want to match the bulk filling fraction of figs/walls%s-%04.2f.dat, than the number of extra spheres per area to add is %04.10f. So you'll want to multiply %04.2f by your cavity volume and divide by (4/3)pi. Then add %04.10f times the Area of your cavity to this number\n", name, eta, name, eta, Extra_per_A, eta, Extra_per_A); int wallslen = 20; double Extra_spheres = (eta*wallslen*wallslen*wallslen/(4*M_PI/3) + Extra_per_A*wallslen*wallslen); fprintf (fout, "For filling fraction %04.02f and walls of length %d you'll want to use %.0f spheres.\n\n", eta, wallslen, Extra_spheres); fclose(fout); } { //double peak = peak_memory()/1024.0/1024; //double current = current_memory()/1024.0/1024; //printf("Peak memory use is %g M (current is %g M)\n", peak, current); } took("Plotting stuff"); printf("density %g gives ff %g for eta = %g and T = %g\n", density(0,0,gd.Nz/2), density(0,0,gd.Nz/2)*4*M_PI/3, eta, teff); return density(0, 0, gd.Nz/2)*4*M_PI/3; // return bulk filling fraction }
int main(int argc, char **argv) { double ff, temp; if (argc != 4) { printf("usage: %s ff lambda kT\n", argv[0]); return 1; } printf("git version: %s\n", version_identifier()); sscanf(argv[1], "%lg", &ff); sscanf(argv[2], "%lg", &lambda); sscanf(argv[3], "%lg", &temp); printf("ff %g lam %g temp %g\n", ff, lambda, temp); HomogeneousSW_liquid hf; hf.R() = radius; hf.epsilon() = epsilon; hf.kT() = temp; hf.lambda() = lambda; hf.n() = ff/(M_PI*uipow(sigma, 3)/6); hf.mu() = 0; printf("n3 = %g comes from n = %g\n", hf.get_n3(), hf.n()); printf("bulk energy is not %g\n", hf.energy()); printf("mu was arbitrarily %g\n", hf.mu()); hf.mu() = hf.d_by_dn(); // set mu based on derivative of hf printf("mu is found to be %g\n", hf.mu()); printf("our dfdn is now %g\n", hf.d_by_dn()); printf("bulk energy is %g\n", hf.energy()); //hf.printme("XXX:"); printf("cell energy should be %g\n", hf.energy()*xmax*ymax*zmax); // const double dn = 0.01*hf.n(); // for (double anothern=dn; anothern<150*dn; anothern+=dn) { // hf.n() = anothern; // printf("%8g %g\n", anothern*M_PI*uipow(sigma, 3)/6, hf.energy()); // } // exit(1); SW_liquidVeff f(xmax, ymax, zmax, dx); f.R() = hf.R(); f.epsilon() = hf.epsilon(); f.lambda() = hf.lambda(); f.kT() = hf.kT(); //f.Veff() = 0; f.mu() = hf.mu(); f.Vext() = 0; f.Veff() = -temp*log(hf.n()); // start with a uniform density as a guess { const int Ntot = f.Nx()*f.Ny()*f.Nz(); const Vector r = f.get_r(); for (int i=0; i<Ntot; i++) { const double Vmax = 400*temp; f.Vext()[i] = 0; if (r[i] > sigma && r[i] < sigma*lambda) { f.Vext()[i] = -epsilon; } if (r[i] <= sigma) { f.Vext()[i] = Vmax; f.Veff()[i] += Vmax; } } } printf("my energy is %g\n", f.energy()); took("Finding the energy a single time"); run_sw_liquid(ff, &f, temp); return 0; }
int main(int argc, const char *argv[]) { took("Starting program"); // ---------------------------------------------------------------------------- // Define "Constants" -- set from arguments then unchanged // ---------------------------------------------------------------------------- // NOTE: debug can slow things down VERY much int debug = false; int test_weights = false; int print_weights = false; int no_weights = false; double fix_kT = 0; int flat_histogram = false; int gaussian_fit = false; int walker_weights = false; int wang_landau = false; double wl_factor = 0.125; double wl_fmod = 2; double wl_threshold = 0.1; double wl_cutoff = 1e-6; sw_simulation sw; sw.len[0] = sw.len[1] = sw.len[2] = 1; sw.walls = 0; int wall_dim = 1; unsigned long int seed = 0; char *dir = new char[1024]; sprintf(dir, "papers/square-well-liquid/data"); char *filename = new char[1024]; sprintf(filename, "default_filename"); sw.N = 1000; long iterations = 2500000; long initialization_iterations = 500000; double acceptance_goal = .4; double R = 1; double well_width = 1.3; double ff = 0.3; double neighbor_scale = 2; sw.dr = 0.1; double de_density = 0.1; double de_g = 0.05; double max_rdf_radius = 10; int totime = 0; // scale is not a quite "constant" -- it is adjusted during the initialization // so that we have a reasonable acceptance rate double translation_scale = 0.05; poptContext optCon; // ---------------------------------------------------------------------------- // Set values from parameters // ---------------------------------------------------------------------------- poptOption optionsTable[] = { {"N", '\0', POPT_ARG_INT, &sw.N, 0, "Number of balls to simulate", "INT"}, {"ww", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &well_width, 0, "Ratio of square well width to ball diameter", "DOUBLE"}, {"ff", '\0', POPT_ARG_DOUBLE, &ff, 0, "Filling fraction. If specified, the " "cell dimensions are adjusted accordingly without changing the shape of " "the cell"}, {"walls", '\0', POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &sw.walls, 0, "Number of walled dimensions (dimension order: x,y,z)", "INT"}, {"initialize", '\0', POPT_ARG_LONG | POPT_ARGFLAG_SHOW_DEFAULT, &initialization_iterations, 0, "Number of iterations to run for initialization", "INT"}, {"iterations", '\0', POPT_ARG_LONG | POPT_ARGFLAG_SHOW_DEFAULT, &iterations, 0, "Number of iterations to run for", "INT"}, {"de_g", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &de_g, 0, "Resolution of distribution functions", "DOUBLE"}, {"dr", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &sw.dr, 0, "Differential radius change used in pressure calculation", "DOUBLE"}, {"de_density", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &de_density, 0, "Resolution of density file", "DOUBLE"}, {"max_rdf_radius", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &max_rdf_radius, 0, "Set maximum radius for RDF data collection", "DOUBLE"}, {"lenx", '\0', POPT_ARG_DOUBLE, &sw.len[x], 0, "Relative cell size in x dimension", "DOUBLE"}, {"leny", '\0', POPT_ARG_DOUBLE, &sw.len[y], 0, "Relative cell size in y dimension", "DOUBLE"}, {"lenz", '\0', POPT_ARG_DOUBLE, &sw.len[z], 0, "Relative cell size in z dimension", "DOUBLE"}, {"filename", '\0', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &filename, 0, "Base of output file names", "STRING"}, {"dir", '\0', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &dir, 0, "Save directory", "dir"}, {"neighbor_scale", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &neighbor_scale, 0, "Ratio of neighbor sphere radius to interaction scale " "times ball radius. Drastically reduces collision detections","DOUBLE"}, {"translation_scale", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &translation_scale, 0, "Standard deviation for translations of balls, " "relative to ball radius", "DOUBLE"}, {"seed", '\0', POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &seed, 0, "Seed for the random number generator", "INT"}, {"acceptance_goal", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &acceptance_goal, 0, "Goal to set the acceptance rate", "DOUBLE"}, {"nw", '\0', POPT_ARG_NONE, &no_weights, 0, "Don't use weighing method " "to get better statistics on low entropy states", "BOOLEAN"}, {"kT", '\0', POPT_ARG_DOUBLE, &fix_kT, 0, "Use a fixed temperature of kT" " rather than adjusted weights", "DOUBLE"}, {"flat", '\0', POPT_ARG_NONE, &flat_histogram, 0, "Use a flat histogram method", "BOOLEAN"}, {"gaussian", '\0', POPT_ARG_NONE, &gaussian_fit, 0, "Use gaussian weights for flat histogram", "BOOLEAN"}, {"walkers", '\0', POPT_ARG_NONE, &walker_weights, 0, "Use a walker optimization weight histogram method", "BOOLEAN"}, {"wang_landau", '\0', POPT_ARG_NONE, &wang_landau, 0, "Use Wang-Landau histogram method", "BOOLEAN"}, {"wl_factor", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &wl_factor, 0, "Initial value of Wang-Landau factor", "DOUBLE"}, {"wl_fmod", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &wl_fmod, 0, "Wang-Landau factor modifiction parameter", "DOUBLE"}, {"wl_threshold", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &wl_threshold, 0, "Threhold for normalized standard deviation in " "energy histogram at which to adjust Wang-Landau factor", "DOUBLE"}, {"wl_cutoff", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &wl_cutoff, 0, "Cutoff for Wang-Landau factor", "DOUBLE"}, {"time", '\0', POPT_ARG_INT, &totime, 0, "Timing of display information (seconds)", "INT"}, {"R", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &R, 0, "Ball radius (for testing purposes; should always be 1)", "DOUBLE"}, {"test_weights", '\0', POPT_ARG_NONE, &test_weights, 0, "Periodically print weight histogram during initialization", "BOOLEAN"}, {"debug", '\0', POPT_ARG_NONE, &debug, 0, "Debug mode", "BOOLEAN"}, POPT_AUTOHELP POPT_TABLEEND }; optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); poptSetOtherOptionHelp(optCon, "[OPTION...]\nNumber of balls and filling " "fraction or cell dimensions are required arguments."); int c = 0; // go through arguments, set them based on optionsTable while((c = poptGetNextOpt(optCon)) >= 0); if (c < -1) { fprintf(stderr, "\n%s: %s\n", poptBadOption(optCon, 0), poptStrerror(c)); return 1; } poptFreeContext(optCon); // ---------------------------------------------------------------------------- // Verify we have reasonable arguments and set secondary parameters // ---------------------------------------------------------------------------- // check that only one method is used if(bool(no_weights) + bool(flat_histogram) + bool(gaussian_fit) + bool(wang_landau) + bool(walker_weights) + (fix_kT != 0) != 1){ printf("Exactly one histigram method must be selected!"); return 254; } if(sw.walls >= 2){ printf("Code cannot currently handle walls in more than one dimension.\n"); return 254; } if(sw.walls > 3){ printf("You cannot have walls in more than three dimensions.\n"); return 254; } if(well_width < 1){ printf("Interaction scale should be greater than (or equal to) 1.\n"); return 254; } // Adjust cell dimensions for desired filling fraction const double fac = R*pow(4.0/3.0*M_PI*sw.N/(ff*sw.len[x]*sw.len[y]*sw.len[z]), 1.0/3.0); for(int i = 0; i < 3; i++) sw.len[i] *= fac; printf("\nSetting cell dimensions to (%g, %g, %g).\n", sw.len[x], sw.len[y], sw.len[z]); if (sw.N <= 0 || initialization_iterations < 0 || iterations < 0 || R <= 0 || neighbor_scale <= 0 || sw.dr <= 0 || translation_scale < 0 || sw.len[x] < 0 || sw.len[y] < 0 || sw.len[z] < 0) { fprintf(stderr, "\nAll parameters must be positive.\n"); return 1; } sw.dr *= R; const double eta = (double)sw.N*4.0/3.0*M_PI*R*R*R/(sw.len[x]*sw.len[y]*sw.len[z]); if (eta > 1) { fprintf(stderr, "\nYou're trying to cram too many balls into the cell. " "They will never fit. Filling fraction: %g\n", eta); return 7; } // If a filename was not selected, make a default if (strcmp(filename, "default_filename") == 0) { char *name_suffix = new char[10]; char *wall_tag = new char[10]; if(sw.walls == 0) sprintf(wall_tag,"periodic"); else if(sw.walls == 1) sprintf(wall_tag,"wall"); else if(sw.walls == 2) sprintf(wall_tag,"tube"); else if(sw.walls == 3) sprintf(wall_tag,"box"); if (fix_kT) { sprintf(name_suffix, "-kT%g", fix_kT); } else if (no_weights) { sprintf(name_suffix, "-nw"); } else if (flat_histogram) { sprintf(name_suffix, "-flat"); } else if (gaussian_fit) { sprintf(name_suffix, "-gaussian"); } else if (wang_landau) { sprintf(name_suffix, "-wang_landau"); } else if (walker_weights) { sprintf(name_suffix, "-walkers"); } else { name_suffix[0] = 0; // set name_suffix to the empty string } sprintf(filename, "%s-ww%04.2f-ff%04.2f-N%i%s", wall_tag, well_width, eta, sw.N, name_suffix); printf("\nUsing default file name: "); delete[] name_suffix; delete[] wall_tag; } else printf("\nUsing given file name: "); printf("%s\n",filename); printf("------------------------------------------------------------------\n"); printf("Running %s with parameters:\n", argv[0]); for(int i = 1; i < argc; i++) { if(argv[i][0] == '-') printf("\n"); printf("%s ", argv[i]); } printf("\n"); if (totime > 0) printf("Timing information will be displayed.\n"); if (debug) printf("DEBUG MODE IS ENABLED!\n"); else printf("Debug mode disabled\n"); printf("------------------------------------------------------------------\n\n"); // ---------------------------------------------------------------------------- // Define sw_simulation variables // ---------------------------------------------------------------------------- sw.iteration = 0; // start at zeroeth iteration sw.state_of_max_interactions = 0; sw.state_of_max_entropy = 0; // translation distance should scale with ball radius sw.translation_distance = translation_scale*R; // neighbor radius should scale with radius and interaction scale sw.neighbor_R = neighbor_scale*R*well_width; // Find the upper limit to the maximum number of neighbors a ball could have sw.max_neighbors = max_balls_within(2+neighbor_scale*well_width); // Energy histogram sw.interaction_distance = 2*R*well_width; sw.energy_levels = sw.N/2*max_balls_within(sw.interaction_distance); sw.energy_histogram = new long[sw.energy_levels](); // Walkers sw.current_walker_plus = false; sw.walker_plus_threshold = 0; sw.walker_minus_threshold = 0; sw.walkers_plus = new long[sw.energy_levels](); sw.walkers_total = new long[sw.energy_levels](); // Energy weights, state density int weight_updates = 0; sw.ln_energy_weights = new double[sw.energy_levels](); // Radial distribution function (RDF) histogram long *g_energy_histogram = new long[sw.energy_levels](); const int g_bins = round(min(min(min(sw.len[y],sw.len[z]),sw.len[x]),max_rdf_radius) / de_g / 2); long **g_histogram = new long*[sw.energy_levels]; for(int i = 0; i < sw.energy_levels; i++) g_histogram[i] = new long[g_bins](); // Density histogram const int density_bins = round(sw.len[wall_dim]/de_density); const double bin_volume = sw.len[x]*sw.len[y]*sw.len[z]/sw.len[wall_dim]*de_density; long **density_histogram = new long*[sw.energy_levels]; for(int i = 0; i < sw.energy_levels; i++) density_histogram[i] = new long[density_bins](); printf("memory use estimate = %.2g G\n\n", 8*double((6 + g_bins + density_bins)*sw.energy_levels)/1024/1024/1024); sw.balls = new ball[sw.N]; if(totime < 0) totime = 10*sw.N; // a guess for the number of iterations to run for initializing the histogram int first_weight_update = sw.energy_levels; // Initialize the random number generator with our seed random::seed(seed); // ---------------------------------------------------------------------------- // Set up the initial grid of balls // ---------------------------------------------------------------------------- for(int i = 0; i < sw.N; i++) // initialize ball radii sw.balls[i].R = R; // Balls will be initially placed on a face centered cubic (fcc) grid // Note that the unit cells need not be actually "cubic", but the fcc grid will // be stretched to cell dimensions const int spots_per_cell = 4; // spots in each fcc periodic unit cell const int cells_floor = ceil(sw.N/spots_per_cell); // minimum number of cells int cells[3]; // array to contain number of cells in x, y, and z dimensions for(int i = 0; i < 3; i++){ cells[i] = ceil(pow(cells_floor*sw.len[i]*sw.len[i] /(sw.len[(i+1)%3]*sw.len[(i+2)%3]),1.0/3.0)); } // It is usefull to know our cell dimensions double cell_width[3]; for(int i = 0; i < 3; i++) cell_width[i] = sw.len[i]/cells[i]; // Increase number of cells until all balls can be accomodated int total_spots = spots_per_cell*cells[x]*cells[y]*cells[z]; int i = 0; while(total_spots < sw.N) { if(cell_width[i%3] <= cell_width[(i+1)%3] && cell_width[(i+1)%3] <= cell_width[(i+2)%3]) { cells[i%3] += 1; cell_width[i%3] = sw.len[i%3]/cells[i%3]; total_spots += spots_per_cell*cells[(i+1)%3]*cells[(i+2)%3]; } i++; } // Define ball positions relative to cell position vector3d* offset = new vector3d[4](); offset[x] = vector3d(0,cell_width[y],cell_width[z])/2; offset[y] = vector3d(cell_width[x],0,cell_width[z])/2; offset[z] = vector3d(cell_width[x],cell_width[y],0)/2; // Reserve some spots at random to be vacant bool *spot_reserved = new bool[total_spots](); int p; // Index of reserved spot for(int i = 0; i < total_spots-sw.N; i++) { p = floor(random::ran()*total_spots); // Pick a random spot index if(spot_reserved[p] == false) // If it's not already reserved, reserve it spot_reserved[p] = true; else // Otherwise redo this index (look for a new spot) i--; } // Place all balls in remaining spots int b = 0; vector3d cell_pos; for(int i = 0; i < cells[x]; i++) { for(int j = 0; j < cells[y]; j++) { for(int k = 0; k < cells[z]; k++) { for(int l = 0; l < 4; l++) { if(!spot_reserved[i*(4*cells[z]*cells[y])+j*(4*cells[z])+k*4+l]) { sw.balls[b].pos = vector3d(i*cell_width[x],j*cell_width[y], k*cell_width[z]) + offset[l]; b++; } } } } } delete[] offset; delete[] spot_reserved; took("Placement"); // ---------------------------------------------------------------------------- // Print info about the initial configuration for troubleshooting // ---------------------------------------------------------------------------- { int most_neighbors = initialize_neighbor_tables(sw.balls, sw.N, sw.neighbor_R + 2*sw.dr, sw.max_neighbors, sw.len, sw.walls); if (most_neighbors < 0) { fprintf(stderr, "The guess of %i max neighbors was too low. Exiting.\n", sw.max_neighbors); return 1; } printf("Neighbor tables initialized.\n"); printf("The most neighbors is %i, whereas the max allowed is %i.\n", most_neighbors, sw.max_neighbors); } // ---------------------------------------------------------------------------- // Make sure initial placement is valid // ---------------------------------------------------------------------------- bool error = false, error_cell = false; for(int i = 0; i < sw.N; i++) { if (!in_cell(sw.balls[i], sw.len, sw.walls, sw.dr)) { error_cell = true; error = true; } for(int j = 0; j < i; j++) { if (overlap(sw.balls[i], sw.balls[j], sw.len, sw.walls)) { error = true; break; } } if (error) break; } if (error){ print_bad(sw.balls, sw.N, sw.len, sw.walls); printf("Error in initial placement: "); if(error_cell) printf("balls placed outside of cell.\n"); else printf("balls are overlapping.\n"); return 253; } fflush(stdout); // ---------------------------------------------------------------------------- // Initialization of cell // ---------------------------------------------------------------------------- double avg_neighbors = 0; sw.interactions = count_all_interactions(sw.balls, sw.N, sw.interaction_distance, sw.len, sw.walls); // First, let us figure out what the max entropy point is. sw.initialize_max_entropy_and_translation_distance(); if (gaussian_fit) { sw.initialize_gaussian(10); } else if (flat_histogram) { { sw.initialize_gaussian(log(1e40)); const int state_of_max_entropy = sw.state_of_max_entropy; sw.initialize_max_entropy_and_translation_distance(); sw.state_of_max_entropy = state_of_max_entropy; } const double scale = log(10); double width; double range; do { width = sw.initialize_gaussian(scale); range = sw.state_of_max_interactions - sw.state_of_max_entropy; // Now shift to the max entropy state... const int state_of_max_entropy = sw.state_of_max_entropy; sw.initialize_max_entropy_and_translation_distance(); sw.state_of_max_entropy = state_of_max_entropy; printf("***\n"); printf("*** Gaussian has width %.1f compared to range %.0f (ratio %.2f)\n", width, range, width/range); printf("***\n"); } while (width < 0.25*range); } else if (fix_kT) { sw.initialize_canonical(fix_kT); } else if (wang_landau) { sw.initialize_wang_landau(wl_factor, wl_threshold, wl_cutoff); } else { for(long iteration = 1; iteration <= initialization_iterations + first_weight_update; iteration++) { // --------------------------------------------------------------- // Move each ball once // --------------------------------------------------------------- for(int i = 0; i < sw.N; i++) { move_one_ball(i, sw.balls, sw.N, sw.len, sw.walls, sw.neighbor_R, sw.translation_distance, sw.interaction_distance, sw.max_neighbors, sw.dr, &sw.moves, sw.interactions, sw.ln_energy_weights); sw.interactions += sw.moves.new_count - sw.moves.old_count; sw.energy_histogram[sw.interactions]++; if(walker_weights){ sw.walkers_total[sw.interactions]++; if(sw.interactions >= sw.walker_minus_threshold) sw.current_walker_plus = false; else if(sw.interactions <= sw.walker_plus_threshold) sw.current_walker_plus = true; if(sw.current_walker_plus) sw.walkers_plus[sw.interactions]++; } } assert(sw.interactions == count_all_interactions(sw.balls, sw.N, sw.interaction_distance, sw.len, sw.walls)); // --------------------------------------------------------------- // Update weights // --------------------------------------------------------------- if(!(no_weights || gaussian_fit)){ if(iteration == first_weight_update){ flat_hist(sw.energy_histogram, sw.ln_energy_weights, sw.energy_levels); weight_updates++; } else if((flat_histogram || walker_weights) && (iteration > first_weight_update) && ((iteration-first_weight_update) % int(first_weight_update*uipow(2,weight_updates)) == 0)){ printf("Weight update: %d.\n", int(uipow(2,weight_updates))); if (flat_histogram) flat_hist(sw.energy_histogram, sw.ln_energy_weights, sw.energy_levels); else if(walker_weights){ walker_hist(sw.energy_histogram, sw.ln_energy_weights, sw.energy_levels, sw.walkers_plus, sw.walkers_total, &sw.moves); } weight_updates++; if(test_weights) print_weights = true; } // for testing purposes; prints energy histogram and weight array if(print_weights){ char *headerinfo = new char[4096]; sprintf(headerinfo, "# cell dimensions: (%5.2f, %5.2f, %5.2f), walls: %i," " de_density: %g, de_g: %g\n# seed: %li, N: %i, R: %f," " well_width: %g, translation_distance: %g\n" "# initialization_iterations: %li, neighbor_scale: %g, dr: %g," " energy_levels: %i\n", sw.len[0], sw.len[1], sw.len[2], sw.walls, de_density, de_g, seed, sw.N, R, well_width, sw.translation_distance, initialization_iterations, neighbor_scale, sw.dr, sw.energy_levels); char *countinfo = new char[4096]; sprintf(countinfo, "# iteration: %li, working moves: %li, total moves: %li, " "acceptance rate: %g\n", iteration, sw.moves.working, sw.moves.total, double(sw.moves.working)/sw.moves.total); const char *testdir = "test"; char *w_fname = new char[1024]; char *e_fname = new char[1024]; mkdir(dir, 0777); // create save directory sprintf(w_fname, "%s/%s", dir, testdir); mkdir(w_fname, 0777); // create test directory sprintf(w_fname, "%s/%s/%s-w%02i.dat", dir, testdir, filename, weight_updates); sprintf(e_fname, "%s/%s/%s-E%02i.dat", dir, testdir, filename, weight_updates); FILE *w_out = fopen(w_fname, "w"); if (!w_out) { fprintf(stderr, "Unable to create %s!\n", w_fname); exit(1); } fprintf(w_out, "%s", headerinfo); fprintf(w_out, "%s", countinfo); fprintf(w_out, "\n# interactions value\n"); for(int i = 0; i < sw.energy_levels; i++) fprintf(w_out, "%i %f\n", i, sw.ln_energy_weights[i]); fclose(w_out); FILE *e_out = fopen((const char *)e_fname, "w"); fprintf(e_out, "%s", headerinfo); fprintf(e_out, "%s", countinfo); fprintf(e_out, "\n# interactions counts\n"); for(int i = 0; i < sw.energy_levels; i++) fprintf(e_out, "%i %ld\n",i,sw.energy_histogram[i]); fclose(e_out); delete[] headerinfo; delete[] countinfo; delete[] w_fname; delete[] e_fname; print_weights = false; } } // --------------------------------------------------------------- // Print out timing information if desired // --------------------------------------------------------------- if (totime > 0 && iteration % totime == 0) { char *iter = new char[1024]; sprintf(iter, "%i iterations", totime); took(iter); delete[] iter; printf("Iteration %li, acceptance rate of %g, translation_distance: %g.\n", iteration, (double)sw.moves.working/sw.moves.total, sw.translation_distance); printf("We've had %g updates per kilomove and %g informs per kilomoves, " "for %g informs per update.\n", 1000.0*sw.moves.updates/sw.moves.total, 1000.0*sw.moves.informs/sw.moves.total, (double)sw.moves.informs/sw.moves.updates); const long checks_without_tables = sw.moves.total*sw.N; int total_neighbors = 0; int most_neighbors = 0; for(int i = 0; i < sw.N; i++) { total_neighbors += sw.balls[i].num_neighbors; most_neighbors = max(sw.balls[i].num_neighbors, most_neighbors); } avg_neighbors = double(total_neighbors)/sw.N; const long checks_with_tables = sw.moves.total*avg_neighbors + sw.N*sw.moves.updates; printf("We've done about %.3g%% of the distance calculations we would " "have done without tables.\n", 100.0*checks_with_tables/checks_without_tables); printf("The max number of neighbors is %i, whereas the most we have is " "%i.\n", sw.max_neighbors, most_neighbors); printf("Neighbor scale is %g and avg. number of neighbors is %g.\n\n", neighbor_scale, avg_neighbors); fflush(stdout); } } } { // Now let's iterate to the point where we are at maximum // probability before we do teh real simulation. const double st = sw.state_of_max_entropy; sw.initialize_max_entropy_and_translation_distance(); sw.state_of_max_entropy = st; } took("Initialization"); // ---------------------------------------------------------------------------- // Generate info to put in save files // ---------------------------------------------------------------------------- mkdir(dir, 0777); // create save directory char *headerinfo = new char[4096]; sprintf(headerinfo, "# cell dimensions: (%5.2f, %5.2f, %5.2f), walls: %i," " de_density: %g, de_g: %g\n# seed: %li, N: %i, R: %f," " well_width: %g, translation_distance: %g\n" "# initialization_iterations: %li, neighbor_scale: %g, dr: %g," " energy_levels: %i\n", sw.len[0], sw.len[1], sw.len[2], sw.walls, de_density, de_g, seed, sw.N, R, well_width, sw.translation_distance, initialization_iterations, neighbor_scale, sw.dr, sw.energy_levels); char *e_fname = new char[1024]; sprintf(e_fname, "%s/%s-E.dat", dir, filename); char *w_fname = new char[1024]; sprintf(w_fname, "%s/%s-lnw.dat", dir, filename); char *density_fname = new char[1024]; sprintf(density_fname, "%s/%s-density-%i.dat", dir, filename, sw.N); char *g_fname = new char[1024]; sprintf(g_fname, "%s/%s-g.dat", dir, filename); // ---------------------------------------------------------------------------- // MAIN PROGRAM LOOP // ---------------------------------------------------------------------------- clock_t output_period = CLOCKS_PER_SEC; // start at outputting every minute // top out at one hour interval clock_t max_output_period = clock_t(CLOCKS_PER_SEC)*60*30; clock_t last_output = clock(); // when we last output data sw.moves.total = 0; sw.moves.working = 0; // Reset energy histogram for(int i = 0; i < sw.energy_levels; i++) sw.energy_histogram[i] = 0; for(long iteration = 1; iteration <= iterations; iteration++) { // --------------------------------------------------------------- // Move each ball once, add to energy histogram // --------------------------------------------------------------- for(int i = 0; i < sw.N; i++) { move_one_ball(i, sw.balls, sw.N, sw.len, sw.walls, sw.neighbor_R, sw.translation_distance, sw.interaction_distance, sw.max_neighbors, sw.dr, &sw.moves, sw.interactions, sw.ln_energy_weights); sw.interactions += sw.moves.new_count - sw.moves.old_count; sw.energy_histogram[sw.interactions]++; } assert(sw.interactions == count_all_interactions(sw.balls, sw.N, sw.interaction_distance, sw.len, sw.walls)); // --------------------------------------------------------------- // Add data to density and RDF histograms // --------------------------------------------------------------- // Density histogram if(sw.walls){ for(int i = 0; i < sw.N; i++){ density_histogram[sw.interactions] [int(floor(sw.balls[i].pos[wall_dim]/de_density))] ++; } } // RDF if(!sw.walls){ g_energy_histogram[sw.interactions]++; for(int i = 0; i < sw.N; i++){ for(int j = 0; j < sw.N; j++){ if(i != j){ const vector3d r = periodic_diff(sw.balls[i].pos, sw.balls[j].pos, sw.len, sw.walls); const int r_i = floor(r.norm()/de_g); if(r_i < g_bins) g_histogram[sw.interactions][r_i]++; } } } } // --------------------------------------------------------------- // Save to file // --------------------------------------------------------------- const clock_t now = clock(); if ((now - last_output > output_period) || iteration == iterations) { last_output = now; assert(last_output); if (output_period < max_output_period/2) output_period *= 2; else if (output_period < max_output_period) output_period = max_output_period; const double secs_done = double(now)/CLOCKS_PER_SEC; const int seconds = int(secs_done) % 60; const int minutes = int(secs_done / 60) % 60; const int hours = int(secs_done / 3600) % 24; const int days = int(secs_done / 86400); printf("Saving data after %i days, %02i:%02i:%02i, %li iterations " "complete.\n", days, hours, minutes, seconds, iteration); fflush(stdout); char *countinfo = new char[4096]; sprintf(countinfo, "# iteration: %li, working moves: %li, total moves: %li, " "acceptance rate: %g\n", iteration, sw.moves.working, sw.moves.total, double(sw.moves.working)/sw.moves.total); // Save energy histogram FILE *e_out = fopen((const char *)e_fname, "w"); fprintf(e_out, "%s", headerinfo); fprintf(e_out, "%s", countinfo); fprintf(e_out, "\n# interactions counts\n"); for(int i = 0; i < sw.energy_levels; i++) if(sw.energy_histogram[i] != 0) fprintf(e_out, "%i %ld\n",i,sw.energy_histogram[i]); fclose(e_out); // Save weights histogram FILE *w_out = fopen((const char *)w_fname, "w"); fprintf(w_out, "%s", headerinfo); fprintf(w_out, "%s", countinfo); fprintf(w_out, "\n# interactions ln(weight)\n"); for(int i = 0; i < sw.energy_levels; i++) if(sw.energy_histogram[i] != 0){ fprintf(w_out, "%i %g\n",i,sw.ln_energy_weights[i]); } fclose(w_out); // Save RDF if(!sw.walls){ FILE *g_out = fopen((const char *)g_fname, "w"); fprintf(g_out, "%s", headerinfo); fprintf(g_out, "%s", countinfo); fprintf(g_out, "\n# data table containing values of g"); fprintf(g_out, "\n# first column reserved for specifying energy level"); fprintf(g_out, "\n# column number rn (starting from the second column, " "counting from zero) corresponds to radius r given by " "r = (rn + 0.5) * de_g"); const double density = sw.N/sw.len[x]/sw.len[y]/sw.len[z]; const double total_vol = sw.len[x]*sw.len[y]*sw.len[z]; for(int i = 0; i < sw.energy_levels; i++){ if(g_histogram[i][g_bins-1] > 0){ // if we have RDF data at this energy fprintf(g_out, "\n%i",i); for(int r_i = 0; r_i < g_bins; r_i++) { const double probability = (double)g_histogram[i][r_i] / g_energy_histogram[i]; const double r = (r_i + 0.5) * de_g; const double shell_vol = 4.0/3.0*M_PI*(uipow(r+de_g/2, 3) - uipow(r-de_g/2, 3)); const double n2 = probability/total_vol/shell_vol; const double g = n2/sqr(density); fprintf(g_out, " %8.5f", g); } } } fclose(g_out); } // Saving density data if(sw.walls){ FILE *densityout = fopen((const char *)density_fname, "w"); fprintf(densityout, "%s", headerinfo); fprintf(densityout, "%s", countinfo); fprintf(densityout, "\n# data table containing densities in slabs " "(bins) of thickness de_density away from a wall"); fprintf(densityout, "\n# row number corresponds to energy level"); fprintf(densityout, "\n# column number dn (counting from zero) " "corresponds to distance d from wall given by " "d = (dn + 0.5) * de_density"); for(int i = 0; i < sw.energy_levels; i++){ fprintf(densityout, "\n"); for(int r_i = 0; r_i < density_bins; r_i++) { const double bin_density = (double)density_histogram[i][r_i] *sw.N/sw.energy_histogram[i]/bin_volume; fprintf(densityout, "%8.5f ", bin_density); } } fclose(densityout); } delete[] countinfo; } } // ---------------------------------------------------------------------------- // END OF MAIN PROGRAM LOOP // ---------------------------------------------------------------------------- delete[] sw.balls; delete[] sw.ln_energy_weights; delete[] sw.energy_histogram; delete[] g_histogram; delete[] density_histogram; delete[] headerinfo; return 0; }
int main(int argc, char *argv[]) { if (argc == 5) { if (sscanf(argv[1], "%lg", &xmax) != 1) { printf("Got bad x argument: %s\n", argv[1]); return 1; } if (sscanf(argv[2], "%lg", &ymax) != 1) { printf("Got bad y argument: %s\n", argv[2]); return 1; } if (sscanf(argv[3], "%lg", &zmax) != 1) { printf("Got bad z argument: %s\n", argv[3]); return 1; } if (sscanf(argv[4], "%lg", &N) != 1) { printf("Got bad N argument: %s\n", argv[4]); return 1; } using_default_box = false; printf("Box is %g x %g x %g hard sphere diameters, and it holds %g of them\n", xmax, ymax, zmax, N); } char *datname = (char *)malloc(1024); sprintf(datname, "papers/contact/figs/box-%02.0f,%02.0f,%02.0f-%02.0f-energy.dat", xmax, ymax, zmax, N); FILE *o = fopen(datname, "w"); const double myvolume = (xmax+2)*(ymax+2)*(zmax+2); const double meandensity = N/myvolume; Functional f = OfEffectivePotential(HS + IdealGas()); double mu = find_chemical_potential(f, 1, meandensity); f = OfEffectivePotential(HS + IdealGas() + ChemicalPotential(mu)); Lattice lat(Cartesian(xmax+3,0,0), Cartesian(0,ymax+3,0), Cartesian(0,0,zmax+3)); GridDescription gd(lat, 0.05); Grid potential(gd); Grid constraint(gd); constraint.Set(notinwall); took("Setting the constraint"); printf("xmax = %g\nymax = %g\nzmax = %g\nmeandensity=%g\n", xmax, ymax, zmax, meandensity); f = constrain(constraint, f); constraint.epsNativeSlice("papers/contact/figs/box-constraint.eps", Cartesian(0,ymax+4,0), Cartesian(0,0,zmax+4), Cartesian(0,-ymax/2-2,-zmax/2-2)); printf("Constraint has become a graph!\n"); potential = meandensity*constraint + 1e-4*meandensity*VectorXd::Ones(gd.NxNyNz); potential = -potential.cwise().log(); Minimizer min = Precision(1e-6, PreconditionedConjugateGradient(f, gd, 1, &potential, QuadraticLineMinimizer)); double mumax = mu, mumin = mu, dmu = 4.0/N; double Nnow = N_from_mu(&min, &potential, constraint, mu); const double fraccuracy = 1e-3; if (fabs(Nnow/N - 1) > fraccuracy) { if (Nnow > N) { while (Nnow > N) { mumin = mumax; mumax += dmu; dmu *= 2; Nnow = N_from_mu(&min, &potential, constraint, mumax); // Grid density(gd, EffectivePotentialToDensity()(1, gd, potential)); // density = EffectivePotentialToDensity()(1, gd, potential); // density.epsNativeSlice("papers/contact/figs/box.eps", // Cartesian(0,ymax+2,0), Cartesian(0,0,zmax+2), // Cartesian(0,-ymax/2-1,-zmax/2-1)); // density.epsNativeSlice("papers/contact/figs/box-diagonal.eps", // Cartesian(xmax+2,0,zmax+2), Cartesian(0,ymax+2,0), // Cartesian(-xmax/2-1,-ymax/2-1,-zmax/2-1)); printf("mumax %g gives N %g\n", mumax, Nnow); took("Finding N from mu"); } printf("mu is between %g and %g\n", mumin, mumax); } else { while (Nnow < N) { mumax = mumin; if (mumin > dmu) { mumin -= dmu; dmu *= 2; } else if (mumin > 0) { mumin = -mumin; } else { mumin *= 2; } Nnow = N_from_mu(&min, &potential, constraint, mumin); // density = EffectivePotentialToDensity()(1, gd, potential); // density.epsNativeSlice("papers/contact/figs/box.eps", // Cartesian(0,ymax+2,0), Cartesian(0,0,zmax+2), // Cartesian(0,-ymax/2-1,-zmax/2-1)); // density.epsNativeSlice("papers/contact/figs/box-diagonal.eps", // Cartesian(xmax+2,0,zmax+2), Cartesian(0,ymax+2,0), // Cartesian(-xmax/2-1,-ymax/2-1,-zmax/2-1)); printf("mumin %g gives N %g\n", mumin, Nnow); took("Finding N from mu"); } printf("mu is between %g and %g\n", mumin, mumax); } while (fabs(N/Nnow-1) > fraccuracy) { mu = 0.5*(mumin + mumax); Nnow = N_from_mu(&min, &potential, constraint, mu); // density = EffectivePotentialToDensity()(1, gd, potential); // density.epsNativeSlice("papers/contact/figs/box.eps", // Cartesian(0,ymax+2,0), Cartesian(0,0,zmax+2), // Cartesian(0,-ymax/2-1,-zmax/2-1)); // density.epsNativeSlice("papers/contact/figs/box-diagonal.eps", // Cartesian(xmax+2,0,zmax+2), Cartesian(0,ymax+2,0), // Cartesian(-xmax/2-1,-ymax/2-1,-zmax/2-1)); printf("Nnow is %g vs %g with mu %g\n", Nnow, N, mu); took("Finding N from mu"); if (Nnow > N) { mumin = mu; } else { mumax = mu; } } } printf("N final is %g (vs %g) with mu = %g\n", Nnow, N, mu); double energy = min.energy(); printf("Energy is %.15g\n", energy); Grid density(gd, EffectivePotentialToDensity()(1, gd, potential)); double mean_contact_density = ContactDensitySimplest(1.0).integral(1, density)/myvolume; fprintf(o, "%g\t%g\t%g\t%.15g\t%.15g\n", xmax, ymax, zmax, energy, mean_contact_density); Grid energy_density(gd, f(1, gd, potential)); Grid contact_density(gd, ContactDensitySimplest(1.0)(1, gd, density)); Grid n0(gd, ShellConvolve(1)(1, density)); Grid wu_contact_density(gd, FuWuContactDensity(1.0)(1, gd, density)); char *plotname = (char *)malloc(1024); sprintf(plotname, "papers/contact/figs/box-100c--%02.0f,%02.0f,%02.0f-%02.0f.dat", xmax, ymax, zmax, N); plot_grids_100_center(plotname, density, energy_density, contact_density); sprintf(plotname, "papers/contact/figs/box-100s--%02.0f,%02.0f,%02.0f-%02.0f.dat", xmax, ymax, zmax, N); plot_grids_100_side(plotname, density, energy_density, contact_density); sprintf(plotname, "papers/contact/figs/box-110c--%02.0f,%02.0f,%02.0f-%02.0f.dat", xmax, ymax, zmax, N); plot_grids_110(plotname, density, energy_density, contact_density); sprintf(plotname, "papers/contact/figs/box-x-%02.0f,%02.0f,%02.0f-%02.0f.dat", xmax, ymax, zmax, N); x_plot(plotname, density, energy_density, contact_density, wu_contact_density); free(plotname); density.epsNativeSlice("papers/contact/figs/box.eps", Cartesian(0,ymax+2,0), Cartesian(0,0,zmax+2), Cartesian(0,-ymax/2-1,-zmax/2-1)); density.epsNativeSlice("papers/contact/figs/box-diagonal.eps", Cartesian(xmax+2,0,zmax+2), Cartesian(0,ymax+2,0), Cartesian(-xmax/2-1,-ymax/2-1,-zmax/2-1)); took("Plotting stuff"); fclose(o); }
int main(int argc, const char *argv[]) { printf("Running %s version %s\n", argv[0], version_identifier()); for (int i=0; argv[i]; i++) { printf("%s ", argv[i]); } printf("\n"); took("Starting program"); // ---------------------------------------------------------------------------- // Define "Constants" -- set from arguments then unchanged // ---------------------------------------------------------------------------- // NOTE: debug can slow things down VERY much int debug = false; sw_simulation sw; sw.sticky_wall = 0; sw.len[0] = sw.len[1] = sw.len[2] = 1; sw.walls = 0; sw.N = 10; sw.translation_scale = 0.05; unsigned long int seed = 0; char *data_dir = new char[1024]; sprintf(data_dir, "free-energy-data"); char *filename = new char[1024]; sprintf(filename, "default_filename"); char *filename_suffix = new char[1024]; sprintf(filename_suffix, "default_filename_suffix"); long simulation_runs = 1000000; double acceptance_goal = .4; double R = 1; const double well_width = 1; double ff = 0.3; double ff_small = -1; bool force_cube=false; bool pack_and_save_cube=false; double neighbor_scale = 2; double de_g = 0.05; double max_rdf_radius = 10; int totime = 0; double scaling_factor = 1.0; int small_cell_check_period = (1 * sw.N * sw.N)/10; poptContext optCon; // ---------------------------------------------------------------------------- // Set values from parameters // ---------------------------------------------------------------------------- poptOption optionsTable[] = { {"N", '\0', POPT_ARG_INT, &sw.N, 0, "Number of balls to simulate", "INT"}, {"ff", '\0', POPT_ARG_DOUBLE, &ff, 0, "Filling fraction. If specified, the " "cell dimensions are adjusted accordingly without changing the shape of " "the cell."}, {"ff_small", '\0', POPT_ARG_DOUBLE, &ff_small, 0, "Small filling fraction. If specified, " "This sets the desired filling fraction of the shrunk cell. Otherwise it defaults to ff."}, {"force_cube", '\0', POPT_ARG_NONE, &force_cube, 0, "forces box to be a cube", "BOOLEAN"}, {"pack_and_save_cube", '\0', POPT_ARG_NONE, &pack_and_save_cube, 0, "packs cube, save positions, then returns", "BOOLEAN"}, {"walls", '\0', POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &sw.walls, 0, "Number of walled dimensions (dimension order: x,y,z)", "INT"}, {"runs", '\0', POPT_ARG_LONG | POPT_ARGFLAG_SHOW_DEFAULT, &simulation_runs, 0, "Number of \"runs\" for which to run the simulation", "INT"}, {"de_g", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &de_g, 0, "Resolution of distribution functions", "DOUBLE"}, {"max_rdf_radius", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &max_rdf_radius, 0, "Set maximum radius for RDF data collection", "DOUBLE"}, {"lenx", '\0', POPT_ARG_DOUBLE, &sw.len[x], 0, "Relative cell size in x dimension", "DOUBLE"}, {"leny", '\0', POPT_ARG_DOUBLE, &sw.len[y], 0, "Relative cell size in y dimension", "DOUBLE"}, {"lenz", '\0', POPT_ARG_DOUBLE, &sw.len[z], 0, "Relative cell size in z dimension", "DOUBLE"}, {"filename", '\0', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &filename, 0, "Base of output file names", "STRING"}, {"filename_suffix", '\0', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &filename_suffix, 0, "Output file name suffix", "STRING"}, {"data_dir", '\0', POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT, &data_dir, 0, "Directory in which to save data", "data_dir"}, {"neighbor_scale", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &neighbor_scale, 0, "Ratio of neighbor sphere radius to interaction scale " "times ball radius. Drastically reduces collision detections","DOUBLE"}, {"translation_scale", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &sw.translation_scale, 0, "Standard deviation for translations of balls, " "relative to ball radius", "DOUBLE"}, {"seed", '\0', POPT_ARG_INT | POPT_ARGFLAG_SHOW_DEFAULT, &seed, 0, "Seed for the random number generator", "INT"}, {"acceptance_goal", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &acceptance_goal, 0, "Goal to set the acceptance rate", "DOUBLE"}, {"time", '\0', POPT_ARG_INT, &totime, 0, "Timing of display information (seconds)", "INT"}, {"R", '\0', POPT_ARG_DOUBLE | POPT_ARGFLAG_SHOW_DEFAULT, &R, 0, "Ball radius (for testing purposes; should always be 1)", "DOUBLE"}, {"debug", '\0', POPT_ARG_NONE, &debug, 0, "Debug mode", "BOOLEAN"}, {"sf", '\0', POPT_ARG_DOUBLE, &scaling_factor, 0, "Factor by which to scale the small cell", "DOUBLE"}, {"sc_period", '\0', POPT_ARG_INT, &small_cell_check_period, 0, "Check the small cell every P iterations", "INT"}, POPT_AUTOHELP POPT_TABLEEND }; optCon = poptGetContext(NULL, argc, argv, optionsTable, 0); poptSetOtherOptionHelp(optCon, "[OPTION...]\nNumber of balls and filling " "fraction or cell dimensions are required arguments."); int c = 0; // go through arguments, set them based on optionsTable while((c = poptGetNextOpt(optCon)) >= 0); if (c < -1) { fprintf(stderr, "\n%s: %s\n", poptBadOption(optCon, 0), poptStrerror(c)); return 1; } poptFreeContext(optCon); // ---------------------------------------------------------------------------- // Verify we have reasonable arguments and set secondary parameters // ---------------------------------------------------------------------------- if(sw.walls >= 2){ printf("Code cannot currently handle walls in more than one dimension.\n"); return 254; } if(sw.walls > 3){ printf("You cannot have walls in more than three dimensions.\n"); return 254; } if(well_width < 1){ printf("Interaction scale should be greater than (or equal to) 1.\n"); return 254; } if(ff_small != -1 && scaling_factor != 1.0){ printf("You can't specify both the small filling fraction and the scaling factor."); return 1; } if (ff != 0) { // The user specified a filling fraction, so we must make it so! const double volume = 4*M_PI/3*R*R*R*sw.N/ff; const double min_cell_width = 2*sqrt(2)*R; // minimum cell width const int numcells = (sw.N+3)/4; // number of unit cells we need const int max_cubic_width = pow(volume/min_cell_width/min_cell_width/min_cell_width, 1.0/3); if (max_cubic_width*max_cubic_width*max_cubic_width >= numcells) { // We can get away with a cubic cell, so let's do so. Cubic // cells are nice and comfortable! sw.len[x] = sw.len[y] = sw.len[z] = pow(volume, 1.0/3); } else { printf("N = %d\n", sw.N); printf("ff = %g\n", ff); printf("min_cell_width = %g\n", min_cell_width); printf("volume**1/3 = %g\n", pow(volume, 1.0/3)); printf("max_cubic_width**3 = %d, numcells = %d\n", max_cubic_width*max_cubic_width*max_cubic_width, numcells); // A cubic cell won't work with our initialization routine, so // let's go with a lopsided cell that should give us something // that will work. int xcells = int( pow(numcells, 1.0/3) ); int cellsleft = (numcells + xcells - 1)/xcells; int ycells = int( sqrt(cellsleft) ); int zcells = (cellsleft + ycells - 1)/ycells; // The above should give a zcells that is largest, followed by // ycells and then xcells. Thus we make the lenz just small // enough to fit these cells, and so on, to make the cell as // close to cubic as possible. sw.len[z] = zcells*min_cell_width; if (xcells == ycells) { sw.len[x] = sw.len[y] = sqrt(volume/sw.len[z]); } else { sw.len[y] = min_cell_width*ycells; sw.len[x] = volume/sw.len[y]/sw.len[z]; } printf("Using lopsided %d x %d x %d cell (total goal %d)\n", xcells, ycells, zcells, numcells); } } // if the user didn't specifiy a small filling fraction, then we should get it. if(ff_small == -1){ ff_small = (4*M_PI/3*R*R*R*sw.N)/ (sw.len[x]*sw.len[y]*sw.len[z]*scaling_factor*scaling_factor*scaling_factor); } // if they did, then we need to get the scale factor else{ scaling_factor = std::cbrt(ff/ff_small); } printf("\nSetting cell dimensions to (%g, %g, %g).\n", sw.len[x], sw.len[y], sw.len[z]); printf("\nFilling fraction of small cell is %g", ff_small); if (sw.N <= 0 || simulation_runs < 0 || R <= 0 || neighbor_scale <= 0 || sw.translation_scale < 0 || sw.len[x] < 0 || sw.len[y] < 0 || sw.len[z] < 0) { fprintf(stderr, "\nAll parameters must be positive.\n"); return 1; } const double eta = (double)sw.N*4.0/3.0*M_PI*R*R*R/(sw.len[x]*sw.len[y]*sw.len[z]); if (eta > 1) { fprintf(stderr, "\nYou're trying to cram too many balls into the cell. " "They will never fit. Filling fraction: %g\n", eta); return 7; } // If a filename was not selected, make a default if (strcmp(filename, "default_filename") == 0) { char *wall_tag = new char[100]; if(sw.walls == 0) sprintf(wall_tag,"periodic"); else if(sw.walls == 1) sprintf(wall_tag,"wall"); else if(sw.walls == 2) sprintf(wall_tag,"tube"); else if(sw.walls == 3) sprintf(wall_tag,"box"); sprintf(filename, "%s-ww%04.2f-ff%04.2f-N%i-sf%f", wall_tag, well_width, eta, sw.N, scaling_factor); printf("\nUsing default file name: "); delete[] wall_tag; } else printf("\nUsing given file name: "); // If a filename suffix was specified, add it if (strcmp(filename_suffix, "default_filename_suffix") != 0) sprintf(filename, "%s-%s", filename, filename_suffix); printf("%s\n",filename); printf("------------------------------------------------------------------\n"); printf("Running %s with parameters:\n", argv[0]); for(int i = 1; i < argc; i++) { if(argv[i][0] == '-') printf("\n"); printf("%s ", argv[i]); } printf("\nUsing scaling factor of %f", scaling_factor); printf("\n"); if (totime > 0) printf("Timing information will be displayed.\n"); if (debug) printf("DEBUG MODE IS ENABLED!\n"); else printf("Debug mode disabled\n"); printf("------------------------------------------------------------------\n\n"); // ---------------------------------------------------------------------------- // Define sw_simulation variables // ---------------------------------------------------------------------------- sw.iteration = 0; // start at zeroeth iteration sw.max_entropy_state = 0; sw.min_energy_state = 0; sw.energy = 0; sw.min_important_energy = 0; // translation distance should scale with ball radius sw.translation_scale *= R; // neighbor radius should scale with radius and interaction scale sw.neighbor_R = neighbor_scale*R*well_width; // Find the upper limit to the maximum number of neighbors a ball could have sw.max_neighbors = max_balls_within(2+neighbor_scale*well_width); // Energy histogram and weights sw.interaction_distance = 2*R*well_width; sw.energy_levels = 1; // hard spheres can only have one energy! sw.energy_histogram = new long[sw.energy_levels](); sw.ln_energy_weights = new double[sw.energy_levels](); // Observed and sampled energies sw.pessimistic_observation = new bool[sw.energy_levels](); sw.pessimistic_samples = new long[sw.energy_levels](); sw.optimistic_samples = new long[sw.energy_levels](); // Transitions from one energy to another sw.biggest_energy_transition = max_balls_within(sw.interaction_distance); sw.transitions_table = new long[sw.energy_levels*(2*sw.biggest_energy_transition+1)](); // Walker histograms sw.walkers_up = new long[sw.energy_levels](); printf("memory use estimate = %.2g G\n\n", 8*double(6*sw.energy_levels)/1024/1024/1024); sw.balls = new ball[sw.N]; if(totime < 0) totime = 10*sw.N; // Initialize the random number generator with our seed random::seed(seed); // ---------------------------------------------------------------------------- // Set up the initial grid of balls // ---------------------------------------------------------------------------- for(int i = 0; i < sw.N; i++) // initialize ball radii sw.balls[i].R = R; //########################### pack and save #################### if(pack_and_save_cube==true){ INITBOX *box=load_cube(data_dir); if(box!=NULL && box->numAtoms<sw.N) {delete box; box=NULL;} if(box!=NULL){//---------loaded baseAtoms up to max of sw.N printf("loading from baseAtoms.txt\n"); for(int count=0;count<(100*box->numAtoms);count++){ //mixes indices so the culled atoms are random //atoms are only culled from the end... int n1=floor(random::ran()*(box->numAtoms)); int n2=floor(random::ran()*(box->numAtoms)); double xTemp=box->list[n1].x; double yTemp=box->list[n1].y; double zTemp=box->list[n1].z; box->list[n1].x=box->list[n2].x; box->list[n1].y=box->list[n2].y; box->list[n1].z=box->list[n2].z; box->list[n2].x=xTemp; box->list[n2].y=yTemp; box->list[n2].z=zTemp; } //box2 is used to cull atoms from the end (if needed) //box2 is simulated to mix the atoms up after culling INITBOX *box2=new INITBOX(box->lx); for(int i=0;i<sw.N;i++) box2->addAtom(box->list[i].x,box->list[i].y,box->list[i].z); delete box; box2->temperature=1000.0; for(int i=0;i<100;i++) box2->simulate(sw.N*100);//mix box sw.len[x] = sw.len[y] = sw.len[z] = box2->lx; for(int i=0;i<sw.N;i++) { sw.balls[i].pos=vector3d(box2->list[i].x,box2->list[i].y,box2->list[i].z); } delete box2; } else{//if no baseAtoms.txt then try to pack the box if(ff==0){printf("must initialize using --ff\n"); return 254;} printf("building baseAtoms.txt\n"); const double volume = 4*M_PI/3*R*R*R*sw.N/ff; sw.len[x] = sw.len[y] = sw.len[z] = pow(volume, 1.0/3); if(pack_cube(sw)==false) {printf("could not fill box\n"); return 254;} }//done initializing positions mkdir(data_dir, 0777); // create save directory char *posData = new char[4096]; sprintf(posData,"%s/baseAtoms.txt",data_dir); FILE *pos_out = fopen((const char *)posData, "w"); sprintf(posData,"L = %g\nN = %i\n",sw.len[x],sw.N); fprintf(pos_out,"%s",posData); for(int i=0;i<sw.N;i++){ sprintf(posData,"%g %g %g", sw.balls[i].pos.x,sw.balls[i].pos.y,sw.balls[i].pos.z); fprintf(pos_out,"%s",posData); if(i+1<sw.N) fprintf(pos_out,"\n"); } fclose(pos_out); delete[] posData; took("Placement"); return 0; } //########################### DONE pack and save ################# if(force_cube==true){//try to load baseAtoms.txt if(ff==0){printf("must initialize using --ff\n"); return 254;} printf("attempting to load baseAtoms.txt\n"); const double volume = 4*M_PI/3*R*R*R*sw.N/ff; sw.len[x] = sw.len[y] = sw.len[z] = pow(volume, 1.0/3); INITBOX *box=load_cube(data_dir); if(box==NULL) { printf("requires initialization on the smallest box\nuse the --pack_and_save --ff -N flags\n"); return 254; } if(box->numAtoms<sw.N){ printf("boxAtoms.txt contains less atoms than expected\n"); delete box; return 254; } if(box->lx>sw.len[x]){ printf("baseAtoms must be in a box smaller than current simulation\n"); delete box; return 254; } box->temperature=1000.0; for(int i=0;i<100;i++) box->simulate(sw.N*100);//mix box double scaleFactor=sw.len[x]/box->lx; for(int i=0;i<sw.N;i++){ double x=(box->list[i].x)*scaleFactor; double y=(box->list[i].y)*scaleFactor; double z=(box->list[i].z)*scaleFactor; sw.balls[i].pos=vector3d(x,y,z); } delete box; } else { // Balls will be initially placed on a face centered cubic (fcc) grid // Note that the unit cells need not be actually "cubic", but the fcc grid will // be stretched to cell dimensions const double min_cell_width = 2*sqrt(2)*R; // minimum cell width const int spots_per_cell = 4; // spots in each fcc periodic unit cell int cells[3]; // array to contain number of cells in x, y, and z dimensions for(int i = 0; i < 3; i++){ cells[i] = int(sw.len[i]/min_cell_width); // max number of cells that will fit } // It is usefull to know our cell dimensions double cell_width[3]; for(int i = 0; i < 3; i++) cell_width[i] = sw.len[i]/cells[i]; // If we made our cells to small, return with error for(int i = 0; i < 3; i++){ if(cell_width[i] < min_cell_width){ printf("Placement cell size too small: (%g, %g, %g) coming from (%g, %g, %g)\n", cell_width[0],cell_width[1],cell_width[2], sw.len[0], sw.len[1], sw.len[2]); printf("Minimum allowed placement cell width: %g\n",min_cell_width); printf("Total simulation cell dimensions: (%g, %g, %g)\n", sw.len[0],sw.len[1],sw.len[2]); printf("Fixing the chosen ball number, filling fractoin, and relative\n" " simulation cell dimensions simultaneously does not appear to be possible\n"); return 176; } } // Define ball positions relative to cell position vector3d* offset = new vector3d[4](); offset[x] = vector3d(0,cell_width[y],cell_width[z])/2; offset[y] = vector3d(cell_width[x],0,cell_width[z])/2; offset[z] = vector3d(cell_width[x],cell_width[y],0)/2; // Reserve some spots at random to be vacant const int total_spots = spots_per_cell*cells[x]*cells[y]*cells[z]; bool *spot_reserved = new bool[total_spots](); int p; // Index of reserved spot for(int i = 0; i < total_spots-sw.N; i++) { p = floor(random::ran()*total_spots); // Pick a random spot index if(spot_reserved[p] == false) // If it's not already reserved, reserve it spot_reserved[p] = true; else // Otherwise redo this index (look for a new spot) i--; } // Place all balls in remaining spots int b = 0; for(int i = 0; i < cells[x]; i++) { for(int j = 0; j < cells[y]; j++) { for(int k = 0; k < cells[z]; k++) { for(int l = 0; l < 4; l++) { if(!spot_reserved[i*(4*cells[z]*cells[y])+j*(4*cells[z])+k*4+l]) { sw.balls[b].pos = vector3d(i*cell_width[x],j*cell_width[y], k*cell_width[z]) + offset[l]; b++; } } } } } delete[] offset; delete[] spot_reserved; } took("Placement"); // ---------------------------------------------------------------------------- // Print info about the initial configuration for troubleshooting // ---------------------------------------------------------------------------- { int most_neighbors = initialize_neighbor_tables(sw.balls, sw.N, sw.neighbor_R, sw.max_neighbors, sw.len, sw.walls); if (most_neighbors < 0) { fprintf(stderr, "The guess of %i max neighbors was too low. Exiting.\n", sw.max_neighbors); return 1; } printf("Neighbor tables initialized.\n"); printf("The most neighbors is %i, whereas the max allowed is %i.\n", most_neighbors, sw.max_neighbors); } // ---------------------------------------------------------------------------- // Make sure initial placement is valid // ---------------------------------------------------------------------------- for(int i = 0; i < sw.N; i++) { for(int j = 0; j < i; j++) { if (overlap(sw.balls[i], sw.balls[j], sw.len, sw.walls)) { print_bad(sw.balls, sw.N, sw.len, sw.walls); printf("Error in initial placement: balls are overlapping.\n"); return 253; } } } fflush(stdout); // ---------------------------------------------------------------------------- // Initialization of cell // ---------------------------------------------------------------------------- sw.initialize_translation_distance(); // -------------------------------------------------------------------------- // end initilization routine. // -------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Generate info to put in save files // ---------------------------------------------------------------------------- mkdir(data_dir, 0777); // create save directory char *headerinfo = new char[4096]; sprintf(headerinfo, "# version: %s\n" "# cell dimensions: (%g, %g, %g)\n" "# walls: %i\n" "# de_g: %g\n" "# seed: %li\n" "# N: %i\n" "# R: %f\n" "# well_width: %g\n" "# translation_scale: %g\n" "# neighbor_scale: %g\n" "# scaling factor: %g\n" "# ff: %g\n" "# ff_small: %g\n", version_identifier(), sw.len[0], sw.len[1], sw.len[2], sw.walls, de_g, seed, sw.N, R, well_width, sw.translation_scale, neighbor_scale, scaling_factor, ff, ff_small); char *g_fname = new char[1024]; sprintf(g_fname, "%s/%s.dat", data_dir, filename); took("Initialization"); // ---------------------------------------------------------------------------- // MAIN PROGRAM LOOP // ---------------------------------------------------------------------------- sw.moves.total = 0; sw.moves.working = 0; sw.iteration = 0; // tracking for free energy int current_valid_run = 0; int current_failed_run = 0; int longest_valid_run = 0; int longest_failed_run = 0; int total_checks_of_small_cell = 0; int total_valid_small_checks = 0; int total_failed_small_checks = 0; int valid_runs = 0; int failed_runs = 0; double average_valid_run = 0; double average_failed_run = 0; // Reset energy histogram and sample counts for(int i = 0; i < sw.energy_levels; i++){ sw.energy_histogram[i] = 0; sw.pessimistic_samples[i] = 0; sw.optimistic_samples[i] = 0; } do { // --------------------------------------------------------------- // Move each ball once, add to energy histogram // --------------------------------------------------------------- for(int i = 0; i < sw.N; i++){ sw.move_a_ball(); } // just hacking stuff in to see what works // do the small bit every 100 n^2 iterations for now if (sw.iteration % small_cell_check_period == 0) { total_checks_of_small_cell++; if(overlap_in_small_cell(sw, scaling_factor)){ total_failed_small_checks++; if (current_failed_run == 0){ // then valid run just ended so record it valid_runs++; if(current_valid_run > longest_valid_run) longest_valid_run = current_valid_run; average_valid_run = average_valid_run + (current_valid_run - average_valid_run)/valid_runs; current_valid_run = 0; } current_failed_run++; if(debug){printf("%i - false\n", current_failed_run);} } else{ total_valid_small_checks++; if (current_valid_run == 0){ // then failed run just ended so record it failed_runs++; if(current_failed_run > longest_failed_run) longest_failed_run = current_failed_run; average_failed_run = average_failed_run + (current_failed_run - average_failed_run)/failed_runs; current_failed_run = 0; } current_valid_run++; if(debug){printf("%i - true\n", current_valid_run);} } } // --------------------------------------------------------------- // Save to file // --------------------------------------------------------------- if (time_to_save() || valid_runs == simulation_runs) { const clock_t now = clock(); const double secs_done = double(now)/CLOCKS_PER_SEC; const int seconds = int(secs_done) % 60; const int minutes = int(secs_done / 60) % 60; const int hours = int(secs_done / 3600) % 24; const int days = int(secs_done / 86400); const long percent_done = 100*valid_runs/simulation_runs; printf("Saving data after %i days, %02i:%02i:%02i, %li iterations (%ld%%) " "complete.\n", days, hours, minutes, seconds, sw.iteration, percent_done); fflush(stdout); char *countinfo = new char[4096]; sprintf(countinfo, "# iterations: %li\n" "# working moves: %li\n" "# total moves: %li\n" "# acceptance rate: %g\n" "# longest failed run: %i\n" "# longest valid run: %i\n" "# total checks of small cell: %i\n" "# total failed small checks: %i\n" "# total valid small checks: %i\n" "# valid runs: %i\n" "# failed runs: %i\n" "# average valid run: %g\n" "# average failed run: %g\n\n", sw.iteration, sw.moves.working, sw.moves.total, double(sw.moves.working)/sw.moves.total, longest_failed_run, longest_valid_run, total_checks_of_small_cell, total_failed_small_checks, total_valid_small_checks, valid_runs, failed_runs, average_valid_run, average_failed_run); // Save data if(!sw.walls){ FILE *g_out = fopen((const char *)g_fname, "w"); fprintf(g_out, "%s", headerinfo); fprintf(g_out, "%s", countinfo); fclose(g_out); } delete[] countinfo; } } while (valid_runs < simulation_runs); // ---------------------------------------------------------------------------- // END OF MAIN PROGRAM LOOP // ---------------------------------------------------------------------------- for (int i=0; i<sw.N; i++) { delete[] sw.balls[i].neighbors; } delete[] sw.balls; delete[] sw.ln_energy_weights; delete[] sw.energy_histogram; delete[] sw.transitions_table; delete[] sw.walkers_up; delete[] sw.pessimistic_observation; delete[] sw.pessimistic_samples; delete[] sw.optimistic_samples; delete[] headerinfo; delete[] g_fname; delete[] data_dir; delete[] filename; delete[] filename_suffix; return 0; }