本文へ移動
cccskills
無料GitHub で公開

orca-uv-vis

Generate ORCA input files for TD-DFT UV-Vis calculations and parse/plot the resulting absorption spectrum. Use when the user asks about UV-Vis spectra, absorption spectra, TD-DFT calculations, excited state calculations in ORCA, or wants to plot results from an ORCA TD-DFT output file. Also trigger when the user mentions oscillator strengths, electronic transitions, or simulated UV-Vis.

日本語の概要は準備中です。原文の説明を表示しています。

Hello-QM/catgo-LRGスター 208(GitHub 208 + cccskills 0)

実行スコア 未検証

インストール方法を見る

含まれるファイル(1)

  • SKILL.md12.9 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

ORCA UV-Vis Calculation Pipeline

This skill covers two stages: generating an ORCA input file for a TD-DFT calculation, and post-processing the output to plot a Gaussian-broadened UV-Vis absorption spectrum.

Scope: Input generation, local post-processing, and (optionally) HPC submission via the CatGo workflow engine. The "Submitting to HPC" section below covers the proven Expanse flow. If the user is running on their own non-CatGo infrastructure, just generate the input file from the template in Stage 1 and skip the submission section.

Target version: ORCA 6.x. Output block layout in ORCA 5 is close but not identical; the parser below is written against the ORCA 6 format used by CatGo's own parser (server/catgo/utils/orca_output.py::OrcaUvVisOutput).

Stage 1: Input Generation

Before generating the input file, ask the user for:

  • XYZ geometry file path (assume already optimized; if the user hasn't optimized, route them to orca-opt first)
  • Solvent for CPCM (e.g. hexane, water, ethanol, dichloromethane, acetonitrile)
  • Charge and multiplicity (default to 0 1 if not specified)

Generate an ORCA input file with these fixed settings:

  • Functional: CAM-B3LYP
  • Basis set: DEF2-TZVP
  • Full TD-DFT (not TDA)
  • 30 roots
  • CPCM solvation inline on the keyword line
  • No RI / auxiliary basis
  • No special SCF convergence tricks

Template:

!CAM-B3LYP DEF2-TZVP CPCM(HEXANE)
%TDDFT
   NROOTS   30
END
%output jsongbwfile True jsonpropfile True end
*XYZFILE 0 1 geometry.xyz

Substitute the user's solvent, charge, multiplicity, and XYZ path. If the user provides inline coordinates instead of a file, use * XYZ <charge> <mult> followed by the coordinates and close with *.

The %output ... end line makes ORCA emit the JSON files OPI's Output.parse() consumes during post-processing (Stage 2). Keep it.

Building the %tddft block with OPI

OPI's BlockTddft exposes every TD-DFT knob (nroots, iroot, irootmult, maxdim, maxiter, etol, rtol, tda, lrcpcm, cpcmeq, donto, saveunrnatorb, spinflip, soc, socgrad, triplets, ...) as a typed Pydantic field. Bad keys raise at construction.

The catgo backend builds the route line, %pal, %maxcore, charge/multiplicity, and geometry from node params — it does not emit a %TDDFT block of its own. So OPI only contributes the %tddft and %output blocks here, which we paste into extra_blocks as text. Do not use Calculator.write_input() — that writes a full input file and would duplicate the route line / pal / geometry the backend already emits.

from opi.input.blocks import BlockTddft, BlockOutput

tddft_block = BlockTddft(nroots=30, tda=False, triplets=False, donto=True)
output_block = BlockOutput(jsongbwfile=True, jsonpropfile=True)

extra_blocks_text = tddft_block.format_orca() + "\n" + output_block.format_orca()
# Pass extra_blocks_text into the node's `extra_blocks` param.

format_orca() emits exactly one %...end block per call. The result for the snippet above is:

%tddft
    nroots 30
    tda False
    donto True
    triplets False
end
%output
    jsonpropfile True
    jsongbwfile True
end

TD-DFT with 30 roots at def2-TZVP is expensive — tell the user this is a heavy calculation and that they should expect to run it on a cluster or at least overnight on a workstation, not on a laptop.

Submitting to HPC (Expanse) — proven flow

Use this when the user wants the CatGo workflow engine to run the TD-DFT job on Expanse. Skip if they only want the input file.

Use catgo_workflow (graph-based), NOT catgo_workflow_engine (task-based). The graph-based tool auto-captures the viewer structure on create. Task-based add_task doesn't, so jobs fail with "No input structure provided". Param keys differ: graph-based uses method/basis, task-based uses orca_method/orca_basis.

1. Confirm structure is loaded and find session_id

catgo_view(action: "get_state")
curl -s http://localhost:8000/api/hpc/connections

Copy the session_id for host: login.expanse.sdsc.edu.

2. Create the workflow

catgo_workflow(action: "create", name: "UV-Vis CAM-B3LYP TD-DFT")

3. Add the TD-DFT node

Use the orca_uvvis node type, which has dedicated TD-DFT params (nroots, triplets, tda, donto, solvation, solvent, calc_type, aux_basis) plus the standard dispersion field. Do NOT use extra_keywords or extra_blocks — they are NOT read by the engine and are silently dropped.

catgo_workflow(action: "batch", workflow_id: "<wf_id>", operations: [
  {"op": "add_node", "node_type": "orca_uvvis", "label": "tddft",
   "params": {
     "software": "orca",
     "method": "CAM-B3LYP",
     "basis": "def2-TZVP",
     "calc_type": "tddft",
     "nroots": 30,
     "tda": false,
     "triplets": false,
     "donto": true,
     "solvation": "CPCM",
     "solvent": "hexane",
     "dispersion": "D4",
     "charge": 0,
     "multiplicity": 1,
     "num_cores": 16,
     "max_core_mb": 4000
   }},
  {"op": "connect", "from_id": "<structure_input_id>", "to_id": "tddft",
   "from_handle": "structure", "to_handle": "structure"}
])

Canonical UV-Vis node params (verified against server/workflow/engines/orca.py:244-268)

ParameterDefaultDescription
methodCAM-B3LYPFunctional
basisdef2-TZVPBasis set
dispersion(none)D4 | D3BJ | D3
calc_typetddfttddft or steom (STEOM-DLPNO-CCSD)
nroots10Number of excited states
tdatrueTamm-Dancoff approximation; pass false for full TD-DFT
tripletsfalseCompute triplet states
dontofalseNatural transition orbitals
solvationnoneCPCM | none
solventwaterAny ORCA-recognised solvent name
aux_basisdef2-TZVP/CAux basis (used by STEOM path)
num_cores / max_core_mb4 / 4000

4. Run with the full HPC run_config

TD-DFT with 30 roots at def2-TZVP is heavy — bump walltime and use shared or compute (debug caps at 30 min). Read server/templates/orca_generic.sh and pass its contents as default_template.

catgo_workflow(action: "run", workflow_id: "<wf_id>", run_config: {
  "execution_mode": "hpc",
  "default_session_id": "<expanse_session_id>",
  "base_work_dir": "/expanse/lustre/projects/sdp126/jyang25/ORCA/catgo",
  "default_job_params": {
    "nodes": 1, "ntasks": 16, "cpus_per_task": 1,
    "walltime": "12:00:00", "partition": "shared"
  },
  "cluster_configs": {
    "<expanse_session_id>": {
      "account": "sdp126",
      "partition": "shared",
      "module_loads": "module load cpu/0.17.3b\nmodule load gcc/10.2.0/npcyll4\nexport PATH=$HOME/openmpi-4.1.8/bin:$PATH\nexport LD_LIBRARY_PATH=$HOME/openmpi-4.1.8/lib:$LD_LIBRARY_PATH",
      "orca_dir": "/home/jyang25/orca_6_1_1_RRP8",
      "default_template": "<contents of server/templates/orca_generic.sh>",
      "default_job_params": {
        "nodes": 1, "ntasks": 16, "cpus_per_task": 1,
        "walltime": "12:00:00", "partition": "shared"
      }
    }
  }
})

The local-scratch template stages I/O to $TMPDIR/orca_$SLURM_JOB_ID and copies results back. Required on Expanse — Lustre kills ORCA's many-small-file I/O during the 30-root TD-DFT response solver.

5. Monitor

catgo_workflow(action: "status", workflow_id: "<wf_id>")

6. Pull files for post-processing

When status is COMPLETED, pull ORCA.out plus the JSON files OPI parses, then run the parser/plotter from Stage 2 below against the local copy:

mkdir -p ./local_run
for f in ORCA.out ORCA.property.json ORCA.json; do
  curl -s -X POST http://localhost:8000/api/hpc/files/read-content \
    -H 'Content-Type: application/json' \
    -d "{\"session_id\":\"<expanse_session_id>\",\"file_path\":\"<work_dir>/$f\"}" \
    > ./local_run/$f
done

Submission gotchas

  • catgo_workflow_engine.add_task doesn't auto-attach the viewer structure → "No input structure provided".
  • partition=workq (Shaheen default) is invalid on Expanse → use debug/shared/compute.
  • partition=debug capped at 30 min — TD-DFT/30-roots almost always needs more.
  • Missing account=sdp126 → "Invalid account or account/partition combination".
  • Missing module_loads + orca_dir → orca not on PATH; the response solver silently produces nothing.
  • After re-connecting to Expanse, the session_id changes — re-discover via /api/hpc/connections and update both default_session_id and the cluster_configs key.

Stage 2: Post-Processing

Reading the Spectrum via OPI

OPI surfaces the absorption spectrum as output.results_properties.geometries[-1].absorption_spectrum — a list[Spectrum] keyed by representation ("Length" / "Velocity") and pointgroup. This replaces the regex parser entirely:

  • The rfind-vs-find STEOM-DLPNO-CCSD workaround is unnecessary; the model returns one entry per (representation, pointgroup) and you pick the one you want.
  • The "STEOM rows have state labels, TD-DFT rows don't" branch is unnecessary; both produce the same Spectrum shape.
  • Bonus: ECD rotational strengths come for free at geometries[-1].ecd_spectrum.

Spectrum.excitationenergies is a list of rows; columns are unnamed in the model but the order for ORCA 6.1.1 is fixed at [energy_eV, energy_cm, wavelength_nm, fosc, |mu|^2]. The shared helper exposes this as UVVIS_COLS.

Reference Parser and Plotter

import sys
sys.path.insert(0, ".claude/skills")  # for the _shared helper
import numpy as np
import matplotlib.pyplot as plt
from _shared.orca_opi import parse_local, UVVIS_COLS


def parse_orca_tddft(work_dir="./local_run"):
    out = parse_local(work_dir)
    spectra = out.results_properties.geometries[-1].absorption_spectrum
    if not spectra:
        raise ValueError("No absorption_spectrum block found — check ORCA.property.json")
    # Prefer length representation; fall back to whatever's first.
    target = next((s for s in spectra if s.representation == "Length"), spectra[0])

    wl_col = UVVIS_COLS["wavelength_nm"]
    f_col = UVVIS_COLS["fosc"]
    wavelengths = np.array([row[wl_col] for row in target.excitationenergies])
    fosc = np.array([row[f_col] for row in target.excitationenergies])
    return wavelengths, fosc


def gaussian(x, center, height, sigma=15):
    return height * np.exp(-0.5 * ((x - center) / sigma) ** 2)


def plot_uv_vis(wavelengths, fosc, output_png="uv_vis_spectrum.png"):
    x = np.linspace(200, 800, 2000)
    spectrum = sum(gaussian(x, w, f) for w, f in zip(wavelengths, fosc))
    peak = spectrum.max()
    if peak > 0:
        spectrum = spectrum / peak

    fig, ax = plt.subplots(figsize=(8, 5))
    ax.plot(x, spectrum, color="#2563eb", linewidth=1.5, label="Broadened")
    f_peak = fosc.max() if fosc.size and fosc.max() > 0 else 1.0
    ax.vlines(wavelengths, 0, fosc / f_peak, color="#ef4444", alpha=0.7, label="Transitions")
    ax.set_xlabel("Wavelength (nm)")
    ax.set_ylabel("Normalized Absorbance")
    ax.set_xlim(200, 800)
    ax.set_ylim(0, 1.05)
    ax.legend(loc="upper right", frameon=False)
    fig.tight_layout()
    fig.savefig(output_png, dpi=150)
    print(f"Spectrum saved to {output_png}")


if __name__ == "__main__":
    work_dir = sys.argv[1] if len(sys.argv) > 1 else "./local_run"
    png_name = sys.argv[2] if len(sys.argv) > 2 else "uv_vis_spectrum.png"
    wl, f = parse_orca_tddft(work_dir)
    plot_uv_vis(wl, f, png_name)

Viewing the spectrum in the IDE

After plot_uv_vis(...) writes the PNG, surface it inline with the shared helper:

from _shared.orca_opi import show_png
show_png("uv_vis_spectrum.png", "UV-Vis spectrum")
# prints `![UV-Vis spectrum](uv_vis_spectrum.png)`

Then reply to the user with that markdown link so Claude Code renders the figure inline in chat.

Plotting Defaults

  • Wavelength grid: 200–800 nm, 2000 points
  • Gaussian broadening: σ = 15 nm in wavelength space (simple and visually reasonable for most organic chromophores; call out that eV-space broadening is more physically correct if the user cares about vibronic lineshapes)
  • Envelope normalized to max = 1
  • Sticks normalized by the maximum oscillator strength so they sit on the same axis as the envelope
  • Figure size 8×5, DPI 150
  • Colors: envelope #2563eb (blue), sticks #ef4444 (red) — matches CatGo's red-TS / blue-accent conventions

Requesting eV on the x-axis

If the user asks for eV instead of nm, convert via E_eV = 1240 / wavelength_nm and rebuild the x-grid from (e.g.) 1.5–6.5 eV. Broadening σ of ~0.3 eV is a sensible default in eV space.

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

コメント

ログインなしで書き込めます。使ってみた感想、質問、動かなかった環境などを気軽にどうぞ。

まだコメントはありません。最初のコメントを書いてみませんか。

送信するとすぐに公開されます。メールアドレスや電話番号などの個人情報は書かないでください。URL は 2 つまでです。

0 / 1000 文字

このフォームは reCAPTCHA で保護されており、Google のプライバシーポリシーと利用規約が適用されます。

同じリポジトリのスキル

abinit

無料

Generate and manage ABINIT DFT calculations. Use when the user requests ABINIT, or needs DFPT phonons, GW calculations, or BSE optical spectra.

日本語の概要は準備中です。原文の説明を表示しています。

Hello-QM/catgo-LRG2082026年10月23日 更新

Use when the user asks to place an adsorbate molecule on a surface, find adsorption sites, or set up a surface+adsorbate model for DFT.

日本語の概要は準備中です。原文の説明を表示しています。

Hello-QM/catgo-LRG2082026年10月23日 更新

Use when the user asks for adsorption energy, binding energy, or wants to compare how strongly a molecule binds to a surface.

日本語の概要は準備中です。原文の説明を表示しています。

Hello-QM/catgo-LRG2082026年10月23日 更新

Use when the user asks to analyze computational results: Gibbs free energy, OER/HER/CO2RR overpotentials, adsorption energy, convergence tests, DOS/d-band analysis, or Bader charge analysis.

日本語の概要は準備中です。原文の説明を表示しています。

Hello-QM/catgo-LRG2082026年10月23日 更新

Use AmberTools antechamber for molecular force field parameterization. Generates GAFF/GAFF2 parameters and AM1-BCC or RESP charges for use in AMBER or LAMMPS classical MD simulations.

日本語の概要は準備中です。原文の説明を表示しています。

Hello-QM/catgo-LRG2082026年10月23日 更新

atom-ops

無料

One-shot recipes for adding, deleting, moving, and replacing individual atoms in the active CatGo viewer structure. Use whenever the user asks to "add an atom", "delete atoms", "remove this atom", "move atom N", "replace H with Li", or any single-atom edit — including "add a hydrogen on top of atom 12" / "delete atoms 5–9" / "swap the oxygen at site 3 for fluorine". Skips the discovery loop (no need to list structure tools or check adsorption sites first); goes straight to the matching `catgo_structure` action. Triggers in Chinese on 加原子, 删原子, 减原子, 移动原子, 替换原子, 增加氢, 删除氧, 把 ... 换成 ....

日本語の概要は準備中です。原文の説明を表示しています。

Hello-QM/catgo-LRG2082026年10月23日 更新

Hello-QM のスキルをすべて見る

このスキルの問題を報告する