def test_cbmc_setters(self, methane_oplsaa): moveset = mc.MoveSet("gemc", [methane_oplsaa]) with pytest.raises(TypeError, match=r"must be of type int"): moveset.cbmc_n_insert = 12.2 with pytest.raises(ValueError, match=r"must be greater than zero"): moveset.cbmc_n_insert = -2 moveset.cbmc_n_insert = 20 assert moveset.cbmc_n_insert == 20 with pytest.raises(TypeError, match=r"must be of type int"): moveset.cbmc_n_dihed = 12.2 with pytest.raises(ValueError, match=r"must be greater than zero"): moveset.cbmc_n_dihed = -2 moveset.cbmc_n_dihed = 20 assert moveset.cbmc_n_dihed == 20 with pytest.raises(TypeError, match=r"unyt_array"): moveset.cbmc_rcut = [3.0 * u.angstrom] with pytest.raises(TypeError, match=r"unyt_array"): moveset.cbmc_rcut = 3.0 with pytest.raises(ValueError, match=r"less than zero"): moveset.cbmc_rcut = [3.0 * u.angstrom, -3.0 * u.angstrom] with pytest.raises(IterableUnitCoercionError): moveset.cbmc_rcut = [0.4 * u.nm, 8.0 * u.angstrom] moveset.cbmc_rcut = 5.0 * u.angstrom assert len(moveset.cbmc_rcut) == 2 assert moveset.cbmc_rcut[0].to_value("angstrom") == 5.0 assert moveset.cbmc_rcut[1].to_value("angstrom") == 5.0 moveset = mc.MoveSet("nvt", [methane_oplsaa]) moveset.cbmc_rcut = 7.0 * u.angstrom assert len(moveset.cbmc_rcut) == 1 assert moveset.cbmc_rcut[0].to_value("angstrom") == 7.0
def test_mismatch_boxes(self, methane_oplsaa, box): with pytest.raises(ValueError, match=r"requires 1 simulation"): system = mc.System([box, box], [methane_oplsaa], mols_to_add=[[10], [0]]) moveset = mc.MoveSet("nvt", [methane_oplsaa]) mc.run(system, moveset, 300.0, "equilibration", 500) with pytest.raises(ValueError, match=r"requires 2 simulation"): system = mc.System([box], [methane_oplsaa], mols_to_add=[[10]]) moveset = mc.MoveSet("gemc", [methane_oplsaa]) mc.run(system, moveset, 300.0, "equilibration", 500)
def test_corrupt_topologies(self, methane_oplsaa, box): with pytest.raises(TypeError, match=r"corrupted"): system = mc.System([box], [methane_oplsaa], mols_to_add=[[10]]) moveset = mc.MoveSet("nvt", [methane_oplsaa]) system._species_topologies = methane_oplsaa mc.run(system, moveset, 300.0, "equilibration", 500) with pytest.raises(TypeError, match=r"corrupted"): system = mc.System([box], [methane_oplsaa], mols_to_add=[[10]]) moveset = mc.MoveSet("nvt", [methane_oplsaa]) system.species_topologies[0] = 1 mc.run(system, moveset, 300.0, "equilibration", 500)
def test_corrupt_natoms(self, methane_oplsaa, box): with pytest.raises(ValueError, match=r"corrupted"): system = mc.System([box], [methane_oplsaa], mols_to_add=[[10]]) moveset = mc.MoveSet("nvt", [methane_oplsaa]) system.mols_in_boxes[0][0] = 10 mc.run(system, moveset, 300.0, "equilibration", 500)
def test_ensemble_npt(self, methane_oplsaa): moveset = mc.MoveSet("npt", [methane_oplsaa]) assert moveset.ensemble == "npt" assert moveset.prob_translate == 0.33 assert moveset.prob_rotate == 0.33 assert moveset.prob_regrow == 0.335 assert moveset.prob_volume == 0.005 assert moveset.prob_angle == 0.0 assert moveset.prob_dihedral == 0.0 assert moveset.prob_insert == 0.0 assert moveset.prob_swap == 0.0 # Per box attributes assert len(moveset.max_translate) == 1 assert len(moveset.max_rotate) == 1 assert len(moveset.max_volume) == 1 assert len(moveset.prob_swap_from_box) == 1 assert moveset.prob_swap_from_box[0] == 1.0 assert moveset.max_volume[0] == 500.0 * (u.angstrom ** 3) # Per species-per-box assert len(moveset.max_translate[0]) == 1 * u.angstrom assert len(moveset.max_rotate[0]) == 1 * u.degree # Per species attributes assert len(moveset.insertable) == 1 assert len(moveset.prob_swap_species) == 1 assert len(moveset.prob_regrow_species) == 1 # Should be regrow-able but not insertable assert moveset.prob_regrow_species[0] == 1.0 assert moveset.insertable[0] == False
def test_gcmc_lattice(self, fixed_lattice_trappe, methane_trappe): moveset = mc.MoveSet("gcmc", [fixed_lattice_trappe, methane_trappe]) assert moveset.ensemble == "gcmc" assert moveset.prob_translate == pytest.approx(0.8) assert moveset.prob_rotate == 0.0 assert moveset.prob_regrow == 0.0 assert moveset.prob_volume == 0.0 assert moveset.prob_angle == 0.0 assert moveset.prob_dihedral == 0.0 assert moveset.prob_insert == 0.1 assert moveset.prob_swap == pytest.approx(0.0) # Per box attributes assert len(moveset.max_translate) == 1 assert len(moveset.max_rotate) == 1 assert len(moveset.max_volume) == 1 assert len(moveset.prob_swap_from_box) == 1 assert moveset.prob_swap_from_box[0] == 1.0 assert moveset.max_volume[0] == 0.0 # Per species-per-box assert len(moveset.max_translate[0]) == 2 assert len(moveset.max_rotate[0]) == 2 # Per species attributes assert len(moveset.insertable) == 2 assert len(moveset.prob_swap_species) == 2 assert len(moveset.prob_regrow_species) == 2 # Lattice should not be insertable or regrow-able assert moveset.insertable[0] == False assert moveset.prob_regrow_species[0] == 0.0 # Methane should be insertable and not regrow-able assert moveset.insertable[1] == True assert moveset.prob_regrow_species[1] == 0.0
def test_single_site_nvt(self, methane_trappe): moveset = mc.MoveSet("nvt", [methane_trappe]) assert moveset.ensemble == "nvt" assert moveset.prob_rotate == 0.0 assert moveset.prob_regrow == 0.0 assert moveset.prob_translate == 1.0 assert moveset.prob_volume == 0.0 assert moveset.prob_angle == 0.0 assert moveset.prob_dihedral == 0.0 assert moveset.prob_insert == 0.0 assert moveset.prob_swap == 0.0 # Per box attributes assert len(moveset.max_translate) == 1 assert len(moveset.max_rotate) == 1 assert len(moveset.max_volume) == 1 assert len(moveset.prob_swap_from_box) == 1 assert moveset.prob_swap_from_box[0] == 1.0 assert moveset.max_volume[0] == 0.0 # Per species-per-box assert len(moveset.max_translate[0]) == 1 assert len(moveset.max_rotate[0]) == 1 # Per species attributes assert len(moveset.insertable) == 1 assert len(moveset.prob_swap_species) == 1 assert len(moveset.prob_regrow_species) == 1 # Should NOT be insertable or regrow-able assert moveset.insertable[0] == False assert moveset.prob_regrow_species[0] == 0.0
def test_add_multiple_restricted_insertions(self, methane_oplsaa): moveset = mc.MoveSet("gcmc", [methane_oplsaa]) moveset.add_restricted_insertions([methane_oplsaa], [["slitpore"]], [[3 * u.angstrom]]) with pytest.warns(None) as record: moveset.add_restricted_insertions([methane_oplsaa], [["cylinder"]], [[3 * u.angstrom]])
def test_restricted_gemc(self, methane_oplsaa, typ, value): moveset = mc.MoveSet("gemc", [methane_oplsaa]) moveset.add_restricted_insertions([methane_oplsaa], [[None], [typ]], [[None], [value]]) assert moveset._restricted_type == [[None], [typ]] assert moveset._restricted_value == [[None], [value]]
def test_invalid_species_list(self, methane_oplsaa): with pytest.raises( TypeError, match=r"species_topologies should " "be a list of species", ): moveset = mc.MoveSet("nvt", methane_oplsaa)
def run_nvt(**custom_args): # Use mBuild to create a methane molecule methane = mbuild.load("C", smiles=True) # Create an empty mbuild.Box box = mbuild.Box(lengths=[3.0, 3.0, 3.0]) # Load force field oplsaa = foyer.forcefields.load_OPLSAA() # Use foyer to apply force field to methane methane_ff = oplsaa.apply(methane) # Create box and species list box_list = [box] species_list = [methane_ff] # Use Cassandra to insert some initial number of methane molecules mols_to_add = [[50]] # Define the System system = mc.System(box_list, species_list, mols_to_add=mols_to_add) # Define the MoveSet moveset = mc.MoveSet("nvt", species_list) # Run a simulation at 300 K for 10000 MC moves mc.run( system=system, moveset=moveset, run_type="equilibration", run_length=10000, temperature=300.0 * u.K, **custom_args, )
def test_ensemble_gcmc(self, methane_oplsaa): moveset = mc.MoveSet("gcmc", [methane_oplsaa]) assert moveset.ensemble == "gcmc" assert moveset.prob_translate == 0.25 assert moveset.prob_rotate == 0.25 assert moveset.prob_regrow == 0.30 assert moveset.prob_volume == 0.0 assert moveset.prob_angle == 0.0 assert moveset.prob_dihedral == 0.0 assert moveset.prob_insert == 0.1 assert moveset.prob_swap == 0.0 # Per box attributes assert len(moveset.max_translate) == 1 assert len(moveset.max_rotate) == 1 assert len(moveset.max_volume) == 1 assert len(moveset.prob_swap_from_box) == 1 assert moveset.prob_swap_from_box[0] == 1.0 assert moveset.max_volume[0] == 0.0 * (u.angstrom ** 3) # Per species-per-box assert len(moveset.max_translate[0]) == 1 assert len(moveset.max_rotate[0]) == 1 # Per species attributes assert len(moveset.insertable) == 1 assert len(moveset.prob_swap_species) == 1 assert len(moveset.prob_regrow_species) == 1 # Should be insertable and regrow-able assert moveset.insertable[0] == True assert moveset.prob_regrow_species[0] == 1.0
def test_single_site_gemc(self, methane_trappe): moveset = mc.MoveSet("gemc", [methane_trappe]) assert moveset.ensemble == "gemc" assert moveset.prob_rotate == 0.0 assert moveset.prob_regrow == 0.0 assert moveset.prob_translate == pytest.approx(0.895) assert moveset.prob_volume == 0.005 assert moveset.prob_angle == 0.0 assert moveset.prob_dihedral == 0.0 assert moveset.prob_insert == 0.0 assert moveset.prob_swap == 0.1 # Per box attributes assert len(moveset.max_translate) == 2 assert len(moveset.max_rotate) == 2 assert len(moveset.max_volume) == 1 assert len(moveset.prob_swap_from_box) == 2 assert moveset.prob_swap_from_box[0] == 0.5 assert moveset.prob_swap_from_box[1] == 0.5 assert moveset.max_volume[0] == 500.0 # Per species-per-box assert len(moveset.max_translate[0]) == 1 assert len(moveset.max_translate[1]) == 1 assert len(moveset.max_rotate[0]) == 1 assert len(moveset.max_rotate[1]) == 1 # Per species attributes assert len(moveset.insertable) == 1 assert len(moveset.prob_swap_species) == 1 assert len(moveset.prob_regrow_species) == 1 # Should be insertable and NOT regrow-able assert moveset.insertable[0] == True assert moveset.prob_regrow_species[0] == 0.0
def test_restricted_gemc_npt(self, methane_oplsaa): moveset = mc.MoveSet("gemc_npt", [methane_oplsaa]) moveset.add_restricted_insertions( [methane_oplsaa], [[None], ["slitpore"]], [[None], [3 * u.angstrom]], ) assert moveset._restricted_type == [[None], ["slitpore"]] assert moveset._restricted_value == [[None], [3 * u.angstrom]]
def run_gcmc_adsorption(**custom_args): # Use mbuild to create a zeolite supercell from CIF lattice = mbuild.lattice.load_cif(get_example_cif_path("TON")) compound_dict = { "Si": mbuild.Compound(name="Si"), "O": mbuild.Compound(name="O"), } ton = lattice.populate(compound_dict, 3, 3, 6) # Create a coarse-grained methane methane = mbuild.Compound(name="_CH4") # Load forcefields trappe_zeo = foyer.Forcefield(get_example_ff_path("trappe_zeo")) trappe = foyer.forcefields.load_TRAPPE_UA() # Use foyer to apply forcefields ton_ff = trappe_zeo.apply(ton) methane_ff = trappe.apply(methane) # Create box and species list box_list = [ton] species_list = [ton_ff, methane_ff] # Since we have an occupied box we need to specify # the number of each species present in the intial config mols_in_boxes = [[1, 0]] system = mc.System(box_list, species_list, mols_in_boxes=mols_in_boxes) moveset = mc.MoveSet("gcmc", species_list) default_args = { "chemical_potentials": ["none", -30.0 * (u.kJ / u.mol)], "rcut_min": 0.5 * u.angstrom, "vdw_cutoff": 14.0 * u.angstrom, "charge_cutoff": 14.0 * u.angstrom, "coord_freq": 100, "prop_freq": 10, } # Combine default/custom args and override default custom_args = {**default_args, **custom_args} mc.run( system=system, moveset=moveset, run_type="equilibration", run_length=10000, temperature=300.0 * u.K, **custom_args, )
def run_cassandra_surf(chem_pot, temp): # Create box and species list box_list = [surface] species_list = [typed_surface,typed_ethane] # Since we have an occupied box we need to specify # the number of each species present in the intial config mols_in_boxes = [[2,0]] system = mc.System(box_list, species_list, mols_in_boxes=mols_in_boxes) moveset = mc.MoveSet("gcmc", species_list) custom_args = { "run_name": f"surfequil_{chem_pot:.0f}_{temp:.0f}", "chemical_potentials": ["none",chem_pot*u.Unit('kJ/mol')], "rcut_min": 0.3980 * 2.5* u.angstrom, #(or 3.0) "vdw_cutoff": min(box.lengths)/2.1* u.angstrom, "charge_style": "none", #"charge_cutoff": 14.0, "coord_freq": 100, "prop_freq": 10, } mc.run( system=system, moveset=moveset, run_type="equilibration", run_length= 3600549, # To reach ~1.33 hours temperature=temp*u.K, **custom_args ) # Set max translate and volume for production moveset.max_translate = [[0* u.angstrom,10.0* u.angstrom]] # angstroms # Update run_name and restart_name custom_args["run_name"] = f"surfprod_{chem_pot:.0f}_{temp:.0f}" custom_args["restart_name"] = f"surfequil_{chem_pot:.0f}_{temp:.0f}" mc.restart( system=system, moveset=moveset, run_type="production", run_length= 24097256, # To reach ~6.67 hours, total 8 hrs temperature=temp*u.K, **custom_args, )
def run_gcmc_adsorption(**custom_args): # Use mbuild to create molecules lattice = carbon_lattice() methane = mbuild.load("C", smiles=True) # Load forcefields trappe = foyer.forcefields.load_TRAPPE_UA() oplsaa = foyer.forcefields.load_OPLSAA() # Use foyer to apply forcefields typed_lattice = trappe.apply(lattice) methane_ff = oplsaa.apply(methane) # Create box and species list box_list = [lattice] species_list = [typed_lattice, methane_ff] # Since we have an occupied box we need to specify # the number of each species present in the intial config mols_in_boxes = [[1, 0]] system = mc.System(box_list, species_list, mols_in_boxes=mols_in_boxes) moveset = mc.MoveSet("gcmc", species_list) default_args = { "chemical_potentials": ["none", -30.0 * (u.kJ / u.mol)], "rcut_min": 0.5 * u.angstrom, "vdw_cutoff": 14.0 * u.angstrom, "charge_cutoff": 14.0 * u.angstrom, "coord_freq": 100, "prop_freq": 10, } # Combine default/custom args and override default custom_args = {**default_args, **custom_args} mc.run( system=system, moveset=moveset, run_type="equilibration", run_length=10000, temperature=300.0 * u.K, **custom_args, )
def run_nvt_spce(**custom_args): # If no custom args are passed, assign empty dictionary #if custom_args is None: # custom_args = {} # Load water with SPC/E geometry from mol2 file molecule = mbuild.load(get_example_mol2_path("spce")) # Create an empty mbuild.Box box = mbuild.Box(lengths=[3.0, 3.0, 3.0]) # Load forcefields spce = foyer.Forcefield(get_example_ff_path("spce")) # Use foyer to apply forcefields molecule_ff = spce.apply(molecule) # Create box and species list box_list = [box] species_list = [molecule_ff] # Use Cassandra to insert some initial number of species mols_to_add = [[50]] # Define the system object system = mc.System(box_list, species_list, mols_to_add=mols_to_add) # Get the move probabilities moveset = mc.MoveSet("nvt", species_list) default_args = { "angle_style": ["fixed"], } # Combine default/custom args and override default custom_args = {**default_args, **custom_args} # Run a simulation with at 300 K with 10000 MC moveset mc.run( system=system, moveset=moveset, run_type="equilibration", run_length=10000, temperature=300.0 * u.K, **custom_args, )
def run_gcmc_restricted(**custom_args): # Use mbuild to create molecules methane = mbuild.load("C", smiles=True) # Create an empty mbuild.Box box = mbuild.Box(lengths=[5.0, 5.0, 5.0]) # Load forcefields oplsaa = foyer.forcefields.load_OPLSAA() # Use foyer to apply forcefields methane_ff = oplsaa.apply(methane) # Create box and species list box_list = [box] species_list = [methane_ff] mols_to_add = [[10]] system = mc.System(box_list, species_list, mols_to_add=mols_to_add) moveset = mc.MoveSet("gcmc", species_list) # Specify restricted insertions moveset.add_restricted_insertions( species_list, [["sphere"]], [[20 * u.angstrom]] ) default_args = { "chemical_potentials": [-35.0 * (u.kJ / u.mol)], "prop_freq": 10, } # Combine default/custom args and override default custom_args = {**default_args, **custom_args} mc.run( system=system, moveset=moveset, run_type="equilibration", run_length=100, temperature=300.0 * u.K, **custom_args, )
def run_nvt_mbuild(fix_bonds, **custom_args): dme = mbuild.load("COC", smiles=True) dee = mbuild.load("CCOCC", smiles=True) # Create an empty mbuild.Box box = mbuild.Box(lengths=[3.0, 3.0, 3.0]) # fill box box = mbuild.fill_box([dme, dee], n_compounds=[10, 10], box=box) # Load forcefields ff = foyer.forcefields.load_OPLSAA() # Use foyer to apply forcefields dme_ff = ff.apply(dme) dee_ff = ff.apply(dee) # Create box and species list box_list = [box] species_list = [dme_ff, dee_ff] # Use Cassandra to insert some initial number of species mols_in_boxes = [[10, 10]] # Define the system object system = mc.System( box_list, species_list, mols_in_boxes=mols_in_boxes, fix_bonds=fix_bonds, ) # Get the move probabilities moveset = mc.MoveSet("nvt", species_list) # Run a simulation with at 300 K with 10000 MC moves mc.run( system=system, moveset=moveset, run_type="equilibration", run_length=100, temperature=300.0 * u.K, **custom_args, )
def run_npt(**custom_args): # Use mbuild to create molecules methane = mbuild.load("C", smiles=True) # Create an empty mbuild.Box box = mbuild.Box(lengths=[3.0, 3.0, 3.0]) # Load forcefields oplsaa = foyer.forcefields.load_OPLSAA() # Use foyer to apply forcefields methane_ff = oplsaa.apply(methane) # Create box and species list box_list = [box] species_list = [methane_ff] # Use Cassandra to insert some initial number of species mols_to_add = [[5]] # Define the system object system = mc.System(box_list, species_list, mols_to_add=mols_to_add) # Get the move probabilities moveset = mc.MoveSet("npt", species_list) default_args = { "pressure": 1.0 * u.bar, } # Combine default/custom args and override default custom_args = {**default_args, **custom_args} # Run a simulation with at 300 K with 10000 MC moveset # Note we must define a pressure for an NPT simulation mc.run( system=system, moveset=moveset, run_type="equilibration", run_length=10000, temperature=300.0 * u.K, **custom_args, )
# Create a single site methane molecule methane = mbuild.Compound(name="_CH4") # Apply the force field methane_ff = ff.apply(methane) # Create an empty 3x3x3 nm^3 simulation box box = mbuild.Box([3., 3., 3.]) # Define the box/species lists box_list = [box] species_list = [methane_ff] # Tell Cassandra to add 100 methane at the start mols_to_add = [[100]] # Create the System and MoveSet system = mc.System(box_list, species_list, mols_to_add=mols_to_add) moveset = mc.MoveSet("npt", species_list) # Run the Monte Carlo simulation mc.run( system=system, moveset=moveset, run_type="equilibration", run_length=300000, temperature=240 * u.K, pressure=10.0 * u.bar, )
def test_invalid_restricted_type_and_species(self, methane_oplsaa): moveset = mc.MoveSet("gcmc", [methane_oplsaa]) with pytest.raises(ValueError, match=r"Length of 'species'"): moveset.add_restricted_insertions( [methane_oplsaa], [["slitpore", None]], [[1, None]] )
def test_change_ensemble(self, methane_oplsaa): moveset = mc.MoveSet("gcmc", [methane_oplsaa]) with pytest.raises( AttributeError, match=r"Ensemble cannot be changed" ): moveset.ensemble = "nvt"
def run_gemc(**custom_args): # Use mbuild to create molecules methane = mbuild.Compound(name="_CH4") # Create two empty mbuild.Box # (vapor = larger, liquid = smaller) liquid_box = mbuild.Box(lengths=[3.0, 3.0, 3.0]) vapor_box = mbuild.Box(lengths=[4.0, 4.0, 4.0]) # Load forcefields trappe = foyer.forcefields.load_TRAPPE_UA() # Use foyer to apply forcefields typed_methane = trappe.apply(methane) # Create box and species list box_list = [liquid_box, vapor_box] species_list = [typed_methane] mols_to_add = [[350], [100]] system = mc.System(box_list, species_list, mols_to_add=mols_to_add) moveset = mc.MoveSet("gemc", species_list) moveset.prob_volume = 0.010 moveset.prob_swap = 0.11 thermo_props = [ "energy_total", "energy_intervdw", "pressure", "volume", "nmols", "mass_density", ] default_args = { "run_name": "equil", "charge_style": "none", "rcut_min": 2.0 * u.angstrom, "vdw_cutoff": 14.0 * u.angstrom, "units": "sweeps", "steps_per_sweep": 450, "coord_freq": 50, "prop_freq": 10, "properties": thermo_props, } # Combine default/custom args and override default custom_args = {**default_args, **custom_args} mc.run( system=system, moveset=moveset, run_type="equilibration", run_length=250, temperature=151.0 * u.K, **custom_args, ) mc.restart( restart_from="equil", run_name="prod", run_type="production", total_run_length=750, )
def main(): # Load TON from a CIF file, replicate the cell # Use mbuild to create a zeolite supercell from CIF cif_path = resource_filename( "mc_examples", "realistic_workflows/zeolite_adsorption/resources/structures/TON.cif") lattice = mbuild.lattice.load_cif(cif_path) compound_dict = { "Si": mbuild.Compound(name="Si"), "O": mbuild.Compound(name="O"), } zeolite = lattice.populate(compound_dict, 2, 2, 6) # Create a CG methane, load and apply ff methane = mbuild.Compound(name="_CH4") ff_path = resource_filename( "mc_examples", "realistic_workflows/zeolite_adsorption/resources/ffxml/adsorbates.xml", ) ff_ads = foyer.Forcefield(ff_path) methane_ff = ff_ads.apply(methane) # Define pure fluid temperatures and chemical potentials temperatures = [298 * u.K, 309 * u.K, 350 * u.K] mus_fluid = np.arange(-49, -30, 3) * u.Unit("kJ/mol") # Define the pressures at which we wish to study adsorption pressures = [ 0.01, 0.1, 0.25, 0.5, 0.75, 1.0, 2.0, 3.0, 5.0, ] * u.bar # Select the zeolite ff zeo_ff_names = ["june", "trappe"] # Define a few custom_args that will be # the same for all zeolite simulations custom_args = { "charge_style": "none", "vdw_cutoff": 14.0 * u.angstrom, "prop_freq": 10, "max_molecules": [1, 10000], } # Loop over different zeolite ff's for zeo_ff_name in zeo_ff_names: # Load and apply ff to the zeolite structure ff_path = resource_filename( "mc_examples", f"realistic_workflows/zeolite_adsorption/resources/ffxml/zeo_{zeo_ff_name}.xml", ) ff_zeo = foyer.Forcefield(ff_path) zeolite_ff = ff_zeo.apply(zeolite) # Create the box_list, species_list, System, and MoveSet. # These are not dependent upon (T,P) condition box_list = [zeolite] species_list = [zeolite_ff, methane_ff] mols_in_boxes = [[1, 0]] system = mc.System(box_list, species_list, mols_in_boxes=mols_in_boxes) moveset = mc.MoveSet("gcmc", species_list) # Loop over each temperature to compute an isotherm for temperature in temperatures: # Before we begin we must determine the # chemical potentials required to achieve # the desired pressures fluid_pressures = [] for mu_fluid in mus_fluid: dirname = f"fluid_T_{temperature:0.1f}_mu_{mu_fluid:.1f}".replace( " ", "_").replace("/", "-") thermo = ThermoProps(dirname + "/prod.out.prp") fluid_pressures.append(np.mean(thermo.prop("Pressure"))) fluid_pressures = u.unyt_array(fluid_pressures) # Fit a line to mu vs. P slope, intercept, r_value, p_value, stderr = linregress( np.log(fluid_pressures.to_value(u.bar)).flatten(), y=mus_fluid.to_value("kJ/mol").flatten(), ) # Determine chemical potentials mus = (slope * np.log(pressures.in_units(u.bar)) + intercept) * u.Unit("kJ/mol") # Loop over each pressure and run the MC simulation! for (pressure, mu) in zip(pressures, mus): print(f"\nRun simulation: T = {temperature}, P = {pressure}\n") dirname = f"zeo_ff_{zeo_ff_name}_T_{temperature:0.1f}_P_{pressure:0.2f}".replace( " ", "_").replace("/", "-") if not os.path.isdir(dirname): os.mkdir(dirname) else: pass with temporary_cd(dirname): mc.run( system=system, moveset=moveset, run_type="equil", run_length=50000, temperature=temperature, run_name="equil", chemical_potentials=["none", mu], **custom_args, ) mc.restart( restart_from="equil", run_name="prod", run_type="prod", total_run_length=200000, )
def main(): # Create a water molecule with the spce geometry water = spce_water ff = foyer.Forcefield(get_ff("pore-spce-jc.xml")) water_typed = ff.apply(water) # Define conditions temperature = 298.0 * u.K # Define a range of (shifted) chemical potentials mus_adsorbate = np.arange(-58, -42, 2) * u.Unit("kJ/mol") # Define custom_args that are the same for all pure phase simulations custom_args = { "cutoff_style": "cut", "charge_style": "ewald", "rcut_min": 0.5 * u.angstrom, "vdw_cutoff": 9.0 * u.angstrom, "prop_freq": 10, "angle_style": ["fixed"], } for mu_adsorbate in mus_adsorbate: print(f"\nRun simulation: T = {temperature}, mu = {mu_adsorbate}\n") dirname = f"T_{temperature:0.1f}_mu_{mu_adsorbate:.1f}".replace( " ", "_" ).replace( "/", "-" ) if not os.path.isdir(dirname): os.mkdir(dirname) else: pass with temporary_cd(dirname): # Box size depends on chemical potential # Test simulations show mu' = -48 kJ/mol; p ~ 0.01 bar # Employ IG law to estimate remaining box sizes; target 40 waters mu_0 = -48 * u.kJ/u.mol p_0 = 0.01 * u.bar n_water_target = 40 p_ig = p_0 * np.exp((mu_adsorbate-mu_0)/(u.kb * temperature)) vol = n_water_target * u.kb * temperature / p_ig boxl = (vol**(1./3.)).to_value("nm") custom_args["charge_cutoff"] = 0.25 * boxl * u.nm species_list = [water_typed] box_list = [mbuild.Box([boxl, boxl, boxl])] system = mc.System( box_list, species_list, ) moveset = mc.MoveSet("gcmc", species_list) moveset.prob_regrow = 0.0 moveset.prob_translate = 0.3 moveset.prob_rotate = 0.3 moveset.prob_insert = 0.2 mc.run( system=system, moveset=moveset, run_type="equil", run_length=500000, temperature=temperature, run_name="equil", chemical_potentials=[mu_adsorbate], **custom_args, ) mc.restart( system=system, moveset=moveset, run_type="prod", run_length=1000000, temperature=temperature, run_name="prod", restart_name="equil", chemical_potentials=[mu_adsorbate], **custom_args, )
box = mbuild.Box([box_length, box_length, box_length]) vapor_box = mbuild.fill_box(ethane, n_compounds=N_vapor, box=box) # Initial liquid box from existing configuration liquid_box = mbuild.load("liqbox_equil.gro") N_liquid = len([child for child in liquid_box.children]) # Create the System and MoveSet box_list = [liquid_box, vapor_box] species_list = [ethane_ff] mols_in_boxes = [[N_liquid], [N_vapor]] system = mc.System( box_list, species_list, mols_in_boxes=mols_in_boxes, ) moveset = mc.MoveSet("gemc", species_list) # Run the Monte Carlo simulation mc.run( system=system, moveset=moveset, run_type="equilibration", run_length=500000, temperature=temperature, vdw_cutoff=10.0 * u.angstrom, charge_cutoff=10.0 * u.angstrom, mixing_rule="geometric", )
def run_gcmc( filled_pore, pore_width, temperature, mu, nsteps_nvt, nsteps_gcmc, pve_ion=mbuild.Compound(name="Na"), nve_ion=mbuild.Compound(name="Cl"), **custom_args, ): """Run desorption simulation at the specified temperature and chemical potential Parameters ---------- filled_pore : porebuilder.GraphenePoreSolvent pore filled with water and (optional) ions pore_width : u.unyt_quantity (length) width of pore for restricted insertions temperature: u.unyt_quantity (temperature) desired temperature mu : u.unyt_quantity (energy) desired chemical potential for water nsteps_nvt : int number of MC steps for NVT equilibration nsteps_gcmc : int number of MC steps for GCMC simulation pve_ion : mbuild.Compound, optional, default=Na positive ion nve_ion : mbuild.Compound, optional, default=Cl negative ion custom_args : opt, additional keyword arguments provide additional custom keyword arguments to MoSDeF Cassandra and override the default values Returns ------- None: runs simulation """ # Load foyer ff ff = foyer.Forcefield(get_ff("pore-spce-jc.xml")) # Extract just the pore and apply ff empty_pore = filled_pore.children[0] typed_pore = ff.apply(empty_pore) # Create a water molecule with the spce geometry and apply ff typed_water = ff.apply(spce_water) typed_pve = ff.apply(pve_ion) typed_nve = ff.apply(nve_ion) # Determine the number of waters in the pore n_water = len( [child for child in filled_pore.children if child.name == "SOL"]) n_ion_pairs = int( (len([child for child in filled_pore.children]) - 1 - n_water) / 2) # Create box and species list box_list = [filled_pore] species_list = [typed_pore, typed_pve, typed_nve, typed_water] # Specify mols at start of the simulation mols_in_boxes = [[1, n_ion_pairs, n_ion_pairs, n_water]] # Create MC system system = mc.System(box_list, species_list, mols_in_boxes=mols_in_boxes) moves = mc.MoveSet("nvt", species_list) # Set move probabilities moves.prob_translate = 0.5 moves.prob_rotate = 0.5 moves.prob_regrow = 0.0 # Set thermodynamic properties thermo_props = [ "energy_total", "energy_intervdw", "energy_interq", "nmols", ] default_args = { "run_name": "nvt", "cutoff_style": "cut", "charge_style": "ewald", "rcut_min": 0.5 * u.angstrom, "vdw_cutoff": 9.0 * u.angstrom, "charge_cutoff": 9.0 * u.angstrom, "properties": thermo_props, "angle_style": ["harmonic", "harmonic", "harmonic", "fixed"], "coord_freq": 100000, "prop_freq": 1000, } custom_args = {**default_args, **custom_args} # Run NVT equilibration mc.run( system=system, moveset=moves, run_type="equilibration", run_length=nsteps_nvt, temperature=temperature, **custom_args, ) # Create MC system equilibrated_box = load_final_xyz_frame("nvt.out.xyz") box_list = [equilibrated_box] system = mc.System(box_list, species_list, mols_in_boxes=mols_in_boxes) moves = mc.MoveSet("gcmc", species_list) # Set move probabilities moves.prob_translate = 0.25 moves.prob_rotate = 0.25 moves.prob_insert = 0.25 moves.prob_regrow = 0.0 # Make Na/Cl NOT insertable moves.insertable[1] = False moves.insertable[2] = False # Specify the restricted insertion restricted_type = [[None, None, None, "slitpore"]] restricted_value = [[None, None, None, 0.5 * pore_width]] moves.add_restricted_insertions(species_list, restricted_type, restricted_value) # Run GCMC custom_args["run_name"] = "gcmc" mc.run( system=system, moveset=moves, run_type="equilibration", run_length=nsteps_gcmc, temperature=temperature, chemical_potentials=["none", "none", "none", mu], **custom_args, )
def main(): # Create a CG methane, load and apply ff methane = mbuild.Compound(name="_CH4") ff_path = resource_filename( "mc_examples", "realistic_workflows/zeolite_adsorption/resources/ffxml/adsorbates.xml", ) ff_ads = foyer.Forcefield(ff_path) methane_ff = ff_ads.apply(methane) # Define a few keyword args that will be the # same for all fluid phase simulations custom_args = { "charge_style": "none", "vdw_cutoff": 14.0 * u.angstrom, "prop_freq": 10, } # Define temperatures and chemical potential values # for the single phase GCMC simulations temperatures = [298 * u.K, 309 * u.K, 350 * u.K] mus = np.arange(-49, -30, 3) * u.Unit("kJ/mol") # Loop over temperatures and mus and run simulations for temperature in temperatures: for mu in mus: # For each simulation -- first estimate # the box volume to target ~40 molecules n_methane_target = 40 beta = 1.0 / (u.kb * temperature) mass = 16.04 * u.amu debroglie = np.sqrt(2 * np.pi * u.hbar**2 * beta / mass) vol = n_methane_target * debroglie**3 * np.exp( -beta.to("mol/kJ") * mu) boxl = (vol**(1.0 / 3.0)).to_value("nm") if boxl < 2.0 * custom_args["vdw_cutoff"].to_value("nm"): boxl = 2.0 * custom_args["vdw_cutoff"].to_value("nm") # Define the species list, box list, system, moveset # We start with an empty box species_list = [methane_ff] box_list = [mbuild.Box([boxl, boxl, boxl])] system = mc.System(box_list, species_list) moveset = mc.MoveSet("gcmc", species_list) # Create a new directory, temporary cd, and run # the equilibration and production simulations! print(f"\nRun simulation: T = {temperature}, mu = {mu}\n") dirname = f"fluid_T_{temperature:0.1f}_mu_{mu:.1f}".replace( " ", "_").replace("/", "-") if not os.path.isdir(dirname): os.mkdir(dirname) else: pass with temporary_cd(dirname): mc.run( system=system, moveset=moveset, run_type="equil", run_length=50000, temperature=temperature, run_name="equil", chemical_potentials=[mu], **custom_args, ) mc.restart( restart_from="equil", run_name="prod", run_type="prod", total_run_length=400000, )