Beispiel #1
0
int main(){
    cout << "Float size: " << sizeof(flt) << " epsilon: " << std::numeric_limits<flt>::epsilon() << "\n";
    assert(std::numeric_limits<flt>::epsilon() < force_max*10);

    // new random seed each time, for velocities and placement
    seed();
    
    // Volume of the spheres
    // Each sphere is σ^d * π/(2d), i.e. π σ^2/4 for 2D, π σ^3/6 for 3D
    // Total volume of the spheres takes a constant N out front
    const flt Vs = (Ns * pow(sigma, NDIM) + Nl * pow(sigmal, NDIM)) * M_PI_2 / NDIM;
    
    // Initial length of the box is [(volume of spheres) / phi0]^(1/d)
    const flt L = pow(Vs / phi0, OVERNDIM);
    cout << "Using L = " << L << "\n";
    
    // Create the bounding box (sides of length L), and a "vector" of Natoms atoms
    boost::shared_ptr<OriginBox> obox(new OriginBox(L));

    // Create a vector of the masses of the atoms
    // We just use all mass 1, because this is a packing
    boost::shared_ptr<AtomVec> atomptr(new AtomVec(Nl + Ns, 1.0));
    AtomVec & atoms = *atomptr;
    
    // Harmonic Interaction
    // Its called "Repulsion" for historical reasons
    // It takes a pointer to the box, a pointer to the atoms, and a "skin depth" for the NeighborList
    boost::shared_ptr<NListed<EpsSigExpAtom, RepulsionPair> >
        hertzian(new NListed<EpsSigExpAtom, RepulsionPair>(obox, atomptr, 0.1*sigma));
    boost::shared_ptr<NeighborList> nl = hertzian->neighbor_list();
    // ^ this is the Interaction
    
    // Note that NListed is a class template; its an Interaction that
    // takes various structs as template parameters, and turns them into
    // a neighbor Interaction
    // See interaction.hpp for a whole bunch of them
    // Also note that the NeighborList is not the same as the
    // "neighborlisted" Interaction; multiple interactions can use the
    // same NeighborList
    
    // Now we run through all the atoms, set their positions / velocities,
    // and add them to the Repulsion Interaction (i.e., to the neighbor list)
    for (uint i=0; i < atoms.size(); i++){
        atoms[i].x = obox->rand_loc(); // random location in the box
        atoms[i].v = Vec::Zero(); // A zero-vector
        atoms[i].f = Vec::Zero();
        atoms[i].a = Vec::Zero();

        flt sig = i < Ns ? sigma : sigmal;
        
        // Add it to the Repulsion potential
        hertzian->add(EpsSigExpAtom(atoms.get_id(i), epsilon, sig, 2));
        //                                                          ^ exponent for the harmonic Interaction
    }

    // force an update the NeighborList, so we can get an accurate energy
    nl->update_list(true);

    cout << "Starting. Neighborlist contains " << nl->numpairs() << " / " <<
        (atoms.size()*(atoms.size()-1))/2 << " pairs\n";
    
    //Now we make our "Collection"
    CollectionNLCG collec = CollectionNLCG(obox, atomptr, dt, P0);
    
    // This is very important! Otherwise the NeighborList won't update!
    collec.add_tracker(nl);
    // And add the Interaction
    collec.add_interaction(hertzian);
    
    writefile(atoms, *obox);
    
    //Print out total energy, kinetic_energy energy, and potential energy
    cout << "H: " << collec.hamiltonian() << " K: " << collec.kinetic_energy()
        << " U: " << hertzian->energy(*obox) << " phi: " << (Vs/obox->V()) << "\n";
    
    // Run the simulation! And every _ steps, write a frame to the .xyz
    // file and print out the energies again
    uint i = 0;
    for(flt curP=startP; curP>P0; curP/=10){
        cout << "P: " << curP << "\n";
        collec.set_pressure_goal(curP);
        while (true) {
            for(uint j=0; j<1000; j++){
                collec.timestep();
            }
            i++;
            writefile(atoms, *obox);

            flt pdiff = collec.pressure() / curP - 1.0;
            flt force_err = 0;

            for(uint k=0; k<atoms.size(); k++){
                flt fmag = atoms[k].f.norm();
                if(fmag > force_err) force_err = fmag;
            }

            cout.precision(sizeof(flt));
            cout << i << " H: " << collec.hamiltonian() << " K: " << collec.kinetic_energy() 
                << " U: " << hertzian->energy(*obox) << " phi: " << (Vs/obox->V()) << "\n";
            cout.precision(6);
            cout << "        Pdiff: " << pdiff << " force_err: " << force_err << "\n";

            if(abs(pdiff) < P_frac and force_err < force_max){
                cout << "Done!\n";
                break;
            }
        }
    }
};
Beispiel #2
0
int main(){
    // new random seed each time, for velocities and placement
    seed();
    
    const flt Vs = Natoms * pow(sigma, NDIM) * M_PI_2 / NDIM;
    const flt L = pow(Vs / phi, OVERNDIM);
    cout << "Using L = " << L << "\n";
    
    // Create the bounding box (sides of length L), and a "vector" of Natoms atoms
    boost::shared_ptr<OriginBox> obox(new OriginBox(L));
    boost::shared_ptr<AtomVec> atomptr(new AtomVec(Natoms, 1.0));
    AtomVec & atoms = *atomptr;
    
    // LJ Interaction
    // We'll cut it off at 2.5σ, and have a NeighborList out to 1.4 times that
    boost::shared_ptr<NListed<EpsSigCutAtom, LennardJonesCutPair> > 
        LJ(new NListed<EpsSigCutAtom, LennardJonesCutPair>(obox, atomptr, 0.4*(sigcut*sigma)));
    boost::shared_ptr<NeighborList> nl = LJ->neighbor_list();
    // ^ this is the Interaction
    
    // Note that NListed is a class template; its an Interaction that
    // takes various structs as template parameters, and turns them into 
    // a neighbor Interaction
    // See Interaction.hpp for a whole bunch of them
    // Also note that the NeighborList is not the same as the
    // "neighborlisted" Interaction; multiple interactions can use the
    // same NeighborList
    
    // Now we run through all the atoms, set their positions / velocities,
    // and add them to the LJ Interaction (i.e., to the neighbor list)
    for (uint i=0; i < atoms.size(); i++){
        if((i+1) % 50 == 0) cout << (Natoms - (i+1)) / 50 << ", "; cout.flush();
        
        // we track energy to see if things are overlapping
        flt E0 = LJ->energy(*obox);
        atoms[i].x = obox->rand_loc(); // random location in the box
        atoms[i].v = rand_vec(); // from a Gaussian
        atoms[i].f = Vec::Zero();
        atoms[i].a = Vec::Zero();
        
        // Add it to the Lennard-Jones potential
        LJ->add(EpsSigCutAtom(atoms.get_id(i), epsilon, sigma, sigcut));
        // force an update the NeighborList, so we can get an accurate energy
        nl->update_list(true);
        // If we're overlapping too much, try a new location
        while(LJ->energy(*obox) > E0 + epsilon/2.0){
            atoms[i].x = obox->rand_loc(); // random location in the box
            nl->update_list(true);
        }
    }

    cout << "Starting. Neighborlist contains " << nl->numpairs() << " / " <<
        (atoms.size()*(atoms.size()-1))/2 << " pairs.\n";
    
    //Now we make our "Collection"
    CollectionVerlet collec = CollectionVerlet(boost::static_pointer_cast<Box>(obox), atomptr, dt);
    
    // This is very important! Otherwise the NeighborList won't update!
    collec.add_tracker(nl);
    // And add the Interaction
    collec.add_interaction(LJ);
    
    // subtract off center of mass velocity, and set a total energy
    collec.reset_com_velocity();
    collec.scale_velocities_to_energy(Natoms / 4.0);
    
    // We'll put the energies to stdout and the coordinates to a new file.
    // VMD is good for 3D visualization purposes, and it can read .xyz files
    // see 'writefile' function
    
    ofstream outfile;
    outfile.open("LJatoms.xyz", ios::out);
    writefile(outfile, atoms, *obox);
    
    //Print out total energy, kinetic_energy energy, and potential energy
    cout << "E: " << collec.energy() << " K: " << collec.kinetic_energy() 
        << " U: " << LJ->energy(*obox) << "\n";
    // Run the simulation! And every _ steps, write a frame to the .xyz
    // file and print out the energies again
    for(uint i=0; i<500; i++){
        for(uint j=0; j<1000; j++){
            collec.timestep();
        }
        writefile(outfile, atoms, *obox);
        cout << (500-i) << " E: " << collec.energy() << " K: " << collec.kinetic_energy() 
            << " U: " << LJ->energy(*obox) << "\n";
    }
    
    // Unnecessary extra:
    // Write a "tcl" file with the box boundaries
    // the "tcl" file is made specifically for VMD
    ofstream pbcfile;
    pbcfile.open("LJatoms-pbc.tcl", ios::out);
    pbcfile << "set cell [pbc set {";
    for(uint j=0; j<NDIM; j++){
        pbcfile << obox->box_shape()[j] << " ";
    }
    pbcfile << "} -all];\n";
    pbcfile << "pbc box -toggle -center origin -color red;\n";
    // Now you should be able to run "vmd -e LJatoms-pbc.tcl LJatoms.xyz"
    // and it will show you the movie and also the bounding box
    // if you have .vmdrc in that same directory, you should also be able
    // to toggle the box with the "b" button
    
    cout << "Done. Neighborlist contains " << nl->numpairs() << " / " <<
        (atoms.size()*(atoms.size()-1))/2 << " pairs.\n";
};
Beispiel #3
0
	obox obox::transform(const mtx& m) const
	{
		return obox(x1y1z1 * m, x2y1z1 * m, x1y2z1 * m, x2y2z1 * m, x1y1z2 * m, x1y1z2 * m, x1y2z2 * m, x2y2z2 * m);
	}