Communicator¶
eOn has a server client architecture for running its calculations. The
simulation data is stored on the server and clients are sent jobs and return the
results. Each time eOn is run it first checks to see if any results have come
back from clients and processes them, then submits more jobs if
needed. In eOn there are several different ways to run jobs. One can run them
locally on the server, via MPI, or using a job queuing system such as
SGE.
One driver in a directory¶
akmc, parallel_replica, unbiased_parallel_replica, basin_hopping,
and escape_rate share a lock file named lockfile in the results
directory. The driver creates that file with an exclusive open, writes
its process id, and flushes the file. A second driver that finds a live
owner leaves without starting a second run. Basin hopping, parallel
replica, and escape rate log Couldn't get lock. Adaptive kinetic Monte
Carlo logs the owner’s process id and exits.
A lock whose process is gone, or a file that is empty or cut off mid-write,
is removed and the driver tries once more. On platforms with fcntl the
driver holds an exclusive flock for the life of the run, so a reused
process id is not treated as the owner. The driver removes the lock when
it exits. A forked child does not remove it. The parent keeps the lock
until the parent exits.
LockFile.acquirelock takes the lock. aquirelock is the previous
spelling and still calls acquirelock. The akmc, basin hopping,
parallel replica, and escape rate drivers call acquirelock.
Note
From 2.0 on, prefer a workflow manager over eOn-generated submit
scripts. For AiiDA the plugin is AiiDA (aiida-eon) (pip install aiida-eon).
Configuration¶
[Communicator]
- pydantic model eon.schema.CommunicatorConfig[source]¶
- Fields:
type (Literal['local', 'local_lib', 'inprocess', 'cluster', 'mpi'])jobs_per_bundle (int)num_jobs (int)max_jobs (int)client_path (str)number_of_CPUs (int)script_path (str)name_prefix (str)queued_jobs (str)cancel_job (str)submit_job (str)
- field type: Literal['local', 'local_lib', 'inprocess', 'cluster', 'mpi'] = 'local'¶
- Options:
‘local’: Subprocess
eonclienton the same machine (file-based jobs).‘local_lib’ / ‘inprocess’: In-process
pyeonclient.Matter(no client binary; requires-Dwith_pyeonclient=true). Structures stay Matter end-to-end.‘cluster’: Job scheduler via user shell scripts.
‘mpi’: Server and clients as an MPI job.
Communicator type
- field jobs_per_bundle: int = 1¶
In
eOn, a job is defined as a task that theeonclientexecutes, such as a process search or a parallel replica run. Sometimes it makes sense to run more than one of the same type of job at a time.For example, when using empirical potentials to do saddle searches a single search might only take several seconds on modern CPUs. In order to improve performance more than one client job (e.g., process search, dimer, minimization) can be run at the same time.
Number of jobs per bundle.
- field num_jobs: int = 1¶
The meaning of this variable changes depending on the communicator type. For
local, it is the number of jobs run every time the program is invoked. Forcluster, it is the desired sum of the queued and running jobs.Number of jobs.
- field max_jobs: int = 0¶
For communicators with queues (
cluster), no more jobs will be queued if the number of jobs queued and in progress equals or exceeds this number. A default of 0 means unlimited.Maximum number of akmc jobs that can be running at once for the current state.
- field client_path: str = 'eonclient'¶
If only a name and not a path is given,
eOnlooks for the binary in the same directory as the configuration file. If not found there, it searches through the directories in the$PATHenvironment variable.Path to the eon client binary.
- field number_of_CPUs: int = 1¶
Number of jobs that will run simultaneously for the local communicator.
- field script_path: str = './'¶
Path to the user-defined scripts for submitting jobs to the communicator for the cluster communicator.
- field name_prefix: str = 'eon'¶
Prefix added to job names to make them identifiable by the user for the cluster communicator.
- field queued_jobs: str = 'queued_jobs.sh'¶
This may return more than just
eOnjobs.Name of the script that returns the job IDs of all the running and queued jobs for the cluster communicator.
- field cancel_job: str = 'cancel_job.sh'¶
Takes a single argument, the JobID.
Name of the script that cancels a job for the cluster communicator.
- field submit_job: str = 'submit_job.sh'¶
It takes two command line arguments. The first is the name of the job. This is not required for
eOnuse, but is highly recommended so that users can identify which job is which. The second argument is the working directory. This is the path where theeOnclient should be executed. All of the needed client files will be placed in this directory. The script must return the job id of the submitted job. This is howeOninternally keeps track of jobs.Name of the script that submits a single job to the queuing system for the cluster communicator.
Examples¶
An example communicator section using the local communicator with an Eon client
binary named eonclient-custom that either exists in the $PATH or in the same
directory as the configuration file and uses makes use of 8 CPUs.
[Communicator]
type = "local"
client_path = "eonclient-custom"
number_of_cpus = 8
The local communicator starts each eonclient with UCX_MEM_EVENTS=no
unless the environment already sets that variable. An eonclient that
links MPI loads Unified Communication X on every run. A local client has
no MPI peers, so it never uses those memory hooks. Conda OpenMPI spends
about 0.4 s on them per process, against about 0.02 s for a one-call job.
In-process (type = local_lib / inprocess)¶
LocalInProcess runs jobs as pyeonclient.Matter in the server process.
There is no eonclient subprocess. It needs a build with
-Dwith_pyeonclient=true.
[Communicator]
type = "inprocess"
Dispatch follows Parameters.job:
Job |
What runs |
|---|---|
minimization (default) |
|
point |
energy / forces only |
process_search / saddle_search |
|
A job carries geometry as a Structure or a readcon.ConFrame
(structure, conframe, reactant, pos, or pos.con). .con text is
refused. The result dict returns product and, when a saddle exists,
saddle as ConFrame objects. Those frames are not written to disk.
_matter stays the potential-bearing client object and _structure the
numpy working set. results.dat is still synthesized as text so the classic
explorer can parse scalars.
The same record is the dict job_result. Its fields are
termination_reason (the status integer), termination_reason_text
(GOOD, FAIL, or cancelled), job_type, potential_energy, and
total_force_calls.
cancel_state returns 1 only while submit_jobs is inside a batch. That
call sets a token the next job sees, and a second token that a compiled
relax, band, or saddle search polls during the current call. A call while
no batch is running returns 0. The token is cleared when submit_jobs
returns.
Additional topics¶
Changed in version 2.0: Potentials which can be run in parallel, like those accessed through ASE (e.g. ORCA) are always run in parallel, for the others, there is little to no benefit for this additional overhead.
MPI¶
Note
Open MPI 5 on 3.4 ran an adaptive kinetic Monte Carlo check with one server rank and two client ranks.
The MPI communicator runs the server and the clients as one MPI job. The number of clients, and so the number of jobs in flight, comes from the MPI launch.
Build the client with -Dwith_mpi=enabled; the resulting eonclient only runs
under MPI. Two environment variables set the layout. EON_NUMBER_OF_CLIENTS
is how many ranks become clients, and EON_SERVER_PATH is a Python script
that starts the server. Launch the clients, not the server: one extra rank
turns into the server and runs that script. With [Communicator] type = mpi,
adaptive kinetic Monte Carlo, parallel replica, and basin hopping wait on
that communicator. examples/prd_mpi and examples/bh_mpi use this launch.
# server.py
import eon.server
eon.server.main()
#!/bin/bash
export EON_NUMBER_OF_CLIENTS=7
export EON_SERVER_PATH=$PWD/server.py
mpirun -n 8 /path/to/eonclient
This launch needs -Dwith_mpi=enabled, the client/server program.
It does not need -Dwith_rgpot_mpi=enabled, which builds calculator groups.
mpirun -np 42 /path/to/eonclient
A client whose job fails, through a potential error, a config.ini it cannot
load or a job type it does not know, logs the error into that job’s directory
and hands the directory back without results.dat. The server logs
returned no results for it and the rank takes the next job.
Cluster¶
Warning
Not tested on 2.0
An example communicator section for the cluster communicator using the provided
sge scripts and a name prefix of al_diffusion_:
[Communicator]
type = "cluster"
name_prefix = "al_diffusion_"
script_path = "/home/user/eon/tools/clusters/sge"
The Slurm scripts in tools/clusters/slurm take their site options from
the environment of the server process. EON_SBATCH_ARGS sets extra
sbatch options (account, partition, nodes, tasks, time) and EON_CLIENT
the command each job runs, eonclient by default:
export EON_SBATCH_ARGS="-A myaccount -p cpu -N 1 --ntasks=48 -t 01:00:00"
export EON_CLIENT=eonclient
eon-server
[Communicator]
type = "cluster"
script_path = "/path/to/eon/tools/clusters/slurm"
A potential that needs several MPI ranks, such as CPMD behind ext_pot,
starts them from its wrapper inside the job (srun -n 48 cpmd.x ...); the
client itself stays one process. When a state reaches its confidence the
server cancels only the jobs still queued. Jobs that already finished are
harvested on the next pass and filtered by state.