Source code for orbkit.options

# -*- coding: iso-8859-1 -*-
'''Module containing and processing all orbkit options.'''

lgpl = '''ORBKIT
Gunter Hermann, Vincent Pohl, and Axel Schild

Institut fuer Chemie und Biochemie, Freie Universitaet Berlin, 14195 Berlin, Germany

This file is part of ORBKIT.

ORBKIT is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as 
published by the Free Software Foundation, either version 3 of 
the License, or any later version.

ORBKIT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with ORBKIT.  If not, see <http://www.gnu.org/licenses/>.
'''

lgpl_short = '''This is ORBKIT.
Copyright (C) 2017 Gunter Hermann, Vincent Pohl, and Axel Schild. 
This program comes with ABSOLUTELY NO WARRANTY. 
This is free software, and you are welcome to redistribute it 
under certain conditions. Type '-l' for details.
'''

import os
import sys
from copy import deepcopy
thismodule = sys.modules[__name__]

from orbkit import grid

available = [
  'filename','itype','cclib_parser','outputname','otype',
  'numproc','mo_set','calc_ao','all_mo','calc_mo','spin','drv','laplacian',
  'slice_length','is_vector','grid_file','adjust_grid','center_grid','random_grid',
  'z_reduced_density','gross_atomic_density','mo_tefd',
  'quiet','no_log','no_output','no_slice','interactive'
  ]

itypes = ['molden',
          'aomix',
          'gamess', 
          'gaussian.log', 
          'gaussian.fchk',
          'wfn',
          'wfx',
          'cclib',
          'orbkit.dump']                        #: Specifies possible input types.

otypes = ['h5', 'cb', 'am', 'hx', 'vmd', 'mayavi'] #: Specifies possible output types.

drv_options = ['None','x','y','z',
               'xx','yy','zz','x2','y2','z2',
               'xy','yx','xz','zx','yz','zy']     #: Specifies possible derivative variables.

[docs]def get_options(): '''Returns all possible options and their value.''' opts = [(i,globals()[i]) for i in available] return dict(opts)
def init_parser(): '''Initializes parser and processes the options. ''' import optparse global parser def default_if_called(option, opt, value, parser, default=1e4): try: arg = parser.rargs[0] if ((arg[:2] == "--" and len(arg) > 2) or (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")): raise ValueError value = int(float(arg)) except (IndexError, ValueError): value = int(default) setattr(parser.values, option.dest, value) #optparse.Option.STORE_ACTIONS += ('call_back',) usage = 'Usage: %prog [options] -i INPUT' parser = optparse.OptionParser(usage=usage,description=lgpl_short) parser.add_option("-l", dest="show_lgpl", default=False,action="store_true", help="show license information and exit") parser.add_option("--quiet",dest="quiet", default=False,action="store_true", help="suppress terminal output") parser.add_option("--no_log",dest="no_log", default=False,action="store_true", help="suppress output of a INPUT.oklog logfile") group = optparse.OptionGroup(parser, "Input/Output Options") group.add_option("-i", "--input", dest="filename",metavar="INPUT", default='', type="string",nargs=1, help="input file") group.add_option("-e", "--itype", dest="itype", default='molden', type="choice",choices=itypes, help="input type: '" + "', '".join(itypes) + "' [default: '%default']") group.add_option("--cclib_parser",dest="cclib_parser", type="string", help='''if '--itype=cclib', this argument determines what cclib.parser will be used, e.g., 'Gaussian' or 'GAMESS'.''') group.add_option("-o", "--output",dest="outputname", type="string", help='''name of the output file [default: base name of INPUT]''') group.add_option("-t", "--otype", dest="otype", type="choice", action="append", choices=otypes, help='''output formats (multiple calls possible): '{0}' (HDF5 file), '{1}' (Gaussian cube file), '{4}' (VMD network), '{2}' (ZIBAmiraMesh file), '{3}' (ZIBAmira network), '{5}' (simple interactive Mayavi interface) [default: '{0}']'''.format(*otypes)) parser.add_option_group(group) group = optparse.OptionGroup(parser, "Computational Options") group.add_option("-p", "--numproc",dest="numproc", default=1, type="int", help='''number of subprocesses to be started during the execution [default: %default]''') group.add_option("--mo_set",dest="mo_set", default=[], type="string",action="append", help='''read the plain text file MO_SET containing row vectors of molecular orbital indeces (delimiter=' ', Integer numbering or MOLPRO's symmetry numbering) and compute the electron density using exclusively those orbitals'''.replace(' ','').replace('\n','')) group.add_option("--calc_ao",dest="calc_ao", default=False,action="store_true", help="calculate and save all AOs.") group.add_option("--calc_mo",dest="calc_mo", default=[], type="string", action="append", help=('''calculate and save the MOs specified in the plain text file CALC_MO by the indices (delimiter=' ') (Type 'all_mo' to store all occupied and virtual orbitals)''').replace(' ','').replace('\n','')) group.add_option("--all_mo",dest="all_mo", default=False, action="store_true", help='''take into account all (occupied and virtual) MOs for all computations''') group.add_option("--spin",dest="spin", default=None, type=spin, choices=['alpha','beta'], help='''consider only `alpha` or `beta` molecular orbitals for the computations. Only available for unrestricted calculations.'''.replace(' ','').replace('\n','')) group.add_option("-d", "--drv",dest="drv",choices=drv_options, type="choice",action="append", help=('''compute the analytical derivative of the requested quantities with respect to DRV, i.e., 'x', 'y', and/or 'z'. For 2nd derivatives, specify the respective combinations , e.g., 'xx' or 'yz'. (multiple calls possible)''' ).replace(' ','').replace('\n','')) group.add_option("--laplacian",dest="laplacian", default=False, action="store_true", help='''compute the analytical laplacian of the density or the specified mo_set, respectively. ''') parser.add_option_group(group) group = optparse.OptionGroup(parser, "Grid-Related Options") group.add_option("-s", "--slice_length",dest="slice_length", default=1e4, type="int", help=('''specify how many grid points are computed at once (per subprocess).''').replace(' ','').replace('\n','')) group.add_option("-v", "--vector",dest="is_vector", default=False, action="store_true", help=('''store the output in a vector format.''') #help=('''perform the computations for a vector grid, #i.e., with x, y, and z as vectors. Compute successively #VECTOR points at once per subprocess #[default: -v %0.0e]''' % dvec #).replace(' ','').replace('\n','') ) group.add_option("--grid", dest="grid_file", type="string", help='''read the grid from the plain text file GRID_FILE''') group.add_option("--adjust_grid",dest="adjust_grid", type="float",nargs=2, help=('''create a grid using a spacing of X a_0 and having the size of the molecule plus D a_0 in each direction, e.g., --adjust_grid=D X''' ).replace(' ','').replace('\n','')) group.add_option("--random_grid", dest="random_grid", default=False, action="store_true", help=optparse.SUPPRESS_HELP) group.add_option("--center", dest="center_grid", metavar="ATOM",type="int", help='''center with respect to the origin and the atom number ATOM (input order)''') parser.add_option_group(group) group = optparse.OptionGroup(parser, "Additional Options") group.add_option("--z_reduced_density",dest="z_reduced_density", default=False, action="store_true", help="reduce the density with respect to the z-axis") group.add_option("--gross_atomic_density",dest="gross_atomic_density", metavar="INDEX",action="append",type="int", help='''compute the atom-projected electron density with respect to atom INDEX (multiple calls possible)''') group.add_option("--mo_tefd",dest="mo_tefd", type="int",nargs=2,action="append", help=('''compute the molecular orbital transition electronic flux density between the orbitals I and J specify the requested component with "--drv", e.g., --mo_tefd=I J --drv=x (multiple calls possible)''' ).replace(' ','').replace('\n','')) # The following parser options are hidden group.add_option("--no_slice",dest="no_slice", default=False, action="store_true", help=optparse.SUPPRESS_HELP) group.add_option("--no_output",dest="no_output", default=False, action="store_true", help=optparse.SUPPRESS_HELP) group.add_option("--not_interactive",dest="interactive", default=True, action="store_false", help=optparse.SUPPRESS_HELP) parser.add_option_group(group) (kwargs, args) = parser.parse_args() # Print the licence, if requested if kwargs.show_lgpl: print(lgpl.replace('\nThis file is part of orbkit.\n','')) sys.exit(0) # Print help if no input file has been set if kwargs.filename == '': parser.print_help() sys.exit(1) if kwargs.otype is None: kwargs.otype = ['h5'] for i,j in vars(kwargs).items(): setattr(thismodule,i,j) # Check the options for compatibility and correctness check_options(error=parser.error, interactive=interactive, info=False) return # init_parser def raise_error(string,error=IOError): if hasattr(thismodule,'parser'): error = parser.error raise error(string) def print_message(string): print(string)
[docs]def check_options(error=raise_error,display=print_message, interactive=False,info=True,check_io=True): '''Checks options for errors. **Parameters:** error : function, optional Handles the errors. display : function, optional Handles the print commands. interactive : bool, optional If True and a file does not exist, asks the user to insert name of existing file. info : bool, optional If True, some additional information is printed. :Default Error and Exception Handling: Prints the errors and continues. ''' #--- Input/Output Options ---# if check_io: # Look for the input file setattr(thismodule,'filename',check_if_exists(filename, what='filename for the input file', interactive=interactive, error=error)) # Check the input type for correctness if itype not in itypes: error('Invalid input file format (choose from "%s")\n' % '", "'.join(itypes)) if itype == 'cclib' and cclib_parser is None: error('The input type cclib requires the specification of parser, ' + 'e.g., --cclib_parser=Gaussian') fid_base = os.path.splitext(filename)[0] if outputname is None: setattr(thismodule,'outputname',fid_base) elif not (os.path.dirname(outputname) == '' or os.path.exists(os.path.dirname(outputname))): error('Output path "%s" does not exist!' % os.path.dirname(outputname)) # Check the output types for correctness if otype is None: setattr(thismodule,'otype',[]) elif not isinstance(otype,list): setattr(thismodule,'otype',[otype]) if not all(i in otypes for i in otype): error('Invalid output file formats (choose from "%s")\n' % '", "'.join(otypes)) # Check if h5py is installed if 'h5' in otype: try: import h5py except ImportError: error('ImportError: The module h5py is not installed!\n') #--- Grid-Related Options ---# # Look for the grid input file if grid_file is not None: setattr(thismodule,'grid_file',check_if_exists(grid_file, what='filename for the grid input file', interactive=interactive, error=error)) if adjust_grid is not None: if (not isinstance(adjust_grid,(list,tuple)) or (len(adjust_grid) != 2) or (not isinstance(adjust_grid[0],(int,float))) or (not isinstance(adjust_grid[1],(int,float))) ): error('The grid parameter (--adjust_grid), has to be a list containing ' 'containing two floats.\n') elif adjust_grid[1] == 0: error('The grid spacing (second value in --adjust_grid) cannot be zero.\n') #--- Computational Options ---# if not isinstance(numproc,int): error('The number of processes (--numproc) has to be an integer value.\n') # Check the files specified by --calc_mo or --mo_set for existance def check_mo(attr): data = getattr(thismodule,attr) if not data: setattr(thismodule,attr,False) return False if isinstance(data,int): data = str(data) if isinstance(data,str): data = [data] try: for d in data: d = str(d) if not (',' in d.lower() or ':' in d.lower()): i = deepcopy(d) if i != 'homo' and i != 'lumo': for r in ['homo','lumo','-','+']: i = i.replace(r,'') int(i.split('.')[0]) except ValueError: if len(data) == 1: data = data[0] if data.lower() != 'all_mo': setattr(thismodule,attr, check_if_exists(data, what='filename for the MO list', interactive=interactive)) else: setattr(thismodule,attr,data) else: display('You have called `%s` multiple times. So, you have\n' % attr + 'to give the molecular orbital labels explicitly, i.e.,\n' + 'no filenames and no usage of the keyword `all_mo`.\n\n') error('Entry `%s` is not valid!' % d) return True i = check_mo('calc_mo') j = check_mo('mo_set') if i and j: error('Please choose --calc_mo OR --mo_set, not both. \n'+ '--calc_mo will be done.\n') if not isinstance(all_mo,bool): error('The option --all_mo has to be a boolean.\n') if spin is not None and not (spin == 'alpha' or spin == 'beta'): error('The option --spin has to be `alpha` or `beta`.\n') if (drv is not None) and not all(i in drv_options for i in drv): error('Invalid derivative option (choose from "%s")\n' % '", "'.join(drv_options)) if laplacian: if not (drv is None or drv == ['xx','yy','zz'] or drv == ['x2','y2','z2']): display('Note: You have set the option --laplacian and specified values\n' + 'for --drv. Both options are not compatible.\n\n' + 'The options have been changed to -dxx -dyy -dzz.\n') setattr(thismodule,'drv', ['xx','yy','zz']) #--- Additional Options ---# if gross_atomic_density is not None and drv is not None: error('The derivative of the gross atomic density is not implemented.\n') if mo_tefd is not None: setattr(thismodule,'all_mo',True) if mo_tefd is not None and drv is None: error('The computation of molecular orbital transition electronic \n' + 'flux density between two orbitals requires the selection of \n' + 'the component (e.g. --drv=x)\n') # The following options cannot be checked before running the main program if info: string = 'The option %s--center cannot be checked before %s...\n' if center_grid is not None: display(string % ('--center','reading\nthe input file')) if gross_atomic_density is not None: display(string % ('--gross_atomic_density', 'reading\nthe input file')) if mo_tefd is not None: display(string % ('--mo_tefd', 'reading\nthe input file')) return True
[docs]def check_if_exists(fid, what='',error=IOError,display=sys.stdout.write, interactive=False): '''Checks the existence of a file. **Parameters:** fid : string Specifies filename of the requested file. what : string, optional Describes the file. error : function, optional Handles the errors. display : function, optional Handles the print commands. interactive : bool, optional If True and a file does not exist, asks the user to insert name of existing file. **Returns:** fid : string Specifies filename of the requested file. ''' while not (isinstance(fid,str) and os.path.exists(fid)): if fid != '': display('%s does not exist!\n' % fid) if interactive: fid = raw_input('Please insert a correct %s: ' % what) else: error('Insert a correct %s!\n' % what) break return fid
def check_grid_output_compatibilty(error=raise_error): if not grid.is_regular and ('cb' in otype or 'vmd' in otype or 'am' in otype or 'hx' in otype or 'mayavi' in otype): error('For a non-regular vector grid, only HDF5 ' + 'is available as output format. Choose: --otype=h5\n') # initiating the parser variables # the names are chosen according to core.init_parser() #--- Input/Output Options --- filename = '' #: Specifies input file name. (str) itype = 'molden' #: Specifies input file type. See :data:`itypes` for details. (str) cclib_parser = None #: If itype is 'cclib', specifies the cclib.parser. (str) outputname = None #: Specifies output file (base) name. (str) otype = 'h5' #: Specifies output file type. See :data:`otypes` for details. (str or list of str or None) #--- Computational Options --- numproc = 1 #: Specifies number of subprocesses for multiprocessing. (int) mo_set = False #: Specifies molecular orbitals used for density calculation. (filename or list of indices) calc_ao = False #: If True, all atomic orbitals will be computed and saved. calc_mo = False #: Specifies which molecular orbitals will be calculated. (filename or list of indices) all_mo = False #: If True, all molecular orbitals will be computed. (bool) spin = None #: If not None, exclusively 'alpha' or 'beta' molecular orbitals are taken into account. (None,'alpha', or 'beta') drv = None #: Specifies derivative variables. (list of str) laplacian = False #: If True, computes the laplacian of the density or of the mo_set. (bool) #--- Grid-Related Options --- slice_length = 1e4 #: Specifies the number of points per subprocess. (int) vector = None # This option is only present because of backward compatibility is_vector = False #: If True, vector grid is used for the output. (bool) grid_file = None #: Specifies file to read grid from. (filename) adjust_grid = None #: If not None, create a grid using a spacing of X a_0 and having the size of the molecule plus D a_0 in each direction. (list: [D, x]) center_grid = None #: If not None, grid is centered to specified atom and origin. (int) random_grid = False #: If True, creates random grid around atom positions. (bool) #--- Additional Options --- z_reduced_density = False #: If True, reduces the density with respect to the z-axis. (bool) gross_atomic_density = None #: Computes the gross atomic electron density with respect to specified atom. (int or list of int) mo_tefd = None #: Computes the molecular orbital transition electronic flux density between the orbitals I and J specify the requested component with :data:`orbkit.options.drv`. (list of [I, J]) #--- Options for Advanced Users --- quiet = False #: If True, omits terminal output. (bool) no_log = False #: If True, omits logfile output. (bool) no_output = False #: If True, omits creation of output. (bool) no_slice = False #: If True, omits slicing of the grid. (bool) interactive = False #: If True, asks user to select unclarified options. (bool) #--- Default values for the grid parameters --- grid.reset_grid()