Source code for EPWpy.EPWpy_run

#
from __future__ import annotations

__author__= "Sabyasachi Tiwari"
__copyright__= "Copyright 2024, EPWpy project"
__version__= "1.0"
__maintainer__= "Sabyasachi Tiwari"
__maintainer_email__= "sabyasachi.tiwari@austin.utexas.edu"
__status__= "Production"
__date__= "May 03, 2024"
import numpy as np
import os
import subprocess as sp
from EPWpy.utilities.printing import *
from EPWpy.utilities.write_job import *
#
[docs] class PyRun: """ The **PyRun** class provides an interface to execute external electronic structure and many-body codes such as **Quantum ESPRESSO (QE)** and **BerkeleyGW (BGW)** within the **EPWpy** framework. It can be used both as part of a higher-level EPWpy workflow or as a standalone runner to execute specific computational tasks. Parameters ---------- procs : int Number of processors to be used for the execution. env : str Type of execution environment. Typical values include: - `"mpirun"` for MPI execution, - `"srun"` for SLURM-based parallel runs, - `"ibrun"` for TACC systems, - `"local"` for serial runs. code : str Path to the executable code or command to run. For example: `"/path/to/pw.x"` or `"/path/to/bgw.x"`. Attributes ---------- env : str Environment command used to launch the executable. procs : int Number of processors assigned to the job. code : str Full path or command to the simulation code being executed. Examples -------- >>> from epwpy.run import PyRun >>> run_qe = PyRun(procs=8, env="mpirun", code="/path/to/pw.x") >>> run_qe <PyRun object for QE execution> Notes ----- - The class is primarily used internally by EPWpy to manage code execution for different simulation stages (DFT, DFPT, EPW, etc.). - In HPC environments, `env` should correspond to the launcher provided by the scheduler (e.g., `ibrun` on TACC or `srun` on SLURM systems). """ def __init__(self, procs, env, code): """ Initialize a new PyRun instance with the specified runtime configuration. Parameters ---------- procs : int Number of processors to use. env : str Type of execution environment (`mpirun`, `srun`, `ibrun`, etc.). code : str Path to the executable or command to be run. Returns ------- None Note ------- Every run requires a utility which needs to be provided usinf obj.util = pw.x """ self.procs = procs self.env = env self.code = code self.serial = True self.write = False
[docs] @decorated_progress def run_custom(self, folder='./custom', name='custom', util=None): """ Run a custom executable within the EPWpy environment. This method provides a flexible interface for executing any external code (e.g., a user-defined tool, a Quantum ESPRESSO utility, or a post-processing script) using the same EPWpy execution infrastructure. It automatically handles directory changes, input/output file naming, and command construction before delegating to :meth:`runner`. Parameters ---------- folder : str, optional Directory in which the calculation should be executed. Default is `'./custom'`. name : str, optional Base name of the input/output files. Default is `'custom'`, corresponding to `'custom.in'` and `'custom.out'`. util : str or None, optional Name of the executable or utility to run. If ``None``, attempts to use the value stored in :attr:`self.util`. Behavior -------- - Sets the working directory :attr:`self.dir` to `folder`. - Defines :attr:`self.filein` and :attr:`self.fileout` based on `name`. - Constructs :attr:`self.util` using either: * The provided `util` string, if specified. * The existing :attr:`self.util` if `util` is ``None``. - Invokes :meth:`runner` to execute or script-write the command. Returns ------- subprocess.Popen or None The process handle from :meth:`runner`, or ``None`` if the command is written to a script instead of executed. Raises ------ ValueError If both `util` and :attr:`self.util` are ``None``, meaning no executable is defined. Examples -------- >>> run = PyRun(procs=4, env='srun', code='/path/to/qe') >>> run.run_custom(folder='./pp', name='dos', util='dos.x') # Executes equivalent to: # srun -n 4 /path/to/qe/dos.x dos.in > dos.out Notes ----- - This method is useful for integrating third-party or auxiliary codes into automated EPWpy workflows. - If the environment variables (`self.env`, `self.procs`, etc.) are properly configured, `run_custom()` behaves identically to EPW-specific runners. """ if util is None: self.util = f'{util} ' + str(self.proc_set) + ' -in ' else: self.util = f'{util} ' self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' self.runner()
[docs] @decorated_progress def run_scf(self, folder='./scf', name='scf'): """ Run a self-consistent field (SCF) calculation using Quantum ESPRESSO. This method constructs and executes the SCF calculation command, automatically setting the parallelization options (`-nk` and `-nt`) based on user input or preconfigured processor settings. Parameters ---------- folder : str, optional Directory where the SCF calculation will be executed. Default is `'./scf'`. name : str, optional Base name for the input and output files. Default is `'scf'`, corresponding to `'scf.in'` and `'scf.out'`. Behavior -------- - Determines the number of k-point and thread pools from :meth:`set_processors` if :attr:`self.proc_set` is ``None``. - Constructs the Quantum ESPRESSO SCF command using `pw.x`. - Sets the execution directory (:attr:`self.dir`), input (:attr:`self.filein`), and output (:attr:`self.fileout`) filenames. - Calls :meth:`runner` to execute the command or write it to a script. Returns ------- subprocess.Popen or None The process handle from :meth:`runner`, or ``None`` if the job is written to a script instead of being executed directly. Notes ----- - Requires a properly configured Quantum ESPRESSO environment. - This is typically the first stage of an EPW workflow, preceding NSCF, PH, and EPW runs. - Uses `pw.x` as the default executable unless overridden by :attr:`self.proc_set`. Examples -------- >>> run = PyRun(procs=8, env='srun', code='/path/to/qe') >>> run.run_scf(folder='./scf', name='graphene_scf') # Executes equivalent to: # srun -n 8 /path/to/qe/pw.x -nk 4 -nt 2 -in graphene_scf.in > graphene_scf.out """ if self.proc_set is None: nt, nk = self.set_processors(self.procs) nt = int(nt) nk = int(nk) self.util = 'pw.x -nk ' + str(nk) + ' -nt ' + str(nt) + ' -in ' else: self.util = 'pw.x ' + str(self.proc_set) + ' -in ' self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' print("EPWpy_run.py: run_scf()") self.runner()
[docs] @decorated_progress def run_nscf(self, folder='./nscf', name='nscf'): """ Run a non-self-consistent field (NSCF) calculation using Quantum ESPRESSO. This method executes the NSCF stage, which computes the electronic structure on a denser k-point grid using the converged charge density from the SCF run. It constructs the appropriate `pw.x` command and runs it via :meth:`runner`. Parameters ---------- folder : str, optional Directory where the NSCF calculation will be executed. Default is `'./nscf'`. name : str, optional Base name for the input and output files. Default is `'nscf'`, corresponding to `'nscf.in'` and `'nscf.out'`. Behavior -------- - Determines the number of thread and k-point pools using :meth:`set_processors` if :attr:`self.proc_set` is ``None``. - Constructs the NSCF command using Quantum ESPRESSO’s `pw.x` executable. - Sets the execution directory (:attr:`self.dir`), input (:attr:`self.filein`), and output (:attr:`self.fileout`) file paths. - Calls :meth:`runner` to execute or write the NSCF command. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - The NSCF run should follow a completed SCF calculation in the same system folder. - This step is essential for generating the wavefunctions required for phonon or EPW calculations. - Uses `pw.x` by default, unless overridden via :attr:`self.proc_set`. Examples -------- >>> run = PyRun(procs=8, env='srun', code='/path/to/qe') >>> run.run_nscf(folder='./nscf', name='graphene_nscf') # Executes equivalent to: # srun -n 8 /path/to/qe/pw.x -nk 4 -nt 2 -in graphene_nscf.in > graphene_nscf.out """ if self.proc_set is None: nt, nk = self.set_processors(self.procs) nt = int(nt) nk = int(nk) self.util = 'pw.x -nk ' + str(nk) + ' -nt ' + str(nt) + ' -in ' else: self.util = 'pw.x ' + str(self.proc_set) + ' -in ' self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' self.runner()
[docs] @decorated_progress def run_bs(self, folder='./bs', name='bs'): """ Run a band structure (BS) calculation using Quantum ESPRESSO. This method executes the band structure step of a typical DFT workflow. It reads the converged charge density from a previous SCF calculation and computes eigenvalues along a predefined high-symmetry k-path. Parameters ---------- folder : str, optional Directory where the band structure calculation will be executed. Default is `'./bs'`. name : str, optional Base name for the input and output files. Default is `'bs'`, corresponding to `'bs.in'` and `'bs.out'`. Behavior -------- - If :attr:`self.proc_set` is ``None``, automatically determines the number of k-point and thread pools using :meth:`set_processors`. - Constructs the command line for Quantum ESPRESSO’s `pw.x` executable. - Sets the working directory (:attr:`self.dir`), input file (:attr:`self.filein`), and output file (:attr:`self.fileout`). - Executes the calculation via :meth:`runner`. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires a prior SCF calculation with a converged charge density file (`*.save`). - Typically used for generating electronic band structures along high-symmetry directions specified in the NSCF k-path. - Uses `pw.x` as the default executable unless overridden by :attr:`self.proc_set`. Examples -------- >>> run = PyRun(procs=8, env='srun', code='/path/to/qe') >>> run.run_bs(folder='./bs', name='graphene_bs') # Executes equivalent to: # srun -n 8 /path/to/qe/pw.x -nk 4 -nt 2 -in graphene_bs.in > graphene_bs.out """ if self.proc_set is None: nt, nk = self.set_processors(self.procs) nt = int(nt) nk = int(nk) self.util = 'pw.x -nk ' + str(nk) + ' -nt ' + str(nt) + ' -in ' else: self.util = 'pw.x ' + str(self.proc_set) + ' -in ' self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' self.runner()
[docs] @decorated_progress def run_ph(self, folder='./ph', name='ph'): """ Run a phonon calculation using Quantum ESPRESSO's ph.x module. This method executes the phonon calculation stage, which computes phonon frequencies, dynamical matrices, and related properties required for electron-phonon coupling analysis. It sets up the appropriate working directory, input/output files, and constructs the parallel execution command before calling :meth:`runner`. Parameters ---------- folder : str, optional Directory where the phonon calculation will be executed. Default is `'./ph'`. name : str, optional Base name of the input/output files. Default is `'ph'`, corresponding to `'ph.in'` and `'ph.out'`. Behavior -------- - If :attr:`self.proc_set` is ``None``, determines the number of thread and k-point pools using :meth:`set_processors`. - Constructs the execution command using `ph.x`, including the `-pd .true.` flag for parallel diagonalization. - Sets the working directory (:attr:`self.dir`), input file (:attr:`self.filein`), and output file (:attr:`self.fileout`). - Calls :meth:`runner` to execute or script-write the phonon job. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires a prior SCF/NSCF calculation for the converged charge density. - The `-pd .true.` flag enables parallel phonon calculations. - This step is essential for subsequent EPW calculations involving electron-phonon interactions. Examples -------- >>> run = PyRun(procs=8, env='srun', code='/path/to/qe') >>> run.run_ph(folder='./ph', name='graphene_ph') # Executes equivalent to: # srun -n 8 /path/to/qe/ph.x -pd .true. -nk 4 -nt 2 -in graphene_ph.in > graphene_ph.out """ if self.proc_set is None: nt, nk = self.set_processors(self.procs) nt = int(nt) nk = int(nk) self.util = 'ph.x -pd .true. -nk ' + str(nk) + ' -nt ' + str(nt) + ' -in ' else: self.util = 'ph.x ' + str(self.proc_set) + ' -in ' self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' self.runner()
[docs] @decorated_progress def run_pp(self, folder='./pp', name='pp'): """ Run a post-processing (PP) calculation using Quantum ESPRESSO's pp.x module. This method executes a generic post-processing step, which can be used to compute charge densities, potential maps, densities of states, or other derived quantities from previously calculated wavefunctions or densities. It sets up the appropriate working directory, input/output files, and constructs the execution command before delegating to :meth:`runner`. Parameters ---------- folder : str, optional Directory where the post-processing calculation will be executed. Default is `'./pp'`. name : str, optional Base name of the input/output files. Default is `'pp'`, corresponding to `'pp.in'` and `'pp.out'`. Behavior -------- - If :attr:`self.proc_set` is ``None``, builds a default serial or basic parallel `pp.x` command. - Otherwise, constructs the command using the specified processor setup. - Sets the working directory (:attr:`self.dir`), input file (:attr:`self.filein`), and output file (:attr:`self.fileout`). - Calls :meth:`runner` to execute or script-write the post-processing job. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires a prior SCF or NSCF calculation providing the necessary wavefunctions or densities. - The `pp.x` module is flexible; this runner assumes the user has prepared the input file (`pp.in`) appropriately for the desired analysis. Examples -------- >>> run = PyRun(procs=4, env='mpirun', code='/path/to/qe') >>> run.run_pp(folder='./pp', name='graphene_pp') # Executes equivalent to: # mpirun -np 4 /path/to/qe/pp.x -in graphene_pp.in > graphene_pp.out """ if self.proc_set is None: self.util = 'pp.x -in ' else: self.util = 'pp.x ' + str(self.proc_set) + ' -in ' self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' self.runner()
[docs] @decorated_progress def run_epw1(self, folder='./epw', name='epw1'): """ Execute the first stage of an EPW (Electron–Phonon Wannier) calculation. This method configures and runs the **EPW step 1** task, which typically computes the electron–phonon coupling matrix elements on coarse Brillouin-zone grids. It sets up the appropriate working directory, input/output filenames, and executable command, then delegates execution to the :meth:`runner` method. Parameters ---------- folder : str, optional Directory in which the EPW 1 calculation will be executed. Default is `'./epw'`. name : str, optional Base name of the EPW input/output files. Default is `'epw1'`, corresponding to input file `'epw1.in'` and output file `'epw1.out'`. Behavior -------- - Sets the working directory attribute :attr:`self.dir` to `folder`. - Defines :attr:`self.filein` and :attr:`self.fileout` using `name`. - Constructs :attr:`self.util`, the command to run `epw.x`, depending on whether :attr:`self.proc_set` is defined: * If :attr:`self.proc_set` is ``None``: builds ``epw.x -nk <nprocs> -in``. * Otherwise: uses the explicit process configuration stored in :attr:`self.proc_set`. - Calls :meth:`runner` to execute (or script-write) the command. Returns ------- subprocess.Popen or None The process handle from :meth:`runner`, or ``None`` if the run command is only written to a script. Notes ----- - Relies on pre-defined attributes such as :attr:`self.procs`, :attr:`self.env`, and :attr:`self.code`, which should be set before invoking this method. - Designed to integrate into EPWpy’s automated workflow; users normally call higher-level workflow functions rather than this routine directly. Examples -------- >>> run = PyRun(procs=8, env='mpirun', code='/path/to/qe') >>> run.proc_set = None >>> run.run_epw1(folder='./epw', name='epw1') # Executes equivalent to: # mpirun -np 8 /path/to/qe/epw.x -nk 8 -in epw1.in > epw1.out """ self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' if self.proc_set is None: nk = int(self.procs) self.util = f'epw.x -nk {nk} -in ' else: self.util = f'epw.x {self.proc_set} -in' self.runner()
[docs] @decorated_progress def run_abinit(self, folder='./abinit', name='abi'): """ Runner for abinit """ self.dir = folder nk = int(self.procs) self.filein = name+'.abi' self.fileout = name+'.log' self.util = 'abinit ' self.runner()
[docs] @decorated_progress def run_vasp(self, folder='./vasp', name=' ', flavor='std'): """ Runner for abinit """ self.dir = folder nk = int(self.procs) self.filein = name#+'.abi' self.fileout = 'output'#+'.log' self.util = f'vasp_{flavor}' self.runner()
[docs] @decorated_progress def run_epw2(self, folder='./epw', name='epw2'): """ Execute the second stage of an EPW (Electron–Phonon Wannier) calculation. This method launches **EPW step 2**, which typically performs fine-grid interpolation of electron–phonon coupling data, transport property calculations, or other post-processing tasks following EPW step 1. It configures the appropriate run parameters and calls the :meth:`runner` method to execute the job. Parameters ---------- folder : str, optional Directory where the EPW step 2 calculation will be executed. Default is `'./epw'`. name : str, optional Base name of the EPW input/output files. Default is `'epw2'`, corresponding to input file `'epw2.in'` and output file `'epw2.out'`. Behavior -------- - Sets the working directory attribute :attr:`self.dir` to `folder`. - Defines :attr:`self.filein` and :attr:`self.fileout` using `name`. - Constructs :attr:`self.util`, the EPW command string, depending on whether :attr:`self.proc_set` is defined: * If :attr:`self.proc_set` is ``None``: builds ``epw.x -nk <nprocs> -in``. * Otherwise: uses the explicit process setup stored in :attr:`self.proc_set`. - Calls :meth:`runner` to execute or write the command script. Returns ------- subprocess.Popen or None The process handle from :meth:`runner`, or ``None`` if the run command is only written to a job script. Notes ----- - Assumes that :attr:`self.procs`, :attr:`self.env`, :attr:`self.code`, and :attr:`self.proc_set` (if applicable) have been initialized. - Typically called automatically by higher-level EPWpy workflow managers after successful completion of :meth:`run_epw1`. Examples -------- >>> run = PyRun(procs=8, env='mpirun', code='/path/to/qe') >>> run.proc_set = None >>> run.run_epw2(folder='./epw', name='epw2') # Executes equivalent to: # mpirun -np 8 /path/to/qe/epw.x -nk 8 -in epw2.in > epw2.out """ self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' if self.proc_set is None: nk = int(self.procs) self.util = f'epw.x -nk {nk} -in ' else: self.util = f'epw.x {self.proc_set} -in' self.runner()
[docs] @decorated_progress def run_epw3(self, folder='./epw', name='epw3'): """ Runner for epw3 """ self.dir = folder nk = int(self.procs) self.filein = name+'.in' self.fileout = name+'.out' self.util = 'epw.x -nk '+str(nk)+' -in ' self.runner()
[docs] @decorated_progress def run_zg(self, folder='./zg', name='zg'): """ Run a ZG (Zeta-Gamma) calculation using the ZG.x executable. This method executes the ZG step of the workflow, which is typically used for specialized post-processing or analysis tasks defined by the ZG.x module. It sets up the working directory, input/output files, and constructs the execution command before delegating to :meth:`runner`. Parameters ---------- folder : str, optional Directory where the ZG calculation will be executed. Default is `'./zg'`. name : str, optional Base name for the input and output files. Default is `'zg'`, corresponding to `'zg.in'` and `'zg.out'`. Behavior -------- - Sets :attr:`self.dir`, :attr:`self.filein`, and :attr:`self.fileout`. - Constructs the command string :attr:`self.util` as `'ZG.x -in '`. - Calls :meth:`runner` to execute or script-write the ZG calculation. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires a properly prepared input file (`zg.in`) according to the ZG.x module specifications. - This runner does not currently support parallelization flags, but could be extended to include them if needed. Examples -------- >>> run = PyRun(procs=4, env='mpirun', code='/path/to/zg') >>> run.run_zg(folder='./zg', name='graphene_zg') # Executes equivalent to: # mpirun -np 4 /path/to/zg/ZG.x -in graphene_zg.in > graphene_zg.out """ self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' self.util = 'ZG.x -in ' self.runner()
[docs] @decorated_progress def run_q2r(self, folder='./ph', name='q2r'): """ Run a q2r calculation using Quantum ESPRESSO's q2r.x module. This method executes the q2r step, which converts dynamical matrices (computed by `ph.x`) from reciprocal space to real-space interatomic force constants. The output is typically used for phonon interpolation or subsequent electron-phonon calculations. Parameters ---------- folder : str, optional Directory where the q2r calculation will be executed. Default is `'./ph'`. name : str, optional Base name for the input/output files. Default is `'q2r'`, corresponding to `'q2r.in'` and `'q2r.out'`. Behavior -------- - Sets the working directory (:attr:`self.dir`), input file (:attr:`self.filein`), and output file (:attr:`self.fileout`). - Constructs the command string (:attr:`self.util`) as `'q2r.x -in '`. - Delegates execution or script-writing to :meth:`runner`. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires prior phonon calculations using `ph.x` to generate the necessary dynamical matrices. - The generated real-space force constants are essential for EPW or post-processing phonon calculations. Examples -------- >>> run = PyRun(procs=4, env='mpirun', code='/path/to/qe') >>> run.run_q2r(folder='./ph', name='graphene_q2r') # Executes equivalent to: # mpirun -np 4 /path/to/qe/q2r.x -in graphene_q2r.in > graphene_q2r.out """ self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' self.util = 'q2r.x -in ' self.runner()
[docs] @decorated_progress def run_dvscf_q2r(self, folder='./ph', name='dvscf_q2r'): """ Runner for dvscf_q2r """ self.dir=folder self.filein=name+'.in' self.fileout=name+'.out' self.util='dvscf_q2r.x -in ' self.runner()
[docs] @decorated_progress def run_postahc(self, folder='./ph', name='postahc'): """ Runner for postahc """ self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = 'postahc.x -in ' self.runner()
[docs] @decorated_progress def run_eps(self, folder='./eps', name='eps'): """ Runner for epsilon """ self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = 'epsilon_Gaus.x -in' self.runner()
[docs] @decorated_progress def run_nscf_tetra(self, folder='./nscf_tetra', name='nscf'): namein = name+'.in' nameout = name+'.out' nt, nk = self.set_processors(self.procs) nt = int(nt) nk = int(nk) self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' if self.proc_set is None: self.util = 'pw.x -nk '+str(nk)+' -nt '+str(nt)+' -in ' else: self.util = 'pw.x '+str(self.proc_set)+' -in ' #print("running nscf with "+str(nk)+' nk and '+str(nt)+" tasks") p1 = self.runner() if(self.serial): p1.wait()
[docs] @decorated_progress def run_bands(self, folder='./bs', name='bands'): """ Runner for bands """ self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = 'bands.x -in' #print("running post-proc bands") self.runner()
[docs] @decorated_progress def run_nscf2supercond(self, folder='./nscf', name='nscf2supercond'): """ Runner for nscf2supercond """ self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = '../EPW/bin/nscf2supercond.x -in' #print("running nscf2supercond to extract eigen energies") self.runner()
[docs] @decorated_progress def run_matdyn(self, folder='./ph', name='matdyn'): """ Run a matdyn calculation using Quantum ESPRESSO's matdyn.x module. This method executes the matdyn step, which calculates phonon frequencies and eigenvectors along a specified path in the Brillouin zone, producing phonon band structures and related properties. It is typically used after q2r to obtain interpolated phonon bands. Parameters ---------- folder : str, optional Directory where the matdyn calculation will be executed. Default is `'./ph'`. name : str, optional Base name for the input/output files. Default is `'matdyn'`, corresponding to `'matdyn.in'` and `'matdyn.out'`. Behavior -------- - Sets the working directory (:attr:`self.dir`), input file (:attr:`self.filein`), and output file (:attr:`self.fileout`). - Constructs the command string (:attr:`self.util`) as `'matdyn.x -in'`. - Calls :meth:`runner` to execute or script-write the matdyn calculation. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires prior q2r calculations to generate real-space force constants. - Produces interpolated phonon band structures, which can be used for plotting or electron-phonon calculations in EPW. Examples -------- >>> run = PyRun(procs=4, env='mpirun', code='/path/to/qe') >>> run.run_matdyn(folder='./ph', name='graphene_matdyn') # Executes equivalent to: # mpirun -np 4 /path/to/qe/matdyn.x -in graphene_matdyn.in > graphene_matdyn.out """ self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' self.util = 'matdyn.x -in' p1 = self.runner()
[docs] @decorated_progress def run_dynmat(self, folder='./ph', name='dynmat'): """ Run a dynmat calculation using Quantum ESPRESSO's dynmat.x module. This method executes the dynmat step, which computes the full dynamical matrices for the system, typically used for phonon analysis, lattice dynamics, and further post-processing. It is usually performed after SCF and NSCF calculations, and optionally after phonon (`ph.x`) runs. Parameters ---------- folder : str, optional Directory where the dynmat calculation will be executed. Default is `'./ph'`. name : str, optional Base name for the input/output files. Default is `'dynmat'`, corresponding to `'dynmat.in'` and `'dynmat.out'`. Behavior -------- - Sets the working directory (:attr:`self.dir`), input file (:attr:`self.filein`), and output file (:attr:`self.fileout`). - Constructs the command string (:attr:`self.util`) as `'dynmat.x -in'`. - Calls :meth:`runner` to execute or script-write the dynmat calculation. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires a prior SCF/NSCF calculation and, if applicable, phonon inputs. - Produces dynamical matrices used for phonon dispersion, EPW calculations, or other lattice dynamics analyses. Examples -------- >>> run = PyRun(procs=4, env='mpirun', code='/path/to/qe') >>> run.run_dynmat(folder='./ph', name='graphene_dynmat') # Executes equivalent to: # mpirun -np 4 /path/to/qe/dynmat.x -in graphene_dynmat.in > graphene_dynmat.out """ self.dir = folder self.filein = name + '.in' self.fileout = name + '.out' self.util = 'dynmat.x -in' p1 = self.runner()
[docs] @decorated_progress def run_phdos(self, folder='./ph', name='phdos'): self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = 'matdyn.x -in' #print("running phonon dos calculation") p1 = self.runner()
[docs] @decorated_progress def run_dos(self, folder='./nscf', name='dos'): """ Run DOS calculation using QE """ self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = 'dos.x -in' #print("running electron DOS calculation") p1 = self.runner()
[docs] @decorated_progress def run_pdos(self, folder='./nscf', name='pdos'): """ Run PDOS calculation """ self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = 'projwfc.x -in' #print("running electron PDOS calculation") p1 = self.runner()
[docs] @decorated_progress def run_fbw(self, folder='./fbw', name='fbw'): nk = int(self.procs) self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = 'epw.x -nk '+str(nk)+' -in ' #print("running FBW calculation") p1 = self.runner()
[docs] @decorated_progress def run_fbw_mu(self, folder='./fbw_mu', name='fbw_mu'): nk = int(self.procs) self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = 'epw.x -nk '+str(nk)+' -in ' #print("running FBW+mu calculation") p1 = self.runner()
[docs] @decorated_progress def run_epw_outerbands(self, folder='./epw_outerbands', name='epw_outerbands'): nk = int(self.procs) self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = 'epw.x -nk '+str(nk)+' -in ' #print("running epw calculation with Coulomb correction") p1 = self.runner()
[docs] @decorated_progress def run_nesting(self, folder='./nesting', name='nesting'): nk = int(self.procs) self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = 'epw.x -nk '+str(nk)+' -in ' #print("running nesting function calculation") p1 = self.runner()
[docs] @decorated_progress def run_phselfen(self, folder='./phselfen', name='phselfen'): nk = int(self.procs) self.dir = folder self.filein = name+'.in' self.fileout = name+'.out' self.util = 'epw.x -nk '+str(nk)+' -in ' p1 = self.runner()
[docs] @decorated_progress def run_wannier(self, folder='./wannier', name='win'): """ Runner for Wannier """ self.dir = folder name = name.replace('\'','') self.filein = name+'.win' self.fileout = name+'.wout' self.util = 'wannier90.x -pp ' serial = self.serial self.serial = True p1 = self.runner() self.filein = name+'.pw2wan' self.fileout = name+'.pw2wan.out' self.util = 'pw2wannier90.x -pd .true. -in' p1 = self.runner(changedir = False) self.filein = name self.util = 'wannier90.x' p1 = self.runner(changedir = False)
#self.serial=serial #self.runner()
[docs] def run_pw2bgw(self, folder=' ', name=None): """ Runner for pw2BGW """ self.dir = folder if(name !=None): pw2bgw = name else: pw2bgw = self.prefix self.filein = pw2bgw+'.pw2bgw' self.fileout = pw2bgw+'.out' self.util = 'pw2bgw.x -pd .true. -in' self.runner()
[docs] @decorated_progress def run_epsilon(self, folder=' ', name=None, flavor='cplx'): """ Run the epsilon calculation using the BGW (BerkeleyGW) epsilon module. This method executes the dielectric function calculation (`epsilon.x`) in BerkeleyGW. It computes the screened Coulomb interaction, which is essential for many-body perturbation theory calculations such as GW and excitonic properties. Parameters ---------- folder : str, optional Directory where the epsilon calculation will be executed. Default is a blank string `' '`, which indicates the current directory. name : str, optional Base name for the input/output files. If ``None``, defaults to `'epsilon'`. flavor : str, optional Flavor of the executable, typically `'cplx'` for complex or `'rpa'` for real calculations. Default is `'cplx'`. Behavior -------- - Sets the working directory (:attr:`self.dir`). - Determines the input (:attr:`self.filein`) and output (:attr:`self.fileout`) filenames based on `name`. - Constructs the execution command (:attr:`self.util`) for `epsilon.flavor.x`. - Calls :meth:`runner` to execute or script-write the epsilon calculation. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires prior GW-related input preparation (e.g., wavefunctions and screening files). - This runner supports different flavors of the executable (complex or real). - Typically used as the first step in a BerkeleyGW GW workflow. Examples -------- >>> run = PyRun(procs=8, env='mpirun', code='/path/to/bgw') >>> run.run_epsilon(folder='./epsilon', name='epsilon.inp', flavor='cplx') # Executes equivalent to: # mpirun -np 8 /path/to/bgw/epsilon.cplx.x -in epsilon.inp """ self.dir = folder if name is not None: eps_file = name else: eps_file = 'epsilon' self.filein = eps_file + '.inp' self.fileout = eps_file + '.out' self.util = 'epsilon.' + str(flavor) + '.x -in' self.runner()
[docs] @decorated_progress def run_sigma(self, folder=' ', name=None, flavor='cplx'): """ Run the sigma calculation using the BGW (BerkeleyGW) sigma module. This method executes the self-energy calculation (`sigma.x`) in BerkeleyGW. It computes the electron self-energy based on a prior dielectric screening calculation (epsilon) and wavefunctions, which is required for GW quasiparticle energy corrections. Parameters ---------- folder : str, optional Directory where the sigma calculation will be executed. Default is a blank string `' '`, indicating the current directory. name : str, optional Base name for the input/output files. If ``None``, defaults to `'sigma'`. flavor : str, optional Flavor of the executable, typically `'cplx'` for complex or `'rpa'` for real calculations. Default is `'cplx'`. Behavior -------- - Sets the working directory (:attr:`self.dir`). - Determines the input (:attr:`self.filein`) and output (:attr:`self.fileout`) filenames based on `name`. - Constructs the execution command (:attr:`self.util`) for `sigma.flavor.x`. - Calls :meth:`runner` to execute or script-write the sigma calculation. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires prior epsilon and wavefunction calculations. - This calculation provides the GW quasiparticle self-energy. - Supports different flavors of the executable (complex or real). Examples -------- >>> run = PyRun(procs=8, env='mpirun', code='/path/to/bgw') >>> run.run_sigma(folder='./sigma', name='sigma.inp', flavor='cplx') # Executes equivalent to: # mpirun -np 8 /path/to/bgw/sigma.cplx.x -in sigma.inp """ self.dir = folder if name is not None: sigma_file = name else: sigma_file = 'sigma' self.filein = sigma_file + '.inp' self.fileout = sigma_file + '.out' self.util = 'sigma.' + str(flavor) + '.x -in' self.runner()
[docs] @decorated_progress def run_sig2wan(self, folder=' ', name=None): """ Run the sigma-to-Wannier conversion using BGW's sig2wan module. This method executes the `sig2wan.x` program in BerkeleyGW, which converts the computed electron self-energy (sigma) into a format compatible with Wannier interpolation. This step is typically used to interface GW corrections with Wannier90 or EPW workflows. Parameters ---------- folder : str, optional Directory where the sig2wan calculation will be executed. Default is `' '`, indicating the current directory. name : str, optional Base name for the input/output files. If ``None``, defaults to `'sig2wan'`. Behavior -------- - Sets the working directory (:attr:`self.dir`). - Determines the input (:attr:`self.filein`) and output (:attr:`self.fileout`) filenames based on `name`. - Constructs the execution command (:attr:`self.util`) for `sig2wan.x`. - Calls :meth:`runner` to execute or script-write the sig2wan calculation. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires prior sigma calculations from `sigma.x`. - The output can be used in Wannier90 or EPW workflows for band structure interpolation including GW corrections. Examples -------- >>> run = PyRun(procs=8, env='mpirun', code='/path/to/bgw') >>> run.run_sig2wan(folder='./sig2wan', name='graphene_sig2wan') # Executes equivalent to: # mpirun -np 8 /path/to/bgw/sig2wan.x -in graphene_sig2wan.in > graphene_sig2wan.out """ self.dir = folder if name is not None: sig2wan_file = name else: sig2wan_file = 'sig2wan' self.filein = sig2wan_file + '.inp' self.fileout = sig2wan_file + '.out' self.util = 'sig2wan.x -in' self.runner()
[docs] @decorated_progress def run_kernel(self, folder=' ', name=None, flavor='cplx'): """ Run the kernel calculation using the BGW (BerkeleyGW) kernel module. This method executes the `kernel.x` program in BerkeleyGW, which computes the electron-hole interaction kernel required for solving the Bethe-Salpeter Equation (BSE). The kernel is essential for excitonic and optical properties calculations following GW and epsilon computations. Parameters ---------- folder : str, optional Directory where the kernel calculation will be executed. Default is `' '`, indicating the current directory. name : str, optional Base name for the input/output files. If ``None``, defaults to `'kernel'`. flavor : str, optional Flavor of the executable, typically `'cplx'` for complex or `'rpa'` for real calculations. Default is `'cplx'`. Behavior -------- - Sets the working directory (:attr:`self.dir`). - Determines the input (:attr:`self.filein`) and output (:attr:`self.fileout`) filenames based on `name`. - Constructs the execution command (:attr:`self.util`) for `kernel.flavor.x`. - Calls :meth:`runner` to execute or script-write the kernel calculation. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires prior epsilon and sigma calculations. - Produces the electron-hole kernel necessary for BSE excitonic calculations. - Supports different flavors of the executable (complex or real). Examples -------- >>> run = PyRun(procs=8, env='mpirun', code='/path/to/bgw') >>> run.run_kernel(folder='./kernel', name='graphene_kernel', flavor='cplx') # Executes equivalent to: # mpirun -np 8 /path/to/bgw/kernel.cplx.x -in graphene_kernel.in > graphene_kernel.out """ self.dir = folder if name is not None: kernel_file = name else: kernel_file = 'kernel' self.filein = kernel_file + '.inp' self.fileout = kernel_file + '.out' self.util = 'kernel.' + str(flavor) + '.x -in' self.runner()
[docs] @decorated_progress def run_absorption(self, folder=' ', name=None, flavor='cplx'): """ Run the absorption calculation using the BGW (BerkeleyGW) absorption module. This method executes the `absorption.x` program in BerkeleyGW, which computes the optical absorption spectrum of the system. It uses the previously computed electron-hole interaction kernel (from `kernel.x`) and quasiparticle energies (from `sigma.x`) to calculate excitonic effects and optical properties. Parameters ---------- folder : str, optional Directory where the absorption calculation will be executed. Default is `' '`, indicating the current directory. name : str, optional Base name for the input/output files. If ``None``, defaults to `'absorption'`. flavor : str, optional Flavor of the executable, typically `'cplx'` for complex or `'rpa'` for real calculations. Default is `'cplx'`. Behavior -------- - Sets the working directory (:attr:`self.dir`). - Determines the input (:attr:`self.filein`) and output (:attr:`self.fileout`) filenames based on `name`. - Constructs the execution command (:attr:`self.util`) for `absorption.flavor.x`. - Calls :meth:`runner` to execute or script-write the absorption calculation. Returns ------- subprocess.Popen or None The process handle returned by :meth:`runner` if executed, or ``None`` if the job is written to a script instead. Notes ----- - Requires prior kernel and sigma calculations. - Produces optical absorption spectra, including excitonic effects. - Supports different flavors of the executable (complex or real). Examples -------- >>> run = PyRun(procs=8, env='mpirun', code='/path/to/bgw') >>> run.run_absorption(folder='./absorption', name='graphene_abs', flavor='cplx') # Executes equivalent to: # mpirun -np 8 /path/to/bgw/absorption.cplx.x -in graphene_abs.in > graphene_abs.out """ self.dir = folder if name is not None: absorption_file = name else: absorption_file = 'absorption' self.filein = absorption_file + '.inp' self.fileout = absorption_file + '.out' self.util = 'absorption.' + str(flavor) + '.x -in' self.runner()
# @decorated_progress
[docs] def runner(self, changedir=True): """ Main execution routine for running external simulation executables. This method constructs and executes the appropriate command-line instruction to launch a target code (e.g., Quantum ESPRESSO, EPW, or BGW) based on the user-specified environment (`env`), number of processors, and runtime configuration. It supports parallel environments such as `mpirun`, `srun`, and `ibrun`, as well as serial execution. If a run script writer is active (`self.writer.script_params['write_script'] == True`), the method writes the command to a script instead of executing it. Parameters ---------- changedir : bool, optional Whether to change to the working directory (`self.dir`) before execution. Default is ``True``. Behavior -------- - If `self.env` is provided, constructs a parallel execution command based on the environment type (`mpirun`, `srun`, `ibrun`, etc.). - If no `env` is provided, assumes a direct serial run. - Redirects standard output to `self.fileout`. - When `self.writer.script_params['write_script']` is ``True``, writes the run command to a job script instead of executing. - When `self.serial` is ``True``, the process waits for completion (`p1.wait()`). Returns ------- subprocess.Popen A Popen process object representing the executed command, unless the command is only written to a script (in which case no process is launched). Raises ------ FileNotFoundError If `changedir=True` but `self.dir` does not exist. AttributeError If required attributes such as `self.code`, `self.util`, or `self.filein` are missing. Examples -------- >>> run = PyRun(procs=8, env='mpirun', code='/path/to/qe') >>> run.util = 'pw.x' >>> run.filein = 'scf.in' >>> run.fileout = 'scf.out' >>> process = run.runner() >>> process.wait() Notes ----- - The constructed command typically looks like: .. code-block:: bash mpirun -np 8 /path/to/qe/pw.x scf.in > scf.out - The method can be adapted for other HPC launchers by extending the `env` conditionals. - For debugging, verbosity levels control printed output: * `verbosity > 1` prints the command before execution * `verbosity > 2` appends real-time log following (`tail -f`) """ if (changedir == True): try: os.chdir(self.dir) except FileNotFoundError: pass cmd = None if self.env: if (self.env == 'mpirun'): cmd = f'{self.env} -np {self.procs} {self.code}/{self.util} {self.filein} > {self.fileout}' elif (self.env == 'srun'): cmd = f'{self.env} -n {self.procs} {self.code}/{self.util} {self.filein} > {self.fileout}' elif (self.env == 'ibrun'): cmd = f'{self.env} {self.code}/{self.util} {self.filein} > {self.fileout}' else: cmd = f'{self.env} {self.procs} {self.code}/{self.util} {self.filein} > {self.fileout}' else: cmd = f'{self.code}/{self.util} {self.filein} > {self.fileout}' """ Runner will not execute run command if type(self.script==dict) Checking if self.script==dict """ if (self.writer.script_params['write_script'] == True): print("EPWpy_run.py runner(): Script is writing") write_cmd = cmd.replace(self.code, '$QE') if (changedir == True): self.writer.write_execute(f'cd {self.dir}') self.writer.write_execute(write_cmd) else: # print("EPWpy_run.py runner(): Executing instead") if (self.verbosity > 1): print('running: ',cmd) #if (self.verbosity > 2): # cmd +=f'{cmd} | tail -f {self.fileout}' p1=sp.Popen(cmd, shell=True) if (self.env == 'serial'): p1=sp.Popen('/'+self.code+'/'+self.util+' '+self.filein+' > '+self.fileout, stdout=self.fileout, stderr=sp.STDOUT, universal_newlines=True, shell=True) if (self.serial): if self.verbosity > 2: for line in p1.stdout: print(line, end='') # live output p1.wait() return(p1)
[docs] def set_processors(self,procs): if (np.sqrt(procs)%2 == 0): return(np.sqrt(procs),np.sqrt(procs)) else: return(1,procs)