from ase import Atoms, Atom from jasp import * atoms = Atoms([Atom('O', [5, 5, 5], magmom=1)], cell=(6, 6, 6)) with jasp( 'molecules/O_sv', encut=300, xc='PBE', ispin=2, ismear=0, sigma=0.001, setups={'O': '_sv'}, # specifies O_sv potential atoms=atoms) as calc: print 'Total energy = {0} eV'.format(atoms.get_potential_energy())
from ase import Atoms, Atom from vasp import Vasp import numpy as np np.set_printoptions(precision=3, suppress=True) atoms = Atoms([Atom('C', [0, 0, 0]), Atom('O', [1.2, 0, 0])], cell=(6, 6, 6)) atoms.center() ENCUTS = [250, 300, 350, 400, 450, 500] calcs = [Vasp('molecules/co-en-{0}'.format(en), encut=en, xc='PBE', atoms=atoms) for en in ENCUTS] energies = [calc.potential_energy for calc in calcs] print(energies) calcs[0].stop_if(None in energies) import matplotlib.pyplot as plt plt.plot(ENCUTS, energies, 'bo-') plt.xlabel('ENCUT (eV)') plt.ylabel('Total energy (eV)') plt.savefig('images/co-encut-v.png')
def calculate(element, h, vacuum, xc, magmom): atom = Atoms([Atom(element, (0, 0, 0))]) if magmom > 0.0: mms = [magmom for i in range(len(atom))] atom.set_initial_magnetic_moments(mms) atom.center(vacuum=vacuum) mixer = MixerSum(beta=0.2) if element == 'O': mixer = MixerSum(nmaxold=1, weight=100) atom.set_positions(atom.get_positions()+[0.0, 0.0, 0.0001]) calc_atom = GPAW(h=h, xc=data[element][xc][2], eigensolver='rmm-diis', occupations=FermiDirac(0.0, fixmagmom=True), mixer=mixer, nbands=-2, txt='%s.%s.txt' % (element, xc)) atom.set_calculator(calc_atom) mixer = Mixer(beta=0.2, weight=100) compound = molecule(element+'2') if compound == 'O2': mixer = MixerSum(beta=0.2) mms = [1.0 for i in range(len(compound))] compound.set_initial_magnetic_moments(mms) calc = GPAW(h=h, xc=data[element][xc][2], eigensolver='rmm-diis', mixer=mixer, txt='%s2.%s.txt' % (element, xc)) compound.set_distance(0,1, data[element]['R_AA_B3LYP']) compound.center(vacuum=vacuum) compound.set_calculator(calc) if data[element][xc][3] == 'hyb_gga': # only for hybrids e_atom = atom.get_potential_energy() e_compound = compound.get_potential_energy() calc_atom.set(xc=xc) calc.set(xc=xc) if 0: qn = QuasiNewton(compound) qn.attach(Trajectory( element+'2'+'_'+xc+'.traj', 'w', compound).write) qn.run(fmax=0.02) e_atom = atom.get_potential_energy() e_compound = compound.get_potential_energy() dHf_0 = (e_compound - 2 * e_atom + data[element]['ZPE_AA_B3LYP'] + 2 * data[element]['dHf_0_A']) dHf_298 = (dHf_0 + data[element]['H_298_H_0_AA_B3LYP'] - 2 * data[element]['H_298_H_0_A']) * (mol / kcal) dist_compound = compound.get_distance(0,1) de = dHf_298-data[element][xc][1] E[element][xc] = de if rank == 0: print((xc, h, vacuum, dHf_298, data[element][xc][1], de, de/data[element][xc][1])) if element == 'H': equal(dHf_298, data[element][xc][1], 0.25, msg=xc+': ') # kcal/mol elif element == 'O': equal(dHf_298, data[element][xc][1], 7.5, msg=xc+': ') # kcal/mol else: equal(dHf_298, data[element][xc][1], 2.15, msg=xc+': ') # kcal/mol equal(de, E_ref[element][xc], 0.06, msg=xc+': ') # kcal/mol
# run CuO calculation from vasp import Vasp from ase import Atom, Atoms import numpy as np # CuO # http://cst-www.nrl.navy.mil/lattice/struk/b26.html # http://www.springermaterials.com/docs/info/10681727_51.html a = 4.6837 b = 3.4226 c = 5.1288 beta = 99.54/180*np.pi y = 0.5819 a1 = np.array([0.5*a, -0.5*b, 0.0]) a2 = np.array([0.5*a, 0.5*b, 0.0]) a3 = np.array([c*np.cos(beta), 0.0, c*np.sin(beta)]) atoms = Atoms([Atom('Cu', 0.5*a2), Atom('Cu', 0.5*a1 + 0.5*a3), Atom('O', -y*a1 + y*a2 + 0.25*a3), Atom('O', y*a1 - y*a2 - 0.25*a3)], cell=(a1, a2, a3)) calc = Vasp('bulk/CuO', encut=400, kpts=[8, 8, 8], ibrion=2, isif=3, nsw=30, xc='PBE', atoms=atoms) print(atoms.get_potential_energy())
from ase import Atoms, Atom from ase.calculators.lammpsrun import LAMMPS a = [6.5, 6.5, 7.7] d = 2.3608 NaCl = Atoms([Atom('Na', [0, 0, 0]), Atom('Cl', [0, 0, d])], cell=a, pbc=True) calc = LAMMPS(tmp_dir='./', keep_tmp_files=True) NaCl.set_calculator(calc) print NaCl.get_stress()
for rot in [20, 200]: new = org.copy() new.translate(-new.get_center_of_mass()) new.rotate(rot, axis) dist = distance(org, new, True) dist2 = distance(org, new, False) print('rotation', axis, ', angle', rot, '-> distance', dist) assert dist < maxdist assert dist == dist2 if 0: # reflect new = Atoms() cm = org.get_center_of_mass() for a in org: new.append(Atom(a.symbol, -(a.position - cm))) dist = distance(org, new) print('reflected -> distance', dist) # permute for i, a in enumerate(org): if i < 3: a.symbol = 'H' for indxs in itertools.permutations(range(3)): new = org.copy() for c in range(3): new[c].position = org[indxs[c]].position dist = distance(org, new) print('permutation', indxs, '-> distance', dist) assert dist < maxdist
from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal a = 4.05 d = a / 2**0.5 bulk = Atoms([Atom('Al', (0, 0, 0)), Atom('Al', (0.5, 0.5, 0.5))], pbc=True) bulk.set_cell((d, d, a), scale_atoms=True) h = 0.25 calc = GPAW(h=h, nbands=2 * 8, kpts=(2, 2, 2), convergence={ 'eigenstates': 1e-10, 'energy': 1e-5 }) bulk.set_calculator(calc) e0 = bulk.get_potential_energy() niter0 = calc.get_number_of_iterations() calc = GPAW(h=h, nbands=2 * 8, kpts=(2, 2, 2), convergence={ 'eigenstates': 1e-10, 'energy': 1e-5, 'bands': 5 }, eigensolver='dav') bulk.set_calculator(calc) e1 = bulk.get_potential_energy() niter1 = calc.get_number_of_iterations()
from ase import Atom, Atoms m = Atoms('H2') a = m[0] b = Atom('H') for c in [a, b]: assert c.x == 0 c.z = 24.0 assert c.position[2] == 24.0 assert c.symbol == 'H' c.number = 92 assert c.symbol == 'U' c.symbol = 'Fe' assert c.number == 26 c.tag = 42 assert c.tag == 42 c.momentum = (1, 2, 3) assert m[0].tag == 42 momenta = m.get_momenta() m = Atoms('LiH') for a in m: print a.symbol for a in m: if a.symbol == 'H': a.z = 0.75 assert m.get_distance(0, 1) == 0.75 a = m.pop() m += a del m[:1] print m
from gpaw import GPAW from gpaw.lrtddft.kssingle import KSSingles from gpaw.analyse.overlap import Overlap from gpaw.test import equal txt = '-' txt = None load = True load = False xc = 'LDA' R = 0.7 # approx. experimental bond length a = 4.0 c = 5.0 H2 = Atoms([ Atom('H', (a / 2, a / 2, (c - R) / 2)), Atom('H', (a / 2, a / 2, (c + R) / 2)) ], cell=(a, a, c)) calc = GPAW(xc=xc, nbands=3, spinpol=False, eigensolver='rmm-diis', txt=txt) H2.set_calculator(calc) H2.get_potential_energy() gsname = exname = 'rraman' exkwargs = {'eps': 0.0, 'jend': 1} pz = ResonantRaman(H2, KSSingles, gsname=gsname, exname=exname, exkwargs=exkwargs,
import numpy as np from ase import Atom, Atoms from ase.units import Hartree from gpaw.mpi import size from gpaw import GPAW from gpaw.response.bse import BSE GS = 1 bse = 1 casida = 1 compare = 1 if GS: d = 2.89 cluster = Atoms([Atom('Na', (0, 0, 0)), Atom('Na', (0, 0, d)), ], pbc=True) cluster.set_cell((15.,15.,18.), scale_atoms=False) cluster.center() calc=GPAW(h=0.3,nbands=8) cluster.set_calculator(calc) cluster.get_potential_energy() calc.write('Na2.gpw','all') if bse: bse = BSE('Na2.gpw',w=np.linspace(0,15,151), q=np.array([0,0,0.0001]),optical_limit=True,ecut=50.,
from jasp import * from ase import Atom, Atoms atoms = Atoms([Atom('O', [4, 4.5, 5], magmom=2)], cell=(8, 9, 10)) with jasp('molecules/O-sp-triplet-lowsym-sv', xc='PBE', ismear=0, ispin=2, sigma=0.01, setups={'O': '_sv'}, atoms=atoms) as calc: try: E_O = atoms.get_potential_energy() except (VaspSubmitted, VaspQueued): E_O = None print('Magnetic moment on O = {0} Bohr' ' magnetons'.format(atoms.get_magnetic_moment())) # now relaxed O2 dimer atoms = Atoms( [Atom('O', [5, 5, 5], magmom=1), Atom('O', [6.22, 5, 5], magmom=1)], cell=(10, 10, 10)) with jasp( 'molecules/O2-sp-triplet-sv', xc='PBE', ismear=0, sigma=0.01, ispin=2, # turn spin-polarization on ibrion=2, # make sure we relax the geometry nsw=10, setups={'O': '_sv'}, atoms=atoms) as calc:
def read_vasp_out(filename='OUTCAR', index=-1, force_consistent=False): """Import OUTCAR type file. Reads unitcell, atom positions, energies, and forces from the OUTCAR file and attempts to read constraints (if any) from CONTCAR/POSCAR, if present. """ import numpy as np from ase.calculators.singlepoint import SinglePointCalculator from ase import Atoms, Atom try: # try to read constraints, first from CONTCAR, then from POSCAR constr = read_vasp('CONTCAR').constraints except Exception: try: constr = read_vasp('POSCAR').constraints except Exception: constr = None if isinstance(filename, basestring): f = open(filename) else: # Assume it's a file-like object f = filename data = f.readlines() natoms = 0 images = [] atoms = Atoms(pbc=True, constraint=constr) energy = 0 species = [] species_num = [] stress = None symbols = [] ecount = 0 poscount = 0 magnetization = [] magmom = None for n, line in enumerate(data): if re.search('[0-9]-[0-9]', line): data[n] = re.sub('([0-9])-([0-9])', r'\1 -\2', line) for n, line in enumerate(data): if 'POTCAR:' in line: temp = line.split()[2] for c in ['.', '_', '1']: if c in temp: temp = temp[0:temp.find(c)] species += [temp] if 'ions per type' in line: species = species[:len(species) // 2] temp = line.split() ntypes = min(len(temp) - 4, len(species)) for ispecies in range(ntypes): species_num += [int(temp[ispecies + 4])] natoms += species_num[-1] for iatom in range(species_num[-1]): symbols += [species[ispecies]] if 'direct lattice vectors' in line: cell = [] for i in range(3): temp = data[n + 1 + i].split() cell += [[float(temp[0]), float(temp[1]), float(temp[2])]] atoms.set_cell(cell) if 'Free energy of the ion-electron system (eV)' in line: e_alpha_z = float(data[n + 2].split()[4]) e_ewald = float(data[n + 3].split()[4]) e_hartree = float(data[n + 4].split()[4]) e_exchange = float(data[n + 5].split()[3]) e_vxc_exc = float(data[n + 6].split()[3]) e_paw_double1, e_paw_double2 = map(float, data[n + 7].split()[4:6]) e_t_s = float(data[n + 8].split()[4]) e_eigen = float(data[n + 9].split()[3]) e_atomic = float(data[n + 10].split()[4]) e_solv = float(data[n + 11].split()[3]) if 'Edisp (eV)' in line: e_vdw = float(data[n].split()[2]) if 'FREE ENERGIE OF THE ION-ELECTRON SYSTEM' in line: # choose between energy wigh smearing extrapolated to zero # or free energy (latter is consistent with forces) energy_zero = float(data[n + 4].split()[6]) energy_free = float(data[n + 2].split()[4]) energy = energy_zero if force_consistent: energy = energy_free if ecount < poscount: # reset energy for LAST set of atoms, not current one - # VASP 5.11? and up images[-1].calc.results['e_alpha_z'] = e_alpha_z images[-1].calc.results['e_ewald'] = e_ewald images[-1].calc.results['e_hartree'] = e_hartree images[-1].calc.results['e_exchange'] = e_exchange images[-1].calc.results['e_vxc_exc'] = e_vxc_exc images[-1].calc.results['e_paw_double1'] = e_paw_double1 images[-1].calc.results['e_paw_double2'] = e_paw_double2 images[-1].calc.results['e_t_s'] = e_t_s images[-1].calc.results['e_eigen'] = e_eigen images[-1].calc.results['e_atomic'] = e_atomic images[-1].calc.results['e_solv'] = e_solv images[-1].calc.results['e_vdw'] = e_vdw images[-1].calc.results['energy'] = energy images[-1].calc.set(energy=energy) ecount += 1 if 'magnetization (x)' in line: magnetization = [] for i in range(natoms): magnetization += [float(data[n + 4 + i].split()[4])] if 'number of electron' in line: parts = line.split() if len(parts) > 5 and parts[0].strip() != "NELECT": magmom = float(parts[5]) if 'in kB ' in line: stress = -np.array([float(a) for a in line.split()[2:]]) stress = stress[[0, 1, 2, 4, 5, 3]] * 1e-1 * ase.units.GPa if 'POSITION ' in line: forces = [] positions = [] for iatom in range(natoms): temp = data[n + 2 + iatom].split() atoms += Atom(symbols[iatom], [float(temp[0]), float(temp[1]), float(temp[2])]) forces += [[float(temp[3]), float(temp[4]), float(temp[5])]] positions += [[float(temp[0]), float(temp[1]), float(temp[2])]] atoms.set_calculator( SinglePointCalculator(atoms, energy=energy, forces=forces, stress=stress)) images += [atoms] if len(magnetization) > 0: mag = np.array(magnetization, float) images[-1].calc.magmoms = mag images[-1].calc.results['magmoms'] = mag if magmom: images[-1].calc.results['magmom'] = magmom atoms = Atoms(pbc=True, constraint=constr) poscount += 1 # return requested images, code borrowed from ase/io/trajectory.py if isinstance(index, int): return images[index] else: step = index.step or 1 if step > 0: start = index.start or 0 if start < 0: start += len(images) stop = index.stop or len(images) if stop < 0: stop += len(images) else: if index.start is None: start = len(images) - 1 else: start = index.start if start < 0: start += len(images) if index.stop is None: stop = -1 else: stop = index.stop if stop < 0: stop += len(images) return [images[i] for i in range(start, stop, step)]
def find_defects(solid, bulko, rcutoff, atomlistcheck=False, trackvacs=False, trackswaps=False, debug=False, dcheck=0.6): """Function to find interstitials, vacancies, and substitutional atoms (swaps) in a defected structure. Identifies species by comparison to perfect structure. Inputs: solid = ASE atoms class for defected structure bulko = ASE atoms class for perfect structure rcutoff = float value of distance to surrounding atoms to include atomlistcheck = False/list of atom types and concentrations according to atomlist format trackvacs = True/False whether or not to identify vacancies in defect trackswaps = True/False whether or not to identify substitutional defects debug = False/file object to write debug structures""" # Combine perfect and defect structures together b = bulko.copy() b.extend(solid) b.set_pbc(True) #Debug: Write solid and bulko to file if debug: print len(bulko) write_xyz(debug, b, 'Find Ints: Solid and Bulko') # Identify nearest neighbor atoms for each atom in perfect structure ntot = len(bulko) ctoff1 = [1.2 for one in b] nl = NeighborList(ctoff1, bothways=True, self_interaction=False) nl.update(b) slist = [] blist = [] wlist = [] #Loop over each atom in perfect structure for one in range(ntot): indices, offsets = nl.get_neighbors(one) for index, d in zip(indices, offsets): index = int(index) if index >= ntot: pos = b[index].position + numpy.dot(d, bulko.get_cell()) natm1 = Atom(position=pos) dist, dx, dy, dz = calc_dist(b[one], natm1) if dist <= dcheck: #Assume atoms closer than 0.6 Angstroms to be equivalent slist.append(index - ntot) blist.append(one) if b[one].symbol == b[index].symbol: wlist.append(index - ntot) #Identify those atoms corresponding to interstitials, vacancies, and substitutions oslist = [atm.index for atm in solid if atm.index not in slist] vlist = [atm.index for atm in bulko if atm.index not in blist] swlist = [ atm.index for atm in solid if atm.index not in wlist and atm.index not in oslist ] # Create Atoms objects for each identified defect ntot = len(solid) cluster = Atoms() for one in oslist: cluster.append(solid[one]) vacant = Atoms() if trackvacs == True: for one in vlist: vacant.append( Atom(symbol=bulko[one].symbol, position=bulko[one].position)) solid.append(Atom(symbol='X', position=bulko[one].position)) oslist.append(len(solid) - 1) stro = 'Cluster Identified with length = {0}\nIdentified {1} vacancies\n'.format( len(cluster), len(vlist)) swaps = Atoms() if trackswaps == True: for one in swlist: swaps.append(solid[one]) oslist.append(one) stro = 'Cluster Identified with length = {0}\nIdentified {1} swaps\n'.format( len(cluster), len(swlist)) else: stro = 'Cluster Identified with length = {0}\n'.format(len(cluster)) #Debug: write cluster to file if debug: b = cluster.copy() write_xyz(debug, b, 'Find Ints: Cluster') debug.flush() print 'Found cluster size = ', len(b) # Identify atoms surrounding the identified defects in the defected structure box = Atoms() bulki = Atoms() if rcutoff != 0: if rcutoff > 2.0: cutoffs = [rcutoff for one in solid] else: cutoffs = [2.0 for one in solid] solid.set_pbc(True) nl = NeighborList(cutoffs, bothways=True, self_interaction=False) nl.update(solid) nbatmsd = [] repinds = [] for one in oslist: if one not in repinds: if one < ntot: nbatmsd.append((0, one)) repinds.append(one) for one in oslist: indices, offsets = nl.get_neighbors(one) for index, d in zip(indices, offsets): index = int(index) if index not in repinds and index < ntot: opos = copy.copy(solid[index].position) solid[index].position = solid[index].position + numpy.dot( d, solid.get_cell()) dist = solid.get_distance(one, index) solid[index].position = opos if dist <= rcutoff: nbatmsd.append((dist, index)) repinds.append(index) else: nbatmsd = [] repinds = [] for one in oslist: if one not in repinds: if one < ntot: nbatmsd.append((0, one)) repinds.append(one) nbatmsd = sorted(nbatmsd, key=lambda one: one[0], reverse=True) indices = [] natomsbox = 0 # Select only atoms closest to defects that satisfy concentrations specified by atomlist given in atomlistcheck if atomlistcheck: for sym, c, m, u in atomlistcheck: i = 0 nbsym = [one for one in nbatmsd if solid[one[1]].symbol == sym] if len(nbsym) > c: while i < c: a = nbsym.pop() box.append(solid[a[1]]) indices.append(a[1]) i += 1 else: for a in nbsym: box.append(solid[a[1]]) indices.append(a[1]) i += 1 if len(box) - natomsbox < c: try: while True: for n in range(len(nbatmsd) - 1, -1, -1): inds, offsets = nl.get_neighbors(nbatmsd[n][1]) for one, d in zip(inds, offsets): if len(box) - natomsbox < c: if one not in indices and one < ntot and solid[ one].symbol == sym: opos = copy.copy( solid[one].position) solid[one].position = solid[ one].position + numpy.dot( d, solid.get_cell()) dist = solid.get_distance( nbatmsd[n][1], one) solid[one].position = opos if dist <= rcutoff * 5.0: box.append(solid[one]) indices.append(one) else: raise StopIteration() for one, d in zip(inds, offsets): if len(box) - natomsbox < c: if one not in indices and one < ntot and solid[ one].symbol == sym: opos = copy.copy( solid[one].position) solid[one].position = solid[ one].position + numpy.dot( d, solid.get_cell()) dist = solid.get_distance( nbatmsd[n][1], one) solid[one].position = opos box.append(solid[one]) indices.append(one) else: raise StopIteration() except StopIteration: pass natomsbox = len(box) #Double check for sanity for sym, c, m, u in atomlistcheck: symsbox = [one for one in box if one.symbol == sym] if len(symsbox) != c: stro += 'WARNING!!!! : FAILURE IN FIND_DEFECTS TO MATCH PROVIDED ATOMLIST. DEBUG!!!!\n' # If atomlistcheck is False then use all the atoms in the given cutoff distance else: for a in nbatmsd: box.append(solid[a[1]]) indices.append(a[1]) # Add remaining atoms in defect to defected bulk atoms object for one in range(len(solid)): if one not in indices and one < ntot: bulki.append(solid[one]) #Check for accidental vacancy admissions #checklist=[atm for atm in box if atm.symbol=='X'] #checklist.extend([atm for atm in bulki if atm.symbol=='X']) #Set up new individual indiv = box.copy() bulki.set_cell(bulko.get_cell()) indiv.set_cell(bulko.get_cell()) bulki.set_pbc(True) indiv.set_pbc(True) stro += 'Atomlist check = {0}\n'.format(atomlistcheck) stro += 'Bulko = {0}\n'.format(bulko) stro += 'New individual ({0} atoms) : {1}\n'.format(len(indiv), indiv) stro += 'New bulki ({0} atoms) : {1}\n'.format(len(bulki), bulki) #Debug: write new indiv to file if debug: b = indiv.copy() write_xyz(debug, b, 'Find Ints: New Individual') #Debug: write new bulki to file b = bulki.copy() write_xyz(debug, b, 'Find Ints: New Bulki') debug.flush() print len(bulko) return indiv, bulki, vacant, swaps, stro
def set_position(self, position): Atom.set(self, 'position', position) self._mark()
def do_lattice(latt_name): if latt_name == "cubic": print("--------------------") print("Simple cubic lattice") print("--------------------") atoms = Atoms( [Atom('H', (0.0, 0.0, 0.0))], pbc=True ) LatVecs = gen_lattice_sc(5.0) atoms.set_cell( LatVecs ) atoms.write("H_sc.xsf") elif latt_name == "fcc": print("-----------") print("FCC lattice") print("-----------") atoms = Atoms( [Atom('H', (0.0, 0.0, 0.0))], pbc=True ) LatVecs = gen_lattice_fcc(5.0) atoms.set_cell( LatVecs ) atoms.write("H_fcc.xsf") elif latt_name == "bcc": print("-----------") print("BCC lattice") print("-----------") atoms = Atoms( [Atom('H', (0.0, 0.0, 0.0))], pbc=True ) LatVecs = gen_lattice_bcc(5.0) atoms.set_cell( LatVecs ) atoms.write("H_bcc.xsf") elif latt_name == "hexagonal": print("-----------------") print("Hexagonal lattice") print("-----------------") atoms = Atoms( [Atom('H', (0.0, 0.0, 0.0))], pbc=True ) LatVecs = gen_lattice_hexagonal(5.0, 8.0) atoms.set_cell( LatVecs ) atoms.write("H_hexagonal.xsf") elif latt_name == "tetragonal": print("------------------") print("Tetragonal lattice") print("------------------") atoms = Atoms( [Atom("H", (0.0, 0.0, 0.0))], pbc=True ) LatVecs = gen_lattice_tetragonal_P(5.0, 6.0) atoms.set_cell( LatVecs ) atoms.write("H_tetragonal.xsf") elif latt_name == "orthorhombic": print("--------------------") print("Orthorhombic lattice") print("--------------------") atoms = Atoms( [Atom('H', (0.0, 0.0, 0.0))], pbc=True ) LatVecs = gen_lattice_orthorhombic(5.0, 8.0, 6.0) atoms.set_cell( LatVecs ) atoms.write("H_orthorhombic.xsf") elif latt_name == "rhombohedral type 1": print("-----------------------------") print("Rhombohedral lattice (type 1)") print("-----------------------------") atoms = Atoms( [Atom("H", (0.0, 0.0, 0.0))], pbc=True ) LatVecs = gen_lattice_rhombohedral(5.0, 80.0) # gamma < 90 degree atoms.set_cell( LatVecs ) # atoms.write("H_rhombohedral.xsf") # elif latt_name == "monoclinic": print("------------------") print("Monoclinic lattice") print("------------------") atoms = Atoms( [Atom("H", (0.0, 0.0, 0.0))], pbc=True ) LatVecs = gen_lattice_monoclinic(5.0, 8.0, 6.0, 80.0) atoms.set_cell( LatVecs ) atoms.write("H_monoclinic.xsf") else: raise RuntimeError("Unknown lattice name:", lattice) KPT, X, XKPT, PATH_STR, KPT_SPEC = gen_kpath( atoms,lattice=latt_name ) # Nsegment = len(PATH_STR) print("Nsegment = ", Nsegment) # for isegment in range(Nsegment): # x = X[isegment] kpt = KPT[isegment] path_str = PATH_STR[isegment] kpt_spec = KPT_SPEC[isegment] # Nkpt = len(x) print(Nkpt) for ik in range(Nkpt): sys.stdout.write("%18.10f %18.10f %18.10f: %18.10f\n" % (kpt[ik,0],kpt[ik,1],kpt[ik,2],x[ik])) # kpt_spec = np.array(kpt_spec) Nkpt_spec = len(path_str) print(Nkpt_spec) for ik in range(Nkpt_spec): sys.stdout.write("%18.10f %18.10f %18.10f %s\n" % (kpt_spec[ik,0], kpt_spec[ik,1], kpt_spec[ik,2], path_str[ik]))
from jasp import * from ase import Atom, Atoms # fcc LC = [3.5, 3.55, 3.6, 3.65, 3.7, 3.75] volumes, energies = [], [] for a in LC: atoms = Atoms( [Atom('Ni', (0, 0, 0), magmom=2.5)], cell=0.5 * a * np.array([[1.0, 1.0, 0.0], [0.0, 1.0, 1.0], [1.0, 0.0, 1.0]])) with jasp('bulk/Ni-{0}'.format(a), xc='PBE', encut=350, kpts=(12, 12, 12), ispin=2, atoms=atoms) as calc: try: e = atoms.get_potential_energy() energies.append(e) volumes.append(atoms.get_volume()) except: pass if len(energies) != len(LC): import sys sys.exit() import matplotlib.pyplot as plt plt.plot(LC, fcc_energies) plt.xlabel('Lattice constant ($\AA$)') plt.ylabel('Total energy (eV)') plt.savefig('images/Ni-fcc.png')
def take_cluster(old_conf_name, type_map, idx, jdata): cutoff = jdata['cluster_cutoff'] cutoff_hard = jdata.get('cluster_cutoff_hard', None) sys = dpdata.System(old_conf_name, fmt = 'lammps/dump', type_map = type_map) atom_names = sys['atom_names'] atom_types = sys['atom_types'] cell = sys['cells'][0] coords = sys['coords'][0] symbols = [atom_names[atom_type] for atom_type in atom_types] # detect fragment frag_numb, frag_index, graph = _crd2frag(symbols, coords, True, cell, return_bonds=True) # get_distances all_atoms = Atoms(symbols = symbols, positions = coords, pbc=True, cell=cell) all_atoms[idx].tag = 1 distances = all_atoms.get_distances(idx, range(len(all_atoms)), mic=True) distancescutoff = distances < cutoff cutoff_atoms_idx = np.where(distancescutoff)[0] if cutoff_hard is not None: distancescutoff_hard = distances < cutoff_hard cutoff_atoms_idx_hard = np.where(distancescutoff_hard)[0] # make cutoff atoms in molecules taken_atoms_idx = [] added = [] for ii in range(frag_numb): frag_atoms_idx = np.where(frag_index == ii)[0] if cutoff_hard is not None: # drop atoms out of the hard cutoff anyway frag_atoms_idx = np.intersect1d(frag_atoms_idx, cutoff_atoms_idx_hard) if np.any(np.isin(frag_atoms_idx, cutoff_atoms_idx)): if 'cluster_minify' in jdata and jdata['cluster_minify']: # support for organic species take_frag_idx=[] for aa in frag_atoms_idx: if np.any(np.isin(aa, cutoff_atoms_idx)): # atom is in the soft cutoff # pick up anyway take_frag_idx.append(aa) elif np.count_nonzero(np.logical_and(distancescutoff, graph.toarray()[aa]==1)): # atom is between the hard cutoff and the soft cutoff # and has a single bond with the atom inside if all_atoms[aa].symbol == 'H': # for atom H: just add it take_frag_idx.append(aa) else: # for other atoms (C, O, etc.): replace it with a ghost H atom near_atom_idx = np.nonzero(np.logical_and(distancescutoff, graph.toarray()[aa]>0))[0][0] vector = all_atoms[aa].position - all_atoms[near_atom_idx].position new_position = all_atoms[near_atom_idx].position + vector / np.linalg.norm(vector) * 1.09 added.append(Atom('H', new_position)) elif np.count_nonzero(np.logical_and(distancescutoff, graph.toarray()[aa]>1)): # if that atom has a double bond with the atom inside # just pick up the whole fragment (within the hard cutoff) # TODO: use a more fantastic method take_frag_idx=frag_atoms_idx break else: take_frag_idx = frag_atoms_idx taken_atoms_idx.append(take_frag_idx) all_taken_atoms_idx = np.concatenate(taken_atoms_idx) # wrap cutoff_atoms = sum(added, all_atoms[all_taken_atoms_idx]) cutoff_atoms.wrap( center=coords[idx] / cutoff_atoms.get_cell_lengths_and_angles()[0: 3], pbc=True) coords = cutoff_atoms.get_positions() sys.data['coords'] = np.array([coords]) sys.data['atom_types'] = np.array(list(atom_types[all_taken_atoms_idx]) + [atom_names.index('H')]*len(added)) sys.data['atom_pref'] = np.array([cutoff_atoms.get_tags()]) for ii, _ in enumerate(atom_names): sys.data['atom_numbs'][ii] = np.count_nonzero(sys.data['atom_types']==ii) return sys
def _branch_molecule(self, molecule, molecules): """Construct all the molecules one atom larger from a given molecule and add the unique ones to a dictionary. Parameters: ----------- molecule : Gratoms object Molecule to create branching structures from. molecules : dict Molecule structures to check for unique matches against. Returns: -------- new_molecules : list All unique molecules discovered while branching. molecules : dict Molecule structures to check for unique matches updated with new_molecules. """ new_molecules = [] nodes = molecule.nodes counter = np.bincount(molecule.get_atomic_numbers(), minlength=len(self.base_valence)) for base_node in nodes: # Check if an additional bond can be formed valence = nodes[base_node]['valence'] base_el = molecule.nodes[base_node]['number'] # Creating new nodes for el, cnt in enumerate(self.element_pool): # Skip elements exceeding specified limit if counter[el] >= cnt: continue if valence <= 0: continue # Don't form new bonds if the users rules prohibit if self.nbond_limits[base_el, el] == 0: continue G = molecule.copy() node_index = len(G) G.nodes[base_node]['valence'] -= 1 G += Atom(el) G.nodes[node_index]['valence'] = self.base_valence[el] - 1 G.graph.add_edge(base_node, node_index, bonds=1) comp_tag, bond_tag = G.get_chemical_tags() isomorph_found = False if comp_tag not in molecules: molecules[comp_tag] = {} if bond_tag not in molecules[comp_tag]: molecules[comp_tag][bond_tag] = [] else: for G1 in molecules[comp_tag][bond_tag]: if G.is_isomorph(G1): isomorph_found = True break if not isomorph_found: new_molecules += [G] molecules[comp_tag][bond_tag] += [G] # Bonds to existing nodes if self.multiple_bond_search: for existing_node in nodes: if valence <= 0: continue # Atoms don't bond to themselves if existing_node == base_node: continue valence_new = nodes[existing_node]['valence'] el = molecule.nodes[existing_node]['number'] if valence_new <= 0: continue if self._maximum_bond_limit(molecule, base_node, existing_node): continue G = molecule.copy() G.nodes[base_node]['valence'] -= 1 G.nodes[existing_node]['valence'] -= 1 if G.graph.has_edge(base_node, existing_node): G.graph[base_node][existing_node]['bonds'] += 1 else: G.graph.add_edge(base_node, existing_node, bonds=1) comp_tag, bond_tag = G.get_chemical_tags() isomorph_found = False if comp_tag not in molecules: molecules[comp_tag] = {} if bond_tag not in molecules[comp_tag]: molecules[comp_tag][bond_tag] = [] else: for G1 in molecules[comp_tag][bond_tag]: if G.is_isomorph(G1): isomorph_found = True break if not isomorph_found: new_molecules += [G] molecules[comp_tag][bond_tag] += [G] return new_molecules, molecules
from ase import Atom, Atoms import numpy as np a = 3.61 # lattice constant atoms = Atoms([Atom('Cu', [0, 0, 0])], cell=0.5 * a * np.array([[1.0, 1.0, -1.0], [-1.0, 1.0, 1.0], [1.0, -1.0, 1.0]])) print 'BCC lattice constant = {0:1.3f} Ang'.format( a * (11.8 / atoms.get_volume())**(1. / 3.))
x_label = "K_BT" if is_lat_const: x_label = "Lattice constant" my_fig = plt.figure(0) energies = [i/2 for i in energies] if not is_lat_const: plt.semilogx(changing_parameter, energies) plt.semilogx(changing_parameter, energies,'*') else: plt.plot(changing_parameter, energies) plt.plot(changing_parameter, energies,'*') plt.xlabel(x_label) plt.ylabel('Energy, eV') my_fig.savefig(x_label + '_two_atoms', bbox_inches='tight') plt.show() #plot_changing_param_vs_energy(350,380,5,False,False,False,True) #plot_changing_param_vs_energy(2,12,1,False,True,False,False) #plot_changing_param_vs_energy(200,1200,100,True,False,False,False) b = 1.5 bulk = Atoms([Atom('Cu', (0, 0, 0))], cell=np.array([[b, b, 0.0], [0.0, b, b], [b, 0.0, b]]), pbc = True).repeat((1, 2, 1)) view(bulk)
from ase import Atoms, Atom from jasp import * import numpy as np np.set_printoptions(precision=3, suppress=True) co = Atoms([Atom('C', [0, 0, 0]), Atom('O', [1.2, 0, 0])], cell=(6., 6., 6.)) with jasp( 'molecules/simple-co', # output dir xc='PBE', # the exchange-correlation functional nbands=6, # number of bands encut=350, # planewave cutoff ismear=1, # Methfessel-Paxton smearing sigma=0.01, # very small smearing factor for a molecule atoms=co) as calc: print 'energy = {0} eV'.format(co.get_potential_energy()) print co.get_forces()
def read_turbomole_gradient(f='gradient', index=-1): """ Method to read turbomole gradient file """ # read entire file lines = [x.strip() for x in f.readlines()] # find $grad section start = end = -1 for i, line in enumerate(lines): if not line.startswith('$'): continue if line.split()[0] == '$grad': start = i elif start >= 0: end = i break if end <= start: raise RuntimeError('File does not contain a valid \'$grad\' section') def formatError(): raise RuntimeError('Data format in file does not correspond to known ' 'Turbomole gradient format') # trim lines to $grad del lines[:start+1] del lines[end-1-start:] # Interpret $grad section from ase import Atoms, Atom from ase.calculators.singlepoint import SinglePointCalculator from ase.units import Bohr images = [] while len(lines): # loop over optimization cycles # header line # cycle = 1 SCF energy = -267.6666811409 |dE/dxyz| = 0.157112 fields = lines[0].split('=') try: # cycle = int(fields[1].split()[0]) energy = float(fields[2].split()[0]) # gradient = float(fields[3].split()[0]) except (IndexError, ValueError): formatError() # coordinates/gradient atoms = Atoms() forces = [] for line in lines[1:]: fields = line.split() if len(fields) == 4: # coordinates # 0.00000000000000 0.00000000000000 0.00000000000000 c try: symbol = fields[3].lower().capitalize() position = tuple([Bohr * float(x) for x in fields[0:3] ]) except ValueError: formatError() atoms.append(Atom(symbol, position)) elif len(fields) == 3: # gradients # -.51654903354681D-07 -.51654903206651D-07 0.51654903169644D-07 try: grad = [float(x.replace('D', 'E')) * Bohr for x in fields[0:3] ] except ValueError: formatError() forces.append(grad) else: # next cycle break # calculator calc = SinglePointCalculator(atoms, energy=energy, forces=forces) atoms.set_calculator(calc) # save frame images.append(atoms) # delete this frame from data to be handled del lines[:2*len(atoms)+1] return images[index]
slab.set_pbc((1, 1, 0)) slab.calc = EMT() Z = slab.get_positions()[:, 2] indices = [i for i, z in enumerate(Z) if z < Z.mean()] constraint = FixAtoms(indices=indices) slab.set_constraint(constraint) dyn = QuasiNewton(slab) dyn.run(fmax=0.05) Z = slab.get_positions()[:, 2] print Z[0] - Z[1] print Z[1] - Z[2] print Z[2] - Z[3] b = 1.2 h = 1.5 slab += Atom('C', (d / 2, -b / 2, h)) slab += Atom('O', (d / 2, +b / 2, h)) s = slab.copy() dyn = QuasiNewton(slab) dyn.run(fmax=0.05) #view(slab) # Make band: images = [slab] for i in range(6): image = slab.copy() image.set_constraint(constraint) image.calc = EMT() images.append(image) image[-2].position = image[-1].position image[-1].x = d
def test_COCu111(): # Distance between Cu atoms on a (111) surface: a = 3.6 d = a / sqrt(2) fcc111 = Atoms(symbols='Cu', cell=[(d, 0, 0), (d / 2, d * sqrt(3) / 2, 0), (d / 2, d * sqrt(3) / 6, -a / sqrt(3))], pbc=True) slab = fcc111 * (2, 2, 2) slab.set_cell([2 * d, d * sqrt(3), 1]) slab.set_pbc((1, 1, 0)) slab.calc = EMT() Z = slab.get_positions()[:, 2] indices = [i for i, z in enumerate(Z) if z < Z.mean()] constraint = FixAtoms(indices=indices) slab.set_constraint(constraint) dyn = QuasiNewton(slab) dyn.run(fmax=0.05) Z = slab.get_positions()[:, 2] print(Z[0] - Z[1]) print(Z[1] - Z[2]) print(Z[2] - Z[3]) b = 1.2 h = 1.5 slab += Atom('C', (d / 2, -b / 2, h)) slab += Atom('O', (d / 2, +b / 2, h)) dyn = QuasiNewton(slab) dyn.run(fmax=0.05) # Make band: images = [slab] for i in range(4): image = slab.copy() # Set constraints and calculator: image.set_constraint(constraint) image.calc = EMT() images.append(image) # Displace last image: image = images[-1] image[-2].position = image[-1].position image[-1].x = d image[-1].y = d / sqrt(3) dyn = QuasiNewton(images[-1]) dyn.run(fmax=0.05) neb = NEB(images, climb=not True) # Interpolate positions between initial and final states: neb.interpolate(method='idpp') for image in images: print(image.positions[-1], image.get_potential_energy()) dyn = BFGS(neb, maxstep=0.04, trajectory='mep.traj') dyn.run(fmax=0.1) for image in images: print(image.positions[-1], image.get_potential_energy()) # Trying to read description of optimization from trajectory traj = Trajectory('mep.traj') assert traj.description['optimizer'] == 'BFGS' for key, value in traj.description.items(): print(key, value) print(traj.ase_version)
def load_xyz(filename='xyz.in', atom_types=None): """ Reads and returns the structure input file from GPUMD. Args: filename (str): Name of structure file atom_types (list(str)): List of atom types (elements). Returns: tuple: atoms, M, cutoff atoms (ase.Atoms): ASE atoms object with x,y,z, mass, group, type, cell, and PBCs from input file. group is stored in tag, atom type may not correspond to correct atomic symbol M (int): Max number of neighbor atoms cutoff (float): Initial cutoff for neighbor list build """ # read file with open(filename) as f: xyz_lines = f.readlines() # get global structure params l1 = tuple(xyz_lines[0].split()) # first line N, M, use_triclinic, has_velocity, \ num_of_groups = [int(val) for val in l1[:2]+l1[3:]] cutoff = float(l1[2]) l2 = tuple(xyz_lines[1].split()) # second line if use_triclinic: pbc, cell = [int(val) for val in l2[:3]], [float(val) for val in l2[3:]] else: pbc, L = [int(val) for val in l2[:3]], [float(val) for val in l2[3:]] # get atomic params info = dict() atoms = Atoms() atoms.set_pbc((pbc[0], pbc[1], pbc[2])) if use_triclinic: atoms.set_cell(np.array(cell).reshape((3,3))) else: atoms.set_cell([(L[0], 0, 0), (0, L[1], 0), (0, 0, L[2])]) for index, line in enumerate(xyz_lines[2:]): data = dict() lc = tuple(line.split()) # current line type_, mass = int(lc[0]), float(lc[4]) position = [float(val) for val in lc[1:4]] atom = Atom(type_, position, mass=mass) lc = lc[5:] # reduce list length for easier indexing if has_velocity: velocity = [float(val) for val in lc[:3]] lc = lc[3:] data['velocity'] = velocity if num_of_groups: groups = [int(group) for group in lc] data['groups'] = groups atoms.append(atom) info[index] = data atoms.info = info if atom_types: __set_atoms(atoms, atom_types) return atoms, M, cutoff
from ase import Atom, Atoms from gpaw import GPAW from gpaw.test import equal a = 5.0 d = 1.0 x = d / 3**0.5 atoms = Atoms([ Atom('C', (0.0, 0.0, 0.0)), Atom('H', (x, x, x)), Atom('H', (-x, -x, x)), Atom('H', (x, -x, -x)), Atom('H', (-x, x, -x)) ], cell=(a, a, a), pbc=False) atoms.positions[:] += a / 2 calc = GPAW(h=0.25, nbands=4, convergence={'eigenstates': 1e-11}) atoms.set_calculator(calc) energy = atoms.get_potential_energy() niter = calc.get_number_of_iterations() # The three eigenvalues e[1], e[2], and e[3] must be degenerate: e = atoms.get_calculator().wfs.kpt_u[0].eps_n print e[1] - e[3] equal(e[1], e[3], 9.3e-8) energy_tolerance = 0.0003 niter_tolerance = 0 equal(energy, -23.6277, energy_tolerance)
def lattice_alteration_nn(indiv, Optimizer): """Move function to perform random move along random axis for nearest neighbor distance to random atoms Inputs: indiv = Individual class object to be altered Optimizer = Optimizer class object with needed parameters Outputs: indiv = Altered Individual class object """ if 'MU' in Optimizer.debug: debug = True else: debug = False if Optimizer.structure=='Defect': if Optimizer.isolate_mutation: indc,indb,vacant,swaps,stro = find_defects(indiv[0],Optimizer.solidbulk,0) ind = indc.copy() ind.extend(indb) else: ind=indiv[0].copy() indc=indiv[0].copy() else: ind=indiv[0].copy() indc=indiv[0].copy() if len(indc) != 0: ctoff1 = [1.0 for one in ind] nl = NeighborList(ctoff1, bothways=True, self_interaction=False) nl.update(ind) try: natomsmove=random.randint(1,len(indc)/2) except ValueError: natomsmove=1 passn=0 for count in range(natomsmove): try: indexmv = random.choice([i for i in range(len(indc))]) indices, offsets = nl.get_neighbors(indexmv) nns = Atoms() nns.append(ind[indexmv]) for index, d in zip(indices,offsets): index = int(index) pos = ind[index].position + numpy.dot(d,ind.get_cell()) nns.append(Atom(symbol=ind[index].symbol, position=pos)) dist = [nns.get_distance(0,i) for i in range(1, len(nns))] r = sum(dist)/len(dist) dir = random.choice([[1,0,0],[-1,0,0],[0,1,0],[0,-1,0],[0,0,1],[0,0,-1]]) ind[indexmv].position += [i*r for i in dir] except: passn+=1 indiv[0]=ind.copy() else: natomsmove=0 passn=0 Optimizer.output.write('Lattice Alteration NN Mutation performed on individual\n') Optimizer.output.write('Index = '+repr(indiv.index)+'\n') natomsmove-=passn Optimizer.output.write('Number of atoms moved = '+repr(natomsmove)+'\n') Optimizer.output.write(repr(indiv[0])+'\n') muttype='LANN'+repr(natomsmove) if indiv.energy==0: indiv.history_index=indiv.history_index+'m'+muttype else: indiv.history_index=repr(indiv.index)+'m'+muttype return indiv
from ase.calculators.vasp import * import matplotlib.pyplot as plt from ase.constraints import FixAtoms from matplotlib import mlab from numpy import * from ase.utils.eos import EquationOfState from ase.lattice.cubic import BodyCenteredCubic from ase import Atom a = 2.87 cell = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] atoms = BodyCenteredCubic('Fe', directions=cell) atoms.set_initial_magnetic_moments([5, 5]) carbon = Atom('C', position=(0, 0.5 * a, 0.75 * a), charge=0.4) atoms = atoms * (2, 2, 2) + carbon #atoms = atoms*(2,2,2) constraint = FixAtoms(indices=[5, 7, 8, 10, 12, 13, 14, 15, 16]) atoms.set_constraint(constraint) view(atoms) def save(filename, arg): f = open(filename, 'a+t') f.write('{0} \n'.format(arg)) f.close()
def test_show_ase(): from ase import Atom, Atoms dimer = Atoms([Atom('X', (0, 0, 0)), Atom('X', (0, 0, 1))]) dimer.set_positions([(1, 2, 3), (4, 5, 6.2)]) nv.show_ase(dimer)
from ase import Atoms, Atom from ase.lattice.surface import fcc110 from ase.optimize.minimahopping import MinimaHopping from ase.calculators.emt import EMT from ase.constraints import FixAtoms, Hookean # Make the Pt 110 slab. atoms = fcc110('Pt', (2, 2, 2), vacuum=7.) # Add the Cu2 adsorbate. adsorbate = Atoms([ Atom('Cu', atoms[7].position + (0., 0., 2.5)), Atom('Cu', atoms[7].position + (0., 0., 5.0)) ]) atoms.extend(adsorbate) # Constrain the surface to be fixed and a Hookean constraint between # the adsorbate atoms. constraints = [ FixAtoms(indices=[atom.index for atom in atoms if atom.symbol == 'Pt']), Hookean(a1=8, a2=9, rt=2.6, k=15.), Hookean(a1=8, a2=(0., 0., 1., -15.), k=15.), ] atoms.set_constraint(constraints) # Set the calculator. calc = EMT() atoms.set_calculator(calc) # Instantiate and run the minima hopping algorithm. hop = MinimaHopping(atoms, Ediff0=2.5, T0=4000.)
from ase import Atoms, Atom from jasp import * JASPRC['queue.ppn'] = 4 atoms = Atoms([ Atom('H', [0.5960812, -0.7677068, 0.0000000]), Atom('O', [0.0000000, 0.0000000, 0.0000000]), Atom('H', [0.5960812, 0.7677068, 0.0000000]) ], cell=(8, 8, 8)) atoms.center() with jasp( 'molecules/h2o-relax-centered', xc='PBE', debug=logging.DEBUG, encut=400, ismear=0, # Gaussian smearing ibrion=2, ediff=1e-8, nsw=10, atoms=atoms) as calc: print("forces") print('=======') print(atoms.get_forces())
def set_atomic_number(self, number): Atom.set(self, 'number', number) self._mark()
def update_charges_van_der_waals(self): """Updates the atomic charges by using the electron density within a sphere of van Der Waals radius. The charge for each atom in the system is integrated from the electron density inside the van Der Waals radius of the atom in hand. The link atoms will affect the distribution of the electron density. """ self.timer.start("van Der Waals charge calculation") # Turn debugging on or off here debugging = False atoms_with_links = self.atoms_for_subsystem calc = self.calculator # The electron density is calculated from the system with link atoms. # This way the link atoms can modify the charge distribution calc.set_atoms(atoms_with_links) if self.charge_source == "pseudo": try: density = np.array(calc.get_pseudo_density()) except AttributeError: error("The DFT calculator on subsystem \"" + self.name + "\" doesn't provide pseudo density.") if self.charge_source == "all-electron": try: density = np.array(calc.get_all_electron_density(gridrefinement=1)) except AttributeError: error("The DFT calculator on subsystem \"" + self.name + "\" doesn't provide all electron density.") # Write the charge density as .cube file for VMD if debugging: write('nacl.cube', atoms_with_links, data=density) grid = self.density_grid if debugging: debug_list = [] # The link atoms are at the end of the list n_atoms = len(atoms_with_links) projected_charges = np.zeros((1, n_atoms)) for i_atom, atom in enumerate(atoms_with_links): r_atom = atom.position z = atom.number # Get the van Der Waals radius R = ase.data.vdw.vdw_radii[z] # Create a 3 x 3 x 3 x 3 array that can be used for vectorized # operations with the density grid r_atom_array = np.tile(r_atom, (grid.shape[0], grid.shape[1], grid.shape[2], 1)) diff = grid - r_atom_array # Numpy < 1.8 doesn't recoxnize axis argument on norm. This is a # workaround for diff = np.linalg.norm(diff, axis=3) diff = np.apply_along_axis(np.linalg.norm, 3, diff) indices = np.where(diff <= R) densities = density[indices] atom_charge = np.sum(densities) projected_charges[0, i_atom] = atom_charge if debugging: debug_list.append((atom, indices, densities)) #DEBUG: Visualize the grid and contributing grid points as atoms if debugging: d = Atoms() d.set_cell(atoms_with_links.get_cell()) # Visualize the integration spheres with atoms for point in debug_list: atom = point[0] indices = point[1] densities = point[2] d.append(atom) print "Atom: " + str(atom.symbol) + ", Density sum: " + str(np.sum(densities)) print "Density points included: " + str(len(densities)) for i in range(len(indices[0])): x = indices[0][i] y = indices[1][i] z = indices[2][i] a = Atom('H') a.position = grid[x, y, z, :] d.append(a) view(d) # Normalize the projected charges according to the electronic charge in # the whole system excluding the link atom to preserve charge neutrality atomic_numbers = np.array(atoms_with_links.get_atomic_numbers()) total_electron_charge = -np.sum(atomic_numbers) total_charge = np.sum(np.array(projected_charges)) projected_charges *= total_electron_charge/total_charge # Add the nuclear charges and initial charges projected_charges += atomic_numbers # Set the calculated charges to the atoms. The call for charges was # changed between ASE 3.6 and 3.7 try: self.atoms_for_interaction.set_initial_charges(projected_charges[0, :].tolist()) except: self.atoms_for_interaction.set_charges(projected_charges[0, :].tolist()) self.pseudo_density = density self.timer.stop()