def __init__(self, *args, **results): """Save energy, forces, stress, ... for the current configuration.""" if args and isinstance(args[0], float): # Old interface: assert not results for key, value in zip(['energy', 'forces', 'stress', 'magmoms'], args): if value is not None: results[key] = value atoms = args[-1] else: if args: atoms = args[0] else: atoms = results.pop('atoms') Calculator.__init__(self) self.results = {} for property, value in results.items(): assert property in all_properties if value is None: continue if property in ['energy', 'magmom']: self.results[property] = value else: self.results[property] = np.array(value, float) self.atoms = atoms.copy()
def run_calculation(self, atoms=None, properties=None, system_changes=all_changes): ''' Internal calculation executor. We cannot use FileIOCalculator directly since we need to support remote execution. This calculator is different from others. It prepares the directory, launches the remote process and raises the exception to signal that we need to come back for results when the job is finished. ''' if properties is None: properties = ['energy'] Calculator.calculate(self, atoms, properties, system_changes) self.write_input(self.atoms, properties, system_changes) if self.command is None: raise RuntimeError('Please configure RemoteQE calculator!') olddir = os.getcwd() errorcode=0 try: os.chdir(self.directory) output = subprocess.check_output(self.command, shell=True) self.jobid=output.split()[0] self.submited=True #print "Job %s submitted. Waiting for it." % (self.jobid) # Waiting loop. To be removed. except subprocess.CalledProcessError as e: errorcode=e.returncode finally: os.chdir(olddir) if errorcode: raise RuntimeError('%s returned an error: %d' % (self.name, errorcode)) self.read_results()
def __init__(self, calculator, db='checkpoints.db', logfile=None): Calculator.__init__(self) self.calculator = calculator if logfile is None: logfile = DevNull() self.checkpoint = Checkpoint(db, logfile) self.logfile = logfile
def calculate(self, atoms, properties, system_changes): """ Calculation of the energy of system and forces of all atoms. """ # The inherited method below just sets the atoms object, # if specified, to self.atoms. Calculator.calculate(self, atoms, properties, system_changes) log = self.log log('Calculation requested.') images = hash_images([self.atoms]) key = images.keys()[0] if properties == ['energy']: log('Calculating potential energy...', tic='pot-energy') self.descriptor.calculate_fingerprints(images=images, log=log, calculate_derivatives=False) energy = self.model.get_energy(self.descriptor.fingerprints[key]) self.results['energy'] = energy log('...potential energy calculated.', toc='pot-energy') if properties == ['forces']: log('Calculating forces...', tic='forces') self.descriptor.calculate_fingerprints(images=images, log=log, calculate_derivatives=True) forces = \ self.model.get_forces(self.descriptor.fingerprints[key], self.descriptor.fingerprintprimes[key]) self.results['forces'] = forces log('...forces calculated.', toc='forces')
def __init__(self, restart=None, ignore_bad_restart_file=False, label=None, atoms=None, calc=None, block=False, **kwargs): '''Basic calculator implementation. restart: str Prefix for restart file. May contain a directory. Default is None: don't restart. ignore_bad_restart_file: bool Ignore broken or missing restart file. By default, it is an error if the restart file is missing or broken. label: str Name used for all files. May contain a directory. atoms: Atoms object Optional Atoms object to which the calculator will be attached. When restarting, atoms will get its positions and unit-cell updated from file. Create a remote execution calculator based on actual ASE calculator calc. ''' logging.debug("Calc: %s Label: %s" % (calc, label)) Calculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs) logging.debug("Dir: %s Ext: %s" % (self.directory, self.ext)) self.calc=calc self.jobid=None self.block=block
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) try: results = self.checkpoint.load(atoms) prev_atoms, results = results[0], results[1:] try: assert atoms_almost_equal(atoms, prev_atoms) except AssertionError: raise AssertionError('mismatch between current atoms and those read from checkpoint file') self.logger.pr('retrieved results for {0} from checkpoint'.format(properties)) # save results in calculator for next time if isinstance(self.calculator, Calculator): if not hasattr(self.calculator, 'results'): self.calculator.results = {} self.calculator.results.update(dict(zip(properties, results))) except NoCheckpoint: if isinstance(self.calculator, Calculator): self.logger.pr('doing calculation of {0} with new-style calculator interface'.format(properties)) self.calculator.calculate(atoms, properties, system_changes) results = [self.calculator.results[prop] for prop in properties] else: self.logger.pr('doing calculation of {0} with old-style calculator interface'.format(properties)) results = [] for prop in properties: method_name = CheckpointCalculator.property_to_method_name[prop] method = getattr(self.calculator, method_name) results.append(method(atoms)) _calculator = atoms.get_calculator try: atoms.set_calculator(self.calculator) self.checkpoint.save(atoms, *results) finally: atoms.set_calculator(_calculator) self.results = dict(zip(properties, results))
def relax(self, atoms=None, properties=['energy'], system_changes=some_changes, flag_damping=2, converge_eps=1.0e-3,nsteps=100,min_iteration=5, converge_num=3,time_interval=2.0, initial_temperature=10.0): """ Relax atom positions by running damped MD in pmd instead of using optimize module in ASE. """ self.set(flag_damping=flag_damping, converge_eps=converge_eps, num_iteration=nsteps, min_iteration=min_iteration, num_out_energy=nsteps, converge_num=converge_num, time_interval=time_interval, initial_temperature=initial_temperature, flag_sort=1) Calculator.calculate(self, atoms, properties, system_changes) # print 'type(atoms),type(self.atoms)= ',type(atoms),type(self.atoms) # print 'self.atoms = ',self.atoms self.write_input(self.atoms, properties, system_changes) olddir = os.getcwd() try: os.chdir(self.directory) errorcode = subprocess.call(self.command, shell=True) finally: os.chdir(olddir) if errorcode: raise RuntimeError('%s returned an error: %d' % (self.name, errorcode)) self.read_results(relax=True)
def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): # We don't call FileIOCalculator.calculate here, because that method # calls subprocess.call(..., shell=True), which we don't want to do. # So, we reproduce some content from that method here. Calculator.calculate(self, atoms, properties, system_changes) # If a parameter file exists in the working directory, delete it # first. If we need that file, we'll recreate it later. localparfile = os.path.join(self.directory, '.dftd3par.local') if os.path.isfile(localparfile): os.remove(localparfile) # Write XYZ or POSCAR file and .dftd3par.local file if we are using # custom damping parameters. self.write_input(self.atoms, properties, system_changes) command = self._generate_command() # Finally, call dftd3 and parse results. with open(self.label + '.out', 'w') as f: errorcode = subprocess.call(command, cwd=self.directory, stdout=f) if errorcode: raise RuntimeError('%s returned an error: %d' % (self.name, errorcode)) self.read_results()
def __init__(self, morses=None, bonds=None, angles=None, dihedrals=None, vdws=None, coulombs=None, **kwargs): Calculator.__init__(self, **kwargs) if (morses is None and bonds is None and angles is None and dihedrals is None and vdws is None and coulombs is None): raise ImportError("At least one of morses, bonds, angles, dihedrals," "vdws or coulombs lists must be defined!") if morses is None: self.morses = [] else: self.morses = morses if bonds is None: self.bonds = [] else: self.bonds = bonds if angles is None: self.angles = [] else: self.angles = angles if dihedrals is None: self.dihedrals = [] else: self.dihedrals = dihedrals if vdws is None: self.vdws = [] else: self.vdws = vdws if coulombs is None: self.coulombs = [] else: self.coulombs = coulombs
def calculate(self, atoms=None, properties=['energy'], system_changes=None): """Runs a calculation, only if necessary.""" if self.calculation_required(atoms, properties): # The subclass implementation should first call this # implementation to set the atoms attribute. Calculator.calculate(self, atoms, properties, system_changes) self.write_input(atoms, properties, system_changes) if self.command is None: raise RuntimeError('Please set $%s environment variable ' % ('ASE_' + self.name.upper() + '_COMMAND') + 'or supply the command keyword') olddir = os.getcwd() try: os.chdir(self.directory) errorcode = subprocess.call(self.command, stdout=subprocess.PIPE, shell=True) finally: os.chdir(olddir) if errorcode: s = '{} returned an error: {}' raise RuntimeError(s.format(self.name, errorcode)) # This sets self.results, and updates the atoms self.read_results()
def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): """EAM Calculator atoms: Atoms object Contains positions, unit-cell, ... properties: list of str List of what needs to be calculated. Can be any combination of 'energy', 'forces' system_changes: list of str List of what has changed since last calculation. Can be any combination of these five: 'positions', 'numbers', 'cell', 'pbc', 'initial_charges' and 'initial_magmoms'. """ Calculator.calculate(self, atoms, properties, system_changes) # we shouldn't really recalc if charges or magmos change if len(system_changes) > 0: # something wrong with this way self.update(self.atoms) self.calculate_energy(self.atoms) if 'forces' in properties: self.calculate_forces(self.atoms) # check we have all the properties requested for property in properties: if property not in self.results: if property is 'energy': self.calculate_energy(self.atoms) if property is 'forces': self.calculate_forces(self.atoms)
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) if self.qmatoms is None: self.initialize_qm(atoms) self.qmatoms.positions = atoms.positions[self.selection] if self.vacuum: self.qmatoms.positions += (self.center - self.qmatoms.positions.mean(axis=0)) energy = self.mmcalc2.get_potential_energy(atoms) forces = self.mmcalc2.get_forces(atoms) energy += self.qmcalc.get_potential_energy(self.qmatoms) qmforces = self.qmcalc.get_forces(self.qmatoms) if self.vacuum: qmforces -= qmforces.mean(axis=0) forces[self.selection] += qmforces energy -= self.mmcalc1.get_potential_energy(self.qmatoms) forces[self.selection] -= self.mmcalc1.get_forces(self.qmatoms) self.results['energy'] = energy self.results['forces'] = forces
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) if system_changes: # if anything at all changed (could be made more fine-grained) self.logger.pr('calculation triggered with properties={0}, system_changes={1}'.format(properties, system_changes)) self.server.put(atoms, 0, self.label) if self.label != 1: # send atoms over socket, unless first time self.logger.pr('socket calculator sending Atoms label={0}'.format(self.label)) self.server.handle_request() # wait for results to be ready self.logger.pr('socket calculator waiting for results label={0}'.format(self.label)) self.server.handle_request() self.label += 1 [results] = self.server.get_results() # we always compute energy, forces and stresses, regardless of what was requested stress = -(results.info['virial']/results.get_volume()) self.results = {'energy': results.info['energy'], 'forces': results.arrays['force'], 'stress': full_3x3_to_Voigt_6_stress(stress)} else: self.logger.pr('calculation avoided with properties={0}, system_changes={1}'.format(properties, system_changes))
def __init__(self, hirshfeld=None, vdwradii=None, calculator=None, Rmax = 10, # maximal radius for periodic calculations vdWDB_alphaC6 = vdWDB_alphaC6, txt=None, ): """Constructor Parameters ========== hirshfeld: the Hirshfeld partitioning object calculator: the calculator to get the PBE energy """ self.hirshfeld = hirshfeld if calculator is None: self.calculator = self.hirshfeld.get_calculator() else: self.calculator = calculator if txt is None: self.txt = self.calculator.txt else: self.txt = get_txt(txt, rank) self.vdwradii = vdwradii self.vdWDB_alphaC6 = vdWDB_alphaC6 self.Rmax = Rmax self.atoms = None self.sR = 0.94 self.d = 20 Calculator.__init__(self)
def __init__(self, restart=None, ignore_bad_restart_file=False, label=None, atoms=None, k=10, rt=1.5, sp_type='rep', **kwargs): Calculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs) # Common parameters to all springs self.sp_type = sp_type self.k = k self.rt = rt # Depending on the spring type use different kernels self.nrg_func = spring_nrg self.f_func = spring_force self.v_nrg = voxel_spring_nrg self.atomwise_nrg = atomwise_spring_nrg if sp_type == 'com': self.nrg_func = com_spring_nrg self.f_func = com_spring_force self.v_nrg = voxel_com_spring_nrg self.atomwise_nrg = atomwise_com_spring_nrg if sp_type == 'att': self.nrg_func = att_spring_nrg self.f_func = att_spring_force self.v_nrg = voxel_att_spring_nrg self.atomwise_nrg = atomwise_att_spring_nrg
def __init__(self, f, cutoff=None): Calculator.__init__(self) self.f = f self.dict = {x: obj.get_cutoff() for x, obj in f.items()} self.df = {x: obj.derivative(1) for x, obj in f.items()} self.df2 = {x: obj.derivative(2) for x, obj in f.items()}
def calculate(self, atoms=None, properties=['energy'], system_changes=['positions', 'numbers', 'cell', 'pbc', 'charges', 'magmoms']): Calculator.calculate(self, atoms, properties, system_changes) epsilon = self.parameters.epsilon rho0 = self.parameters.rho0 r0 = self.parameters.r0 positions = self.atoms.get_positions() energy = 0.0 energies = np.zeros(len(self.atoms)) forces = np.zeros((len(self.atoms), 3)) preF = 2 * epsilon * rho0 / r0 for i1, p1 in enumerate(positions): for i2, p2 in enumerate(positions[:i1]): diff = p2 - p1 r = sqrt(np.dot(diff, diff)) expf = exp(rho0 * (1.0 - r / r0)) energy += epsilon * expf * (expf - 2) energies[i1] += epsilon * expf * (expf - 2) energies[i2] += epsilon * expf * (expf - 2) F = preF * expf * (expf - 1) * diff / r forces[i1] -= F forces[i2] += F self.results['energy'] = energy self.results['forces'] = forces self.results['potential_energies'] = energies
def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): """GEBF Calculator """ Calculator.calculate(self, atoms, properties, system_changes) if len(system_changes) > 0: # something wrong with this way self.update(self.atoms) if 'energy' in properties: self.calculate_energy(self.atoms) if 'forces' in properties: self.calculate_forces(self.atoms) if 'charges' in properties: self.calculate_charges(self.atoms) # check we have all the properties requested for property in properties: if property not in self.results: if property is 'energy': self.calculate_energy(self.atoms) if property is 'forces': self.calculate_forces(self.atoms) if property is 'charges': self.calculate_charges(self.atoms) #FUMPORTANT| atoms.set_initial_charges(self.results['charges'])
def calculate(self, atoms, properties, system_changes): # call parent method: Calculator.calculate(self, atoms, properties, system_changes) if not(system_changes is None): self.update_atoms() if 'energy' in properties: energy = self.ff.Energy() # energy units are kcal/mole according to http://forums.openbabel.org/Energy-units-td1574278.html # and in Avogadro they are reported as kJ/mole ... self.results['energy'] = energy * units.kJ / units.mol if 'forces' in properties: d = 0.001 F_ai = np.zeros( (self.natoms, 3) ) for iatom in xrange( self.natoms ): for iaxis in xrange( 3 ): obatom = self.mol.GetAtom( 1 + iatom ) vec = obatom.GetVector() obatom.SetVector( self._shift_OBvec(vec, iaxis, d) ) self.ff.Setup( self.mol ) eplus = self.ff.Energy() * units.kJ/units.mol obatom.SetVector( self._shift_OBvec(vec, iaxis, -2*d) ) self.ff.Setup( self.mol ) eminus = self.ff.Energy() * units.kJ/units.mol obatom.SetVector( self._shift_OBvec(vec, iaxis, d) ) # put it back F_ai[iatom, iaxis] = (eminus - eplus) / (2 * d) self.results['forces'] = F_ai
def calculate(self, atoms=None, properties=None, system_changes=all_changes): '''Do the calculation.''' if(not properties): properties = ['energy'] Calculator.calculate(self, atoms, properties, system_changes) if('numbers' in system_changes or 'initial_magmoms' in system_changes): self._release_force_env() if(self._force_env_id is None): self._create_force_env() n_atoms = len(self.atoms) if('cell' in system_changes): cell = self.atoms.get_cell() self._send('SET_CELL %d' % self._force_env_id) self._send(' '.join(['%.10f' % x for x in cell.flat])) assert(self._recv() == '* READY') if('positions' in system_changes): self._send('SET_POS %d' % self._force_env_id) self._send('%d' % (3 * n_atoms)) for pos in self.atoms.get_positions(): self._send('%.10f %.10f %.10f' % (pos[0], pos[1], pos[2])) self._send('*END') assert(float(self._recv()) >= 0) # max change -> ignore assert(self._recv() == '* READY') self._send('EVAL_EF %d' % self._force_env_id) assert(self._recv() == '* READY') self._send('GET_E %d' % self._force_env_id) self.results['energy'] = float(self._recv()) * Hartree assert(self._recv() == '* READY') forces = np.zeros(shape=(n_atoms, 3)) self._send('GET_F %d' % self._force_env_id) assert(int(self._recv()) == 3 * n_atoms) for i in range(n_atoms): line = self._recv() forces[i, :] = [float(x) for x in line.split()] assert(self._recv() == '* END') assert(self._recv() == '* READY') self.results['forces'] = forces * Hartree / Bohr self._send('GET_STRESS %d' % self._force_env_id) line = self._recv() assert(self._recv() == '* READY') stress = np.array([float(x) for x in line.split()]).reshape(3, 3) assert(np.all(stress == np.transpose(stress))) # should be symmetric # Convert 3x3 stress tensor to Voigt form as required by ASE stress = np.array([stress[0, 0], stress[1, 1], stress[2, 2], stress[1, 2], stress[0, 2], stress[0, 1]]) self.results['stress'] = stress * Hartree / Bohr**3
def __init__(self, restart=None, ignore_bad_restart_file=False, label='cp2k', atoms=None, command=None, debug=False, **kwargs): """Construct CP2K-calculator object.""" self._debug = debug self._force_env_id = None self._child = None self._shell_version = None self.label = None self.parameters = None self.results = None self.atoms = None # Several places are check to determine self.command if command is not None: self.command = command elif CP2K.command is not None: self.command = CP2K.command elif 'ASE_CP2K_COMMAND' in os.environ: self.command = os.environ['ASE_CP2K_COMMAND'] else: self.command = 'cp2k_shell' # default assert 'cp2k_shell' in self.command Calculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs) # launch cp2k_shell child process if self._debug: print(self.command) self._child = Popen(self.command, shell=True, universal_newlines=True, stdin=PIPE, stdout=PIPE, bufsize=1) assert self._recv() == '* READY' # check version of shell self._send('VERSION') shell_version = self._recv().rsplit(":", 1) assert self._recv() == '* READY' assert shell_version[0] == "CP2K Shell Version" self._shell_version = float(shell_version[1]) assert self._shell_version >= 1.0 # enable harsh mode, stops on any error self._send('HARSH') assert self._recv() == '* READY' if restart is not None: try: self.read(restart) except: if ignore_bad_restart_file: self.reset() else: raise
def __init__(self, restart=None, ignore_bad_restart_file=False, label=None, atoms=None, **kwargs): """Accepted Keypairs calculation: str - only scf[default] supported at the moment ecutwfc: plane wave cuttoff [eV] notice not in Ry! nbands: number of bands for calculation (see pw.x -> nbnd) usesymm: whether or not to use symmetry in calculation (True/False) maxiter: maximum number of iterations in an scf step convergence: {'energy', <value>} - only one implemented kpts: (1, 1, 1) - gamma point (n1, n2, n3) - Morstead Packing [[k1, k2, k3] ... ] - List of kpoints prefix: (self.label is meaningless at moment) str - string to append to output files pseudo: {'atom symbol': 'name of pseudo potential', ...} - dictionary of pseudo per atom outdir: str - relative or absolute path to output directory. Will create it if it does not exist. pseudo_dir: str - relative or absolute path to pseudo directory. occupations: str - 'smearing', 'tetrahedra', 'fixed', 'from_input' input_dft: str - functional to use fft_mesh: [nr1, nr2, nr3] - fft mesh to use for calculation keypairs: way to initialize via the base class PWBase. (DO NOT SET CELL OR ATOM POSITIONS via PWBase this is done automagically via ASE Atoms) debug: if True will print input and output QE files AUTOMATICALLY SET KEYPAIRS: Set so we can always extract stress and forces: control.tstress=True control.tprnfor=True From atoms object: CARD 'CELL PARAMETERS (angstroms)' from atoms.cell CARD 'ATOMIC POSITIONS (angstroms)' from atoms[i] system.nat from number of unique atoms in atoms[i] system.ntyp from len(atoms) Thus DO NOT SET: A, B, C, cosAB, cosBC, cosAC, celldm(1-6) or any of these previously mentioned. Be smart """ Calculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs) self._pw = None
def __init__(self, atoms=None, label=None, top=None, crd=None, mm_options=None, qm_options=None, permutation=None, **kwargs): if not have_sander: raise RuntimeError("sander Python module could not be imported!") Calculator.__init__(self, label, atoms) self.permutation = permutation if qm_options is not None: sander.setup(top, crd.coordinates, crd.box, mm_options, qm_options) else: sander.setup(top, crd.coordinates, crd.box, mm_options)
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms) self.kpts = kpts2ndarray(self.parameters.kpts, atoms) icell = atoms.get_reciprocal_cell() * 2 * np.pi * Bohr n = 7 offsets = np.indices((n, n, n)).T.reshape((n**3, 1, 3)) - n // 2 eps = 0.5 * (np.dot(self.kpts + offsets, icell)**2).sum(2).T eps.sort() self.eigenvalues = eps[:, :20] * Ha self.results = {'energy': 0.0}
def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) natoms = len(self.atoms) sigma = self.parameters.sigma epsilon = self.parameters.epsilon rc = self.parameters.rc if rc is None: rc = 3 * sigma if 'numbers' in system_changes: self.nl = NeighborList([rc / 2] * natoms, self_interaction=False) self.nl.update(self.atoms) positions = self.atoms.positions cell = self.atoms.cell e0 = 4 * epsilon * ((sigma / rc)**12 - (sigma / rc)**6) energy = 0.0 forces = np.zeros((natoms, 3)) stress = np.zeros((3, 3)) for a1 in range(natoms): neighbors, offsets = self.nl.get_neighbors(a1) cells = np.dot(offsets, cell) d = positions[neighbors] + cells - positions[a1] r2 = (d**2).sum(1) c6 = (sigma**2 / r2)**3 c6[r2 > rc**2] = 0.0 energy -= e0 * (c6 != 0.0).sum() c12 = c6**2 energy += 4 * epsilon * (c12 - c6).sum() f = (24 * epsilon * (2 * c12 - c6) / r2)[:, np.newaxis] * d #print d #print r2**.5 #print offsets #print f #print neighbors forces[a1] -= f.sum(axis=0) for a2, f2 in zip(neighbors, f): forces[a2] += f2 stress += np.dot(f.T, d) #stress = np.dot(stress, cell) stress += stress.T.copy() stress *= -0.5 / self.atoms.get_volume() self.results['energy'] = energy self.results['forces'] = forces self.results['stress'] = stress.flat[[0, 4, 8, 5, 2, 1]]
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) nat = len(self.atoms) atnums = self.atoms.numbers atnums_in_system = set(atnums) i_n, j_n, dr_nc, abs_dr_n = neighbour_list( 'ijDd', self.atoms, self.dict) e_n = np.zeros_like(abs_dr_n) de_n = np.zeros_like(abs_dr_n) for params, pair in enumerate(self.dict): if pair[0] == pair[1]: mask1 = atnums[i_n] == pair[0] mask2 = atnums[j_n] == pair[0] mask = np.logical_and(mask1, mask2) e_n[mask] = self.f[pair](abs_dr_n[mask]) de_n[mask] = self.df[pair](abs_dr_n[mask]) if pair[0] != pair[1]: mask1 = np.logical_and( atnums[i_n] == pair[0], atnums[j_n] == pair[1]) mask2 = np.logical_and( atnums[i_n] == pair[1], atnums[j_n] == pair[0]) mask = np.logical_or(mask1, mask2) e_n[mask] = self.f[pair](abs_dr_n[mask]) de_n[mask] = self.df[pair](abs_dr_n[mask]) epot = 0.5*np.sum(e_n) # Forces df_nc = -0.5*de_n.reshape(-1, 1)*dr_nc/abs_dr_n.reshape(-1, 1) # Sum for each atom fx_i = np.bincount(j_n, weights=df_nc[:, 0], minlength=nat) - \ np.bincount(i_n, weights=df_nc[:, 0], minlength=nat) fy_i = np.bincount(j_n, weights=df_nc[:, 1], minlength=nat) - \ np.bincount(i_n, weights=df_nc[:, 1], minlength=nat) fz_i = np.bincount(j_n, weights=df_nc[:, 2], minlength=nat) - \ np.bincount(i_n, weights=df_nc[:, 2], minlength=nat) # Virial virial_v = -np.array([dr_nc[:, 0]*df_nc[:, 0], # xx dr_nc[:, 1]*df_nc[:, 1], # yy dr_nc[:, 2]*df_nc[:, 2], # zz dr_nc[:, 1]*df_nc[:, 2], # yz dr_nc[:, 0]*df_nc[:, 2], # xz dr_nc[:, 0]*df_nc[:, 1]]).sum(axis=1) # xy self.results = {'energy': epot, 'stress': virial_v/self.atoms.get_volume(), 'forces': np.transpose([fx_i, fy_i, fz_i])}
def __init__(self, calculator, jsonfile=None, dumpjson=False): Calculator.__init__(self) self.calculator = calculator self.fmax = {} self.walltime = {} self.energy_evals = {} self.energy_count = {} self.set_label('(none)') if jsonfile is not None: self.read_json(jsonfile) self.dumpjson = dumpjson
def __init__(self, rc=5.0, width=1.0): """TIP3P potential. rc: float Cutoff radius for Coulomb part. width: float Width for cutoff function for Coulomb part. """ self.rc = rc self.width = width Calculator.__init__(self)
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) P = atoms.positions D = np.array([P - p for p in P]) # all distance vectors d = (D**2).sum(2)**0.5 dd = d - self.target d.ravel()[::len(d) + 1] = 1 # avoid dividing by zero d4 = d**4 e = 0.5 * (dd**2 / d4).sum() f = -2 * ((dd * (1 - 2 * dd / d) / d**5)[..., np.newaxis] * D).sum(0) self.results = {'energy': e, 'forces': f}
def calculate(self, atoms=None, properties=['energy'], system_changes=[]): Calculator.calculate(self, atoms, properties, system_changes) # only one property allowed assert(len(properties) == 1) # make sure we have a water molecule, and identify O, H1, H2 chemical_formula = self.atoms.get_chemical_formula(mode='all') if chemical_formula == 'OHH': o = 0 h1= 1 h2 =2 elif chemical_formula == 'HOH': o = 1 h1= 0 h2 =2 elif chemical_formula == 'HHO': o = 2 h1= 0 h2 =1 else: raise RuntimeError("chemical formula '{}' is not a water molecule!".format(chemical_formula)) # compute internal coordinates, both stretch coordinates q1, q2 in [bohr] and theta in radians pos=atoms.get_positions() / Bohr #q1_tmp = (pos[h1] - pos[o]) / Bohr #q2_tmp = (pos[h2] - pos[o]) / Bohr # #q1 = np.linalg.norm(q1_tmp) #q2 = np.linalg.norm(q2_tmp) # #q1_norm = q1_tmp / q1 #q2_norm = q2_tmp / q2 #q_norm_sum = q1_norm + q2_norm #q_norm_sum_norm = q_norm_sum / np.linalg.norm(q_norm_sum) # #theta = 2.0 * abs(np.arcsin(np.linalg.norm(np.cross(q1_norm,q_norm_sum_norm)))) q1,q2,theta = get_internal_coords_h2o(pos[o], pos[h1], pos[h2]) if properties[0] == 'energy': V =0.0 V= h2o_pjt2.pots(q1,q2,theta) self.results['energy'] = V * Ha if properties[0] == 'forces': self.results['forces'] = self.calculate_numerical_forces(atoms, d=0.00000001)
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) if system_changes: if 'energy' in self.results: del self.results['energy'] if 'forces' in self.results: del self.results['forces'] if 'energy' not in self.results: if self.permutation is None: crd = np.reshape(atoms.get_positions(), (1, len(atoms), 3)) else: crd = np.reshape(atoms.get_positions()[self.permutation[0, :]], (1, len(atoms), 3)) sander.set_positions(crd) e, f = sander.energy_forces() self.results['energy'] = e.tot * units.kcal / units.mol if self.permutation is None: self.results['forces'] = (np.reshape(np.array(f), (len(atoms), 3)) * units.kcal / units.mol) else: ff = np.reshape(np.array(f), (len(atoms), 3)) * \ units.kcal / units.mol self.results['forces'] = ff[self.permutation[1, :]] if 'forces' not in self.results: if self.permutation is None: crd = np.reshape(atoms.get_positions(), (1, len(atoms), 3)) else: crd = np.reshape(atoms.get_positions()[self.permutation[0, :]], (1, len(atoms), 3)) sander.set_positions(crd) e, f = sander.energy_forces() self.results['energy'] = e.tot * units.kcal / units.mol if self.permutation is None: self.results['forces'] = (np.reshape(np.array(f), (len(atoms), 3)) * units.kcal / units.mol) else: ff = np.reshape(np.array(f), (len(atoms), 3)) * \ units.kcal / units.mol self.results['forces'] = ff[self.permutation[1, :]]
def __init__(self, hirshfeld=None, vdwradii=None, calculator=None, Rmax=10., # maximal radius for periodic calculations Ldecay=1., # decay length for the smoothing in periodic calculations vdWDB_alphaC6=vdWDB_alphaC6, txt=None, sR=None ): """Constructor Parameters ========== hirshfeld: the Hirshfeld partitioning object calculator: the calculator to get the PBE energy """ self.hirshfeld = hirshfeld if calculator is None: self.calculator = self.hirshfeld.get_calculator() else: self.calculator = calculator if txt is None: txt = get_logging_file_descriptor(self.calculator) self.txt = convert_string_to_fd(txt) self.vdwradii = vdwradii self.vdWDB_alphaC6 = vdWDB_alphaC6 self.Rmax = Rmax self.Ldecay = Ldecay self.atoms = None if sR is None: try: xc_name = self.calculator.get_xc_functional() self.sR = sR_opt[xc_name] except KeyError: raise ValueError('Tkatchenko-Scheffler dispersion correction not implemented for %s functional' % xc_name) else: self.sR = sR self.d = 20 Calculator.__init__(self)
def calculate( self, atoms=None, properties=['energy', 'forces'], system_changes=all_changes, ): """Calculates the desired properties for the given AtomsBatch. Args: atoms (AtomsBatch): custom Atoms subclass that contains implementation of neighbor lists, batching and so on. Avoids the use of the Dataset to calculate using the models created. properties (list of str): 'energy', 'forces' or both system_changes (default from ase) """ Calculator.calculate(self, atoms, properties, system_changes) # run model #atomsbatch = AtomsBatch(atoms) # batch_to(atomsbatch.get_batch(), self.device) batch = batch_to(atoms.get_batch(), self.device) # add keys so that the readout function can calculate these properties batch['energy'] = [] batch['energy_grad'] = [] prediction = self.model(batch) # change energy and force to numpy array energy = prediction['energy'].detach().cpu( ).numpy() * (1 / const.EV_TO_KCAL_MOL) energy_grad = prediction['energy_grad'].detach( ).cpu().numpy() * (1 / const.EV_TO_KCAL_MOL) self.results = { 'energy': energy.reshape(-1) } if 'forces' in properties: self.results['forces'] = -energy_grad.reshape(-1, 3)
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) if isinstance(self.calculator, Calculator): results = [ self.calculator.get_property(prop, atoms) for prop in properties ] else: results = [] for prop in properties: method_name = self.property_to_method_name[prop] method = getattr(self.calculator, method_name) results.append(method(atoms)) if 'energy' in properties or 'energies' in properties: self.energy_evals.setdefault(self.label, 0) self.energy_evals[self.label] += 1 try: energy = results[properties.index('energy')] except IndexError: energy = sum(results[properties.index('energies')]) logger.info('energy call count=%d energy=%.3f', self.energy_evals[self.label], energy) self.results = dict(zip(properties, results)) if 'forces' in self.results: fmax = self.fmax.setdefault(self.label, []) walltime = self.walltime.setdefault(self.label, []) forces = self.results['forces'].copy() energy_count = self.energy_count.setdefault(self.label, []) energy_evals = self.energy_evals.setdefault(self.label, 0) energy_count.append(energy_evals) for constraint in atoms.constraints: constraint.adjust_forces(atoms, forces) fmax.append(abs(forces).max()) walltime.append(time.time()) logger.info('force call fmax=%.3f', fmax[-1]) if self.dumpjson: self.write_json('dump.json')
def __init__(self, fn=None, atomic_numbers=None, F=None, f=None, rep=None, cutoff=None, kind='eam/alloy'): Calculator.__init__(self) if fn is not None: source, parameters, F, f, rep = read_eam(fn, kind=kind) self._db_atomic_numbers = parameters.atomic_numbers self._db_cutoff = parameters.cutoff dr = parameters.distance_grid_spacing dF = parameters.density_grid_spacing # Create spline interpolation self.F = _make_splines(dF, F) self.f = _make_splines(dr, f) self.rep = _make_splines(dr, rep) else: self._db_atomic_numbers = atomic_numbers self.F = F self.f = f self.rep = rep self._db_cutoff = cutoff self.atnum_to_index = -np.ones(np.max(self._db_atomic_numbers) + 1, dtype=int) self.atnum_to_index[self._db_atomic_numbers] = \ np.arange(len(self._db_atomic_numbers)) # Derivative of spline interpolation self.dF = _make_derivative(self.F) self.df = _make_derivative(self.f) self.drep = _make_derivative(self.rep) # Second derivative of spline interpolation self.ddF = _make_derivative(self.F, n=2) self.ddf = _make_derivative(self.f, n=2) self.ddrep = _make_derivative(self.rep, n=2)
def __init__(self, restart=None, ignore_bad_restart_file=False, label='cp2k', atoms=None, command=None, debug=False, **kwargs): """Construct CP2K-calculator object.""" self._debug = debug self._force_env_id = None self._shell = None self.label = None self.parameters = None self.results = None self.atoms = None # Several places are check to determine self.command if command is not None: self.command = command elif CP2K.command is not None: self.command = CP2K.command elif 'ASE_CP2K_COMMAND' in os.environ: self.command = os.environ['ASE_CP2K_COMMAND'] else: self.command = 'cp2k_shell' # default Calculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs) self._shell = Cp2kShell(self.command, self._debug) if restart is not None: try: self.read(restart) except: if ignore_bad_restart_file: self.reset() else: raise
def calculate(self, atoms=None, properties=["energy"], system_changes=all_changes): """ Args: atoms (ase.Atoms): ASE atoms object. properties (list of str): do not use this, no functionality system_changes (list of str): List of changes for ASE. """ # First call original calculator to set atoms attribute # (see https://wiki.fysik.dtu.dk/ase/_modules/ase/calculators/calculator.html#Calculator) Calculator.calculate(self, atoms) # Convert to schnetpack input format model_inputs = self.atoms_converter(atoms) # Call model model_results = self.model(model_inputs) results = {} # Convert outputs to calculator format if self.model_energy is not None: if self.model_energy not in model_results.keys(): raise SpkCalculatorError( "'{}' is not a property of your model. Please " "check the model " "properties!".format(self.model_energy)) energy = model_results[self.model_energy].cpu().data.numpy() results[self.energy] = energy.reshape(-1) * self.energy_units if self.model_forces is not None: if self.model_forces not in model_results.keys(): raise SpkCalculatorError( "'{}' is not a property of your model. Please " "check the model" "properties!".format(self.model_forces)) forces = model_results[self.model_forces].cpu().data.numpy() results[self.forces] = forces.reshape( (len(atoms), 3)) * self.forces_units self.results = results
def set(self, **kwargs): """Set parameters like set(key1=value1, key2=value2, ...).""" msg = '"%s" is not a known keyword for the CP2K calculator. ' \ 'To access all features of CP2K by means of an input ' \ 'template, consider using the "inp" keyword instead.' for key in kwargs: if key not in self.default_parameters: raise CalculatorSetupError(msg % key) changed_parameters = Calculator.set(self, **kwargs) if changed_parameters: self.reset()
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) if system_changes: self.results = {} if 'energy' in properties and 'energy' not in self.results: self.results['energy'] = self.calc.get_potential_energy(atoms) if 'forces' in properties and 'forces' not in self.results: raw_forces = self.calc.get_forces(atoms) self.results['forces'] = symmetrize.forces( atoms.get_cell(), atoms.get_reciprocal_cell().T, raw_forces, self.rotations, self.translations, self.symm_map) if 'stress' in properties and 'stress' not in self.results: raw_stress = self.calc.get_stress(atoms) if len(raw_stress) == 6: # Voigt raw_stress = voigt_6_to_full_3x3_stress(raw_stress) symmetrized_stress = symmetrize.stress( atoms.get_cell(), atoms.get_reciprocal_cell().T, raw_stress, self.rotations) self.results['stress'] = full_3x3_to_voigt_6_stress( symmetrized_stress)
def __init__(self, learner_params, parent_dataset, parent_calc, base_calc, trainer, n_ensembles, n_cores): Calculator.__init__(self) self.n_ensembles = n_ensembles self.parent_calc = parent_calc self.base_calc = base_calc self.calcs = [parent_calc, base_calc] self.trainer = trainer self.learner_params = learner_params self.n_cores = n_cores self.ensemble_sets, self.parent_dataset = bootstrap_ensemble( parent_dataset, n_ensembles=n_ensembles) self.init_training_data() self.ensemble_calc = make_ensemble(self.ensemble_sets, self.trainer, self.base_calc, self.refs, self.n_cores) self.uncertain_tol = learner_params["uncertain_tol"] self.parent_calls = 0 self.init_training_data()
def __init__(self, model=None, atoms=None, to_eV=1.0, properties=['energy', 'forces', 'stress']): """PiNN interface with ASE as a calculator Args: model: tf.Estimator object atoms: optional, ase Atoms object properties: properties to calculate. the properties to calculate is fixed for each calculator, to avoid resetting the predictor during get_* calls. """ Calculator.__init__(self) self.implemented_properties = properties self.model = model self.pbc = False self.atoms = atoms self.predictor = None self.to_eV = to_eV
def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) # calculate energy-subtract subtract = 0 if self.subtract: for a in self.atoms: subtract += self.single_atom_energy(a.symbol) # single-point calculation output = self._run(self.atoms) if output is None: raise RuntimeError('gaussian calculation failed!') self.calc = output.calc self.results = output.calc.results # set dummy stress if 'stress' not in self.results: self.results['stress'] = np.zeros(6) # subtract single atom energies self.results['energy'] -= subtract
def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): # Calculator essentially does: self.atoms = atoms Calculator.calculate(self, atoms, properties, system_changes) has_results = [p in self.results for p in properties] if (len(system_changes) > 0) or (not np.all(has_results)): self.update(self.atoms) if ('energy' in properties) and ('forces' in properties): # Forces evaluation requires energy. No need to compute # energy twice. del properties[properties.index('energy')] for p in properties: if p in self.implemented_properties: self.implemented_properties[p](self.atoms) else: raise NotImplementedError( "Property not implemented: {}".format(p))
def __init__(self, model): Calculator.__init__(self) if not os.path.exists("results/trained_models"): os.mkdir("results/trained_models") self.save_logs = model.save_logs label = model.label self.log = Logger("results/logs/" + label + ".txt") self.log("Filename: %s" % label) self.model = model self.label = "".join(["results/trained_models/", label, ".pt"]) self.fp_scaling = self.model.training_data.fprange self.target_sd = self.model.scalings[0] self.target_mean = self.model.scalings[1] self.lj = self.model.training_data.lj self.Gs = self.model.training_data.Gs self.log("Symmetry function parameters: %s" % self.Gs) if self.lj: self.fitted_params = self.model.lj_data[3] self.params_dict = self.model.lj_data[4] self.lj_model = self.model.lj_data[5]
def _toatoms(self, include_results=False): if not include_results: return ase.atoms.Atoms( self.numbers, self.positions, cell=self.cell, pbc=(self.pbc & np.array([1, 2, 4])).astype(bool), ) if self.constraints: print(self.constraints) constraints = json.loads(self.constraints) print(constraints) if len(constraints[0]['kwargs']['indices']) > 0: constraints = [dict2constraint(d) for d in constraints] else: constraints = None atoms = ase.atoms.Atoms(self.numbers, self.positions, cell=self.cell, pbc=(self.pbc & np.array([1, 2, 4])).astype(bool), magmoms=self.initial_magmoms, charges=self.initial_charges, tags=self.tags, masses=self.masses, momenta=self.momenta, constraint=constraints) atoms.info = {} atoms.info['unique_id'] = self.unique_id atoms.info['key_value_pairs'] = self.key_value_pairs data = self.data if data: atoms.info['data'] = data if not self.calculator == "unknown": params = self.calculator_parameters atoms.calc = Calculator(self.calculator, **params) atoms.calc.name = self.calculator else: all_properties = [ 'energy', 'forces', 'stress', 'dipole', 'charges', 'magmom', 'magmoms', 'free_energy' ] results = {} for prop in all_properties: result = getattr(self, prop, None) if result is not None: results[prop] = result if results: atoms.calc = SinglePointCalculator(atoms, **results) atoms.calc.name = getattr(self, 'calculator', 'unknown') return atoms
def __init__(self, lmp, lmpcmds=None, path='tmp', lmp_file=None, ntyp=None, *args, **kwargs): Calculator.__init__(self, *args, **kwargs) self.lmp = lmp self.lmp_file = lmp_file self.folder = path self.ntyp = ntyp if not os.path.exists(self.folder): os.makedirs(self.folder) self.lammps_data = self.folder + '/data.lammps' self.lammps_in = self.folder + '/in.lammps' self.lmpcmds = lmpcmds self.paras = [] for para in lmpcmds: self.paras.append(para)
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) try: results = self.checkpoint.load(atoms) prev_atoms, results = results[0], results[1:] try: assert atoms_almost_equal(atoms, prev_atoms) except AssertionError: raise AssertionError('mismatch between current atoms and ' 'those read from checkpoint file') self.logfile.write('retrieved results for {0} from checkpoint\n' .format(properties)) # save results in calculator for next time if isinstance(self.calculator, Calculator): if not hasattr(self.calculator, 'results'): self.calculator.results = {} self.calculator.results.update(dict(zip(properties, results))) except NoCheckpoint: if isinstance(self.calculator, Calculator): self.logfile.write('doing calculation of {0} with new-style ' 'calculator interface\n'.format(properties)) self.calculator.calculate(atoms, properties, system_changes) results = [self.calculator.results[prop] for prop in properties] else: self.logfile.write('doing calculation of {0} with old-style ' 'calculator interface\n'.format(properties)) results = [] for prop in properties: method_name = self.property_to_method_name[prop] method = getattr(self.calculator, method_name) results.append(method(atoms)) _calculator = atoms.calc try: atoms.calc = self.calculator self.checkpoint.save(atoms, *results) finally: atoms.calc = _calculator self.results = dict(zip(properties, results))
def test_calculator_label(): from ase.calculators.calculator import Calculator calc = Calculator() assert calc.directory == '.' assert calc.prefix is None assert calc.label is None calc.label = 'dir/pref' assert calc.directory == 'dir' assert calc.prefix == 'pref' assert calc.label == 'dir/pref' calc.label = 'dir2/' assert calc.directory == 'dir2' assert calc.prefix is None assert calc.label == 'dir2/' calc.label = 'hello' assert calc.directory == '.' assert calc.prefix == 'hello' assert calc.label == 'hello' calc.label = None assert calc.label is None assert calc.prefix is None assert calc.directory == '.'
def __init__(self, restart=None, ignore_bad_restart_file=False, label='pmd', atoms=None, command='pmd > out.pmd', dimension=(True,True,True), specorder=None, **kwargs): """Construct PMD-calculator object. Parameters ========== label: str Prefix to use for filenames (in.label, erg.label, ...). Default is 'pmd'. Examples ======== Use default values: >>> h = Atoms('H', calculator=PMD(label='pmd',force_type='NN')) >>> e = h.get_potential_energy() """ Calculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs) if label not in ['pmd']: raise RuntimeError('label must be pmd.') if self.parameters['force_type'] is None: raise RuntimeError('force_type must be specified.') if command is None: self.command = self.label+' > out.'+self.label elif '>' in command: self.command = command.split('>')[0] +' > out.'+self.label else: self.command = command +' > out.'+self.label self.specorder= specorder self.dimension = dimension
def __init__(self, restart=None, ignore_bad_restart_file=False, label=os.curdir, atoms=None, **kwargs): # set any additional keyword arguments # for arg, val in self.parameters.iteritems(): for arg, val in kwargs.items(): if arg in self.valid_args: # satisfy our static 8-char requirement in fortran if (arg == ('sedc_scheme' or 'sedc_xc')): setattr(self, arg, str(val).ljust(8)) elif (arg == 'logfile_name'): setattr(self, arg, str(val).ljust(50)) else: setattr(self, arg, val) else: raise RuntimeError('unknown keyword arg "%s" : not in %s' % (arg, self.valid_args)) self.hirshvolrat_is_set = False Calculator.__init__(self, restart, ignore_bad_restart_file, label, atoms, **kwargs)
def calculate(self, atoms=None, properties=['energy', 'forces'], system_changes=[ 'positions', 'numbers', 'cell', 'pbc', 'charges', 'magmoms' ]): Calculator.calculate(self, atoms) calc_molcell = self.molcell.copy() calc_molcell.atom = ase_atoms_to_pyscf(atoms) # calc_molcell.a = atoms.cell calc_molcell.build(None, None) self.mf = self.mf_class(calc_molcell) for key in self.mf_dict: self.mf.__dict__[key] = self.mf_dict[key] self.results['energy'] = self.mf.scf(verbose=0) self.results['forces'] = -1 * grad.RHF(self.mf).kernel( ) # convert forces to gradient (*-1) !!!!! for the NEB run self.results['mf'] = self.mf
def __setattr__(self, key, value): """Catch attribute sets to emulate legacy behavior. Old LAMMPSRUN allows to just override the parameters dictionary. "Modern" ase calculators can assume that default parameters are always set, overrides of the 'parameters'-dictionary have to be caught and the default parameters need to be added first. A check refuses to set calculator attributes if they are unknown and set outside the '__init__' functions. """ # !TODO: remove and break somebody's code (e.g. the test examples) if (key == "parameters" and value is not None and self.parameters is not None): temp_dict = self.get_default_parameters() if self.parameters: for l_key in self.legacy_parameters: try: temp_dict[l_key] = self.parameters[l_key] except KeyError: pass temp_dict.update(value) value = temp_dict if key in self.legacy_parameters and key != "parameters": warnings.warn(self.legacy_warn_string.format(key)) self.set(**{key: value}) elif key in self.legacy_parameters_map: warnings.warn( self.legacy_warn_string.format("{} for {}".format( self.legacy_parameters_map[key], key))) self.set(**{self.legacy_parameters_map[key]: value}) # Catch setting none-default attributes # one test was assigning an useless Attribute, but it still worked # because the assigned object was before manipulation already handed # over to the calculator (10/2018) elif hasattr(self, key) or inspect.stack()[1][3] == "__init__": Calculator.__setattr__(self, key, value) else: raise AttributeError("Setting unknown Attribute '{}'".format(key))
def calculate(self, atoms=None, properties=['energy'], system_changes=['positions', 'numbers', 'cell', 'pbc', 'charges', 'magmoms']): Calculator.calculate(self, atoms, properties, system_changes) epsilon = self.parameters.epsilon rho0 = self.parameters.rho0 r0 = self.parameters.r0 positions = self.atoms.get_positions() energy = 0.0 forces = np.zeros((len(self.atoms), 3)) preF = 2 * epsilon * rho0 / r0 for i1, p1 in enumerate(positions): for i2, p2 in enumerate(positions[:i1]): diff = p2 - p1 r = sqrt(np.dot(diff, diff)) expf = exp(rho0 * (1.0 - r / r0)) energy += epsilon * expf * (expf - 2) F = preF * expf * (expf - 1) * diff / r forces[i1] -= F forces[i2] += F self.results['energy'] = energy self.results['forces'] = forces
def calculate(self, atoms=None, properties=["energy"], system_changes=all_changes): r""" This method will be called by ASE functions. """ if self.calculation_required(atoms, properties): from mlcalcdriver.base.posinp import Posinp Calculator.calculate(self, atoms) posinp = Posinp.from_ase(atoms) from mlcalcdriver.base.job import Job job = Job(posinp=posinp, calculator=self.schnetpackcalculator) for prop in properties: job.run(prop) results = {} for prop, result in zip(job.results.keys(), job.results.values()): results[prop] = np.squeeze(result) self.results = results
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) if self.qmatoms is None: self.initialize(atoms) self.mmatoms.set_positions(atoms.positions[~self.mask]) self.qmatoms.set_positions(atoms.positions[self.mask]) if self.vacuum: shift = self.center - self.qmatoms.positions.mean(axis=0) self.qmatoms.positions += shift else: shift = (0, 0, 0) self.embedding.update(shift) ienergy, iqmforces, immforces = self.interaction.calculate( self.qmatoms, self.mmatoms, shift) qmenergy = self.qmatoms.get_potential_energy() mmenergy = self.mmatoms.get_potential_energy() energy = ienergy + qmenergy + mmenergy print('Energies: {0:12.3f} {1:+12.3f} {2:+12.3f} = {3:12.3f}'.format( ienergy, qmenergy, mmenergy, energy), file=self.output) qmforces = self.qmatoms.get_forces() mmforces = self.mmatoms.get_forces() mmforces += self.embedding.get_mm_forces() forces = np.empty((len(atoms), 3)) forces[self.mask] = qmforces + iqmforces forces[~self.mask] = mmforces + immforces self.results['energy'] = energy self.results['forces'] = forces
def calculate(self, atoms=None, properties=['energy'], system_changes=changes): Calculator.calculate(self, atoms, properties, system_changes) self.write_input(self.atoms, properties, system_changes) if self.command is None: raise RuntimeError('Please set $%s environment variable ' % ('ASE_' + self.name.upper() + '_COMMAND') + 'or supply the command keyword') olddir = os.getcwd() try: syscall = self.command + ' ' + \ self.parameters['INPUT_FILE'] + '> OUT ' errorcode = subprocess.call(syscall, shell=True) finally: os.chdir(olddir) if errorcode: raise RuntimeError('%s returned an error: %d' % (self.name, errorcode)) self.read_results()
def calculate(self, atoms=None, properties=['energy'], system_changes=[ 'positions', 'numbers', 'cell', 'pbc', 'charges', 'magmoms' ]): Calculator.calculate(self, atoms, properties, system_changes) D = self.parameters.D alpha = self.parameters.alpha r0 = self.parameters.r0 # energy evaluation dist = self.atoms.get_all_distances(mic=True).reshape( -1 ) # calculates all interatomic distances of the system using the minimum image convention dist = dist[ dist != 0] # excludes self-interaction (list of interatomic distances includes distance of atom to itself) expf = np.exp( alpha * r0 * (1.0 - dist / r0)) # calculation of exponential factor of morse energy = 0.5 * np.sum( D * expf * (expf - 2) ) # evaluates Morse term for all distances and sums over the resulting energies, 0.5 is needed to account fo # force evaluation preF = 2 * D * alpha dist_vec = self.atoms.get_all_distances(mic=True, vector=True) dist = self.atoms.get_all_distances(mic=True) dist[dist == 0] = 1e-9 expf = np.exp(alpha * r0 * (1.0 - dist / r0)) F2 = preF * expf * (expf - 1) / dist F2 = -dist_vec * F2[:, :, np.newaxis] forces = np.sum(F2, axis=1) self.results['energy'] = energy self.results['forces'] = forces
def calculate(self, atoms=None, properties=['energy'], system_changes=['positions', 'numbers', 'cell']): Calculator.calculate(self, atoms, properties, system_changes) if not system_changes: return if 'numbers' in system_changes: self.close() self._run_vasp(atoms) new = read(os.path.join(self.path, 'vasprun.xml'), index=-1) self.results = { 'free_energy': new.get_potential_energy(force_consistent=True), 'energy': new.get_potential_energy(), 'forces': new.get_forces()[self.resort], 'stress': new.get_stress() }
def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) if self.atoms.is_distributed: raise NotImplementedError( 'variance is not implemented for distributed atoms') self.atoms.update() energy, energy_var = self.potential([self.atoms], 'energy', variance=True) forces, forces_var = self.potential([self.atoms], 'forces', variance=True) self.results['energy'] = energy.detach().numpy()[0] self.results['forces'] = forces.detach().numpy() # variances self.results['energy_var'] = energy_var.detach().numpy()[0] self.results['forces_var'] = forces_var.detach().numpy() # NOTE: check if this is correct! self.results['free_energy'] = self.results['energy']
def __init__(self, restart=None, ignore_bad_restart_file=False, label='PySCF', atoms=None, scratch=None, **kwargs): """Construct PySCF-calculator object. Parameters ========== label: str Prefix to use for filenames (label.in, label.txt, ...). Default is 'PySCF'. mfclass: PySCF mean-field class molcell: PySCF :Mole: or :Cell: """ Calculator.__init__(self, restart=None, ignore_bad_restart_file=False, label='PySCF', atoms=None, scratch=None, **kwargs) # TODO # This explicitly refers to "cell". How to refer # to both cell and mol together? self.mf=None self.initialize(**kwargs)