ZacrosJob
*********

The "ZacrosJob" class represents a single zacros calculation. This
class is an extension of the PLAMS Job class and so it inherits all
its powerful features like e.g. being executed locally or submitted to
some external queueing system in a transparent way, or executing your
jobs in parallel with a predefined dependency structure. See all
configure possibilities on the PLAMS Job class documentation in this
link: PLAMS.Job.

The "ZacrosJob" class constructor requires a Settings object, and the
set of objects that defines the system, namely: lattice, mechanism,
and the cluster expansion Hamiltonian. See the following lines from
our example (see use case system)

   job = pz.ZacrosJob( settings=sett, lattice=lat,
                       mechanism=[CO_ads, O2_ads, CO_oxi],
                       cluster_expansion=[CO_p, O_p] )

   print(job)

In the previous code, we used the function print() to see the content
of the files that are going to be used with Zacros. This output
information is separated into 4 sections, each corresponding to the
zacros input files: "simulation_input.dat", "lattice_input.dat",
"energetics_input.dat", and "mechanism_input.dat".

   ---------------------------------------------------------------------
   simulation_input.dat
   ---------------------------------------------------------------------
   random_seed         953129
   temperature          500.0
   pressure               1.0

   snapshots                 on time       0.1
   process_statistics        on time       0.1
   species_numbers           on time       0.1
   event_report      off
   max_steps         infinity
   max_time          1.0

   n_gas_species    3
   gas_specs_names              CO           O2          CO2
   gas_energies        0.00000e+00  0.00000e+00 -2.33700e+00
   gas_molec_weights   2.79949e+01  3.19898e+01  4.39898e+01
   gas_molar_fracs     4.50000e-01  5.50000e-01  0.00000e+00

   n_surf_species    2
   surf_specs_names         CO*        O*
   surf_specs_dent            1         1

   finish
   ---------------------------------------------------------------------
   lattice_input.dat
   ---------------------------------------------------------------------
   lattice default_choice
     triangular_periodic 1.0 10 3
   end_lattice
   ---------------------------------------------------------------------
   energetics_input.dat
   ---------------------------------------------------------------------
   energetics

   cluster CO*_0-0
     sites 1
     lattice_state
       1 CO* 1
     site_types 1
     graph_multiplicity 1
     cluster_eng -1.30000e+00
   end_cluster

   cluster O*_0-0
     sites 1
     lattice_state
       1 O* 1
     site_types 1
     graph_multiplicity 1
     cluster_eng -2.30000e+00
   end_cluster

   end_energetics
   ---------------------------------------------------------------------
   mechanism_input.dat
   ---------------------------------------------------------------------
   mechanism

   step CO_adsorption
     gas_reacs_prods CO -1
     sites 1
     initial
       1 * 1
     final
       1 CO* 1
     site_types 1
     pre_expon  1.00000e+01
     activ_eng  0.00000e+00
   end_step

   step O2_adsorption
     gas_reacs_prods O2 -1
     sites 2
     neighboring 1-2
     initial
       1 * 1
       2 * 1
     final
       1 O* 1
       2 O* 1
     site_types 1 1
     pre_expon  2.50000e+00
     activ_eng  0.00000e+00
   end_step

   step CO_oxidation
     gas_reacs_prods CO2 1
     sites 2
     neighboring 1-2
     initial
       1 CO* 1
       2 O* 1
     final
       1 * 1
       2 * 1
     site_types 1 1
     pre_expon  1.00000e+20
     activ_eng  0.00000e+00
   end_step

   end_mechanism

When running the "ZacrosJob" calculation (see "run()" method), all
necessary input files for zacros are generated in the job directory
(see option "name" in the constructor), and Zacros is internally
executed. Then, all output files generated by Zacros are stored for
future reference in the same directory. The information contained in
the output files can be easily accessed by using the class
"ZacrosResults".


API
===

class ZacrosJob(lattice, mechanism, cluster_expansion, initial_state=None, restart=None, **kwargs)

   Create a new ZacrosJob object.

   * "lattice" -- Lattice containing the lattice to be used during the
     calculation.

   * "mechanism" -- Mechanism containing the mechanisms involed in the
     calculation.

   * "cluster_expansion" -- ClusterExpansion containing the list of
     Clusters to use during the simulation.

   * "initial_state" -- Initial state of the system. By default the
     simulation will use an empty lattice.

   * "settings" -- Settings containing the parameters of the Zacros
     calculation.

   * "name" -- A string containing the name of the job. All zacros
     input and output files are stored in a folder with this name. If
     not supplied, the default name is "plamsjob".

   * "restart" -- ZacrosJob object from which the calculation will be
     restarted

   get_input()

      It should generate the Zacros input file. But Zacros has several
      input files. So, we discourage using this function. On the other
      side, this function is also used as a hash to represent the job
      univocally. Because of that, we just return its string
      representation which contains all input files concatenated.

   get_simulation_input()

      Return a string with the content of simulation_input.dat.

   get_lattice_input()

      Return a string with the content of the lattice_input.dat file.

   get_energetics_input()

      Return a string with the content of the energetics_input.dat
      file.

   get_mechanism_input()

      Returns a string with the content of the mechanism_input.dat
      file

   get_initial_state_input()

      Returns a string with the content of the state_input.dat file

   get_restart_input()

      Returns a string with the content of the restart.inf file

   run(jobrunner: JobRunner | None = None, jobmanager: JobRunner | None = None, **kwargs) -> Results

      Run the job. Raises a "ZacrosExecutableNotFoundError" if the
      Zacros executable cannot be found.

   classmethod _check_zacros_executable()

      Checks if the Zacros executable is in the path, otherwise raises
      a "ZacrosExecutableNotFoundError"

   check()

      Look for the normal termination signal in the output. Note, that
      it does not mean your calculation was successful!

   surface_poisoned()

      Returns true in the case the "Warning code 801002" is find in
      the output.

   restart_aborted()

      Returns true in the case the "Restart aborted:" is find in the
      output.

   get_runscript()

      Generate a runscript for slurm

      "name" is taken from the class attribute "_command". "-n" flag
      is added if "settings.runscript.nproc" exists. "[>jobname.out]"
      is used based on "settings.runscript.stdout_redirect".

   classmethod load_external(path, settings=None, finalize=False, restart=None)

      Loads an "external job," a Zacros calculation that either was or
      was not managed by pyZacros. All input and output files produced
      during the calculation should be placed in one folder, and
      *path* should be the path to this folder. The name of the folder
      is used as the job name. Example:

         import scm.pyzacros as pz
         job = ZacrosJob.load_external( path="plams_workdir/plamsjob" )
         print(job)

      * "path" -- Path to the folder containing input and output files
        to restore.

      * "settings" -- The Settings object for the calculation
        ("self.settings") is loaded automatically from the path
        "path". However, by using this option "self.settings" will be
        replaced by "settings".

      * "finalize" -- If "finalize" is "False", the status of the
        returned job is *copied* and results will be restored too.
        Otherwise, results will not be restored, so the job will need
        to be executed again.

      * "restart" -- Selects the "ZacrosJob" to restart from
