Example #1
0
def write_gx(filename, atoms, with_energy = False, with_gradients = False, loop = 1, isyms = None, inums = None, iconns = None, ivars = None, additionals = None):
    energy = None
    if with_energy:
        energy = atoms.get_potential_energy() / Hartree

    grads = None
    if with_gradients:
        grads = -atoms.get_forces() / Hartree * Bohr

    positions = atoms.get_positions().copy()
    atnums = atoms.get_atomic_numbers().copy()
    n = len(atnums)
    if isyms == None:
        def dummy_or_not(at):
            if at == 0:
                return 0
            else:
                return 1

        isyms = array([dummy_or_not(at) for at in atnums])
    if inums == None:
        inums = zeros(n)
    if iconns == None:
        iconns = zeros((n,3))
    if ivars == None:
        ivars = zeros((n,3))

    gxwrite(atnums, positions/Bohr, isyms, inums, iconns, ivars, additionals, grads, energy, loop, file=filename )
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