def _set_coordinates(self, atoms=None): self.xyz = atoms.positions / Bohr if any(atoms.pbc): [a, b, c] = atoms.get_cell() V = abs(np.dot(np.cross(a, b), c)) if V < 1e-2: warnings.warn("Cell volume < 0.01 A^3") self.UC = atoms.get_cell() / Bohr self.periodic = True else: self.UC, self.kgrid, self.periodic = None, None, False
def get_localEnv(frame, centerIdx, cutoff, onlyDict=False): ''' Get the local atomic environment around an atom in an atomic frame. :param frame: ase or quippy Atoms object :param centerIdx: int Index of the local environment center. :param cutoff: float Cutoff radius of the local environment. :return: ase Atoms object Local atomic environment. The center atom is in first position. ''' import ase.atoms import quippy.atoms from ase.neighborlist import NeighborList from ase import Atoms as aseAtoms if isinstance(frame, quippy.atoms.Atoms): atoms = qp2ase(frame) elif isinstance(frame, ase.atoms.Atoms): atoms = frame else: raise ValueError n = len(atoms.get_atomic_numbers()) nl = NeighborList([ cutoff / 2., ] * n, skin=0., sorted=False, self_interaction=False, bothways=True) nl.build(atoms) cell = atoms.get_cell() pbc = atoms.get_pbc() pos = atoms.get_positions() positions = [ pos[centerIdx], ] zList = atoms.get_atomic_numbers() numbers = [ zList[centerIdx], ] indices, offsets = nl.get_neighbors(centerIdx) # print offsets,len(atom.get_atomic_numbers()) for i, offset in zip(indices, offsets): positions.append(pos[i] + np.dot(offset, cell)) numbers.append(zList[i]) atomsParam = dict(numbers=numbers, cell=cell, positions=positions, pbc=pbc) if onlyDict: return atomsParam else: return aseAtoms(**atomsParam)
def dft_d_pbc(atoms, scaling_factor=0.75, interactionlist=None, interactionmatrix=None, cutoff_radius=DF_CUTOFF_RADIUS): """Main function making the D-G06 DFT-D correction available for systems with periodic boundary conditions. Applies the lattice summation defined in "lattice_sum" to the intra- and inter-cell evaluation of the D-G06 correction carried out in "d_g06_cell". >>> HCldim = Atoms('Cl2') >>> x1 = ( 1.65, 0, -0.01) >>> x2 = (-1.65, 0, 0.01) >>> HCldim.set_positions([x1,x2]) >>> HCldim.set_atomic_numbers([ 17, 17]) >>> HCldim.set_cell([(10.0, 0.0, 0.0), (0.0, 10.0, 0.0), (0.0, 0.0, 3.3)]) >>> HCldim.set_pbc([False,]*3) >>> dft_d_pbc(HCldim) (-0.016281380498314325, array([[-0.01672876, 0. , 0.00010139], [ 0.01672876, 0. , -0.00010139]])) >>> iso_c, iso_g = dft_d_iso(HCldim) >>> pbc_c, pbc_g = dft_d_pbc(HCldim) >>> iso_c == pbc_c, iso_g == pbc_g (True, array([[ True, True, True], [ True, True, True]], dtype=bool)) """ # # Obtain data about system atom_numbers = atoms.get_atomic_numbers() positions = atoms.get_positions() periodic_directions = atoms.get_pbc() elem_cell = atoms.get_cell() # # Number of atoms within a single copy N_atoms = len(positions) # # Check input i.e. if interactionlist and interactionmatrix are set properly interactionlist, interactionmatrix = check_interaction_group_input(N_atoms, interactionlist, interactionmatrix) # # Start with Calculation # Get DFT-D parameters params = [d_g06_parameters(ind_1) for ind_1 in atom_numbers] # # Define function "func" as "d_g06" for the lattice summation done in "lattice_sum" def func(t): return d_g06_cell(N_atoms, params, positions, interactionlist, interactionmatrix, cutoff_radius, t_vec=t) # # Call lattice summation with function "d_g06_cell" dispersion_correction, gradient_contribution = lattice_sum( func, positions, elem_cell, periodic_directions, cutoff_radius ) # # Scale dispersion correction and forces according to used XC-functional dispersion_correction = dispersion_correction * scaling_factor gradient_contribution = gradient_contribution * scaling_factor # return dispersion_correction, gradient_contribution
def init_ewaldMBD(self, atoms=None): """ Initialize MBD calculation and evaluate properties. """ mbd.init_grid(self.grid_size) mbd.my_task, mbd.n_tasks = 0, self.num_tasks assert hasattr(self, 'a_div_a0'), \ "Please provide rescaling to obtain initial dispersion parameters from accurate free atom reference data via 'set_rescaling(rescaling)'!" self.pos = atoms.positions / Bohr self.UC = atoms.get_cell() / Bohr symbols = atoms.get_chemical_symbols() self.alpha_f, self.C6_f, self.RvdW_f = get_free_atom_data(symbols) self.alpha_TS = self.alpha_f * self.a_div_a0 self.C6_TS = self.C6_f * self.a_div_a0**2 self.RvdW_TS = self.RvdW_f * self.a_div_a0**(1. / 3.) self.omega_TS = mbd.omega_eff(self.C6_TS, self.alpha_TS) self.beta = xc2beta[self.xc] self.run_electrostatic_screening(mode='C') self.get_reciprocal_space_mbd_energy() mbd.destroy_grid()
def initialize_sdc(self, atoms=None): """ Initialization of all parameters in the sedc-module. Here we initialize all parameters in order to successfully calculate with sdc_recode module. The priority of parameters is user > default > dummy. The bare minimum of required parameters is: * atoms [ ASE atoms-object of the system treated ] * sedc_n_groups [ integer, number of differently treated groups ] * sedc_groups [ array of integers, number of atoms per group ] * sedc_pbc_switches [ np.array of 6-dim vectors specifying the VdW contributions in A,B,C in positive and negative direction ] This has to be done after the creation of our calculator-object, because otherwise we do not have the atoms-module to calculate most of the required properties. """ for arg in self.valid_args: if hasattr(self, arg): # In order to avoid lengthy np-initialization in aims-script if (arg == 'sedc_pbc_g_switches'): setattr(sdc.sdc_recode, arg, eval('np.transpose(self.' + arg + ')')) elif (arg == 'sedc_tssurf_vfree_div_vbulk'): tmp_array = \ np.array(([1] * atoms.get_number_of_atoms()), np.float64) species = [] n_species = 0 for atom in atoms: species_i = atom.number if species_i not in species: species.append(species_i) n_species += 1 species.sort() for i,a in enumerate(atoms): for ss, s in enumerate(species): if s==a.number: tmp_array[i] = \ self.sedc_tssurf_vfree_div_vbulk[ss] sdc.sdc_recode.sedc_tssurf_vfree_div_vbulk = \ tmp_array else: setattr(sdc.sdc_recode, arg, eval('self.' + arg)) elif arg in self.default_parameters: setattr(sdc.sdc_recode, arg, self.default_parameters[arg]) else: if (arg == 'internal_cart_coord'): sdc.sdc_recode.internal_cart_coord = \ atoms.get_positions().transpose().copy() elif (arg == 'sedc_cart_coord'): sdc.sdc_recode.sedc_cart_coord = \ atoms.get_positions().transpose().copy() elif (arg == 'sedc_cell_vectors'): sdc.sdc_recode.sedc_cell_vectors = \ atoms.get_cell().transpose().copy() elif (arg == 'sedc_species'): sdc.sdc_recode.sedc_species = \ atoms.get_atomic_numbers().copy() elif (arg == 'sedc_n_ions'): sdc.sdc_recode.sedc_n_ions = \ atoms.get_number_of_atoms() elif (arg == 'sedc_pbc_g_fold'): sdc.sdc_recode.sedc_pbc_g_fold = [0] * self.sedc_n_groups elif (arg == 'sedc_ts_veff_div_vfree'): if not self.hirshvolrat_is_set: sdc.sdc_recode.sedc_ts_veff_div_vfree = \ np.array(([1] * atoms.get_number_of_atoms()), np.float64) elif (arg == 'sedc_tssurf_vfree_div_vbulk'): sdc.sdc_recode.sedc_tssurf_vfree_div_vbulk = \ np.array(([1] * atoms.get_number_of_atoms()), np.float64) elif (arg == 'sedc_skip_atom'): sdc.sdc_recode.sedc_skip_atom = \ np.array(([-1] * atoms.get_number_of_atoms()), np.float64) elif (arg == 'sedc_pbc_g_only_intra'): sdc.sdc_recode.sedc_pbc_g_only_intra = \ [0] * self.sedc_n_groups elif (arg == 'sedc_pbc_g_cells'): sdc.sdc_recode.sedc_pbc_g_cells = \ np.tile(atoms.get_cell().transpose().copy(), (1, self.sedc_n_groups)) elif (arg == 'sedc_pbc_g_skip'): sdc.sdc_recode.sedc_pbc_g_skip = [0] * self.sedc_n_groups else: print("You've been sloppy my friend. :) Variable:", arg, \ " does not exist!")
def init_MBD(self, atoms=None, do_MBD=True): """ Initialize MBD calculation and evaluate properties. """ from numpy.linalg import eigvals mbd_mod.init_grid(self.n_omega_SCS) mbd_mod.param_ts_energy_accuracy = self.TS_accuracy mbd_mod.param_ts_cutoff_radius = self.TS_cutoff mbd_mod.param_ewald_real_cutoff_scaling = self.ewald_real_cutoff_scaling mbd_mod.param_ewald_rec_cutoff_scaling = self.ewald_rec_cutoff_scaling mbd_mod.param_k_grid_shift = self.k_grid_shift mbd_mod.param_mbd_nbody_max = self.max_nbody_MBD mbd_mod.param_vacuum_axis = self.vacuum_axis mbd_mod.param_zero_negative_eigs = self.set_negative_eigenvalues_zero mbd_mod.my_task, mbd_mod.n_tasks = self.myid, self.ntasks solver_bak = self.eigensolver self.eigensolver = self.eigensolver.strip()[:5].ljust(5) if self.eigensolver not in ['qr ', 'mrrr ', 'dandc']: self.eigensolver = 'qr ' if (self.myid == 0): print("The specified eigensolver '" + solver_bak.strip() + "' is not known (yet).") print("Using default solver 'qr' instead...") mbd_mod.eigensolver = self.eigensolver assert hasattr(self, 'a_div_a0'), \ "Please provide rescaling to obtain initial dispersion parameters from accurate free atom reference data via 'set_rescaling(rescaling)'!" if self.use_alpha_vs_V_for_QDO: self.a_div_a0 **= (4. / 3.) self.modus = '' if (self.ntasks > 1): self.modus += 'P' if np.any(self.vacuum_axis == atoms.pbc): if (self.myid == 0): msg = '\n WARNING: Your specification for vacuum_axis is not in line with ' msg += 'the boundary conditions of the atoms object!\n' print(msg) if (not np.all(self.vacuum_axis)): self.modus += 'C' if not (self.do_reciprocal or self.do_supercell): raise ValueError( "You chose periodic boundary condition via vacuum_axis, but did not specify how to handle it (do_reciprocal or do_supercell)!" ) self.n_atoms = len(atoms) self.pos = atoms.positions / Bohr if np.product(eigvals(atoms.get_cell())) < 1e-2: if not np.all(self.vacuum_axis): raise ValueError( "Volume < 0.01 \AA^3. Please, define reasonable unit cell for periodic calculations." ) else: atoms.set_cell([[1e6, 0., 0.], [0., 1e6, 0.], [0., 0., 1e6]]) self.UC = atoms.get_cell() / Bohr symbols = atoms.get_chemical_symbols() self._get_dispersion_params(atoms) if hasattr(self, 'custom_damping_SCSMBD'): self.damp_par_a = self.custom_damping_SCSMBD['a'] self.damp_par_beta = self.custom_damping_SCSMBD['beta'] else: self._get_SCS_and_MBD_damping_params() if self.do_SCS: if self.get_alpha_full: self.modus += 'A' self._run_electrostatic_screening() if self.do_reciprocal: self.modus = self.modus.replace('C', 'CR') if self.get_MBD_eigenvalues: self.modus += 'E' if self.get_MBD_eigenvectors: self.modus += 'V' if do_MBD: self._get_mbd_energy() if self.do_TS: self._get_TS_energy1() if self.do_TSSCS: if not self.do_SCS: print( 'You requested TS energy with screened (SCS) polarizabilities,' ) print("but didn't set do_SCS to True. Skipping...") else: self._get_TSSCS_energy1() mbd_mod.destroy_grid()