Theoretical calculation of the guess spectrum
This example shows how to generate theoretical initial parameter guesses using quantum-calculated transitions with DFTB+ as the backend. It loads the experimental spectrum to detect absorption bands for parameter initialization.
Note: The
sk_prefixparameter must point to the directory containing your locally downloaded Slater-Koster parameter files required by DFTB+. These are not included in the repository.
from pathlib import Path
from hqs_uv_vis.schema import default_angular_momentum, MoleculeStructure, WorkflowConfig
from hqs_uv_vis.api import AutoVibronicFitter
from hqs_uv_vis.preprocessing import SpectrumPreprocessor
from vibrofit.fitting.simple import detect_absorption_bands
from pydftb.io.parser import parse_xyzfile
def main() -> None:
print("\nStarting Theoretical Guess Generation Pipeline...")
DATA_DIR = Path(__file__).parent
xyz_path = DATA_DIR / "phthalimide.xyz"
molecule = MoleculeStructure(
symbols=parse_xyzfile(xyz_path)["symbols"],
coordinates=parse_xyzfile(xyz_path)["coordinates"],
)
print(f"✓ Loaded geometry containing {len(molecule.symbols)} atoms from {xyz_path.name}.")
config = WorkflowConfig(
band_types=["pekar", "pekar", "gaussian"],
peak_prominence=0.05,
dftb_command="dftb+",
# Must point to the directory containing your downloaded Slater-Koster files.
sk_prefix="/path/to/downloaded/slater-koster/3ob-3-1/", # Example path; update to your local location
angular_momentum=default_angular_momentum(parse_xyzfile(xyz_path)["symbols"]),
num_excitations=10,
wavelength_range_nm=(200.0, 800.0),
min_osc_strength=0.05,
)
exp_spectrum_path = DATA_DIR / "phthalimide_exp.npy"
fitter = AutoVibronicFitter(config)
print("\nPreprocessing Experimental Spectrum...")
preprocessor = SpectrumPreprocessor(exp_spectrum_path)
nu_exp, int_exp = preprocessor.get_conditioned_spectrum(smooth=False)
print("\nDetecting Absorption Bands...")
peak_nu_list = detect_absorption_bands(
nu_exp, int_exp, prominence_thresh=config.peak_prominence
)
print(f"✓ Found {len(peak_nu_list)} peaks: {[round(p, 1) for p in peak_nu_list]} cm⁻¹")
print("\nExecuting Quantum Calculations (or loading from cache)...")
run_hash = fitter.cache.generate_hash(molecule, config)
cached_data = fitter.cache.load_states(run_hash)
if cached_data:
print(f"✓ Cache HIT! Loaded quantum data. Hash: {run_hash}")
data = cached_data
else:
print(f"✓ Cache MISS. Launching quantum orchestrator. Hash: {run_hash}")
data = fitter.orchestrator.run_pipeline(molecule, debug=True)
fitter.cache.save_states(run_hash, data)
print("\nGenerating Theoretical Guesses...")
p0, bounds, theory_results = fitter.generate_theoretical_guesses(
data=data, peak_nu_list=peak_nu_list, nu_exp=nu_exp, debug=True
)
Results
Running the example produces the following initial guess parameters:
| Band | Type | A | S | nu0 / cm^-1 | Omega / cm^-1 | sigma0 / cm^-1 | delta / cm^-1 | sigma / cm^-1 |
|---|---|---|---|---|---|---|---|---|
| 1 | Pekar | 1.000 | 1.936 | 46511.628 | 1303.390 | 459.250 | 130.339 | - |
| 2 | Pekar | 1.000 | 1.000 | 47511.628 | 1300.000 | 300.000 | 50.000 | - |
| 3 | Gaussian | 1.000 | - | 47511.628 | - | - | - | 300.000 |
Copyright © 2026 HQS Quantum Simulations GmbH. All Rights Reserved.