Esempio n. 1
0
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']
Esempio n. 2
0
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
Esempio n. 3
0
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)
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
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
Esempio n. 7
0
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
Esempio n. 8
0
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)