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 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 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): """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): 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=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): # 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 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 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=['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, 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 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 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 calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) energy, forces = 0, np.zeros((self.N, 3)) e, f = self._calculate_harm(atoms) energy += e forces += f e, f = self._calculate_soft(atoms) energy += e forces += f self.results = {'energy': energy, 'forces': forces}
def calculate(self, atoms=None, properties=['energy', 'forces'], system_changes=['positions']): Calculator.calculate(self, atoms, properties, system_changes) if 'energy' in properties: self.results['energy'] = self.energy(atoms) if 'forces' in properties: F = self.forces(atoms) if self.noZ: F[:,-1] = 0 self.results['forces'] = F
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, 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, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) julia_atoms = ASEAtoms(atoms) self.results = {} if 'energy' in properties: self.results['energy'] = julia.energy(self.julip_calculator, julia_atoms) if 'forces' in properties: self.results['forces'] = np.array(julia.forces(self.julip_calculator, julia_atoms)) if 'stress' in properties: self.results['stress'] = np.array(julia.stress(self.julip_calculator, julia_atoms))
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms) cf_by_name = self.corrFunc.get_cf_by_cluster_names( atoms, self.eci.keys()) energy = 0.0 for key, value in self.eci.items(): energy += value * cf_by_name[key] self.results["energy"] = energy * len( atoms) # Should not return energy per atom!
def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) #chem_symbols = list(set(atoms.get_chemical_symbols())) #self.ff = PyXtal_FF(model={'system': chem_symbols}, logo=self.parameters.logo) #self.ff.run(mode='predict', mliap=self.parameters.mliap) # base potential if self.parameters.ff._descriptors['base_potential']: self.base_potential = ZBL( self.parameters.ff._descriptors['base_potential']['inner'], self.parameters.ff._descriptors['base_potential']['outer'], atomic_energy=True) base_results = self.base_potential.calculate(atoms) base_energy = base_results['energy'] base_forces = base_results['force'] base_stress = base_results['stress'] # eV/A^3 base_energies = base_results['energies'] else: base_energy = 0 base_forces = np.zeros([len(atoms), 3]) base_stress = np.zeros([6]) base_energies = 0. desp = compute_descriptor(self.parameters.ff._descriptors, atoms) energies, forces, stress = self.parameters.ff.model.calculate_properties( desp, bforce=True, bstress=True) self.desp = desp self.results['energies'] = energies + base_energies self.results['energy'] = energies.sum() + base_energy self.results['free_energy'] = energies.sum() + base_energy self.results['forces'] = forces + base_forces # pyxtal_ff and lammps uses: xx, yy, zz, xy, xz, yz # ase uses: xx, yy, zz, yz, xz, xy # from eV/A^3 to GPa self.results['stress_zbl'] = base_stress / units.GPa self.results['energy_zbl'] = base_energy self.results['forces_zbl'] = base_forces self.results['stress_ml'] = stress self.results['energy_ml'] = energies.sum() self.results['forces_ml'] = forces # ase counts the stress differently if self.style == 'ase': self.results['stress'] = -(stress * units.GPa + base_stress)[[0, 1, 2, 5, 4, 3]] else: self.results['stress'] = self.results['stress_zbl'] + self.results[ 'stress_ml']
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 forces[a1] -= f.sum(axis=0) for a2, f2 in zip(neighbors, f): forces[a2] += f2 stress += np.dot(f.T, d) if 'stress' in properties: if self.atoms.number_of_lattice_vectors == 3: stress += stress.T.copy() stress *= -0.5 / self.atoms.get_volume() self.results['stress'] = stress.flat[[0, 4, 8, 5, 2, 1]] else: raise PropertyNotImplementedError self.results['energy'] = energy self.results['free_energy'] = energy self.results['forces'] = forces
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 calculate(self, atoms=None, properties=["energy"], system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) image = atoms natoms = len(image) energy = 0.0 forces = np.zeros((natoms, 3)) self.results["energy"] = energy self.results["forces"] = forces
def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) natoms = len(self.atoms) k = self.parameters.k tolerAngs = self.parameters.tolerAngs tolerMult = self.parameters.tolerMult cutoff = self.parameters.cutoff if 'numbers' in system_changes: # Want agregation? cutoff > 2.00 # Want uniform? cutoff < 1.50 # Directional? cutoff < 1.25 self.nl = NeighborList([cutoff / 2] * natoms,\ self_interaction=False) self.nl.update(self.atoms) positions = self.atoms.positions cell = self.atoms.cell 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) # print(neighbors) cells = np.dot(offsets, cell) vecBond = positions[neighbors] + cells - positions[a1] lenBond = np.sqrt((vecBond**2).sum(1)) covalBl = covalRadii[self.atoms.get_atomic_numbers()[a1]]+\ covalRadii[self.atoms.get_atomic_numbers()[neighbors]] compress = covalBl - lenBond energy += k / 2 * ((compress)**2).sum() # only repulsion compress[covalBl - lenBond < tolerAngs] = 0.0 compress[lenBond / covalBl > 1 - tolerMult] = 0.0 # # also attraction # compress[np.abs(covalBl - lenBond) < tolerAngs] = 0.0 # compress[np.abs(1 - lenBond / covalBl) < tolerMult] = 0.0 f = k * (compress)[:, np.newaxis] * vecBond forces[a1] -= f.sum(axis=0) for a2, f2 in zip(neighbors, f): forces[a2] += f2 self.results['energy'] = energy self.results['free_energy'] = energy self.results['forces'] = forces
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) results = [ self.calculator.get_property(prop, atoms) for prop in properties ] # Only count evaluation if system (typically the position) # has changed if system_changes: self.n_evals += 1 self.results = dict(zip(properties, results))
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) R = atoms.get_positions() charges = self.get_virtual_charges(atoms) pbc = atoms.pbc energy = 0.0 forces = np.zeros_like(atoms.get_positions()) for m in range(len(atoms)): D = R[m + 1:] - R[m] shift = np.zeros_like(D) for i, periodic in enumerate(pbc): if periodic: L = atoms.cell.diagonal()[i] shift[:, i] = (D[:, i] + L / 2) % L - L / 2 - D[:, i] D += shift d2 = (D**2).sum(1) d = d2**0.5 x1 = d > self.rc - self.width x2 = d < self.rc x12 = np.logical_and(x1, x2) y = (d[x12] - self.rc + self.width) / self.width t = np.zeros(len(d)) # cutoff function t[x2] = 1.0 t[x12] -= y**2 * (3.0 - 2.0 * y) dtdd = np.zeros(len(d)) dtdd[x12] -= 6.0 / self.width * y * (1.0 - y) c6 = (self.sigma**2 / d2)**3 c12 = c6**2 e_lj = 4 * self.epsilon * (c12 - c6) e_c = k_c * charges[m + 1:] * charges[m] / d energy += np.dot(t, e_lj) energy += np.dot(t, e_c) F = (24 * self.epsilon * (2 * c12 - c6) / d2 * t - e_lj * dtdd / d)[:, None] * D forces[m] -= F.sum(0) forces[m + 1:] += F F = (e_c / d2 * t)[:, None] * D \ - (e_c * dtdd / d)[:, None] * D forces[m] -= F.sum(0) forces[m + 1:] += F self.results['energy'] = energy self.results['forces'] = forces
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) # construct neighbor list i_p, j_p, r_p, r_pc = neighbour_list('ijdD', atoms=atoms, cutoff=self.cutoff) nb_atoms = len(self.atoms) nb_pairs = len(i_p) # normal vectors n_pc = (r_pc.T / r_p).T nx_p, ny_p, nz_p = n_pc.T # construct triplet list first_i = first_neighbours(nb_atoms, i_p) ij_t, ik_t = triplet_list(first_i) # calculate energy G_t = self.G(r_pc[ij_t], r_pc[ik_t]) xi_p = np.bincount(ij_t, weights=G_t, minlength=nb_pairs) F_p = self.F(r_p, xi_p) epot = 0.5 * np.sum(F_p) d1G_t = self.d1G(r_pc[ij_t], r_pc[ik_t]) d2F_d2G_t = (self.d2F(r_p[ij_t], xi_p[ij_t]) * self.d2G(r_pc[ij_t], r_pc[ik_t]).T).T # calculate forces (per pair) fx_p = \ self.d1F(r_p, xi_p) * n_pc[:, 0] + \ self.d2F(r_p, xi_p) * np.bincount(ij_t, d1G_t[:, 0], minlength=nb_pairs) + \ np.bincount(ik_t, d2F_d2G_t[:, 0], minlength=nb_pairs) fy_p = \ self.d1F(r_p, xi_p) * n_pc[:, 1] + \ self.d2F(r_p, xi_p) * np.bincount(ij_t, d1G_t[:, 1], minlength=nb_pairs) + \ np.bincount(ik_t, d2F_d2G_t[:, 1], minlength=nb_pairs) fz_p = \ self.d1F(r_p, xi_p) * n_pc[:, 2] + \ self.d2F(r_p, xi_p) * np.bincount(ij_t, d1G_t[:, 2], minlength=nb_pairs) + \ np.bincount(ik_t, d2F_d2G_t[:, 2], minlength=nb_pairs) # collect atomic forces fx_n = 0.5 * (np.bincount(i_p, weights=fx_p) - np.bincount(j_p, weights=fx_p)) fy_n = 0.5 * (np.bincount(i_p, weights=fy_p) - np.bincount(j_p, weights=fy_p)) fz_n = 0.5 * (np.bincount(i_p, weights=fz_p) - np.bincount(j_p, weights=fz_p)) f_n = np.transpose([fx_n, fy_n, fz_n]) self.results = {'energy': epot, 'forces': f_n}
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", "forces", "stress"], system_changes=["positions", "numbers", "cell", "pbc"], ): """ Inherited method from the ase Calculator class that is called by get_property() Parameters ---------- atoms : Atoms Atoms object whose properties are desired properties : list of str List of what needs to be calculated. Can be any combination of 'energy', 'forces' and 'stress'. system_changes : list of str List of what has changed since last calculation. Can be any combination of these six: 'positions', 'numbers', 'cell', and 'pbc'. """ Calculator.calculate(self, atoms, properties, system_changes) # Update KIM API input data and neighbor list, if necessary if system_changes: if self.need_neigh_update(atoms, system_changes): self.update_neigh(atoms, self.species_map) self.energy = np.array([0.0], dtype=np.double) self.forces = np.zeros([self.num_particles[0], 3], dtype=np.double) self.update_compute_args_pointers(self.energy, self.forces) else: self.update_kim_coords(atoms) self.kim_model.compute(self.compute_args, self.release_GIL) energy = self.energy[0] forces = self.assemble_padding_forces() try: volume = atoms.get_volume() stress = self.compute_virial_stress(self.forces, self.coords, volume) except ValueError: # Volume cannot be computed stress = None # Quantities passed back to ASE self.results["energy"] = energy self.results["free_energy"] = energy self.results["forces"] = forces self.results["stress"] = stress
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: e1 = self.calc1.get_potential_energy(atoms) e2 = self.calc2.get_potential_energy(atoms) self.results['energy'] = e1 + e2 if 'forces' in properties and 'forces' not in self.results: f1 = self.calc1.get_forces(atoms) f2 = self.calc2.get_forces(atoms) self.results['forces'] = f1 + f2
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) dataset = TestDataset(images=atoms, descriptor=self.model.descriptor, Gs=self.Gs, fprange=self.fp_scaling, label=self.model.label) fp_length = dataset.fp_length() unique_atoms = dataset.unique() architecture = copy.copy(self.model.structure) architecture.insert(0, fp_length) batch_size = len(dataset) dataloader = DataLoader(dataset, batch_size, collate_fn=dataset.collate_test, shuffle=False) if properties == ['energy']: model = FullNN(unique_atoms, architecture, "cpu", forcetraining=False) elif properties == ['forces']: model = FullNN(unique_atoms, architecture, "cpu", forcetraining=True) model.load_state_dict(torch.load(self.label)) model.eval() for batch in dataloader: input_data = [batch[0], len(batch[1]), unique_atoms] for element in unique_atoms: input_data[0][element][0] = input_data[0][element][ 0].requires_grad_(True) fp_primes = batch[2] energy, forces = model(input_data, fp_primes) energy = (energy * self.target_sd) + self.target_mean energy = np.concatenate(energy.detach().numpy()) if properties == ['forces']: forces = (forces * self.target_sd).detach().numpy() if self.lj: lj_energy, lj_forces, _ = self.lj_model.lj_pred([atoms], self.fitted_params, self.params_dict) lj_energy = np.squeeze(lj_energy) energy += lj_energy if properties == ['forces']: forces += lj_forces self.results["energy"] = float(energy) self.results["forces"] = forces
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=None, properties=['energy'], system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) # natoms = len(self.atoms) # positions = self.atoms.positions # cell = self.atoms.cell self.results['energy'] = self.energy self.results['forces'] = self.forces
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'] = 0.0 for constraint in self.constraint: self.results['energy'] += constraint.adjust_potential_energy( atoms) if 'forces' in properties and 'forces' not in self.results: self.results['forces'] = np.zeros((len(atoms), 3)) for constraint in self.constraint: constraint.adjust_forces(atoms, self.results['forces'])
def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) X = [self.atoms] managers = self.representation.transform(X) energy = self.model.predict(managers) forces = -self.model.predict(managers, compute_gradients=True) self.results['energy'] = energy self.results['free_energy'] = energy self.results['forces'] = forces
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) if properties == ['energy']: energy = self.model.calculate_energy(atoms) self.results['energy'] = energy[0] if properties == ['forces']: forces = self.model.calculate_forces(atoms) self.results['forces'] = forces[0]
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) julia_atoms = ASEAtoms(atoms) julia_atoms = convert(julia_atoms) self.results = {} if 'energy' in properties: self.results['energy'] = energy(self.julip_calculator, julia_atoms) if 'forces' in properties: self.results['forces'] = np.array( forces(self.julip_calculator, julia_atoms)) if 'stress' in properties: voigt_stress = full_3x3_to_voigt_6_stress( np.array(stress(self.julip_calculator, julia_atoms))) self.results['stress'] = voigt_stress
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) E = 0.0 R = atoms.positions F = np.zeros_like(R) for a, r in enumerate(R): D = R - r d = (D**2).sum(1)**0.5 x = d - 1.0 E += np.vdot(x, x) d[a] = 1 F -= (x / d)[:, None] * D energy = 0.25 * E self.results = {'energy': energy, 'forces': F}
def calculate(self, atoms=None, properties=None, system_changes=all_changes): """calculate and store energy""" if not properties: properties = 'energy' """ If system_changes, atoms etc will be updated. """ Calculator.calculate(self, atoms, properties, system_changes) e_old = self.ann_model.predict(self.atoms)[0][0] self.results['energy'] = float(e_old) self.results['forces'] = np.array(self.cal_force(e_old))
def calculate(self, atoms=None, properties=None, system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) image = atoms natoms = len(image) energy = 0.0 forces = np.zeros((natoms, 3)) self.results["energy"] = energy self.results["forces"] = forces self.results["stress"] = -np.array([0, 0, 0, 0, 0, 0]) self.results["force_stds"] = zeros_like(forces) atoms.info["max_force_stds"] = np.nanmax(self.results["force_stds"])
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) E = 0.0 R = atoms.positions F = np.zeros_like(R) for a, r in enumerate(R): D = R - r d = (D**2).sum(1)**0.5 x = d - 1.0 E += np.vdot(x, x) d[a] = 1 F -= (x / d)[:, None] * D energy = 0.25 * E self.results = {'energy': energy, 'forces': F}
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) data_object = self.a2g.convert(atoms) batch = data_list_collater([data_object]) predictions = self.trainer.predict(batch, per_image=False, disable_tqdm=True) if self.trainer.name == "s2ef": self.results["energy"] = predictions["energy"].item() self.results["forces"] = predictions["forces"].cpu().numpy() elif self.trainer.name == "is2re": self.results["energy"] = predictions["energy"].item()
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) data_object = self.a2g.convert(atoms) batch = data_list_collater([data_object]) if self.pbc_graph: edge_index, cell_offsets, neighbors = radius_graph_pbc( batch, 6, 50, batch.pos.device) batch.edge_index = edge_index batch.cell_offsets = cell_offsets batch.neighbors = neighbors predictions = self.trainer.predict(batch) self.results["energy"] = predictions["energy"][0] self.results["forces"] = predictions["forces"][0]
def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) # start_time2 = time.time() ## make up for stress ## TODO # stress_ani = np.zeros((1, 3)) stress_ani = np.zeros(6) if self.Setup or self.nc.ncl[0].request_setup(): # Setup molecule for MD natoms = len(self.atoms) atom_symbols = self.atoms.get_chemical_symbols() xyz = self.atoms.get_positions() self.nc.set_molecule(xyz.astype(np.float32), atom_symbols) self.nc.set_pbc(self.atoms.get_pbc()[0], self.atoms.get_pbc()[1], self.atoms.get_pbc()[2]) self.Setup = False else: xyz = self.atoms.get_positions() # Set the conformers in NeuroChem self.nc.set_coordinates(xyz.astype(np.float32)) # TODO works only for 3D periodic. For 1,2D - update np.zeros((3,3)) part pbc_inv = (np.linalg.inv(self.atoms.get_cell())).astype( np.float32) if atoms.pbc.all() else np.zeros( (3, 3), dtype=np.float32) self.nc.set_cell((self.atoms.get_cell()).astype(np.float32), pbc_inv) energy, force, stddev = self.nc.compute_mean_props() self.stddev = conv_au_ev * stddev self.results['energy'] = conv_au_ev * energy if 'forces' in properties: forces = conv_au_ev * force # restrain atoms for i in self.reslist: forces[i] = 0.0 self.results['forces'] = -forces self.results['stress'] = conv_au_ev * stress_ani
def calculate(self, atoms=None, properties=["energy"], system_changes=all_changes): if self.calculation_required(atoms, properties): Calculator.calculate(self, atoms) posinp = Posinp.from_ase(atoms) 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=None, properties=['energy'], system_changes=all_changes): Calculator.calculate(self, atoms, properties, system_changes) self.write_pw_input(atoms) self.run_pw() Ep = self.parse_E() F = self.parse_F(atoms) # s = self.parse_Stress() self.results['energy'] = Ep self.results['forces'] = F
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) i_n, j_n, dr_nc, abs_dr_n = neighbour_list('ijDd', self.atoms, self._db_cutoff) epot, virial_v, forces_ic = self.energy_virial_and_forces( self.atoms.numbers, i_n, j_n, dr_nc, abs_dr_n) self.results = { 'energy': epot, 'free_energy': epot, 'stress': virial_v / self.atoms.get_volume(), 'forces': forces_ic }
def calculate(self, atoms=None, properties=['energy'], 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() self.results['mf']=self.mf
def calculate(self, atoms=None, properties=['energy'], system_changes=some_changes): Calculator.calculate(self, atoms, properties, system_changes) 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()
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=["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.h = 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() self.results["mf"] = self.mf
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 calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) if self.np_atoms is None: self.initialize_np(atoms) if self.sp_atoms is None: self.initialize_sp(atoms) energy = 0 forces = np.zeros(shape=(len(atoms), 3)) ## 1. Nanoparticle self.np_atoms.positions = atoms.positions[self.np_selection] if self.vacuum: self.np_atoms.positions += (self.center - self.np_atoms.positions.mean(axis=0)) energy += self.np_calc.get_potential_energy(self.np_atoms) np_forces = self.np_calc.get_forces(self.np_atoms) if self.vacuum: np_forces -= np_forces.mean(axis=0) forces[self.np_selection] += np_forces ## 2. Support. Copy-Paste. TODO: make loop over subsystems self.sp_atoms.positions = atoms.positions[self.sp_selection] if self.vacuum: self.sp_atoms.positions += (self.center - self.sp_atoms.positions.mean(axis=0)) energy += self.sp_calc.get_potential_energy(self.sp_atoms) sp_forces = self.sp_calc.get_forces(self.sp_atoms) if self.vacuum: sp_forces -= sp_forces.mean(axis=0) forces[self.sp_selection] += sp_forces ## 3. INTERACTION if self.ia_calc is not None: ienergy, inpforces, ispforces = self.ia_calc.calculate( self.np_atoms, self.sp_atoms, (0, 0, 0)) forces[self.np_selection] += inpforces forces[self.sp_selection] += ispforces energy += ienergy ## 4. return result self.results['energy'] = energy self.results['forces'] = forces
def calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) if not(system_changes is None): self.update_atoms() species = set(atoms.numbers) charges = [atom.charge for atom in atoms] energy = 0.0 forces = np.zeros((len(atoms), 3)) chems = atoms.get_chemical_symbols() for i, R1, symb1, Q1 in zip(count(), atoms.positions, chems, charges): for j, R2, symb2, Q2 in zip(count(), atoms.positions, chems, charges): if j<=i: continue pair = _tup2str((symb1,symb2)) if pair not in self.parameters: continue A, rho, C = self.parameters[pair] D = R1 - R2 d2 = (D**2).sum() if (d2 > 0.001): d = np.sqrt(d2) coul = COUL_COEF*Q1*Q2/d Aexp = A*np.exp(-d/rho) Cr6 = C/d2**3 energy += Aexp - Cr6 + coul force = (1/rho*Aexp - 6/d*Cr6 + coul/d)*D/d forces[i, :] += force forces[j, :] += -force if 'energy' in properties: self.results['energy'] = energy if 'forces' in properties: self.results['forces'] = forces
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 calculate(self, atoms, properties, system_changes): Calculator.calculate(self, atoms, properties, system_changes) a = self.parameters['a'] rc = self.parameters['rc'] k = self.parameters['k'] beta = self.parameters['beta'] energies = np.zeros(len(atoms)) forces = np.zeros((len(atoms), 3)) velocities = (atoms.get_momenta().T/atoms.get_masses()).T i, j, dr, r = neighbour_list('ijDd', atoms, rc) if len(i) > 0: dr_hat = (dr.T/r).T dv = velocities[j] - velocities[i] de = 0.5*k*(r - a)**2 # spring energies e = 0.5*de # half goes to each end of spring f = (k*(r - a)*dr_hat.T).T + beta*dv energies[:] = np.bincount(i, e) for kk in range(3): forces[:, kk] = np.bincount(i, weights=f[:, kk]) energy = energies.sum() # add energy 0.5*k*(rc - a)**2 for each broken bond if len(i) < self.crystal_bonds: de = 0.5*k*(rc - a)**2 energy += 0.5*de*(self.crystal_bonds - len(i)) # Stokes dissipation if 'stokes' in atoms.arrays: b = atoms.get_array('stokes') forces -= (velocities.T*b).T self.results = {'energy': energy, 'forces': forces}
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=all_changes): sim = self.sim # check that only things we actually pass to PINY are changed if not self.changes.issuperset(system_changes): msg = 'Not all changes are supported: {:s}'.format(str(system_changes)) raise NotImplementedError(msg) # update PINY positions, recalculate ghosts and set them back in atoms sim.set_x((atoms.get_positions() / units.Bohr)[:,:,np.newaxis]) atoms.set_positions(sim.get_x()[:,:,0] * units.Bohr) # now call parent method to remember the atoms, with ghosts updated Calculator.calculate(self, atoms=atoms) # run and extract results sim.update() self.results = { 'energy': sim.get_V().item() * units.Ha, 'forces': - sim.get_dV_dx()[:,:,0] * units.Ha / units.Bohr }