def run(self, set_atoms=False): """Method which explicitly runs LAMMPS.""" self.calls += 1 # set LAMMPS command from environment variable if 'LAMMPS_COMMAND' in os.environ: lammps_cmd_line = shlex.split(os.environ['LAMMPS_COMMAND'], posix=(os.name == 'posix')) if len(lammps_cmd_line) == 0: self.clean() raise RuntimeError('The LAMMPS_COMMAND environment variable ' 'must not be empty') # want always an absolute path to LAMMPS binary when calling from # self.dir lammps_cmd_line[0] = os.path.abspath(lammps_cmd_line[0]) else: self.clean() raise RuntimeError( 'Please set LAMMPS_COMMAND environment variable') if 'LAMMPS_OPTIONS' in os.environ: lammps_options = shlex.split(os.environ['LAMMPS_OPTIONS'], posix=(os.name == 'posix')) else: lammps_options = shlex.split('-echo log -screen none', posix=(os.name == 'posix')) # change into subdirectory for LAMMPS calculations cwd = os.getcwd() os.chdir(self.tmp_dir) # setup file names for LAMMPS calculation label = '{0}{1:>06}'.format(self.label, self.calls) lammps_in = uns_mktemp(prefix='in_' + label, dir=self.tmp_dir) lammps_log = uns_mktemp(prefix='log_' + label, dir=self.tmp_dir) lammps_trj_fd = NamedTemporaryFile(prefix='trj_' + label, dir=self.tmp_dir, delete=(not self.keep_tmp_files)) lammps_trj = lammps_trj_fd.name if self.no_data_file: lammps_data = None else: lammps_data_fd = NamedTemporaryFile( prefix='data_' + label, dir=self.tmp_dir, delete=(not self.keep_tmp_files)) self.write_lammps_data(lammps_data=lammps_data_fd) lammps_data = lammps_data_fd.name lammps_data_fd.flush() # see to it that LAMMPS is started if not self._lmp_alive(): # Attempt to (re)start lammps self._lmp_handle = Popen( #### lammps_cmd_line + lammps_options + ['-log', '/dev/stdout'], lammps_cmd_line + lammps_options, stdin=PIPE, stdout=PIPE) lmp_handle = self._lmp_handle # Create thread reading lammps stdout (for reference, if requested, # also create lammps_log, although it is never used) if self.keep_tmp_files: lammps_log_fd = open(lammps_log, 'wb') fd = SpecialTee(lmp_handle.stdout, lammps_log_fd) else: fd = lmp_handle.stdout thr_read_log = Thread(target=self.read_lammps_log, args=(fd, )) thr_read_log.start() # write LAMMPS input (for reference, also create the file lammps_in, # although it is never used) if self.keep_tmp_files: lammps_in_fd = open(lammps_in, 'wb') fd = SpecialTee(lmp_handle.stdin, lammps_in_fd) else: fd = lmp_handle.stdin self.write_lammps_in(lammps_in=fd, lammps_trj=lammps_trj, lammps_data=lammps_data) if self.keep_tmp_files: lammps_in_fd.close() # Wait for log output to be read (i.e., for LAMMPS to finish) # and close the log file if there is one thr_read_log.join() if self.keep_tmp_files: lammps_log_fd.close() if not self.keep_alive: self._lmp_end() exitcode = lmp_handle.poll() if exitcode and exitcode != 0: cwd = os.getcwd() raise RuntimeError( 'LAMMPS exited in {0} with exit code: {1}.'.format( cwd, exitcode)) # A few sanity checks if len(self.thermo_content) == 0: raise RuntimeError('Failed to retrieve any thermo_style-output') if int(self.thermo_content[-1]['atoms']) != len(self.atoms): # This obviously shouldn't happen, but if prism.fold_...() fails, # it could raise RuntimeError('Atoms have gone missing') self.read_lammps_trj(lammps_trj=lammps_trj, set_atoms=set_atoms) lammps_trj_fd.close() if not self.no_data_file: lammps_data_fd.close() os.chdir(cwd)
def run(self, set_atoms=False): # !TODO: split this function """Method which explicitly runs LAMMPS.""" pbc = self.atoms.get_pbc() if all(pbc): cell = self.atoms.get_cell() elif not any(pbc): # large enough cell for non-periodic calculation - # LAMMPS shrink-wraps automatically via input command # "periodic s s s" # below cell = 2 * np.max(np.abs(self.atoms.get_positions())) * np.eye(3) else: warnings.warn( "semi-periodic ASE cell detected - translation " + "to proper LAMMPS input cell might fail" ) cell = self.atoms.get_cell() self.prism = Prism(cell) self.set_missing_parameters() self.calls += 1 # change into subdirectory for LAMMPS calculations cwd = os.getcwd() os.chdir(self.parameters.tmp_dir) # setup file names for LAMMPS calculation label = "{0}{1:>06}".format(self.label, self.calls) lammps_in = uns_mktemp( prefix="in_" + label, dir=self.parameters.tmp_dir ) lammps_log = uns_mktemp( prefix="log_" + label, dir=self.parameters.tmp_dir ) lammps_trj_fd = NamedTemporaryFile( prefix="trj_" + label, suffix=(".bin" if self.parameters.binary_dump else ""), dir=self.parameters.tmp_dir, delete=(not self.parameters.keep_tmp_files), ) lammps_trj = lammps_trj_fd.name if self.parameters.no_data_file: lammps_data = None else: lammps_data_fd = NamedTemporaryFile( prefix="data_" + label, dir=self.parameters.tmp_dir, delete=(not self.parameters.keep_tmp_files), mode='w', encoding='ascii' ) write_lammps_data( lammps_data_fd, self.atoms, specorder=self.parameters.specorder, force_skew=self.parameters.always_triclinic, velocities=self.parameters.write_velocities, prismobj=self.prism, units=self.parameters.units, atom_style=self.parameters.atom_style ) lammps_data = lammps_data_fd.name lammps_data_fd.flush() # see to it that LAMMPS is started if not self._lmp_alive(): command = self.get_lammps_command() # Attempt to (re)start lammps self._lmp_handle = Popen( shlex.split(command, posix=(os.name == "posix")), stdin=PIPE, stdout=PIPE, ) lmp_handle = self._lmp_handle # Create thread reading lammps stdout (for reference, if requested, # also create lammps_log, although it is never used) if self.parameters.keep_tmp_files: lammps_log_fd = open(lammps_log, "wb") fd = SpecialTee(lmp_handle.stdout, lammps_log_fd) else: fd = lmp_handle.stdout thr_read_log = Thread(target=self.read_lammps_log, args=(fd,)) thr_read_log.start() # write LAMMPS input (for reference, also create the file lammps_in, # although it is never used) if self.parameters.keep_tmp_files: lammps_in_fd = open(lammps_in, "wb") fd = SpecialTee(lmp_handle.stdin, lammps_in_fd) else: fd = lmp_handle.stdin write_lammps_in( lammps_in=fd, parameters=self.parameters, atoms=self.atoms, prismobj=self.prism, lammps_trj=lammps_trj, lammps_data=lammps_data, ) if self.parameters.keep_tmp_files: lammps_in_fd.close() # Wait for log output to be read (i.e., for LAMMPS to finish) # and close the log file if there is one thr_read_log.join() if self.parameters.keep_tmp_files: lammps_log_fd.close() if not self.parameters.keep_alive: self._lmp_end() exitcode = lmp_handle.poll() if exitcode and exitcode != 0: cwd = os.getcwd() raise RuntimeError( "LAMMPS exited in {} with exit code: {}." "".format(cwd, exitcode) ) # A few sanity checks if len(self.thermo_content) == 0: raise RuntimeError("Failed to retrieve any thermo_style-output") if int(self.thermo_content[-1]["atoms"]) != len(self.atoms): # This obviously shouldn't happen, but if prism.fold_...() fails, # it could raise RuntimeError("Atoms have gone missing") trj_atoms = read_lammps_dump( infileobj=lammps_trj, order=False, index=-1, prismobj=self.prism, specorder=self.parameters.specorder, ) if set_atoms: self.atoms = trj_atoms.copy() self.forces = trj_atoms.get_forces() # !TODO: trj_atoms is only the last snapshot of the system; Is it # desirable to save also the inbetween steps? if self.parameters.trajectory_out is not None: # !TODO: is it advisable to create here temporary atoms-objects self.trajectory_out.write(trj_atoms) tc = self.thermo_content[-1] self.results["energy"] = convert( tc["pe"], "energy", self.parameters["units"], "ASE" ) self.results["free_energy"] = self.results["energy"] self.results["forces"] = self.forces.copy() stress = np.array( [-tc[i] for i in ("pxx", "pyy", "pzz", "pyz", "pxz", "pxy")] ) # We need to apply the Lammps rotation stuff to the stress: xx, yy, zz, yz, xz, xy = stress stress_tensor = np.array([[xx, xy, xz], [xy, yy, yz], [xz, yz, zz]]) R = self.prism.rot_mat stress_atoms = np.dot(R, stress_tensor) stress_atoms = np.dot(stress_atoms, R.T) stress_atoms = stress_atoms[[0, 1, 2, 1, 0, 0], [0, 1, 2, 2, 2, 1]] stress = stress_atoms self.results["stress"] = convert( stress, "pressure", self.parameters["units"], "ASE" ) lammps_trj_fd.close() if not self.parameters.no_data_file: lammps_data_fd.close() os.chdir(cwd)
def run(self): """Method which explicitely runs LAMMPS.""" self.calls += 1 # set LAMMPS command from environment variable if 'LAMMPS_COMMAND' in os.environ: lammps_cmd_line = shlex.split(os.environ['LAMMPS_COMMAND']) if len(lammps_cmd_line) == 0: self.clean() raise RuntimeError('The LAMMPS_COMMAND environment variable ' 'must not be empty') # want always an absolute path to LAMMPS binary when calling from self.dir lammps_cmd_line[0] = os.path.abspath(lammps_cmd_line[0]) else: self.clean() raise RuntimeError('Please set LAMMPS_COMMAND environment variable') if 'LAMMPS_OPTIONS' in os.environ: lammps_options = shlex.split(os.environ['LAMMPS_OPTIONS']) else: lammps_options = shlex.split('-echo log -screen none') # change into subdirectory for LAMMPS calculations cwd = os.getcwd() os.chdir(self.tmp_dir) # setup file names for LAMMPS calculation label = '%s%06d' % (self.label, self.calls) lammps_in = uns_mktemp(prefix='in_'+label, dir=self.tmp_dir) lammps_log = uns_mktemp(prefix='log_'+label, dir=self.tmp_dir) lammps_trj_fd = NamedTemporaryFile(prefix='trj_'+label, dir=self.tmp_dir, delete=(not self.keep_tmp_files)) lammps_trj = lammps_trj_fd.name if self.no_data_file: lammps_data = None else: lammps_data_fd = NamedTemporaryFile(prefix='data_'+label, dir=self.tmp_dir, delete=(not self.keep_tmp_files)) self.write_lammps_data(lammps_data=lammps_data_fd) lammps_data = lammps_data_fd.name lammps_data_fd.flush() #Save names of the files just in case self.trajfile = lammps_trj_fd.name self.infile = lammps_in self.logfile = lammps_log self.datafile = lammps_data # see to it that LAMMPS is started if not self._lmp_alive(): # Attempt to (re)start lammps self._lmp_handle = Popen(lammps_cmd_line+lammps_options+['-log', '/dev/stdout'], stdin=PIPE, stdout=PIPE) lmp_handle = self._lmp_handle # Create thread reading lammps stdout (for reference, if requested, # also create lammps_log, although it is never used) if self.keep_tmp_files: lammps_log_fd = open(lammps_log, 'w') fd = special_tee(lmp_handle.stdout, lammps_log_fd) else: fd = lmp_handle.stdout thr_read_log = Thread(target=self.read_lammps_log, args=(fd,)) thr_read_log.start() # write LAMMPS input (for reference, also create the file lammps_in, # although it is never used) if self.keep_tmp_files: lammps_in_fd = open(lammps_in, 'w') fd = special_tee(lmp_handle.stdin, lammps_in_fd) else: fd = lmp_handle.stdin self.write_lammps_in(lammps_in=fd, lammps_trj=lammps_trj, lammps_data=lammps_data) if self.keep_tmp_files: lammps_in_fd.close() # Wait for log output to be read (i.e., for LAMMPS to finish) # and close the log file if there is one thr_read_log.join() if self.keep_tmp_files: lammps_log_fd.close() if not self.keep_alive: self._lmp_end() exitcode = lmp_handle.poll() if exitcode and exitcode != 0: cwd = os.getcwd() raise RuntimeError('LAMMPS exited in %s with exit code: %d.' %\ (cwd,exitcode)) # A few sanity checks if len(self.thermo_content) == 0: raise RuntimeError('Failed to retreive any thermo_style-output') if int(self.thermo_content[-1]['atoms']) != len(self.atoms): # This obviously shouldn't happen, but if prism.fold_...() fails, it could raise RuntimeError('Atoms have gone missing') self.read_lammps_trj(lammps_trj=lammps_trj, set_atoms=True) lammps_trj_fd.close() if not self.no_data_file: lammps_data_fd.close() os.chdir(cwd)