def _get_system_copy(self): 'Routine to get a copy of the equilibrium system' numbers = self.system0.numbers.copy() coords = self.system0.pos.copy() rvecs = self.system_rvecs.copy() masses = self.system0.masses.copy() bonds = self.system0.bonds.copy() ffatypes = self.system0.ffatypes.copy() ffatype_ids = self.system0.ffatype_ids.copy() return System( numbers, coords, rvecs=rvecs, ffatypes=ffatypes, ffatype_ids=ffatype_ids, masses=masses, bonds=bonds )
def _generate_ffs(self, nguests): for iguest in range(len(self._ffs),nguests): if len(self._ffs)==0: # The very first force field, no guests system = System.create_empty() system.cell = Cell(self.guest.cell.rvecs) elif len(self._ffs)==1: # The first real force field, a single guest system = self.guest else: # Take the system of the lastly generated force field (N-1) guests # and add an additional guest system = self._ffs[-1].system.merge(self.guest) self._ffs.append(self.ff_generator(system, self.guest))
def simulate(): T = 298.0*kelvin # Input files fn_guest = 'CO2.chk' fn_host = 'MIL53.chk' fn_pars = ['pars.txt'] host = System.from_file(fn_host).supercell(1,1,1) # Description of allowed MC moves and their corresponding probabilities mc_moves = {'insertion':1.0, 'deletion':1.0, 'translation':1.0, 'rotation':1.0} # Construct equation of state to link pressure, fugacity and chemical potential eos = PREOS.from_name('carbondioxide') # Loop over pressures to construct isotherm pressures = np.array([0.1,0.5,1.0,3.0,5.0,10.0])*bar uptake = np.zeros(pressures.shape) for iP, P in enumerate(pressures): fugacity = eos.calculate_fugacity(T,P) mu = eos.calculate_mu(T,P) # Screen logger screenlog = MCScreenLog(step=10000) # HDF5 logger fh5 = h5.File('trajectory_%d.h5'%iP,'w') hdf5writer = MCHDF5Writer(fh5, step=10000) # Setup the GCMC calculation, this generates a lot of output so when # force fields are generated, so we silence the logging for a while. log.set_level(log.silent) gcmc = GCMC.from_files(fn_guest, fn_pars, host=host, rcut=12.0*angstrom, tr=None, tailcorrections=True, hooks=[screenlog, hdf5writer], reci_ei='ewald_interaction', nguests=30) log.set_level(log.medium) # Set the external conditions gcmc.set_external_conditions(T, fugacity) # Run MC simulation gcmc.run(1000000, mc_moves=mc_moves) uptake[iP] = gcmc.Nmean fh5.close() np.save('results.npy', np.array([pressures,uptake]).T)
def write_raspa_input(guests, parameters, host=None, workdir='.', guestdata=None, hostname='host'): """ Prepare input files that can be used to run RASPA simulations. Only a small subset of the full capabilities of RASPA can be explored. **Arguments:** guests A list specifying the guest molecules. Each entry can be one of two types: (i) the filename of a system file describing one guest molecule, (ii) a System instance of one guest molecule parameters Force-field parameters describing guest-guest and optionally host-guest interaction. Three types are accepted: (i) the filename of the parameter file, which is a text file that adheres to YAFF parameter format, (ii) a list of such filenames, or (iii) an instance of the Parameters class. **Optional arguments:** host Two types are accepted: (i) the filename of a system file describing the host system, (ii) a System instance of the host workdir The directory where output files will be placed. guestdata List with the same length as guests. Each entry contains a tuple either looking as (name, Tc, Pc, omega) or (name). In the latter case, the parameters Tc, Pc, and omega will be loaded from a data file based on the name. Otherwise, these will be left blank in the input file. """ # Load the guest Systems guests = [ System.from_file(guest) if isinstance(guest, str) else guest for guest in guests ] for guest in guests: assert isinstance(guest, System) if guestdata is None: guestdata = [("guest%03d" % iguest, ) for iguest in range(len(guests))] assert len(guests) == len(guestdata) # Load the host System if host is not None: if isinstance(host, str): host = System.from_file(host) assert isinstance(host, System) complex = host # Merge all systems for guest in guests: complex = complex.merge(guest) # Generate the ForceField, we don't really care about settings such as # cutoffs etc. We only need the parameters in the end ff = ForceField.generate(complex, parameters) # Write the force-field parameters write_raspa_forcefield(ff, workdir) # Write masses and charges of all atoms ffatypes, ffatype_ids = write_pseudo_atoms(ff, workdir) # Write the guest information if host == None: counter = 0 else: counter = host.natom for iguest, (guest, data) in enumerate(zip(guests, guestdata)): write_guest(guest, data, workdir, [ ffatypes[iffa] for iffa in ffatype_ids[counter:counter + guest.natom] ]) counter += guest.natom # Write the host coordinates to a cif file if host is not None: dump_cif( host, os.path.join(workdir, '%s.cif' % hostname), ffatypes=[ffatypes[iffa] for iffa in ffatype_ids[:host.natom]]) # A fairly standard input file for GCMC simulations dump_input(workdir, hostname, [data[0] for data in guestdata])
def from_files(cls, guest, parameters, **kwargs): """Automated setup of GCMC simulation **Arguments:** guest Two types are accepted: (i) the filename of a system file describing one guest molecule, (ii) a System instance of one guest molecule parameters Force-field parameters describing guest-guest and optionally host-guest interaction. Three types are accepted: (i) the filename of the parameter file, which is a text file that adheres to YAFF parameter format, (ii) a list of such filenames, or (iii) an instance of the Parameters class. **Optional arguments:** hooks A list of MCHooks host Two types are accepted: (i) the filename of a system file describing the host system, (ii) a System instance of the host All other keyword arguments are passed to the ForceField constructor See the constructor of the :class:`yaff.pes.generator.FFArgs` class for the available optional arguments. """ # Load the guest System if isinstance(guest, str): guest = System.from_file(guest) assert isinstance(guest, System) # We want to control nlow and nhigh here ourselves, so remove it from the # optional arguments if the user provided it. kwargs.pop('nlow', None) kwargs.pop('nhigh', None) # Rough guess for number of adsorbed guests nguests = kwargs.pop('nguests', 10) # Load the host if it is present as a keyword host = kwargs.pop('host', None) # Extract the hooks hooks = kwargs.pop('hooks', []) # Efficient treatment of reciprocal ewald contribution if not 'reci_ei' in kwargs.keys(): kwargs['reci_ei'] = 'ewald_interaction' if host is not None: if isinstance(host, str): host = System.from_file(host) assert isinstance(host, System) # If the guest molecule is currently an isolated molecule, than put # it in the same periodic box as the host if guest.cell is None or guest.cell.nvec==0: guest.cell = Cell(host.cell.rvecs) # Construct a complex of host and one guest and the corresponding # force field excluding host-host interactions hostguest = host.merge(guest) external_potential = ForceField.generate(hostguest, parameters, nlow=host.natom, nhigh=host.natom, **kwargs) else: external_potential = None # # Compare the energy of the guest, once isolated, once in a periodic box # guest_isolated = guest.subsystem(np.arange(guest.natom)) # guest_isolated.cell = Cell(np.zeros((0,3))) # optional_arguments = {} # for key in kwargs.keys(): # if key=='reci_ei': continue # optional_arguments[key] = kwargs[key] # ff_guest_isolated = ForceField.generate(guest_isolated, parameters, **optional_arguments) # e_isolated = ff_guest_isolated.compute() # guest_periodic = guest.subsystem(np.arange(guest.natom)) # ff_guest_periodic = ForceField.generate(guest_periodic, parameters, **optional_arguments) # e_periodic = ff_guest_periodic.compute() # if np.abs(e_isolated-e_periodic)>1e-4: # if log.do_warning: # log.warn("An interaction energy of %s of the guest with its periodic " # "images was detected. The interaction of a guest with its periodic " # "images will however NOT be taken into account in this simulation. " # "If the energy difference is large compared to k_bT, you should " # "consider using a supercell." % (log.energy(e_isolated-e_periodic))) # By making use of nlow=nhigh, we automatically discard intramolecular energies eguest = 0.0 # Generator of guest-guest force fields, excluding interactions # between the first N-1 guests def ff_generator(system, guest): return ForceField.generate(system, parameters, nlow=max(0,system.natom-guest.natom), nhigh=max(0,system.natom-guest.natom), **kwargs) return cls(guest, ff_generator, external_potential=external_potential, eguest=eguest, hooks=hooks, nguests=nguests)