def get_ladabase(): """ Return connector to the database. """ from IPython.ipapi import get as get_ipy ip = get_ipy() if 'ladabase' not in ip.user_ns: raise RuntimeError("ladabase object not found in user namespace.") return ip.user_ns['ladabase']
def _getcomment(self=None, cmdl=None): """ Gets comment from user. """ from sys import stderr from os import remove import re from tempfile import NamedTemporaryFile from IPython.ipapi import TryNext, get as get_ipy try: from .. import fullname except ImportError: print >>stderr, "Could not import fullname with which to tag files in database.\n"\ "Please add `fullname = 'my full name'` in ~/.pylada.\n" return if len(fullname) == 0: print >>stderr, "Username with which to tag files in database is empty.\n"\ "Please add `fullname = 'my full name'` in ~/.pylada.\n" return if self == None: self = get_ipy() with NamedTemporaryFile(mode='w', delete=False) as file: file.write("\n# operator: {0}\n".format(fullname)) if cmdl is not None: file.write("# command-line: {0}\n".format(cmdl)) filename = file.name try: self.shell.hooks.editor(filename, 0) except TryNext: print "Could not open editor." return with open(filename, 'r') as file: comment = file.read() remove(filename) stripped = re.sub('#.*(?:\n|$)', '', comment, re.M) stripped = stripped.replace('\n','').replace(' ', '') if len(stripped) == 0: print "Empty comment. Aborting." comment = None return comment
def create_jobs(path, inputpath="input.py", **kwargs): """ Creates GA-jobs. :Parameters: path Path where the job-dictionary will be saved. Calculations will be performed in the parent directory of this file. Calculations will be performed in same directory as this file. inputpath Path to an input file. Defaults to input.py. kwargs Any keyword/value pair to take precedence over anything in the input file. """ from IPython.ipapi import get as get_ipy from pylada.jobs import JobFolder from pylada.ga.escan.nanowires import read_input from pylada.ga.escan.nanowires.converter import Converter from pylada.ga.escan.nanowires.functional import Darwin input = read_input(inputpath) lattice = input.vff.lattice types = set([u for a in lattice.sites for u in a.type]) - set([input.passivant]) jobfolder = JobFolder() for core_type in input.core_types: for nmin, nmax in input.ranges: for trial in xrange(input.nb_trials): # create conversion object from bitstring to nanowires and back. converter = Converter( input.vff.lattice, growth=input.growth_direction, core_radius=input.core_radius, core_type=core_type, types = list(types), thickness=input.thickness, sep = input.__dict__.get('separation', 1) ) # create objective fucntion. evaluator = input.Evaluator( converter, input.escan, degeneracy = input.__dict__.get('degeneracy', 1e-3) ) # create GA functional itself. functional = Darwin(evaluator, nmin=nmin, nmax=nmax, **input.__dict__) functional.popsize = input.population_size functional.max_gen = input.max_generations functional.rate = input.offspring_rate functional.pools = input.pools if input.rootworkdir is not None: functional.rootworkdir = input.rootworkdir gajob = jobfolder / "{0}_core/{2}_{3}/trial_{1}".format(core_type, trial, nmin, nmax) gajob.functional = functional # saves jobs. ip = get_ipy() ip.user_ns["current_jobfolder"] = jobfolder ip.magic("savejobs " + path)
def create_superstructure(groundstate, input): """ Creates a superstructure from existing structure. """ from os.path import dirname, join from operator import itemgetter from numpy import dot from IPython.ipapi import get as get_ipy from pylada.crystal import fill_structure, vasp_ordered # sanity checks, assert "structure" in groundstate.jobparams,\ ValueError("Could not find structure in ground-state job-dictionary.") assert hasattr(groundstate.functional, "Extract"),\ ValueError("Could not find extraction class in ground-state job-dictionary.") ip = get_ipy() assert "current_jobfolder_path" in ip.user_ns,\ RuntimeError("Could not find path for current job-dictionary.") rootdir = dirname(ip.user_ns["current_jobfolder_path"]) # gets original lattice from job-dictionary. orig_structure = groundstate.jobparams["structure"] # Extracts computed lattice from ground state calculation. extract = groundstate.functional.Extract( join(rootdir, groundstate.name[1:]) ) assert extract.success, RuntimeError("Ground-state computation was not successful.") lattice = extract.structure.to_lattice() # creates superstructure. cell = dot(lattice.cell, input.supercell) result = fill_structure(cell, lattice) assert len(result.atoms) != len(lattice.sites), \ ValueError("Superstructure as large as lattice. Disable this line if that's ok.") # adds magnetic moment if necessary. if hasattr(orig_structure, "magmom"): assert extract.magnetization.shape[0] == len(lattice.sites),\ RuntimeError("Could not find magnetization in ground-state's OUTCAR.") mlat = lattice.deepcopy() for atom, m in zip(mlat.sites, extract.magnetization[:,-1]): if abs(m) < 0.1: atom.type = '0' elif m < 0e0: atom.type = str(int(m-1)) else: atom.type = str(int(m+1)) moments = fill_structure(cell, mlat) result.magmom = [ int(i.type) for i in moments.atoms ] return vasp_ordered(result, attributes=["magmom"]), lattice
def _getcomment(self=None, filename = None): """ Gets comment from user. """ from sys import stderr from os import fdopen, remove from socket import gethostname from IPython.ipapi import TryNext, get as get_ipy try: from .. import database_username except ImportError: print >>stderr, "Could not import database_username with which to tag files in database.\n"\ "Please add `database_username = '******'` in ~/.pylada.\n" return if len(database_username) == 0: print >>stderr, "Username with which to tag files in database is empty.\n"\ "Please add `database_username = '******'` in ~/.pylada.\n" return if self == None: self = get_ipy() import re if filename is None: from tempfile import mkstemp # gets a comment to go with the push. notefile, filename = mkstemp() fdopen(notefile).close() with open(filename, 'w') as file: file.write("\n# operator: {0}\n# hostname: {1}".format(database_username, gethostname())) try: self.shell.hooks.editor(filename, 0) except TryNext: print "Could not open editor." return with open(filename, "r") as file: comment = file.read() stripped = re.sub('#.*(?:\n|$)', '', comment, re.M) stripped = stripped.replace('\n','').replace(' ', '') if len(stripped) == 0: remove(filename) print "Empty comment. Aborting." return return filename
def create_sl(path, direction, nmin, nmax, nstep, x=0.5, density=10e0, input='input.py'): """ Creates dictionary of superlattices. :Parameters: path : str Path to output dictionary. direction : callable(int)->(3x3, 3x1) A callable taking the number of layers on input and returning a tuple consisting of a supercell with the correct number of layers and the direction of growth of the superlattice. The supercell must be have the correct periodicity: two vectors should be parallel to the substrate such that layers can actually be defined. Otherwise, there is not one-to-one correspondance between atoms and layers: the same atom could belong to different layers. A number of examples are given in this module: `direction001`, `direction011`, `direction111`. nmin : int Minimum number of layers. nmax : int Maximum number of layers (excluded). nstep : int Step between layers: [``nmin``, ``nmin``+``nstep``, ``nmin``+2*``nstep``, ..., ``nmax``[ x : float Concentration in Si of the superlattice. Should be between 0 and 1. density : float Kpoint density for escan calculations, input : str Path to input file containing escan functional. """ from IPython.ipapi import get as get_ipy from numpy.linalg import norm, inv from pylada.jobs import JobFolder from pylada.escan import read_input, exec_input, ReducedKDensity from pylada.crystal.binary import zinc_blende from pylada.crystal import layer_iterator ip = get_ipy() input = read_input(input) kescan = exec_input(repr(input.escan).replace('Escan', 'KEscan')).functional lattice = zinc_blende() lattice.sites[0].type = 'Si', 'Ge' lattice.sites[1].type = 'Si', 'Ge' lattice.scale = 5.45 lattice.find_space_group() density = 10e0 * max([1e0/norm(u) for u in inv(lattice.cell)]) rootjobs = ip.user_ns.get('current_jobfolder', JobFolder()) for n0 in range(nmin, nmax, nstep): # create structure cell, dir = direction(n0) structure = lattice.to_structure(cell) # reduction not necessary if cell function done right. N0 = int(len([0 for layer in layer_iterator(structure, dir)]) * x+1e-8) for i, layer in enumerate(layer_iterator(structure, dir)): for atom in layer: atom.type = 'Si' if i < N0 else 'Ge' xp = float(len([0 for atom in structure.atoms if atom.type == 'Si'])) xp /= float(len(structure.atoms)) assert abs(xp - x) < 1e-12 # name and scale. structure.name = "{0[0]}{0[1]}{0[2]}/x_{1:0<4.3}/n_{2}".format(dir, x, n0) structure.scale = scale(structure) # creates job-folder. jobfolder = rootjobs / structure.name jobfolder.jobparams['structure'] = structure.copy() jobfolder.functional = kescan.copy() jobfolder.functional.kpoints = ReducedKDensity(density, (0.5, 0.5, 0.5)) jobfolder.functional.reference = None jobfolder.functional.fft_mesh = fftmesh(structure.cell) jobfolder.functional.nbstates = int(len(structure.atoms) * 4 * 1.5+0.5) if 'current_jobfolder' not in ip.user_ns: ip.user_ns["current_jobfolder"] = rootjobs ip.magic("savejobs " + path) return
def create_start(path, nall = 3, nrand = 5, nmax=100, density=10e0, input='input.py'): """ Creates dictionary with input structures for Si/Ge. :Parameters: path : str Path to output dictionary. nall : int All structure with ``nall`` (excluded) unit-cells are included in the final dictionary. nrand : int Structures between ``nall`` (included) and ``nrand`` (excluded) unit-cells are also considered for inclusion in the final dictionary. However, only ``nmax`` are randomly chosen in the end. nmax : int Structures between ``nall`` (included) and ``nrand`` (excluded) unit-cells are also considered for inclusion in the final dictionary. However, only ``nmax`` are randomly chosen in the end. density : float Kpoint density for escan calculations, input : str Path to input file containing escan functional. Creates a job-dictionary with a number of structures sampled from an exhaustive list of structures to evaluate using escan. """ from random import shuffle from itertools import chain from IPython.ipapi import get as get_ipy from numpy.linalg import norm, inv from pylada.enumeration import Enum from pylada.crystal.binary import zinc_blende from pylada.jobs import JobFolder from pylada.escan import read_input, exec_input, ReducedKDensity from pylada.crystal.gruber import Reduction input = read_input(input) kescan = exec_input(repr(input.escan).replace('Escan', 'KEscan')).functional enum = Enum(zinc_blende()) enum.sites[0].type = 'Si', 'Ge' enum.sites[1].type = 'Si', 'Ge' enum.scale = 5.45 enum.find_space_group() density = density * max([1e0/norm(u) for u in inv(enum.cell * enum.scale).T]) strs = [u for n in range(nall, nrand) for u in enum.xn(n)] shuffle(strs) strs = [enum.as_structure(*u) for u in strs[:nmax]] alls = [structure for n in range(nall) for structure in enum.structures(n)] jobs = JobFolder() for i, structure in enumerate(chain(alls, strs)): structure.name = str(i) nSi = len([a.type for a in structure.atoms if a.type == 'Si']) structure.scale = float(nSi) / float(n) * enum.scale + float(n - nSi) / float(n) * 5.69 jobfolder = jobs / structure.name jobfolder.jobparams['structure'] = structure.copy() jobfolder.structure.cell = Reduction()(jobfolder.structure.cell) jobfolder.functional = kescan.copy() jobfolder.functional.kpoints = ReducedKDensity(density, (0.5, 0.5, 0.5)) jobfolder.functional.reference = None jobfolder.functional.fft_mesh = fftmesh(structure.cell) jobfolder.functional.nbstates = int(len(structure.atoms) * 4 * 1.5+0.5) ip = get_ipy() ip.user_ns["current_jobfolder"] = jobfolder.root ip.magic("savejobs " + path) return
def pointdefect_wave(path=None, inputpath=None, **kwargs): """ Creates point-defect wave using ground-state job-dictionary. :Parameters: path : str or None Path where the modified job-dictionary will be saved. Calculations will be performed in the parent directory of this file. If None, will use the current job-dictionary path. inputpath : str or None Path to an input file. If not present, then no input file is read and all parameters are taken from the non-magnetic wave. kwargs Any keyword/value pair to take precedence over anything in the input file. Creates a point-defect wave from the materials computed in the magnetic and non-magnetic waves. Usage is fairly simple. If the pickle for the magnetic/non-magnetic wave is called ``magnetic_wave``, then one need only open it and call the ``pointdefect_wave``. >>> explore all magnetic_wave >>> import test >>> test.magnetic_wave() >>> launch scattered The above will add point-defect calculations for all meterials and lattices of the ``magnetic_wave`` job-dictionary and save it (to the same path unless an argument is provided to ``magnetic_wave``). Note that changing the location of the current job-dictionary has no effect. It would be possible but sounds too error prone: >>> explore all magnetic_wave >>> goto /Fe2AlO4 # has no effect on what point-defects are added. >>> goto /Al2FeO4 # has no effect on what point-defects are added. >>> import test >>> # creates point-defects for both Fe2AlO4 and Al2FeO4: location does not matter. >>> test.magnetic_wave() >>> launch scattered Point-defects calculations are added to a material if and only if all existing magnetic/non-magnetic jobs for that material have completed successfully. Furthermore, only untagged materials are accepted. Hence, to disable Fe2AlO4 lattices from having point-defects added to it, one can simply tag it: >>> explore all magnetic_wave >>> jobparams["/Fe2AlO4"] = 'off' >>> import test >>> test.magnetic_wave() >>> launch scattered Similarly to make sure point-defect calculations are *not* created for the b5 lattice of the Fe2AlO4 material, one could tag it as follows: >>> explore all magnetic_wave >>> current_jobfolder["/Fe2AlO4/b5"].tag() >>> import test >>> test.magnetic_wave() >>> launch scattered """ from tempfile import NamedTemporaryFile from os.path import dirname, normpath, relpath, join from IPython.ipapi import get as get_ipy from numpy import array, sum, abs from pylada.jobs import JobFolder from pylada.vasp import read_input from pylada.opt import Input from pylada.crystal import defects as ptd # Loads job-folder and path as requested. ip = get_ipy() if "current_jobfolder" not in ip.user_ns: print "No current job-dictionary." return jobfolder = ip.user_ns["current_jobfolder"].root if path is None: if "current_jobfolder_path" not in ip.user_ns: print "No known path for current dictionary and no path specified on input." return path = ip.user_ns["current_jobfolder_path"] basedir = dirname(path) # create input dictionary. First reads non-magnetic input, then magnetic # input, then kwargs. Order of precedence is exact opposite. input = Input() if hasattr(jobfolder, "nonmaginput"): with NamedTemporaryFile() as file: file.write(jobfolder.nonmaginput) file.flush() input.update(read_input(file.name)) if hasattr(jobfolder, "maginput"): with NamedTemporaryFile() as file: file.write(jobfolder.nonmaginput) file.flush() input.update(read_input(file.name)) if inputpath is not None: input.update(read_input(inputpath)) with open(inputpath, "r") as file: jobfolder.maginput = file.read() input.update(kwargs) # saves inputfile to jobfolderioanry if needed. if inputpath is not None: input.update(read_input(inputpath)) with open(inputpath, "r") as file: jobfolder.pointdefectinput = file.read() # saves current script tof file. with open(__file__, "r") as file: jobfolder.pointdefectscript = file.read() if hasattr(input, 'coord_tolerance'): coord_tolerance = input.coord_tolerance nb_new_jobs = 0 # loops over completed structural jobs. for name in magnetic_groundstates(): # gets the ground-states job-dictionary. groundstate = jobfolder[name] # checks that the lattice and material are not tagged. if groundstate[".."].is_tagged: continue if groundstate["../.."].is_tagged: continue # extracts the structure from it. superstructure, lattice = create_superstructure(groundstate, input) # extracts material. material = groundstate.material print 'Working on ', groundstate.name, groundstate.name.split('/')[1] # extracts description of species. species = groundstate.functional.vasp.species # loop over substitutees. for structure, defect, B in ptd.iterdefects(superstructure, lattice, input.point_defects, tolerance=coord_tolerance): # loop over oxidations states. for nb_extrae, oxname in charged_states(input.vasp.species, material, defect.type, B): # creates list of moments. new_moments = deduce_moment(defect.type, species) if len(new_moments) > 1: moments = [ (min(new_moments), "/ls"), (max(new_moments), "/hs") ] else: moments = [ (max(new_moments), "") ] # loop over moments. for moment, suffix in moments: name = "PointDefects/{1}/{2}{0}".format(suffix, structure.name, oxname) # checks if job already exists. Does not change job if it exists! if name in groundstate[".."]: continue # creates new job. jobfolder = groundstate["../"] / name jobfolder.functional = input.relaxer jobfolder.jobparams = groundstate.jobparams.copy() jobfolder.jobparams["structure"] = structure.deepcopy() jobfolder.jobparams["nelect"] = nb_extrae jobfolder.jobparams["relaxation"] = "ionic" jobfolder.jobparams["ispin"] = 2 jobfolder.jobparams["set_symmetries"] = "off" jobfolder.lattice = lattice jobfolder.material = material jobfolder.defect = defect # adds, modifies, or remove moment depending on defect type. if hasattr(superstructure, "magmom") or abs(moment) > 1e-12: jstruct = jobfolder.jobparams["structure"] # construct initial magmom if hasattr(superstructure, "magmom"): jstruct.magmom = [u for u in superstructure.magmom] else: jstruct.magmom = [0 for u in superstructure.atoms] # now modifies according to structure. if B is None or B.lower() == 'none': # interstitial: jstruct.magmom.append(moment) elif defect.type is None or defect.type.lower() == 'none': vacancy_moment(input.vasp.species, jstruct, defect, B, nb_extrae) else: jstruct.magmom[defect.index] = moment # only keep moment if there are moments. if sum(abs(jstruct.magmom)) < 1e-12 * float(len(jstruct.atoms)): del jstruct.magmom nb_new_jobs += 1 # now saves new job folder print "Created {0} new jobs.".format(nb_new_jobs) if nb_new_jobs == 0: return ip.user_ns["current_jobfolder"] = jobfolder.root ip.magic("savejobs " + path)