def test_socketio_espresso(factory): name = factory.name if name == 'abinit': factory.require_version('9.4') atoms = bulk('Si') exe = factory.factory.executable unixsocket = f'ase_test_socketio_{name}' espresso = factory.calc( kpts=[2, 2, 2], ) template = commands[name] command = template.format(exe=exe, unixsocket=unixsocket) espresso.command = command atoms.rattle(stdev=.2, seed=42) with BFGS(ExpCellFilter(atoms)) as opt, \ pytest.warns(UserWarning, match='Subprocess exited'), \ SocketIOCalculator(espresso, unixsocket=unixsocket) as calc: atoms.calc = calc for _ in opt.irun(fmax=0.05): e = atoms.get_potential_energy() fmax = max(np.linalg.norm(atoms.get_forces(), axis=0)) print(e, fmax)
def run_server(launchclient=True): atoms = getatoms() with SocketIOCalculator(log=sys.stdout, port=port, timeout=timeout) as calc: if launchclient: thread = launch_client_thread() atoms.calc = calc opt = BFGS(atoms) opt.run() if launchclient: thread.join() forces = atoms.get_forces() energy = atoms.get_potential_energy() atoms.calc = EMT() ref_forces = atoms.get_forces() ref_energy = atoms.get_potential_energy() refatoms = run_normal() ref_energy = refatoms.get_potential_energy() eerr = abs(energy - ref_energy) ferr = np.abs(forces - ref_forces).max() perr = np.abs(refatoms.positions - atoms.positions).max() print('errs e={} f={} pos={}'.format(eerr, ferr, perr)) assert eerr < 1e-11, eerr assert ferr < 1e-11, ferr assert perr < 1e-11, perr
def __init__(self, workflow: str, label: str = 'balsam', atoms: Atoms = None, job_args: str = None, job_kwargs: Dict[str, Any] = dict(), **kwargs: Any) -> None: ''' Define Balsam Socket IO Calculator Parameters ---------- workflow : str name of the workflow, e.g. >>> workflow='QE_Socket' label : str, optional label for the created balsam calculator, by default 'balsam' atoms : Atoms, optional an Atoms object, by default None job_args : str, optional by default None job_kwargs : Dict[str, Any], optional by default dict(), e.g. >>> balsam_exe_settings = {'num_nodes': 1, 'ranks_per_node': 48, 'threads_per_rank': 1} ''' SocketIOCalculator.__init__(self, port=0) self._port = self.server.serversocket.getsockname()[1] BalsamCalculator.__init__(self, workflow=workflow, label=label, atoms=atoms, job_args=job_args, job_kwargs=job_kwargs, **kwargs)
def calculate(self, atoms: Atoms = None, properties: List[str] = ['energy'], system_changes: List[str] = all_changes) -> None: ''' Run calculator Parameters ---------- atoms : Atoms an Atom object representing the system studied, by default None properties : List[str], optional by default ['energy'] system_changes : List[str], optional by default all_changes ''' Calculator.calculate(self, atoms, properties, system_changes) if self.job is None or not self.job_running(self.job.state): self.job = self.create_job() self.directory = self.job.working_directory self.format_socket_keywords() self.write_input(self.atoms, properties, system_changes) self.job.save() SocketIOCalculator.calculate(self, atoms, properties, system_changes)
def main(): '''Main driver routine.''' system = read(GEO_PATH, format='gen') write('geo.gen', system, format='gen') opt = BFGS(system, trajectory='opt.traj', logfile='opt.log') with SocketIOCalculator(log=sys.stdout, unixsocket=UNIXSOCKET) as calc: Popen(DFTBP_PATH) system.set_calculator(calc) opt.run(fmax=1.00E-09) forces = system.get_forces() energy = system.get_potential_energy()
def test_socketio_python(): from ase.build import bulk from ase.constraints import ExpCellFilter from ase.optimize import BFGS atoms = bulk('Au') * (2, 2, 2) atoms.rattle(stdev=0.05) fmax = 0.01 atoms.cell += np.random.RandomState(42).rand(3, 3) * 0.05 client = PySocketIOClient(EMT) pid = os.getpid() with SocketIOCalculator(launch_client=client, unixsocket=f'ase-python-{pid}') as atoms.calc: with BFGS(ExpCellFilter(atoms)) as opt: opt.run(fmax=fmax) forces = atoms.get_forces() assert np.linalg.norm(forces, axis=0).max() < fmax
def run_server(launchclient=True, sockettype='unix'): atoms = getatoms() port = None unixsocket = None if sockettype == 'unix': unixsocket = f'ase_ipi_protocol_bfgs_test_{pid}' else: assert sockettype == 'inet' port = inet_port with SocketIOCalculator(log=sys.stdout, port=port, unixsocket=unixsocket, timeout=timeout) as calc: if launchclient: thread = launch_client_thread(port=port, unixsocket=unixsocket) atoms.calc = calc with BFGS(atoms) as opt: opt.run() if launchclient: thread.join() forces = atoms.get_forces() energy = atoms.get_potential_energy() atoms.calc = EMT() ref_forces = atoms.get_forces() ref_energy = atoms.get_potential_energy() refatoms = run_normal() ref_energy = refatoms.get_potential_energy() eerr = abs(energy - ref_energy) ferr = np.abs(forces - ref_forces).max() perr = np.abs(refatoms.positions - atoms.positions).max() print('errs e={} f={} pos={}'.format(eerr, ferr, perr)) assert eerr < 1e-11, eerr assert ferr < 1e-11, ferr assert perr < 1e-11, perr
def main(): '''Main driver routine.''' system = read(GEO_PATH, format='gen') write('dummy.gen', system, format='gen') initial = read('NH3_initial.traj') final = read('NH3_final.traj') images = [initial] images += [initial.copy() for ii in range(NIMAGES)] images += [final] neb = NEB(images) neb.interpolate() opt = BFGS(neb, trajectory='i2f.traj') socketids = range(1, NIMAGES + 1) wdirs = ['_calc/image_{:d}'.format(socket) for socket in socketids] unixsockets = ['dftbplus_{:d}'.format(socket) for socket in socketids] write_modhsd(socketids) calcs = [ SocketIOCalculator(log='socket.log', unixsocket=unixsocket) for unixsocket in unixsockets ] for ii, calc in enumerate(calcs): images[ii + 1].set_calculator(calc) for cwd in wdirs: Popen(DFTBP_PATH, cwd=cwd) opt.run(fmax=1.00E-02) for calc in calcs: calc.close()
import sys from ase.build import molecule from ase.optimize import BFGS from ase.calculators.aims import Aims from ase.calculators.socketio import SocketIOCalculator # Environment-dependent parameters -- please configure according to machine # Note that FHI-aim support for the i-PI protocol must be specifically # enabled at compile time, e.g.: make -f Makefile.ipi ipi.mpi species_dir = '/home/aimsuser/src/fhi-aims.171221_1/species_defaults/light' command = 'ipi.aims.171221_1.mpi.x' # This example uses INET; see other examples for how to use UNIX sockets. port = 31415 atoms = molecule('H2O', vacuum=3.0) atoms.rattle(stdev=0.1) aims = Aims(command=command, use_pimd_wrapper=('localhost', port), compute_forces=True, xc='LDA', species_dir=species_dir) opt = BFGS(atoms, trajectory='opt.aims.traj', logfile='opt.aims.log') with SocketIOCalculator(aims, log=sys.stdout, port=port) as calc: atoms.calc = calc opt.run(fmax=0.05)
# In this example we use a UNIX socket. See other examples for INET socket. # UNIX sockets are faster then INET sockets, but cannot run over a network. # UNIX sockets are files. The actual path will become /tmp/ipi_ase_espresso. unixsocket = 'ase_espresso' # Configure pw.x command for UNIX or INET. # # UNIX: --ipi {unixsocket}:UNIX # INET: --ipi {host}:{port} # # See also QE documentation, e.g.: # # https://www.quantum-espresso.org/Doc/pw_user_guide/node13.html # command = ('pw.x < PREFIX.pwi --ipi {unixsocket}:UNIX > PREFIX.pwo'.format( unixsocket=unixsocket)) espresso = Espresso(command=command, ecutwfc=30.0, pseudopotentials=pseudopotentials, pseudo_dir=pseudo_dir) opt = BFGS(atoms, trajectory='opt.traj', logfile='opt.log') with SocketIOCalculator(espresso, log=sys.stdout, unixsocket=unixsocket) as calc: atoms.calc = calc opt.run(fmax=0.05) # Note: QE does not generally quit cleanly - expect nonzero exit codes.
"outfilename": "aims.out", } dft_settings = { # system settings "xc": "pbe", "spin": "none", "compute_forces": True, } # ################# Set aims calculator ###################### workdir = "aims_rundir" port_aims = 12345 aux_settings = {"label": workdir, "use_pimd_wrapper": ("localhost", port_aims)} calc = Aims(**usr_settings, **dft_settings, **aux_settings) # atoms.set_calculator(calc) # ################# Create Client ############################ # inet port_ipi = 10200 host_ipi = "localhost" client = SocketClient(host=host_ipi, port=port_ipi) # ################# Create ASE SERVER ############################ with SocketIOCalculator(calc, log="socketio.log", port=port_aims) as io_calc: atoms.set_calculator(io_calc) client.run(atoms)
def get_aims_and_sockets_calculator( dimensions, # i-Pi settings for sockets port=None, host=None, logfile='socketio.log', # Debug setting check_socket=True, verbose=False, codata_warning=True, # Passthrough of other objects for calculator **kwargs): ''' Method to return a sockets calculator (for i-Pi based socket connectivity) and also an associated FHI-aims calculator for ASE Args: dimensions: Integer Dimensions is _not_ used in this routine, but we make it necessary so the passthrough isn't problematic for inexperienced users. See get_aims_calculator() port: None or Integer The port for connection between FHI-aims and ASE with i-Pi sockets. This is fairly arbitrary as long as it doesn't clash with local settings. If None an integer between 12345 and 60000 will be picked at random. host: String Name of host computer for ASE. Necessary for calculations where MPI runs on the compute nodes. This is now defaulted to None, and then will self-identify the host name if unidentified. Long-term, we should consider removing this variable to insulate the users from having to set it. logfile: String Location of output from sockets communication. check_socket: Boolean Whether we want the automatically identify and resolve port clashes. verbose: Boolean For testing of the interface when searching for empty ports. codata_warning: Boolean Warn the user about Hartree to eV conversion being performed in ASE rather than FHI-aims. ASE uses CODATA 2014 and FHI-aims uses CODATA 2002 which yields energy discrepancies. The warning message can be turned off if set to False. Returns: Socket_calc: Wrapper for ASE calculator Used for i-Pi connectvity, and should be assigned to optimisation/dynamics Object FHI_calc: FHI-aims ASE calculator ''' import socket if host is None: # On machines where ASE and FHI-aims are run separately (e.g. ASE on login node, FHI-aims on compute nodes) # we need to specifically state what the name of the login node is so the two packages can communicate # In order to manage this communication in all situations, here we will find and use the hostname *even* # if on the same computer (it should work irrespective) host = socket.gethostname() # Random port assignment if port: pass else: import random port = random.randint(12345, 60000) if check_socket: port = _check_socket(host, port, verbose) # **kwargs is a passthrough of keyword arguments fhi_calc = get_aims_calculator(dimensions, **kwargs) # Add in PIMD command to get sockets working fhi_calc.set(use_pimd_wrapper=[host, port]) # Setup sockets calculator that "wraps" FHI-aims from ase.calculators.socketio import SocketIOCalculator socket_calc = SocketIOCalculator(fhi_calc, log=logfile, port=port) if codata_warning: print( "You are using i-Pi based socket connectivity between ASE and FHI-aims." ) print( "The communicated energy in Hartree units will be converted to eV in ASE and not FHI-aims." ) print( "The eV/Hartree unit in FHI-aims is given by CODATA 2002 (Web Version 4.0 2003-12-09), Peter J. Mohr, Barry N. Taylor" ) print( "ASE uses CODATA 2014, thus the energy in eV from ASE and the FHI-aims outputs will differ." ) print("Please be consistent in the unit conversion for data analysis!") print( "You can turn off this message by setting 'codata_warning' keyword to False." ) return socket_calc, fhi_calc
import os from ase import Atoms from ase.optimize import BFGS from ase.calculators.aims import Aims from ase.calculators.socketio import SocketIOCalculator os.environ['ASE_AIMS_COMMAND'] = 'aims.x' os.environ[ 'AIMS_SPECIES_DIR'] = '/home/alumne/software/FHIaims/species_defaults/light' atoms = Atoms('HOH', positions=[[0, 0, -1], [0, 1, 0], [0, 0, 1]]) opt = BFGS(atoms, trajectory='opt-aims-socketio.traj') aims = Aims(xc='LDA', compute_forces=True, use_pimd_wrapper=('UNIX:mysocket', 31415)) with SocketIOCalculator(aims, unixsocket='mysocket') as calc: atoms.calc = calc opt.run(fmax=0.05)
def socket_driver(self, **kwargs): from ase.calculators.socketio import SocketIOCalculator calc = SocketIOCalculator(self, **kwargs) return calc
import sys from ase.build import molecule from ase.calculators.dftb import Dftb from ase.calculators.socketio import SocketIOCalculator from ase.optimize import BFGS atoms = molecule('H2O') dftb = Dftb(Hamiltonian_MaxAngularMomentum_='', Hamiltonian_MaxAngularMomentum_O='"p"', Hamiltonian_MaxAngularMomentum_H='"s"', Driver_='', Driver_Socket_='', Driver_Socket_File='Hello') opt = BFGS(atoms, trajectory='test.traj') with SocketIOCalculator(dftb, log=sys.stdout, unixsocket='Hello') as calc: atoms.calc = calc opt.run(fmax=0.01)
# function to make sure the structure stays tetragonal def tetragonalize(atoms): """ make the lattice of atoms object tetragonal """ cell = atoms.cell scaled_pos = atoms.get_scaled_positions() a = (cell[0, 0] + cell[1, 1]) / 2 c = cell[2, 2] new_cell = np.array([[a, 0, 0], [0, a, 0], [0, 0, c]]) atoms.cell = new_cell atoms.set_scaled_positions(scaled_pos) # run the optimization and write out every step with SocketIOCalculator(calc, log="socketio.log", port=port) as calc: atoms.set_calculator(calc) # create the optimizer for the filtered atoms object opt = optimizer(opt_atoms, logfile=log_name, trajectory=trajectory_name) for ii, _ in enumerate(opt.irun(fmax=0.001, steps=20)): # tetragonalize the structure tetragonalize(atoms) # write out every intermediate structure (not necessary) atoms.write(f"{workdir}/geometry.in.next.{ii}", "aims", scaled=True) # write final result atoms.write("geometry.out", "aims", scaled=True)
import sys from ase.build import molecule from ase.io import write from ase.optimize import BFGS from ase.calculators.socketio import SocketIOCalculator unixsocket = 'ase_server_socket' atoms = molecule('H2O', vacuum=3.0) atoms.rattle(stdev=0.1) write('initial.traj', atoms) opt = BFGS(atoms, trajectory='opt.driver.traj', logfile='opt.driver.log') with SocketIOCalculator(log=sys.stdout, unixsocket=unixsocket) as calc: # Server is now running and waiting for connections. # If you want to launch the client process here directly, # instead of manually in the terminal, uncomment these lines: # # from subprocess import Popen # proc = Popen([sys.executable, 'example_client_gpaw.py']) atoms.calc = calc opt.run(fmax=0.05)
# write(os.path.join(working_dir, 'geo.gen'), at, format='gen') # shutil.copyfile(os.path.join(suppporting, "dftb_in.hsd"), # os.path.join(working_dir, "dftb_in.hsd")) # calc = Dftb(atoms=at, # Hamiltonian_='DFTB', # Hamiltonian_SCC='Yes', # Hamiltonian_SCCTolerance=1e-6, # Hamiltonian_MaxAngularMomentum_='', # Hamiltonian_MaxAngularMomentum_H='s', # Hamiltonian_MaxAngularMomentum_O='p', # Hamiltonian_MaxAngularMomentum_C='p', # Hamiltonian_MaxAngularMomentum_N='p', # Hamiltonian_MaxAngularMomentum_S='d') # kpts = (1,1,1)) # at.calc=calc # calc.calculate(at) # sys.exit(0) # text = "Driver = Socket {\n\ # File = \"dftbplus\"\n\ # Protocol = i-PI {}\n\ # MaxSteps = 1000\n\ # Verbosity = 0\n\}\n" # with open(os.path.join(working_dir, "dftb_in.hsd"), "a") as dftb: # dftb.write(text) # sys.exit(0) calculator = SocketIOCalculator(log=sys.stdout, unixsocket=UNIXSOCKET) Popen(DFTBP_PATH)