Example #1
0
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
}
Example #2
0
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;
}
Example #3
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;
}
Example #4
0
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;
}
Example #6
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);
}
Example #7
0
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;
}
Example #8
0
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;
}
Example #9
0
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
}
Example #10
0
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;
}
Example #11
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;
}
Example #12
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;
}