def _internal_compute(self, gpos, vtens): with timer.section("LAMMPS overhead"): self.update_rvecs(self.system.cell.rvecs) self.update_pos(self.system.pos.copy()) with timer.section("LAMMPS"): self.lammps.command("run 0 post no") with timer.section("LAMMPS overhead"): energy = self.lammps.extract_variable("eng",None,0) if gpos is not None: f = self.lammps.gather_atoms("f",1,3) gpos[:] = np.ctypeslib.as_array(f).reshape((-1,3)) gpos[:] = -np.einsum('ij,kj', gpos, self.rot.transpose()) if vtens is not None: w = self.lammps.extract_compute("virial",0,1) vtens_lammps = np.ctypeslib.as_array(w,shape=(6,)) # Lammps gives the virial per volume in pascal, so we have to # multiply with some prefactors vtens_lammps[:] *= -pascal*self.system.cell.volume # The [6x1] vector has to be cast to a symmetric [3x3] tensor # Lammps orders the values as [xx,yy,zz,xy,xz,yz] vtens[np.triu_indices(3)] = vtens_lammps[[0,3,4,1,5,2]] vtens[np.tril_indices(3)] = vtens_lammps[[0,3,1,4,5,2]] # Finally we have to compute the effect of the rotation on the # the virial tensor to get the values in Yaff coordinates vtens[:] = np.dot(self.rot.transpose(),np.dot(vtens[:],self.rot)) return energy
def generate(cls, system, parameters, **kwargs): """Create a force field for the given system with the given parameters. **Arguments:** system An instance of the System class parameters 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. See the constructor of the :class:`yaff.pes.generator.FFArgs` class for the available optional arguments. This method takes care of setting up the FF object, and configuring all the necessary FF parts. This is a lot easier than creating an FF with the default constructor. Parameters for atom types that are not present in the system, are simply ignored. """ if system.ffatype_ids is None: raise ValueError( 'The generators needs ffatype_ids in the system object.') with log.section('GEN'), timer.section('Generator'): from yaff.pes.generator import apply_generators, FFArgs from yaff.pes.parameters import Parameters if log.do_medium: log('Generating force field from %s' % str(parameters)) if not isinstance(parameters, Parameters): parameters = Parameters.from_file(parameters) ff_args = FFArgs(**kwargs) apply_generators(system, parameters, ff_args) return ForceField(system, ff_args.parts, ff_args.nlist)
def generate(cls, system, parameters, **kwargs): """Create a force field for the given system with the given parameters. **Arguments:** system An instance of the System class parameters 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. See the constructor of the :class:`yaff.pes.generator.FFArgs` class for the available optional arguments. This method takes care of setting up the FF object, and configuring all the necessary FF parts. This is a lot easier than creating an FF with the default constructor. Parameters for atom types that are not present in the system, are simply ignored. """ if system.ffatype_ids is None: raise ValueError('The generators needs ffatype_ids in the system object.') with log.section('GEN'), timer.section('Generator'): from yaff.pes.generator import apply_generators, FFArgs from yaff.pes.parameters import Parameters if log.do_medium: log('Generating force field from %s' % str(parameters)) if not isinstance(parameters, Parameters): parameters = Parameters.from_file(parameters) ff_args = FFArgs(**kwargs) apply_generators(system, parameters, ff_args) return ForceField(system, ff_args.parts, ff_args.nlist)
def _internal_compute(self, gpos, vtens): with timer.section('Valence'): self.comlist.forward() self.dlist.forward() self.iclist.forward() energy = 0 energy += self.vlist.forward() if self.term is not None: energy += self.term.compute() if not ((gpos is None) and (vtens is None)): #print('AA gpos before bias: ', gpos[:3]) self.vlist.back() self.iclist.back() self.comlist.gpos[:] = 0.0 self.dlist.back(self.comlist.gpos, vtens) if self.term is not None and vtens is not None: my_vtens = np.zeros((3, 3)) self.term.compute(np.zeros((3, 3)), my_vtens) vtens += my_vtens energy = self._scale(self.comlist.gpos, vtens, energy) #print('COM bias energy: ', energy / molmod.units.kjmol) self.comlist.back(gpos) #print('ValenceCOM gpos after bias: ', gpos[:3]) else: energy = self._scale(None, None, energy) #print('compos 0: ', self.comlist.pos[0, :]) #print('vtab: ', self.vlist.vtab) #print('ValenceCOM energy: ', energy) return energy
def _internal_compute(self, gpos, vtens): with timer.section('PLUMED'): self.plumed.cmd("setStep", self.plumedstep) self.plumed.cmd("setPositions", self.system.pos) self.plumed.cmd("setMasses", self.system.masses) if self.system.charges is not None: self.plumed.cmd("setCharges", self.system.charges) if self.system.cell.nvec > 0: rvecs = self.system.cell.rvecs.copy() self.plumed.cmd("setBox", rvecs) # PLUMED always needs arrays to write forces and virial to, so # provide dummy arrays if Yaff does not provide them # Note that gpos and forces differ by a minus sign, which has to be # corrected for when interacting with PLUMED if gpos is None: my_gpos = np.zeros(self.system.pos.shape) else: gpos[:] *= -1.0 my_gpos = gpos self.plumed.cmd("setForces", my_gpos) if vtens is None: my_vtens = np.zeros((3, 3)) else: my_vtens = vtens self.plumed.cmd("setVirial", my_vtens) # Do the actual calculation, without an update; this should # only be done at the end of a time step self.plumed.cmd("prepareCalc") self.plumed.cmd("performCalcNoUpdate") if gpos is not None: gpos[:] *= -1.0 # Retrieve biasing energy energy = np.zeros((1, )) self.plumed.cmd("getBias", energy) return energy[0]
def _internal_compute(self, gpos, vtens): with timer.section('Ewald neut.'): #TODO: interaction of dipoles with background? I think this is zero, need proof... fac = self.system.charges.sum()**2*np.pi/(2.0*self.system.cell.volume*self.alpha**2)/self.dielectric if self.system.radii is not None: fac -= self.system.charges.sum()*np.pi/(2.0*self.system.cell.volume)*np.sum( self.system.charges*self.system.radii**2 )/self.dielectric if vtens is not None: vtens.ravel()[::4] -= fac return fac
def call_hooks(self): with timer.section('%s hooks' % self.log_name): state_updated = False for hook in self.hooks: if hook.expects_call(self.counter): if not state_updated: for item in self.state_list: item.update(self) state_updated = True hook(self)
def _internal_compute(self, gpos, vtens): with timer.section('Valence'): self.dlist.forward() self.iclist.forward() energy = self.vlist.forward() if not ((gpos is None) and (vtens is None)): self.vlist.back() self.iclist.back() self.dlist.back(gpos, vtens) return energy
def update(self): '''Rebuild or recompute the neighbor lists Based on the changes of the atomic positions or due to calls to ``update_rcut`` and ``update_rmax``, the neighbor lists will be rebuilt from scratch. The heavy computational work is done in low-level C routines. The neighbor lists array is reallocated if needed. The memory allocation is done in Python for convenience. ''' with log.section('NLIST'), timer.section('Nlists'): assert self.rcut > 0 if self._need_rebuild(): # *rebuild* the entire neighborlist if self.system.cell.volume != 0: if self.system.natom / self.system.cell.volume > 10: raise ValueError('Atom density too high') # 1) make an initial status object for the neighbor list algorithm status = nlist_status_init(self.rmax) # The atom index of the first atom in pair is always at least # nlow. The following status initialization avoids searching # for excluded atom pairs in the neighbourlist build status[3] = self.nlow # 2) a loop of consecutive update/allocate calls last_start = 0 while True: done = nlist_build(self.system.pos, self.rcut + self.skin, self.rmax, self.system.cell, status, self.neighs[last_start:], self.nlow, self.nhigh) if done: break last_start = len(self.neighs) new_neighs = np.empty((len(self.neighs) * 3) // 2, dtype=neigh_dtype) new_neighs[:last_start] = self.neighs self.neighs = new_neighs del new_neighs # 3) get the number of neighbors in the list. self.nneigh = nlist_status_finish(status) if log.do_debug: log('Rebuilt, size = %i' % self.nneigh) # 4) store the current state to check in future calls if we # need to do a rebuild or a recompute. self._checkpoint() self.rebuild_next = False else: # just *recompute* the deltas and the distance in the # neighborlist nlist_recompute(self.system.pos, self._pos_old, self.system.cell, self.neighs[:self.nneigh]) if log.do_debug: log('Recomputed')
def run(self): # Run indefinitely (until i-PI sends exit message) while True: with timer.section("WAITHEADER"): # log("WAITHEADER %s" % datetime.now()) header = self.s.await_header() # log("GOTHEADER %s" % datetime.now()) if header == Message("status"): if not self.isinit: self.s.send_header(Message("needinit")) elif self.hasdata: self.s.send_header(Message("havedata")) else: self.s.send_header(Message("ready")) elif header == Message("init"): # ibead = np.fromstring(self.s.await_data(L_INT), np.int32)[0] # len_init = np.fromstring(self.s.await_data(L_INT), np.int32)[0] # init = self.s.await_data(len_init * L_CHAR) if log.do_high: with log.section(self.log_name): # log( "YAFF driver initialized for pid %s (bead %d - %s)" % (os.getpid(), ibead, init) ) log("INIT %s" % datetime.now()) self.isinit = True elif header == Message("posdata"): with timer.section("RECVPOS"), log.section(self.log_name): self.receive_pos() log("RECV %-12s %s" % ("POS", datetime.now())) with timer.section("COMPUTE"): self.compute() elif header == Message("getforce"): with timer.section("SENDFORCE"), log.section(self.log_name): self.send_forces() log("SEND %-12s %s" % ("FORCE", datetime.now())) elif header == Message("exit"): if log.do_high: with log.section(self.log_name): # log('i-PI finished, stopping Yaff driver') log("EXIT %s" % datetime.now()) break else: raise NotImplementedError("Received unknown message %s" % header)
def run(self, nstep=None): with log.section(self.log_name), timer.section(self.log_name): if nstep is None: while True: if self.propagate(): break else: for i in xrange(nstep): if self.propagate(): break self.finalize()
def run(self, nstep=None): with log.section(self.log_name), timer.section(self.log_name): if nstep is None: while True: if self.propagate(): break else: for i in range(nstep): if self.propagate(): break self.finalize()
def call_hooks(self): # Initialize hooks with timer.section('%s hooks' % self.log_name): state_updated = False for hook in self.hooks: if hook.expects_call(self.counter): if not state_updated: for item in self.state_list: item.update(self) state_updated = True hook(self)
def _internal_compute(self, gpos, vtens): with timer.section('Grid'): if gpos is not None: raise NotImplementedError('Cartesian gradients are not supported yet in ForcePartGrid') if vtens is not None: raise NotImplementedError('Cell deformation are not supported by ForcePartGrid') cell = self.system.cell result = 0 for i in xrange(self.system.natom): grid = self.grids[self.system.get_ffatype(i)] result += compute_grid3d(self.system.pos[i], cell, grid) return result
def __init__(self, ff, state=None, hooks=None, counter0=0): """ **Arguments:** ff The ForceField instance used in the iterative algorithm **Optional arguments:** state A list with state items. State items are simple objects that take or derive a property from the current state of the iterative algorithm. hooks A function (or a list of functions) that is called after every iterative. counter0 The counter value associated with the initial state. """ self.ff = ff if state is None: self.state_list = [ state_item.copy() for state_item in self.default_state ] else: #self.state_list = state self.state_list = [ state_item.copy() for state_item in self.default_state ] self.state_list += state self.state = dict((item.key, item) for item in self.state_list) if hooks is None: self.hooks = [] elif hasattr(hooks, '__len__'): self.hooks = hooks else: self.hooks = [hooks] self._add_default_hooks() self.counter0 = counter0 self.counter = counter0 with log.section(self.log_name), timer.section(self.log_name): self.initialize() # Initialize restart hook if present from yaff.sampling.io import RestartWriter for hook in self.hooks: if isinstance(hook, RestartWriter): hook.init_state(self)
def call_hooks(self): with timer.section('%s hooks' % self.log_name): state_updated = False from yaff.sampling.io import RestartWriter for hook in self.hooks: if hook.expects_call(self.counter) and not (isinstance(hook, RestartWriter) and self.counter==self.counter0): if not state_updated: for item in self.state_list: item.update(self) state_updated = True if isinstance(hook, RestartWriter): for item in hook.state_list: item.update(self) hook(self)
def _internal_compute(self, gpos, vtens): with timer.section('Ewald neut.'): #TODO: interaction of dipoles with background? I think this is zero, need proof... fac = self.system.charges.sum()**2 * np.pi / ( 2.0 * self.system.cell.volume * self.alpha**2) / self.dielectric if self.system.radii is not None: fac -= self.system.charges.sum() * np.pi / ( 2.0 * self.system.cell.volume) * np.sum( self.system.charges * self.system.radii**2) / self.dielectric if vtens is not None: vtens.ravel()[::4] -= fac return fac
def _internal_compute(self, gpos, vtens): with timer.section("LAMMPS overhead"): self.update_rvecs(self.system.cell.rvecs) self.update_pos(self.system.pos.copy()) with timer.section("LAMMPS"): self.lammps.command("run 0 post no") with timer.section("LAMMPS overhead"): energy = self.lammps.extract_variable("eng", None, 0) if gpos is not None: f = self.lammps.gather_atoms("f", 1, 3) buffer = np.core.multiarray.int_asbuffer( ctypes.addressof(f), 8 * 3 * self.system.natom) gpos[:] = np.frombuffer(buffer, float).reshape((-1, 3)) # for iatom in xrange(self.system.natom): # for j in xrange(3): # gpos[iatom,j] = f[3*iatom+j] gpos[:] = -np.einsum('ij,kj', gpos, self.rot.transpose()) if vtens is not None: w = self.lammps.extract_compute("virial", 0, 1) buffer = np.core.multiarray.int_asbuffer( ctypes.addressof(w.contents), 8 * 6) vtens_lammps = np.frombuffer(buffer, float) # vtens_lammps = np.zeros(6) # for i in xrange(6): # vtens_lammps[i] = w[i] # Lammps gives the virial per volume in pascal, so we have to # multiply with some prefactors vtens_lammps[:] *= -pascal * self.system.cell.volume # The [6x1] vector has to be cast to a symmetric [3x3] tensor # Lammps orders the values as [xx,yy,zz,xy,xz,yz] vtens[np.triu_indices(3)] = vtens_lammps[[0, 3, 4, 1, 5, 2]] vtens[np.tril_indices(3)] = vtens_lammps[[0, 3, 1, 4, 5, 2]] # Finally we have to compute the effect of the rotation on the # the virial tensor to get the values in Yaff coordinates vtens[:] = np.dot(self.rot.transpose(), np.dot(vtens[:], self.rot)) return energy
def update(self): '''Rebuild or recompute the neighbor lists Based on the changes of the atomic positions or due to calls to ``update_rcut`` and ``update_rmax``, the neighbor lists will be rebuilt from scratch. The heavy computational work is done in low-level C routines. The neighbor lists array is reallocated if needed. The memory allocation is done in Python for convenience. ''' with log.section('NLIST'), timer.section('Nlists'): assert self.rcut > 0 if self._need_rebuild(): # *rebuild* the entire neighborlist if self.system.cell.volume != 0: if self.system.natom/self.system.cell.volume > 10: raise ValueError('Atom density too high') # 1) make an initial status object for the neighbor list algorithm status = nlist_status_init(self.rmax) # 2) a loop of consecutive update/allocate calls last_start = 0 while True: done = nlist_build( self.system.pos, self.rcut + self.skin, self.rmax, self.system.cell, status, self.neighs[last_start:] ) if done: break last_start = len(self.neighs) new_neighs = np.empty((len(self.neighs)*3)/2, dtype=neigh_dtype) new_neighs[:last_start] = self.neighs self.neighs = new_neighs del new_neighs # 3) get the number of neighbors in the list. self.nneigh = nlist_status_finish(status) if log.do_debug: log('Rebuilt, size = %i' % self.nneigh) # 4) store the current state to check in future calls if we # need to do a rebuild or a recompute. self._checkpoint() self.rebuild_next = False else: # just *recompute* the deltas and the distance in the # neighborlist nlist_recompute(self.system.pos, self._pos_old, self.system.cell, self.neighs[:self.nneigh]) if log.do_debug: log('Recomputed')
def _internal_compute(self, gpos, vtens): with timer.section('Grid'): if gpos is not None: raise NotImplementedError( 'Cartesian gradients are not supported yet in ForcePartGrid' ) if vtens is not None: raise NotImplementedError( 'Cell deformation are not supported by ForcePartGrid') cell = self.system.cell result = 0 for i in range(self.system.natom): grid = self.grids[self.system.get_ffatype(i)] result += compute_grid3d(self.system.pos[i], cell, grid) return result
def call_verlet_hooks(self, kind): # In this call, the state items are not updated. The pre and post calls # of the verlet hooks can rely on the specific implementation of the # VerletIntegrator and need not to rely on the generic state item # interface. with timer.section('%s special hooks' % self.log_name): for hook in self.hooks: if isinstance(hook, VerletHook) and hook.expects_call(self.counter): if kind == 'init': hook.init(self) elif kind == 'pre': hook.pre(self) elif kind == 'post': hook.post(self) else: raise NotImplementedError
def __init__(self, ff, state=None, hooks=None, counter0=0): """ **Arguments:** ff The ForceField instance used in the iterative algorithm **Optional arguments:** state A list with state items. State items are simple objects that take or derive a property from the current state of the iterative algorithm. hooks A function (or a list of functions) that is called after every iterative. counter0 The counter value associated with the initial state. """ self.ff = ff if state is None: self.state_list = [state_item.copy() for state_item in self.default_state] else: #self.state_list = state self.state_list = [state_item.copy() for state_item in self.default_state] self.state_list += state self.state = dict((item.key, item) for item in self.state_list) if hooks is None: self.hooks = [] elif hasattr(hooks, '__len__'): self.hooks = hooks else: self.hooks = [hooks] self._add_default_hooks() self.counter0 = counter0 self.counter = counter0 with log.section(self.log_name), timer.section(self.log_name): self.initialize() # Initialize restart hook if present from yaff.sampling.io import RestartWriter for hook in self.hooks: if isinstance(hook, RestartWriter): hook.init_state(self)
def call_verlet_hooks(self, kind): from yaff.sampling.npt import BerendsenBarostat, TBCombination # In this call, the state items are not updated. The pre and post calls # of the verlet hooks can rely on the specific implementation of the # VerletIntegrator and need not to rely on the generic state item # interface. with timer.section('%s special hooks' % self.log_name): for hook in self.hooks: if isinstance(hook, VerletHook) and hook.expects_call( self.counter): if kind == 'init': hook.init(self) elif kind == 'pre': hook.pre(self) elif kind == 'post': hook.post(self) else: raise NotImplementedError
def __call__(self): """Perform a trial move and calculate the associated energy difference, decide whether it is accepted or not, and update the state of the MC simulation accordingly """ with timer.section("MC %s move" % self.log_name): e = self.compute() p = self.probability(e) if np.random.rand()>p: accepted = False self.reject() else: accepted = True self.mc.energy += e self.accept() if log.do_debug: log("MC %s: N = %d energy difference = %s acceptance probability = %6.2f %% accepted = %s" % (self.__class__.__name__, self.mc.N, log.energy(e), p*100.0, accepted)) return accepted
def _internal_compute(self, gpos, vtens): with timer.section('Valence'): cell = self.system.cell if (vtens is not None): rvecs = cell.rvecs if cell.nvec == 1: vtens += self.pext/cell.volume*np.outer(rvecs[0], rvecs[0]) elif cell.nvec == 2: vtens += self.pext/cell.volume*( np.dot(rvecs[0], rvecs[0])*np.outer(rvecs[1], rvecs[1]) + np.dot(rvecs[0], rvecs[0])*np.outer(rvecs[1], rvecs[1]) - np.dot(rvecs[1], rvecs[0])*np.outer(rvecs[0], rvecs[1]) - np.dot(rvecs[0], rvecs[1])*np.outer(rvecs[1], rvecs[0]) ) elif cell.nvec == 3: gvecs = cell.gvecs vtens += self.pext*cell.volume*np.identity(3) else: raise NotImplementedError return cell.volume*self.pext
def _internal_compute(self, gpos, vtens): with timer.section('Bias'): energy = 0.0 # ValenceTerms energy += self.valence._internal_compute(gpos, vtens) #if self.valence_com is not None: # energy += self.valence_com._internal_compute(gpos, vtens) # BiasPotentials if gpos is None: my_gpos = None else: my_gpos = np.zeros((self.system.natom, 3)) if vtens is None: my_vtens = None else: my_vtens = np.zeros((3, 3)) for term in self.terms: if isinstance(term, ValenceTerm): continue energy += term.compute(gpos=my_gpos, vtens=my_vtens) if gpos is not None: gpos[:] += my_gpos if vtens is not None: vtens[:] += my_vtens return energy
def _internal_compute(self, gpos, vtens): with timer.section('Valence'): cell = self.system.cell if (vtens is not None): rvecs = cell.rvecs if cell.nvec == 1: vtens += self.pext / cell.volume * np.outer( rvecs[0], rvecs[0]) elif cell.nvec == 2: vtens += self.pext / cell.volume * ( np.dot(rvecs[0], rvecs[0]) * np.outer( rvecs[1], rvecs[1]) + np.dot(rvecs[0], rvecs[0]) * np.outer(rvecs[1], rvecs[1]) - np.dot(rvecs[1], rvecs[0]) * np.outer( rvecs[0], rvecs[1]) - np.dot(rvecs[0], rvecs[1]) * np.outer(rvecs[1], rvecs[0])) elif cell.nvec == 3: gvecs = cell.gvecs vtens += self.pext * cell.volume * np.identity(3) else: raise NotImplementedError return cell.volume * self.pext
def estimate_hessian(dof, eps=1e-4): """Estimate the Hessian using the symmetric finite difference approximation. **Arguments:** dof A DOF object **Optional arguments:** eps The magnitude of the displacements """ with log.section('HESS'), timer.section('Hessian'): # Loop over all displacements if log.do_medium: log('The following displacements are computed:') log('DOF Dir Energy') log.hline() x1 = dof.x0.copy() rows = np.zeros((len(x1), len(x1)), float) for i in xrange(len(x1)): x1[i] = dof.x0[i] + eps epot, gradient_p = dof.fun(x1, do_gradient=True) if log.do_medium: log('% 7i pos %s' % (i, log.energy(epot))) x1[i] = dof.x0[i] - eps epot, gradient_m = dof.fun(x1, do_gradient=True) if log.do_medium: log('% 7i neg %s' % (i, log.energy(epot))) rows[i] = (gradient_p - gradient_m) / (2 * eps) x1[i] = dof.x0[i] dof.reset() if log.do_medium: log.hline() # Enforce symmetry and return return 0.5 * (rows + rows.T)
def estimate_hessian(dof, eps=1e-4): """Estimate the Hessian using the symmetric finite difference approximation. **Arguments:** dof A DOF object **Optional arguments:** eps The magnitude of the displacements """ with log.section('HESS'), timer.section('Hessian'): # Loop over all displacements if log.do_medium: log('The following displacements are computed:') log('DOF Dir Energy') log.hline() x1 = dof.x0.copy() rows = np.zeros((len(x1), len(x1)), float) for i in xrange(len(x1)): x1[i] = dof.x0[i] + eps epot, gradient_p = dof.fun(x1, do_gradient=True) if log.do_medium: log('% 7i pos %s' % (i, log.energy(epot))) x1[i] = dof.x0[i] - eps epot, gradient_m = dof.fun(x1, do_gradient=True) if log.do_medium: log('% 7i neg %s' % (i, log.energy(epot))) rows[i] = (gradient_p-gradient_m)/(2*eps) x1[i] = dof.x0[i] dof.reset() if log.do_medium: log.hline() # Enforce symmetry and return return 0.5*(rows + rows.T)
def _internal_compute(self, gpos, vtens): with timer.section('Ewald reci.'): return compute_ewald_reci( self.system.pos, self.system.charges, self.system.cell, self.alpha, self.gmax, self.gcut, self.dielectric, gpos, self.work, vtens, self.n_frame )
def _internal_compute(self, gpos, vtens): with timer.section('Ewald reci.'): return compute_ewald_reci(self.system.pos, self.system.charges, self.system.cell, self.alpha, self.gmax, self.gcut, self.dielectric, gpos, self.work, vtens)
def _internal_compute(self, gpos, vtens): with timer.section('Ewald corr.'): return compute_ewald_corr_dd(self.system.pos, self.system.charges, self.system.dipoles, self.system.cell, self.alpha, self.scalings.stab, gpos, vtens)
def _internal_compute(self, gpos, vtens): with timer.section('Ewald reci.'): return compute_ewald_reci_dd( self.system.pos, self.system.charges, self.system.dipoles, self.system.cell, self.alpha, self.gmax, self.gcut, gpos, self.work, vtens )
def _internal_compute(self, gpos, vtens): with timer.section('PP %s' % self.pair_pot.name): return self.pair_pot.compute(self.nlist.neighs, self.scalings.stab, gpos, vtens, self.nlist.nneigh)
def _internal_compute(self, gpos, vtens): with timer.section('Ewald corr.'): return compute_ewald_corr_dd( self.system.pos, self.system.charges, self.system.dipoles, self.system.cell, self.alpha, self.scalings.stab, gpos, vtens )
def run(self, nsteps, mc_moves=None, initial=None, einit=0, translation_stepsize=1.0*angstrom, volumechange_stepsize=10.0*angstrom**3, close_contact=0.4*angstrom): """ Perform Monte-Carlo steps **Arguments:** nsteps Number of Monte-Carlo steps **Optional Arguments:** mc_moves Dictionary containing relative probabilities of the different Monte-Carlo moves. It is not required that the probabilities sum to 1, they are normalized automatically. Example initial System instance describing the initial configuration of guest molecules einit The energy of the initial state translation_stepsize The maximal magnitude of a TrialTranslation volumechange_stepsize The maximal magnitude of a TrialVolumechange close_contact Automatically reject TrialMove if atoms are placed shorter than this distance apart """ if log.do_warning: log.warn("Currently, Yaff does not consider interactions of a guest molecule " "with its periodic images in MC simulations. Make sure that you choose a system size " "that is large compared to the guest dimensions, so it is indeed " "acceptable to neglect these interactions.") with log.section(self.log_name), timer.section(self.log_name): # Initialization self.translation_stepsize = translation_stepsize self.volumechange_stepsize = volumechange_stepsize self.close_contact = close_contact if initial is not None: self.N = initial.natom//self.guest.natom assert self.guest.natom*self.N==initial.natom, ("Initial configuration does not contain correct number of atoms") self.current_configuration = initial self.get_ff(self.N).system.pos[:] = initial.pos if self.ewald_reci is not None: self.ewald_reci.compute_structurefactors( initial.pos, initial.charges, self.ewald_reci.cosfacs, self.ewald_reci.sinfacs) else: self.current_configuration = self.get_ff(self.N).system self.energy = einit if not self.conditions_set: raise ValueError("External conditions have not been set!") # Normalized probabilities and accompanying methods specifying the trial MC moves # Trial moves are sorted alphabetically if mc_moves is None: mc_moves = self.default_trials trials, probabilities = [], [] for t in sorted(mc_moves.keys()): if not t in self.allowed_trials: raise ValueError("Trial move %s not allowed!"%t) trial = getattr(mctrials,"Trial"+t.capitalize(),None) if trial is None: raise NotImplementedError("The requested trial move %s is not implemented"%(t)) # Trials is a list containing instances of Trial classes from the mctrials module trials.append(trial(self)) probabilities.append(mc_moves[t]) probabilities = np.asarray(probabilities) probabilities /= np.sum(probabilities) assert np.all(probabilities>=0.0), "Negative probabilities are not allowed!" # Take the cumulative sum, makes it a bit easier to determine which MC move is selected probabilities = np.cumsum(probabilities) # Array to keep track of accepted (1st column) and tried (2nd column) # moves, with rows corresponding to different possible moves acceptance = np.zeros((len(trials),2), dtype=int) # Start performing MC moves self.Nmean = self.N self.emean = self.energy self.Vmean = self.current_configuration.cell.volume self.counter = 0 self.call_hooks() for istep in range(nsteps): switch = np.random.rand() # Select one of the possible MC moves imove = np.where(switch<probabilities)[0][0] # Call the corresponding method accepted = trials[imove]() # Update records with accepted and tried MC moves acceptance[imove,1] += 1 if accepted: acceptance[imove,0] += 1 self.counter += 1 self.Nmean += (self.N-self.Nmean)/self.counter self.emean += (self.energy-self.emean)/self.counter self.Vmean += (self.current_configuration.cell.volume-self.Vmean)/self.counter self.call_hooks() return acceptance
def _internal_compute(self, gpos, vtens): with timer.section('Ewald reci.'): return compute_ewald_reci_dd(self.system.pos, self.system.charges, self.system.dipoles, self.system.cell, self.alpha, self.gmax, self.gcut, gpos, self.work, vtens, self.n_frame)