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 )
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)
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