def get_embedding_potential(self, grid=None, pot="total"): """ Returns the FDE embedding potential. @param grid: The grid to use. For details, see L{Plot.Grids}. @type grid: subclass of L{grid} """ if not self.job.is_fde_job(): raise PyAdfError("Can get embedding potenial only for FDE jobs") if pot.lower() == "total": prop = PlotPropertyFactory.newPotential("embpot") elif pot.lower() == "nuc": prop = PlotPropertyFactory.newPotential("embnuc") elif pot.lower() == "coul": prop = PlotPropertyFactory.newPotential("embcoul") elif pot.lower() == "xc": prop = PlotPropertyFactory.newPotential("nadxc") elif pot.lower() == "kin": prop = PlotPropertyFactory.newPotential("nadkin") elif pot.lower().startswith("kinpot"): s1, s2 = pot.split(None, 1) prop = PlotPropertyFactory.newPotential("nadkin", func=s2) else: raise PyAdfError("Unknown potential requested") res = densfjob(self, prop, grid=grid, frag="ALL").run() return res.get_gridfunction()
def __init__(self, mol, settings): """ Initialize a numerical differences job @param mol: The molecule on which to perform the numerical differences calculation @type mol: Pyadf.Molecule.molecule @param settings: Settings for the numerical differentiation Can be overriden by child classes @type settings: numdiffsettings """ from Molecule import OBMolecule, OBFreeMolecule metajob.__init__(self) if not (isinstance(mol, OBFreeMolecule.Molecule) or isinstance(mol, OBMolecule.OBMolecule)): raise PyAdfError("Molecule missing in numdiffjob") self.molecule = mol if settings == None: self.settings = numdiffsettings() elif isinstance(settings, numdiffsettings): self.settings = settings else: raise PyAdfError("wrong settings object in numdiffjob")
def check_success(self, outfile, errfile, logfile=None): if logfile is None: logfilename = 'logfile' else: logfilename = logfile # check if the ADF run was successful f = open(logfilename, 'r') lastline = ''.join(f.readlines()[-3:]) f.close() if lastline.find('ERROR') >= 0: raise PyAdfError('ERROR DETECTED in ADF run') elif lastline.find('NORMAL TERMINATION') == -1: raise PyAdfError('Unknown Error in ADF run') # check for warnings in PyAdf f = open(logfilename, 'r') for line in f.readlines(): if line.find('WARNING') >= 0: print " Found WARNING in ADF logfile:" warning = line.split() print ' '.join(warning[3:]) f.close() print os.remove(logfilename) return True
def add_outputfiles(self, results): """ Add the output files produces by an ADF or Dalton job. """ fileid = len(self._resultfiles) results.fileid = fileid # save checksum checksum = results.get_checksum() if checksum in self._id: raise PyAdfError("Checksum error when adding results") self._id[checksum] = fileid # the output files if results.job is not None: outfilename = self.outputfilename f = open(outfilename, 'r') outputstart = -1 outputend = -1 for i, ll in enumerate(f.readlines()): if ll == newjobmarker: outputstart = i outputend = i if outputstart == -1: raise PyAdfError("PyADF marker not found in output") self._output.append((outfilename, outputstart, outputend)) else: self._output.append(None)
def compute_derivative(self): """ Compute the numerical derivative from the perturbed values at the points This method works for scalar properties. (For non-scalar quantities, an extension needs to be coded) It should be used by child classes which implement certain properties as derivatives @returns: the numerical derivative @rtype: float """ stepsize = self.settings.stepsize if self.points is None: raise PyAdfError( 'points have not been initialized in compute_derivative') if self.settings.method == '3point': derivative = (self.points[0] - self.points[1]) / (2 * stepsize) elif self.settings.method == '5point': derivative = (self.points[3] - 8 * self.points[2] + 8 * self.points[1] - self.points[0]) / (12 * stepsize) else: raise PyAdfError( 'unsupported method for numerical differentiation, choose 3point or 5point' ) return derivative
def __init__(self, stepsize=0.01, atomicunits=True, method='3point'): """ Initialize the settings for a numerical differentiation @parameter stepsize: step size for perturbation (default is in atomic units) @type stepsize: float @param atomicunits: Whether the stepsize is given in atomic units. @type atomicunits: bool @param method: The method of numerical differentiation Supported: 3point or 5point central differences @type method: str """ if not isinstance(stepsize, float): raise PyAdfError("wrong stepsize in numdiffsettings") self.stepsize = stepsize if not isinstance(atomicunits, bool): raise PyAdfError("wrong atomicunits in numdiffsettings") self.atomicunits = atomicunits self.method = method
def __init__(self, pathNames, settings, adfsettings=None, basis=None, core=None, fde=None, adffdesettings=None): metajob.__init__(self) if pathNames is None: raise PyAdfError('pathName should be supplied') else: self.pathNames = pathNames if settings is None: raise PyAdfError('no adffdeanalysissettings provided') else: self.settings = settings self.adfsettings = adfsettings self.adffdesettings = adffdesettings if basis is None: raise PyAdfError('No basis provided in adffdeanalysisjob') else: self.basis = basis self.core = core if fde is None: self.fde = {} else: self.fde = fde
def get_fragment_density(self, grid=None, fit=False, orbs=None, order=None, frag=None): if (orbs is not None) and (not 'Loc' in orbs.keys()): if (order is not None) and (order > 1): raise PyAdfError("Derivatives not implemented for orbital densities.") if (frag is not None) and not (frag == 'active') : raise PyAdfError("Orbital densities only available for acyive fragment") return self.get_orbital_density(grid, orbs) elif (order is not None) and (order > 1): # the density itself prop = PlotPropertyFactory.newDensity('dens', fit=fit, orbs=orbs) dres = densfjob(self, prop, grid=grid, frag=frag).run() gfs = [dres.get_gridfunction()] # density gradient if order >= 1: prop = PlotPropertyFactory.newDensity('grad', fit=fit, orbs=orbs) dres = densfjob(self, prop, grid=grid, frag=frag).run() gfs.append(dres.get_gridfunction()) # density hessian if order >= 2: prop = PlotPropertyFactory.newDensity('hess', fit=fit, orbs=orbs) dres = densfjob(self, prop, grid=grid, frag=frag).run() gfs.append(dres.get_gridfunction()) return GridFunctionDensityWithDerivatives(gfs) else: prop = PlotPropertyFactory.newDensity('dens', fit, orbs) dres = densfjob(self, prop, grid=grid, frag=frag).run() return dres.get_gridfunction()
def __init__(self, ebmbe_res, order=None, grid=None, nadkin=None, nadxc=None): """ Constructor for DensityBasedMBEJob. @param ebmbe_res: results of a previous (energy-based) MBEJob @type ebmbe_res: L{MBEResults} @param order: many-body expansion order; if None, same as in mberes will be used @type order: int or None @param grid: the integration grid that will be used for the db expansion @type grid: subclass of L{Grid} @param nadkin: nonadditive kinetic-energy functional (default: PW91k) @type nadkin: str or XCFun Functional object @param nadxc: nonadditive xc functional (default: XC functional from eb-MBE single points, if available) @type nadxc: str or XCFun Functional object """ metajob.__init__(self) self.ebmbe_res = ebmbe_res if order is None: self.order = ebmbe_res.order else: self.order = order if grid is None: raise PyAdfError('DensityBasedMBEJob requires a supermolecular grid.') self.grid = grid if nadkin is None: self._nadkin = 'PW91k' elif isinstance(nadkin, xcfun.Functional): self._nadkin = nadkin elif isinstance(nadkin, str) and nadkin.upper() in ['TF', 'PW91K']: self._nadkin = nadkin else: raise PyAdfError('Invalid nonadditive kinetic-energy functional in db-MBE job') if nadxc is None: if hasattr(self.ebmbe_res.res_by_comb[(0,)].job, 'functional'): self._nadxc = self.ebmbe_res.res_by_comb[(0,)].job.functional elif hasattr(self.ebmbe_res.res_by_comb[(0,)].job, 'settings') and \ hasattr(self.ebmbe_res.res_by_comb[(0,)].job.settings, 'functional'): self._nadxc = self.ebmbe_res.res_by_comb[(0, )].job.settings.functional else: raise PyAdfError('No nonadditive xc functional specified in db-MBE job') if self._nadxc.startswith('GGA '): self._nadxc = self._nadxc[4:] elif isinstance(nadxc, xcfun.Functional): self._nadxc = nadxc elif isinstance(nadxc, str) and nadxc.upper() in ['LDA', 'BP', 'BP86', 'BLYP']: self._nadxc = nadxc else: raise PyAdfError('Invalid nonadditive xc functional in db-MBE job')
def __init__(self, adfres, prop, grid=None, spacing=0.5, frag=None): """ Constructor for densfjob. @param adfres: The results of the ADF job for which the density (or related quantity) should be calculated. @type adfres: L{adfsinglepointresults} or subclass. @param prop: The property to calculate. @type prop: L{PlotProperty} @param grid: The grid to use. If None, a default L{cubegrid} is used. @type grid: subclass of L{grid} @param frag: Which fragment to use. Default is 'Active'. This can be used to get the densities of specific frozen fragments. @type frag: str """ # pylint: disable=W0621 adfjob.__init__(self) self._adfresults = adfres if grid is None: self.grid = cubegrid(adfres.get_molecule(), spacing) else: self.grid = grid if frag is None: self._frag = 'Active' else: self._frag = frag if not isinstance(prop, PlotProperty): raise PyAdfError( 'densfjob needs to be initialized with PlotProperty') else: self.prop = prop # consistency checks for properties that are not implemented if 'orbs' in self.prop.opts: if ('Loc' not in self.prop.opts['orbs']) and \ not (self.prop.opts['orbs'].keys() == ['A']): raise PyAdfError( 'CJDENSF only working for NSYM=1 (irrep A) orbitals') if self.prop.pclass == 'potential': if 'func' in self.prop.opts: if self.prop.ptype not in ['kinpot', 'nadkin']: raise PyAdfError( "Functional cannot be selected in CJDENSF " "with this potential type") self._olddensf = False
def write_runscript_and_execute(self, job): import os import stat import subprocess from Utils import newjobmarker job.before_run() if job.only_serial: nproc = 1 else: nproc = self._conf.get_nproc_for_job(job) runscript = job.get_runscript(nproc=nproc) rsname = './pyadf_runscript' f = open(rsname, 'w') f.write("#!%s \n\n" % self._conf.default_shell) for mod in self._conf.get_env_modules_for_job(job): f.write('module load %s \n' % mod) f.write('\n') f.write(runscript) f.close() os.chmod(rsname, stat.S_IRWXU) outfile = open(self._files.outputfilename, 'a') outfile.write(newjobmarker) outfile.flush() errfile = open(self._files.errfilename, 'a') errfile.write(newjobmarker) errfile.flush() retcode = subprocess.call(rsname, shell=False, stdout=outfile, stderr=errfile) outfile.close() errfile.close() os.remove(rsname) if retcode != 0: raise PyAdfError("Error running job (non-zero return code)") if not job.check_success(self._files.outputfilename, self._files.errfilename): raise PyAdfError("Error running job (check_sucess failed)") job.after_run()
def check_settings(self): """ Check consistency of settings for CPL. @note: set_cplnuclei should be called before! """ if self.cplnuclei is not None and (self.atompert is not None or self.atomresp is not None): raise PyAdfError('You cannot use nuclei and atompert/atomresp') if self.cplnuclei is None: if self.atomresp is None or self.atomresp is None: raise PyAdfError('You have to specify atompert and atomresp')
def delete_file(self, filename): """ Delete a managed file. @param filename: the file name @type filename: str """ if not os.path.abspath(filename) in self._files: raise PyAdfError("file " + filename + " not known") if not (os.getcwd() == self._cwd): raise PyAdfError("delete_file not called in base working directory") if os.path.exists(os.path.abspath(filename)): os.remove(os.path.abspath(filename))
def add_file(self, filename): """ Add an existing file to the file manager. @param filename: the file name @type filename: str """ if not os.path.exists(filename): raise PyAdfError("file " + filename + " not found") if not (os.getcwd() == self._cwd): print os.getcwd(), self._cwd raise PyAdfError("add_file not called in base working directory") self._files.add(os.path.abspath(filename))
def check_success(self, outfile, errfile): # check that Dalton terminated normally if not (os.path.exists('DALTON_MOLECULE.OUT') or os.path.exists('DALTON_MOLECULE.out')): raise PyAdfError('Dalton output file does not exist') f = open(errfile) err = f.readlines() for line in reversed(err): if "SEVERE ERROR" in line: raise PyAdfError("Error running Dalton job") if line == newjobmarker: break f.close() return True
def set_converge(self, converge): self.converge = {} if converge is not None: for k, v in converge.iteritems(): if k not in ('E', 'Grad', 'Rad', 'Angle'): raise PyAdfError('Wrong key for converge in adgeometrysettings.set_converge()') self.converge[k] = v
def import_resultsdir(self, dirname): """ Import results for the specified directory. The directory must have been saved previously with L{copy_all_results_to_dir} and the file manager must be empty. @param dirname: the directory to import from @type dirname: str """ if len(self._resultfiles) > 0: raise PyAdfError('Error importing resultsdir') f = open(os.path.join(dirname, 'adffiles.pickle'), 'r') self._id = pickle.load(f) self._resultfiles = pickle.load(f) self._output = pickle.load(f) f.close() self._ispacked = [True] * len(self._resultfiles) for filelist in self._resultfiles: for f in filelist: f1 = os.path.join(dirname, os.path.basename(f)) f2 = os.path.join('resultfiles', os.path.basename(f)) os.symlink(f1, f2) self.add_file(f2)
def _assembleMolecularOrbitalMenuInputSequence(self): """ Generates an input sequence to be passed to I{define}'s "OCCUPATION NUMBER & MOLECULAR ORBITAL DEFINITION MENU" menu. @returns: Input sequence @rtype: L{str} """ # TODO: IMPLEMENT ALL METHODS TO GUESS THE INITIAL OCCUPATION SUPPLIED # BY `define'. sequence = [] if str(self.settings.guess_initial_occupation_by) == 'eht': sequence.append('eht') sequence.append('y') # use default sequence.append(str(self.settings.charge)) sequence.append('y') # blindly accept else: raise PyAdfError( ("I'm not programmed to handle the case " + "`initial occupation guessed by: {0}'. " + "Sorry.").format( self.settings.guess_initial_occupation_by)) return sequence
def get_runscript(self, nproc=1): runscript = "#!/bin/bash \n\n" runscript += "cat <<eor >qe.in\n" runscript += "echo\n" runscript += self.get_qefile() runscript += "eor\n" runscript += "cat qe.in \n" runscript += "echo \n" runscript += "touch qe.out \n" if self.runtype is "pw": runscript += 'if [ -f "$QEBINDIR/fdepw.x" ]; then\n' runscript += " mpirun -np %i $QEBINDIR/pw.x -in qe \n" % nproc runscript += "else\n" runscript += " mpirun -np %i $QEBINDIR/pw.x -in qe.in \n" % nproc runscript += "fi\n" elif self.runtype is "pp": runscript += "mpirun -np %i $QEBINDIR/pp.x -in qe.in \n" % nproc elif self.runtype is "fdepw": runscript += "mpirun -np %i $QEBINDIR/fdepw.x -in qe \n" % nproc else: raise PyAdfError( 'Unsupported calculation detected when creating runscript') runscript += "retcode=$?\n" runscript += "cat qe.out \n" if self.runtype in ("pw", "fdepw"): runscript += "cp pwscf.save/data-file.xml data-file.xml\n" runscript += "tar cvf pwscf.save.tar pwscf.save >/dev/null\n" runscript += "rm qe.in \n" runscript += "exit $retcode \n" return runscript
def _countAtoms(self, coordfilename): """ Counts and returns the number of atoms in the C{coord} file. File I/O exceptions re reraised. @param coordfilename: File name to count through @type coordfilename: L{str} @returns: Number of atoms @rtype: L{int} @raises PyAdfError: If the file can be read but doesn't match its definition. @deprecated: Should use the L{molecule} class' functionality instead. """ i = float('NaN') # number of atoms with open(coordfilename, 'r') as coordfile: for line in coordfile: if re.match(r'\$coord.*', line): i = -1 # this line doesn't count if i > 0 and re.match(r'\$.*', line): return i i += 1 raise PyAdfError("The file `" + coordfilename + "' is corrupted.")
def get_atoms_block(self): atoms_block = "" if (not self.has_frag_results()) or (len(self._cap_fragments) == 0): atoms_block += fragment.get_atoms_block(self) else: if len(self._mols) > 1: raise PyAdfError("Capped fragments must appear only once") mol = self._mols[0].get_noncap_fragment() suffix = "f=" + self.fragname atoms_block += mol.print_coordinates(index=False, suffix=suffix) for cap_frag, cap_res in zip(self._cap_fragments, self._cap_residue_nums): if cap_res < 5: mol = self._mols[0].get_residues(restype='CAP', resnum=cap_res)[0] mol = capmolecule(mol) suffix = "f=" + self.fragname + " fs=cap" + str( cap_frag.num_cap) atoms_block += mol.print_coordinates(index=False, suffix=suffix) elif cap_res > 4: mol_s = self._mols[0].get_residues(restype='SCP', resnum=cap_res)[0] mol_s = capmolecule(mol_s) suffix = "f=" + self.fragname + " fs=scap" + str( cap_frag.num_cap) atoms_block += mol_s.print_coordinates(index=False, suffix=suffix) return atoms_block
def get_oscillator_strengths(self): """ Returns the CC2 excitation energies (in eV). @returns: a list of the calculated oszillator strengths (FIZME: units?) @rtype: list of float """ os = [] output = self.get_output() startline = None start = re.compile(r".*(CC2\s*Transition properties|CC2\s*Length\s+Gauge Oscillator Strength)") for i, l in enumerate(output): m = start.match(l) if m: startline = i if startline is None: raise PyAdfError('Dalton CC2 oscillator strengths not found in output') oscstr = re.compile(r"""\s* \| \s* \^1A \s* \| \s* (\d+) \s* \| \s*(?P<dipstr>[-+]?(\d+(\.\d*)?|\d*\.\d+)) \s* \| \s*(?P<oscstr>[-+]?(\d+(\.\d*)?|\d*\.\d+)) \s* \| """, re.VERBOSE) for i in range(self.job.nexci): m = oscstr.match(output[startline + 4 + i]) os.append(float(m.group("oscstr"))) return os
def setup_ccnamelist(self): """ Initialize CC namelist options. """ # setting up the cc namelist options self.ccmain = { 'TIMING': 'T', 'IPRNT': '2', 'DOSORT': 'T', 'DOENER': 'T', 'DOFOPR': 'F', 'DOSOPR': 'F' } self.ccener = { 'DOMP2': 'T', 'DOCCSD': 'F', 'DOCCSDT': 'F', 'MAXIT': '100' } self.ccfopr = {'DOMP2G': 'T'} self.ccsort = {} if self.method in ('HF', 'DFT'): pass elif self.method == 'MP2': if self.exportfde == True or self.doprop == True: self.ccmain['DOFOPR'] = 'T' elif self.method == 'CCSD': self.ccener['DOCCSD'] = 'T' elif self.method == 'CCSDt': self.ccener['DOCCSD'] = 'T' self.ccener['DOCCSDT'] = 'T' else: raise PyAdfError("Unsupported method for Dirac single point runs")
def get_excitation_energies(self): """ Returns the CC2 excitation energies (in eV). @returns: list of the calculated excitation energies, in eV @rtype: list of float """ exens = [] output = self.get_output() startline = None start = re.compile(r".*CC2\s*Excitation energies") for i, l in enumerate(output): m = start.match(l) if m: startline = i if startline is None: raise PyAdfError('Dalton CC2 excitation energies not found in output') exen = re.compile(r"""\s* \| \s* \^1A \s* \| \s* (\d+) \s* \| \s*(?P<exenau>[-+]?(\d+(\.\d*)?|\d*\.\d+)) \s* \| \s*(?P<exeneV>[-+]?(\d+(\.\d*)?|\d*\.\d+)) \s* \| """, re.VERBOSE) for i in range(self.job.nexci): m = exen.match(output[startline + 4 + i]) exens.append(float(m.group("exeneV"))) return exens
def get_energy(self): """ Return the total energy. @returns: the total energy in atomic units @rtype: float """ energy = 0.0 output = self.get_output() headerline = 1 start0 = re.compile("\s+TOTAL ENERGY") for i, l in enumerate(output): if start0.match(l): headerline = i if headerline == 1: raise PyAdfError('Total energy not found') en = re.compile( "\s+Total energy (\(active subsystem\))?\s+:\s+(?P<energy>[-+]?(\d+(\.\d*)?|\d*\.\d+))" ) for l in output[headerline:]: m = en.match(l) if m: energy = float(m.group('energy')) return energy
def get_dipole_vector(self): """ Return the dipole moment vector. @returns: the dipole moment vector, in atomic units @rtype: float[3] """ dipole = [0.0, 0.0, 0.0] output = self.get_output() startline = None start = re.compile(r"\s*Dipole moment components") for i, l in enumerate(output): m = start.match(l) if m: startline = i if startline is None: raise PyAdfError('Dalton dipole moment not found in output') for i, c in enumerate(['x', 'y', 'z']): dip = re.compile(r"\s*" + c + r"\s*(?P<dip>[-+]?(\d+(\.\d*)?|\d*\.\d+))") m = dip.match(output[startline + 5 + i]) dipole[i] = float(m.group('dip')) return dipole
def check_success(self, outfile, errfile): # check that Dirac terminated normally if not (os.path.exists('DIRAC_MOLECULE.OUT') or os.path.exists('DIRAC_MOLECULE.out')): raise PyAdfError('Dirac output file does not exist') f = open(errfile) err = f.readlines() for l in reversed(err): if "SEVERE ERROR" in l: raise PyAdfError("Error running Dirac job") if "dirac.x returned non-zero exit code" in l: raise PyAdfError("Error running Dirac job") if l == newjobmarker: break f.close() return True
def copy_file(self, oldfilename, newfilename): """ Copy a managed file. The copied file will B{not} be managed by the file manager. @param oldfilename: the old filename of the managed file @type oldfilename: str @param newfilename: the new filename of the copied file @type newfilename: str """ if not os.path.join(self._cwd, oldfilename) in self._files: raise PyAdfError("file " + oldfilename + " not known") if not os.path.exists(os.path.join(self._cwd, oldfilename)): raise PyAdfError("file " + oldfilename + " not found") if os.path.exists(newfilename): raise PyAdfError("file " + newfilename + " already exists") shutil.copyfile(os.path.join(self._cwd, oldfilename), newfilename)
def link_file(self, oldfilename, newfilename): """ Make a symlink to a managed file. The symlink will B{not} be managed by the file manager. @param oldfilename: the old filename of the managed file @type oldfilename: str @param newfilename: the new filename of the copied file @type newfilename: str """ if not os.path.join(self._cwd, oldfilename) in self._files: raise PyAdfError("file " + oldfilename + " not known") if not os.path.exists(os.path.join(self._cwd, oldfilename)): raise PyAdfError("file " + oldfilename + " not found") if os.path.exists(newfilename): raise PyAdfError("file " + newfilename + " already exists") os.symlink(os.path.join(self._cwd, oldfilename), newfilename)
def check_success(self, outfile, errfile): f = open(outfile) success = False for ll in f.readlines()[-10:]: if '.# Happy landing! #.' in ll: success = True if 'error' in ll: raise PyAdfError("Error termination in Molcas") return success