Example #1
0
    def read(self):
        #
        # The interisting  part to read  in are the grads  and energy,
        # rest  will  be ignored  afterwards
        #
        # FIXME: Somehow  we need (sometimes) to pass  some time here,
        # before we can find the gxfile as output.  This is especially
        # valid when  running several calculations  in parallel.  It's
        # done this way and not with sleep as the problems seems to be
        # related to a  file that should but isn't  there. So it makes
        # sense to read all the files that are there, even if we don't
        # need the output.
        #
        os.system("ls > /dev/null")

        if isfile('o.' + basename(self.input) + '/trace_output'):
            # If there are  some trace files keep content  of them, as
            # if  several  calcualtions   have  been  performed  after
            # another, only for the  last iteration the trace would be
            # available
            f = open('o.' + basename(self.input) + '/trace_output', "r")
            keep = f.read()
            f.close()
            f = open("keep_traces", "a")
            f.write(keep)
            f.close()

        if os.path.exists('gxfile'):
            __, __, __, __, __, __,__, self.__grads, self.__energy, loopi_d = gxread('gxfile')
            if self.__energy is not None:
                return
        else:
            print_error ("ParaGauss ERROR: Found no gxfile to read energy or forces from")
            print_error ("There should be at least the one I created")
            print_error ("Therefore something very strange happened")
            print_error ("ERROR: I quit!!")
            sys.exit(1)

        self.__energy = self.parse_output(self.output)
Example #2
0
    def step(self, forces):
        """Called in a loop by .run() method of Optimizer class
        with forces computed for current geometry.
        """

        # read the metadata from gxfile in columns:
        atnums, positions, isyms, inums, iconns, ivars, adds, grads, energy, loop_d = gxread('gxfile')

        # use current positions as returned by the framework,
        # in case the on-disk version is outdated (units?):
        positions = self.atoms.get_positions()

        # the energy corresponding to the current geometry (units?):
        energy = self.atoms.get_potential_energy()

        if (loop_d != self._loop+1):
            print "WARNING: loop number of gxfile", loop_d, "and intern loop number", self._loop, "differ"
        # for use in gxfile:
        self._loop += 1

        print "GxOptimizer: loop=", self._loop
        print "GxOptimizer: energy=", energy
        print "GxOptimizer: positions=\n", positions
        print "GxOptimizer: forces=\n", forces

        # write gxfile to disk, note that energy gradients == - forces (units?):
        gxwrite(atnums, positions / Bohr, isyms, inums, iconns, ivars, adds, -forces / Hartree * Bohr, energy/Hartree, file='gxfile', loop=self._loop)

        # run external executable to update geometry:
        # exitcode = os.system('optimizer.exe')
        tty = os.popen(self.cmdline,"r")
        for line in tty:
            print "PGOptimizer: ", line.rstrip("\n")

        # the last line of the output should tell if optimizer thinks it is converged:
        line = line.rstrip("\n")

        if line.startswith(" optimizer_main: converged="):
          # in regular runs the last line should tell if convergence was reached:
          self._converged = line.endswith("T")
        else:
          # on errors the last line could be anything, abort by faking convergence:
          print "GxOptimizer: ERROR! UNEXPECTED OUTPUT FROM EXTRENAL OPTIMIZER!"
          self._converged = True

        print "GxOptimizer: converged=", self._converged

        # read the updated geometry from the gxfile:
        atnums, positions1, isyms, inums, iconns, ivars, adds,  grads, energy, loop_d = gxread('gxfile')

        positions1 = positions1 * Bohr

        print "GxOptimizer: new positions=\n", positions1
        print "GxOptimizer: step=\n", positions1 - positions

        self.atoms.set_positions(positions1)
Example #3
0
    def calculate (self, atoms):
        """
         Calculates the energy and forces with ParaGauss.  Uses gxfile
         to comunicate with the rest of the system.
        """
        # read in actual positions and atomic numbers
        self.positions = atoms.get_positions().copy()
        atnums = atoms.get_atomic_numbers().copy()
        if (self.atnums == None):
            self.atnums = atnums

        if len (atnums) != len (self.atnums) or any (array (atnums) != array (self.atnums)):
            print_error
            ("""
            ERROR: (ParaGauss) gxfile does not fit!  Gxfile contains
            wrong atoms!  Please delete or change it before restart.
            """)
            raise Exception ("gxfile does not fit, delete or adjust!")

        n = len(self.atnums)
        loop = 1
        # There  may be  a gxfile  from  another source  make sure  it
        # contains the same meta data than our source:
        t_gx = {}
        if os.path.exists('gxfile'):
            atnums, __, t_gx["isyms"], t_gx["inums"], t_gx["iconns"], t_gx["ivars"], t_gx["additional"], __, __, loop = gxread('gxfile')
            for dat in self.data.keys():
                if (np2.asarray(self.data[dat]) != np2.array(t_gx[dat])).any():
                    print_error ("ERROR: (ParaGauss) gxfile does not fit!")
                    print_error ("ERROR: (ParaGauss) gxfile contains wrong " + dat +" !")
                    print_error ("Please delete or change it before restart")
                    raise Exception("gxfile does not fit, delete or adjust!")

            if (np2.array(atnums) != self.atnums).any():
                print_error ("ERROR: (ParaGauss) gxfile does not fit!")
                print_error ("ERROR: (ParaGauss) gxfile contains wrong atoms!")
                print_error ("Please delete or change it before restart")
                raise Exception("gxfile does not fit, delete or adjust!")

        # Needs not to know size of system at init, but soon they will
        # be needed
        if "isyms" not in self.data:
            if "isyms" in t_gx:
                self.data.update(t_gx)
            else:
                def dummy_or_not(at):
                    if at == 0:
                        return 0
                    else:
                        return 1

                self.data["isyms"] = np2.array([dummy_or_not(at) for at in atnums])
                self.data["inums"] = np2.array(range(1,n+1))
                self.data["iconns"] = np2.zeros((n,3))
                self.data["ivars"] = np2.zeros((n,3))
                self.data["additional"] = None
        # Create gxfile with actual  geometry for calculation units of
        # positions should be Bohrs in here, so they are changed
        gxwrite(self.atnums, self.positions/Bohr, self.data["isyms"], self.data["inums"], self.data["iconns"],\
                     self.data["ivars"], self.data["additional"], None, None, loop, file='gxfile' )
        input = basename(self.input)

        # FIXME: when copy_inp is True, we will occasionally overwrite
        # the  user  supplied  input  with  the version  we  saved  at
        # construction  time over and  over again.  The danger  is the
        # user may assume  he/she can edit the input  while the job is
        # running:
        copy_inp = (self.copy_input == "always") \
            or ((self.copy_input == "inexistent") and not isfile (input))

        if copy_inp:
            # This logic is to warn  the user if he/she edits the file
            # we are supposed to overwrite. FIXME: race condition:
            if isfile (input):
                with open (input, "r") as inputfile:
                    if inputfile.read() != self.inputstring:
                        print_error ("WARNING: Changes in", input, "will be overwritten!")
                        print_error ("         Consider copy_input=\"inexistent\" or \"never\".")

            # (Over)writing input here. FIXME:  should we skip that if
            # the content is already the same?
            with open (input, "w") as inputfile:
                inputfile.write (self.inputstring)

        if self.optimizer is not None:
            with open ("optimizer.input", "w") as optifile:
                optifile.write (self.optimizer)

        # The  geometry file  appears to  be used  for  monitoring the
        # progress by the user.   Write it before starting potentially
        # long-runnuing  process. FIXME: we  are supposed  to "report"
        # also computed properties! Therefore  we call this once again
        # after PG finishes:
        self.report (atoms, "ParaGauss.xyz")

        # The actual  calcualtion starts  about here. FIXME:  at least
        # once I did a mistake  of specifying the input in the command
        # line thus letting PG process the same input twice because it
        # is already appended here:
        cmd = self.cmdline + [input]

        if self.silence:
            stdout = open ("./ParaGauss.out", "w")
        else:
            stdout = sys.stdout

        subprocess.call (cmd, stdout=stdout)

        if self.silence:
            stdout.close()
        # Reads in new energy and forces
        self.read()

        # Do it once again, this time also with the valid energy:
        self.report (atoms, "ParaGauss.xyz")

        self.converged = True
Example #4
0
    def __init__(self,
                 input = "input",
                 cmdline = "runpg /users/alexei/exe/openmpi/mainscf_V3.1.4b7-64",
                 silence = True,
                 optimizer = None,
                 copy_input = "always"
                 ):
        """
        Parameters
        ==========

        |input|

            name of the input  file wich contains all the informations
            ParaGauss needs

        |cmdline|

            Shell command  to start ParaGauss, it will  be executed in
            working directory.  A typical command line reads:

                runpg /users/alexei/exe/openmpi/mainscf_V3.1.4

        |silence|

            if  True (is  as default)  ParaGauss stdout  will go  to a
            separate file if False it would go to the normal stdout

        |optimizer|

            If optimizer input is  needed for a ParaGauss single point
            calculation the programm  takes the content from optimizer
            and provides  it as  optimizer.input in the  directory the
            calculation runs

        |copy_input|

            Allows three different modes:

            always

                (is  the  default) will  create  new  input file  from
                storage  each  time  a quantum  chemistry  calculation
                starts

            never

                will never create an input file

            inexistent

                will create  a new input file for  a quantum chemistry
                calculation if it finds that the file does not exist

                Both always  and inexistent will fetch  the input file
                they  will  create  lateron  in  the  current  working
                directory during initalization
        """

        self.input = input

        # Command line is stored internally as list of arguments:
        if type (cmdline) == type (""):
            cmdline = shlex.split (cmdline)
        self.cmdline = cmdline

        self.silence = silence
        assert (copy_input in ["always", "never", "inexistent"])
        self.copy_input = copy_input

        self.converged = False

        # I am  getting tired of  this voodoo, FIXME: factor  this out
        # into a function:
        if input.startswith("i."):
            # e.g. i.h2o:
            input_base_name = input[2:]
        elif input.endswith(".scm") or input.endswith(".nml"):
            input_base_name = input[:-4]
        else:
            # e.g. input, or anything else:
            input_base_name = input

        if input_base_name == "input":
            self.output = "output"
        else:
            self.output = "o." + input_base_name + "/output"

        # store  metadata here, it  might be  needed (even  in another
        # directory)
        self.data = {}

        if not self.copy_input == "never":
            with open (self.input, "r") as file:
                self.inputstring = file.read()

        if optimizer is None:
            self.optimizer = None
        else:
            with open (optimizer, "r") as file:
                self.optimizer = file.read()
        # print self.inputstring

        self.atnums = None

        # there may be  a gxfile from gxoptimizer we  must not disturb
        # its internal coordinates
        if os.path.exists('gxfile'):
            self.atnums, __, self.data["isyms"], self.data["inums"], self.data["iconns"], self.data["ivars"], \
                self.data["additional"], __, __, loop = gxread('gxfile')

        # We compare against None in self.report() and elsewhere:
        self.__energy = None
Example #5
0
def read_zmt_from_gx(gx_file):
    """
    Read zmat out from a string, convert to easier to interprete results

    give back more results than really needed, to have it easier to use
    them later on

    OUTPUT: [<Name of Atoms>], [Connectivity matrix, format see ZMat input from zmat.py],
            [<variable numbers, with possible repitions>], how often a variable was used more than once,
            [<dihedral angles variable numbers>],
            (number of Cartesian coordinates covered with zmt, number of interal coordinates of zmt),
            [<mask for fixed Atoms>]
    """
    from ase.gxfile import gxread
    from ase.data import chemical_symbols

    atnums, __, __, inums, iconns, ivars, __, __, __, __ = gxread(gx_file)
    # For consistency with the rest, transform the numbers to symbols
    symbols = [chemical_symbols[a] for a in atnums]
    assert(list(inums) == range(1, len(atnums) + 1))


    iconns2 = []
    var_names = []
    var_names_gx = {}
    mult = 0
    dih_names = []
    fixed = []
    j = 1

    #Iconns should contain connectivities, ivars tell
    # what to do with them
    for ic, iv in zip(iconns, ivars):
        a, b, c = ic
        new_vars = []

        # Three atoms are special, because they do not
        # contain 3 variables
        if a == 0:
           t = ()
        elif b == 0:
           t = (a-1,)
           new_vars = [iv[0]]
        elif c == 0:
           t = (a-1, b-1,)
           new_vars = iv[:-1]
        else:
           t = (a-1, b-1, c-1)
           new_vars = iv
        # connectivities from gx also have the wrong basis
        # change them and give back as our connectivity matrix
        iconns2.append(t)

        # Now find out what is to be done to the corresponding
        # variables
        for i, nv in enumerate(new_vars):

             if nv in var_names_gx.keys():
                 # They have appeared already once, thus
                 # should go to With_equals
                 var_names.append(var_names_gx[nv])
                 mult = mult + 1
             else:
                 # New variable
                 var_names.append(j)
                 if i == 2:
                     # For finding the shortest path
                     # Attention here numbering starts with 0
                     # not with 1 as for the var_names
                     dih_names.append(j - 1)
                 if nv == 0:
                     # Normally masked ones are only
                     # considered lateron, gx already
                     # addresses them by giving a 0 to
                     # as their variable number
                     fixed.append(j)
                 else:
                     var_names_gx[nv] = j
                 j = j + 1

    iconns = iconns2

    # create also a mask if there is something about it
    if fixed == []:
        mask = None
    else:
        mask = [ i not in fixed for i in var_names]

    return symbols, iconns, var_names, mult, dih_names, (len(symbols) * 3, j), mask