dopingflow package
Submodules
dopingflow.bandgap module
- class dopingflow.bandgap.BandgapConfig(outdir: 'Path', skip_if_done: 'bool', cutoff: 'float', max_neighbors: 'int', n_workers: 'int', device: 'str', gpu_id: 'int', batch_size: 'int')
Bases:
object- batch_size: int
- cutoff: float
- device: str
- gpu_id: int
- max_neighbors: int
- n_workers: int
- outdir: Path
- skip_if_done: bool
- dopingflow.bandgap.run_bandgap(raw_cfg: dict[str, Any], root: Path, *, config_path: Path | None = None) None
Step 05: Predict bandgap (ALIGNN local model) for relaxed candidates.
- Selection:
If selected_candidates.txt exists in a composition folder -> use it
Else fallback to candidate_*/02_relax/POSCAR
- Outputs per composition folder:
bandgap_alignn_summary.csv
candidate_*/03_band/meta.json
- dopingflow.bandgap.run_bandgap_from_toml(config_path: Path) None
dopingflow.cli module
- dopingflow.cli.bandgap_cmd(config: Path = <typer.models.OptionInfo object>, verbose: bool = <typer.models.OptionInfo object>) None
Step 05: Predict bandgap for filtered relaxed candidates (ALIGNN).
- dopingflow.cli.collect_cmd(config: Path = <typer.models.OptionInfo object>, verbose: bool = <typer.models.OptionInfo object>) None
Step 07: Collect selected candidates into one CSV database.
- dopingflow.cli.filter_cmd(config: Path = <typer.models.OptionInfo object>, only: str | None = <typer.models.OptionInfo object>, force: bool = <typer.models.OptionInfo object>, window_meV: float | None = <typer.models.OptionInfo object>, topn: int | None = <typer.models.OptionInfo object>, verbose: bool = <typer.models.OptionInfo object>) None
Step 04: Filter relaxed candidates (window or top-N).
- dopingflow.cli.formation_cmd(config: Path = <typer.models.OptionInfo object>, verbose: bool = <typer.models.OptionInfo object>) None
Step 06: Compute formation energies using cached references.
- dopingflow.cli.generate_cmd(config: Path = <typer.models.OptionInfo object>, verbose: bool = <typer.models.OptionInfo object>) None
Step 01: Generate random doped structures.
- dopingflow.cli.refs_build_cmd(config: Path = <typer.models.OptionInfo object>, verbose: bool = <typer.models.OptionInfo object>) None
Step 00: Build/cache reference energies.
- dopingflow.cli.relax_cmd(config: Path = <typer.models.OptionInfo object>, verbose: bool = <typer.models.OptionInfo object>) None
Step 03: Relax scanned candidates with M3GNet Relaxer.
- dopingflow.cli.run_all_cmd(config: Path = <typer.models.OptionInfo object>, start: str = <typer.models.OptionInfo object>, stop: str = <typer.models.OptionInfo object>, only: str | None = <typer.models.OptionInfo object>, dry_run: bool = <typer.models.OptionInfo object>, filter_only: str | None = <typer.models.OptionInfo object>, force: bool = <typer.models.OptionInfo object>, window_meV: float | None = <typer.models.OptionInfo object>, topn: int | None = <typer.models.OptionInfo object>, verbose: bool = <typer.models.OptionInfo object>) None
Run the full pipeline in order, with optional step selection.
- Step keys:
refs -> generate -> scan -> relax -> filter -> bandgap -> formation -> collect
- dopingflow.cli.scan_cmd(config: Path = <typer.models.OptionInfo object>, verbose: bool = <typer.models.OptionInfo object>) None
Step 02: Symmetry-unique scan + M3GNet single-point energies (top-k).
dopingflow.collect module
- class dopingflow.collect.DBConfig(outdir: 'Path', skip_if_done: 'bool')
Bases:
object- outdir: Path
- skip_if_done: bool
- dopingflow.collect.read_bandgap_summary(path: Path) Dict[str, Dict[str, Any]]
- dopingflow.collect.read_filtered_table(path: Path) Dict[str, Dict[str, Any]]
- Parse ranking_relax_filtered.csv into:
candidate -> {“rank_relax_filtered”: int, “E_relaxed_eV_filtered”: float, “delta_e_eV”: float, “filter_mode”: str}
- Expected columns written by filtering.py:
rank_filtered, candidate, energy_relaxed_eV, delta_e_eV, …, filter_mode
- dopingflow.collect.read_formation_csv(path: Path) Dict[str, Dict[str, Any]]
formation_energies.csv written by formation.py.
We keep it as a fallback, but prefer candidate_*/04_formation/meta.json for rich info.
- dopingflow.collect.read_formation_meta(path: Path) Dict[str, Any]
candidate_*/04_formation/meta.json written by formation.py.
- dopingflow.collect.read_json(path: Path) dict | None
- dopingflow.collect.read_scan_ranking(path: Path) Dict[str, Dict[str, Any]]
- dopingflow.collect.read_selected_txt(path: Path) List[str]
- dopingflow.collect.run_collect(raw_cfg: dict[str, Any], root: Path, *, config_path: Path | None = None) Path
Step 07: Collect results into ONE flat CSV database (results_database.csv), ONLY for the filtered/selected candidates (Step 04 output).
- Selection priority:
selected_candidates.txt
ranking_relax_filtered.csv
- dopingflow.collect.run_collect_from_toml(config_path: Path) Path
- dopingflow.collect.safe_get(d: dict | None, *keys, default=None)
dopingflow.filtering module
- class dopingflow.filtering.FilterConfig(outdir: 'Path', mode: 'str', window_meV: 'float', max_candidates: 'int', skip_if_done: 'bool')
Bases:
object- max_candidates: int
- mode: str
- outdir: Path
- skip_if_done: bool
- window_meV: float
- dopingflow.filtering.run_filtering(raw_cfg: dict[str, Any], root: Path, *, only: str | None = None, force: bool = False, window_meV: float | None = None, topn: int | None = None) None
Step 04: filter relaxed candidates after Step 03.
- For each composition folder in [structure].outdir:
reads: ranking_relax.csv writes: ranking_relax_filtered.csv, selected_candidates.txt
- Filtering:
[filter].mode=”window”: keep candidates within window_meV above Emin
[filter].mode=”topn”: keep lowest-energy max_candidates
- dopingflow.filtering.run_filtering_from_toml(config_path: Path, *, only: str | None = None, force: bool = False, window_meV: float | None = None, topn: int | None = None) None
dopingflow.formation module
- class dopingflow.formation.FormationConfig(outdir: 'Path', host_species: 'str', anion_species: 'List[str]', skip_if_done: 'bool', normalize: 'str')
Bases:
object- anion_species: List[str]
- host_species: str
- normalize: str
- outdir: Path
- skip_if_done: bool
- dopingflow.formation.run_formation(raw_cfg: dict[str, Any], root: Path, *, config_path: Path | None = None) None
Step 06: Compute formation energies for relaxed (and optionally filtered) candidates.
- Reads:
E_doped from candidate_*/02_relax/meta.json (energy_relaxed_eV)
references from reference_structures/reference_energies.json
- Writes per composition folder:
formation_energies.csv
candidate_*/04_formation/meta.json
- dopingflow.formation.run_formation_from_toml(config_path: Path) None
dopingflow.generate module
- class dopingflow.generate.GenerateConfig(outdir: 'str', poscar_order: 'List[str]', seed_base: 'int', clean_outdir: 'bool', mode: 'str', host_species: 'str', compositions: 'List[Dict[str, float]]', dopants: 'List[str]', must_include: 'List[str]', max_dopants_total: 'int', allowed_totals: 'List[float]', levels: 'List[float]')
Bases:
object- allowed_totals: List[float]
- clean_outdir: bool
- compositions: List[Dict[str, float]]
- dopants: List[str]
- host_species: str
- levels: List[float]
- max_dopants_total: int
- mode: str
- must_include: List[str]
- outdir: str
- poscar_order: List[str]
- seed_base: int
- dopingflow.generate.build_structure_from_counts(pristine: Structure, host_species: str, dopant_counts: Dict[str, int], seed: int) Structure
- dopingflow.generate.composition_tag(effective_pct: Dict[str, float], must_first: List[str] | None = None) str
- dopingflow.generate.enumerate_compositions(dopants: List[str], must_include: List[str], max_dopants_total: int, allowed_totals: List[float], levels: List[float]) List[Dict[str, float]]
- dopingflow.generate.normalize_to_counts_and_effective(n_host: int, requested_pct: Dict[str, float]) tuple[Dict[str, int], Dict[str, float], List[str], float, float]
Convert requested dopant percentages (relative to host sites) into integer dopant counts by rounding to the nearest integer number of substitutions.
- dopingflow.generate.reorder_structure_by_species(s: Structure, order: List[str]) Structure
- dopingflow.generate.run_generate(raw_cfg: dict[str, Any], root: Path, *, config_path: Path | None = None) Path
Generate one random doped POSCAR per composition.
- Requires:
refs-build completed
reference_structures/reference_energies.json exists
relaxed host supercell POSCAR exists
- Output:
<outdir>/<tag>/POSCAR <outdir>/<tag>/metadata.json
- dopingflow.generate.run_generate_from_toml(config_path: Path) Path
- dopingflow.generate.stable_seed_from_tag(tag: str, seed_base: int) int
- dopingflow.generate.validate_composition_minimal(requested_pct: Dict[str, float]) None
dopingflow.logging module
- dopingflow.logging.setup_logging(root: Path, *, verbose: bool = False) Path
Configure logging for dopingflow.
Console output
Per-run log file
Noise suppression
dopingflow.refs module
- class dopingflow.refs.RefConfig(reference_mode: 'str', skip_if_done: 'bool', fmax: 'float', host: 'str', host_dir: 'Path', supercell: 'tuple[int, int, int]', metal_ref: 'List[str]', metals_dir: 'Path', oxides_ref: 'List[str]', oxides_dir: 'Path', gas_ref: 'str', gas_dir: 'Path', oxygen_mode: 'str', muO_shift_ev: 'float')
Bases:
object- fmax: float
- gas_dir: Path
- gas_ref: str
- host: str
- host_dir: Path
- metal_ref: List[str]
- metals_dir: Path
- muO_shift_ev: float
- oxides_dir: Path
- oxides_ref: List[str]
- oxygen_mode: str
- reference_mode: str
- skip_if_done: bool
- supercell: tuple[int, int, int]
- dopingflow.refs.run_refs_build(raw_cfg: dict[str, Any], root: Path, *, config_path: Path | None = None) Path
Build/cache relaxed reference energies needed for formation energy calculations.
- Outputs:
reference_structures/reference_energies.json
reference_structures/relaxed/host_unit_relaxed.POSCAR
reference_structures/relaxed/host_supercell_<a>x<b>x<c>_relaxed.POSCAR
reference_structures/relaxed/refs/<name>_relaxed.POSCAR for each reference
- dopingflow.refs.run_refs_build_from_toml(config_path: Path) Path
dopingflow.relax module
- class dopingflow.relax.RelaxConfig(fmax: 'float', n_workers: 'int', tf_threads: 'int', omp_threads: 'int', order: 'List[str]', outdir: 'Path', skip_if_done: 'bool', skip_candidate_if_done: 'bool', device: 'str', gpu_id: 'int')
Bases:
object- device: str
- fmax: float
- gpu_id: int
- n_workers: int
- omp_threads: int
- order: List[str]
- outdir: Path
- skip_candidate_if_done: bool
- skip_if_done: bool
- tf_threads: int
- dopingflow.relax.run_relax(raw_cfg: dict[str, Any], root: Path, *, config_path: Path | None = None) None
- Step 03: Relax candidates produced by Step 02.
- For each structure folder in [structure].outdir:
relax candidate_*/01_scan/POSCAR
write candidate_*/02_relax/POSCAR and meta.json
write ranking_relax.csv per structure folder
- dopingflow.relax.run_relax_from_toml(config_path: Path) None
dopingflow.scan module
- class dopingflow.scan.ScanConfig(poscar_in: 'str', topk: 'int', symprec: 'float', max_enum: 'int', n_workers: 'int', chunksize: 'int', order: 'List[str]', anion_species: 'List[str]', host_species: 'str', max_unique: 'int', skip_if_done: 'bool', device: 'str', gpu_id: 'int', mode: 'str', sample_budget: 'int', sample_batch_size: 'int', sample_patience: 'int', sample_seed: 'int', sample_max_saved: 'int')
Bases:
object- anion_species: List[str]
- chunksize: int
- device: str
- gpu_id: int
- host_species: str
- max_enum: int
- max_unique: int
- mode: str
- n_workers: int
- order: List[str]
- poscar_in: str
- sample_batch_size: int
- sample_budget: int
- sample_max_saved: int
- sample_patience: int
- sample_seed: int
- skip_if_done: bool
- symprec: float
- topk: int
- dopingflow.scan.run_scan(raw_cfg: dict[str, Any], root: Path, *, config_path: Path | None = None) None
- Step 02: For each structure folder in [structure].outdir:
exact mode: enumerate symmetry-unique dopant permutations on the cation sublattice
sample mode: randomly sample symmetry-unique dopant arrangements
evaluate single-point energy using M3GNet
keep top-k lowest energies
- dopingflow.scan.run_scan_from_toml(config_path: Path) None