mcpbeat

Rowan

jaechang-hits/rowan

Cloud quantum chemistry platform with Python SDK. Run geometry optimization, conformer generation, torsional scans, and energy minimization (DFT/semiempirical), and retrieve properties (dipole, partial charges, frontier orbitals) — no local QC software or HPC needed.

4k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
294
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/jaechang-hits/SciAgent-Skills --skill rowan

The instruction itself

23 sections, as written by the author

rowan

Overview

Rowan is a cloud quantum chemistry platform that exposes DFT and semiempirical calculations through a Python SDK (rowan). Submit calculations (geometry optimization, conformer generation, torsional scans, single-point energies) from Python scripts or Jupyter notebooks, and retrieve results — energies, geometries, partial charges, frontier orbital energies — without managing Gaussian, ORCA, or Psi4 installations. Rowan handles job queuing, execution, and storage. A free tier is available for academic and exploratory use.

When to Use

  • Geometry optimization of small molecules: Getting accurate equilibrium geometries for drug candidates, fragments, or building blocks using DFT.
  • Conformer generation with energy ranking: Generating and optimizing multiple conformers to identify the lowest-energy conformation for docking or property prediction.
  • Torsional potential scans: Mapping the energy profile along a rotatable bond to understand conformational preferences.
  • Quantum mechanical property calculation: Computing dipole moments, partial charges (Mulliken, ESP), HOMO/LUMO energies, and electrostatic potential surfaces.
  • Energy minimization before docking: Refining ligand geometries before input to structure-based docking tools (DiffDock, AutoDock Vina).
  • Comparing isomer stability: Calculating relative energies of tautomers, stereoisomers, or constitutional isomers.
  • For large-scale conformer screening (>1000 molecules), use RDKit's ETKDGv3 + MMFF (force field level, no cloud cost).
  • For protein-scale quantum mechanics/molecular mechanics (QM/MM), specialized packages like ORCA + CP2K are needed.

Prerequisites

  • Python packages: rowan (official Python SDK)
  • Account: Free account at https://rowan.chem.ucla.edu/ (academic) or https://rowanquantum.com/
  • API key: Set ROWAN_API_KEY environment variable after account creation
  • Data requirements: Molecular structures as SMILES strings or XYZ coordinate blocks
pip install rowan

# Set API key (add to .bashrc or .env)
export ROWAN_API_KEY="your_api_key_here"

Quick Start

import rowan

# Authenticate (uses ROWAN_API_KEY environment variable automatically)
client = rowan.RowanClient()

# Run geometry optimization of aspirin at GFN2-xTB level
job = client.compute(
    smiles="CC(=O)Oc1ccccc1C(=O)O",
    method="gfn2-xtb",
    tasks=["optimize"],
)
print(f"Job ID: {job.id}, Status: {job.status}")

# Wait for completion and retrieve energy
result = client.wait(job.id)
print(f"Energy: {result.energy:.6f} Hartree")
print(f"Optimized geometry atoms: {len(result.geometry.atoms)}")

Core API

Module 1: Client Initialization and Authentication

import rowan
import os

# Option 1: automatic (reads ROWAN_API_KEY env variable)
client = rowan.RowanClient()

# Option 2: explicit key
client = rowan.RowanClient(api_key=os.environ["ROWAN_API_KEY"])

print(f"Authenticated as: {client.user.email}")
print(f"Organization: {client.user.organization}")

Module 2: Geometry Optimization

Optimize a molecular geometry to the nearest local minimum.

import rowan

client = rowan.RowanClient()

# GFN2-xTB semiempirical (fast, good for conformer screening)
job_xtb = client.compute(
    smiles="CCc1ccc(cc1)NC(=O)C",    # paracetamol
    method="gfn2-xtb",
    tasks=["optimize"],
)
result_xtb = client.wait(job_xtb.id)
print(f"xTB optimized energy: {result_xtb.energy:.6f} Hartree")
print(f"Geometry: {len(result_xtb.geometry.atoms)} atoms")
# DFT optimization: B3LYP/6-31G* (accurate, slower)
job_dft = client.compute(
    smiles="CCc1ccc(cc1)NC(=O)C",
    method="b3lyp",
    basis_set="6-31g*",
    tasks=["optimize"],
    solvent="water",               # implicit solvent (SMD model)
)
result_dft = client.wait(job_dft.id)
print(f"B3LYP/6-31G* energy (water): {result_dft.energy:.6f} Hartree")
print(f"Dipole moment: {result_dft.dipole_moment:.3f} Debye")

Module 3: Conformer Generation

Generate multiple 3D conformers and rank by energy.

import rowan
import pandas as pd

client = rowan.RowanClient()

# Generate and optimize 10 conformers at GFN2-xTB level
job = client.compute(
    smiles="CC(C)CC1=CC=C(C=C1)C(C)C(=O)O",  # ibuprofen
    method="gfn2-xtb",
    tasks=["conformers"],
    n_conformers=10,
)
result = client.wait(job.id)

# Rank conformers by relative energy
conformers = result.conformers
df = pd.DataFrame([
    {"conformer_id": i,
     "energy_hartree":    c.energy,
     "rel_energy_kcal":   (c.energy - min(c2.energy for c2 in conformers)) * 627.509}
    for i, c in enumerate(conformers)
]).sort_values("rel_energy_kcal")

print(df.to_string(index=False))
print(f"\nLowest energy conformer ID: {df.iloc[0]['conformer_id']}")

Module 4: Torsional Scan

Map energy as a function of a dihedral angle.

import rowan
import numpy as np
import matplotlib.pyplot as plt

client = rowan.RowanClient()

# Scan the C-C=C-C dihedral of butene
job = client.compute(
    smiles="CC=CC",             # but-2-ene
    method="gfn2-xtb",
    tasks=["torsion_scan"],
    torsion_atoms=[0, 1, 2, 3],  # atom indices defining dihedral
    n_scan_points=36,             # 36 points = 10-degree steps
)
result = client.wait(job.id)

angles  = [point.angle  for point in result.torsion_scan]
energies = [point.energy for point in result.torsion_scan]
rel_e = [(e - min(energies)) * 627.509 for e in energies]  # convert to kcal/mol

fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(angles, rel_e, "o-", color="steelblue")
ax.set_xlabel("Dihedral angle (degrees)")
ax.set_ylabel("Relative energy (kcal/mol)")
ax.set_title("Torsional potential: but-2-ene C-C=C-C dihedral")
plt.tight_layout()
plt.savefig("torsion_scan.png", dpi=150)
print("Torsion scan saved -> torsion_scan.png")

Module 5: Single-Point Properties

Compute electronic properties at a fixed geometry (HOMO/LUMO, partial charges, ESP).

import rowan

client = rowan.RowanClient()

# Single-point DFT: get frontier orbital energies and partial charges
job = client.compute(
    smiles="c1ccccc1N",          # aniline
    method="b3lyp",
    basis_set="6-311+g**",
    tasks=["single_point", "partial_charges", "orbitals"],
)
result = client.wait(job.id)

print(f"HOMO energy: {result.homo_energy:.4f} eV")
print(f"LUMO energy: {result.lumo_energy:.4f} eV")
print(f"HOMO-LUMO gap: {result.lumo_energy - result.homo_energy:.4f} eV")
print(f"Dipole moment: {result.dipole_moment:.3f} Debye")

# Partial charges (Mulliken)
for i, (atom, charge) in enumerate(zip(result.geometry.atoms, result.partial_charges)):
    print(f"  Atom {i} ({atom.symbol}): {charge:+.4f} e")

Module 6: Batch Job Submission

Submit multiple molecules concurrently.

import rowan
import pandas as pd
from concurrent.futures import ThreadPoolExecutor, as_completed

client = rowan.RowanClient()

smiles_list = [
    ("aspirin",      "CC(=O)Oc1ccccc1C(=O)O"),
    ("caffeine",     "Cn1cnc2c1c(=O)n(c(=O)n2C)C"),
    ("paracetamol",  "CC(=O)Nc1ccc(O)cc1"),
    ("ibuprofen",    "CC(C)Cc1ccc(cc1)C(C)C(=O)O"),
]

def submit_and_wait(name, smiles):
    job = client.compute(smiles=smiles, method="gfn2-xtb", tasks=["optimize"])
    result = client.wait(job.id)
    return {"name": name, "smiles": smiles, "energy": result.energy}

results = []
with ThreadPoolExecutor(max_workers=4) as executor:
    futures = {executor.submit(submit_and_wait, n, s): n for n, s in smiles_list}
    for future in as_completed(futures):
        results.append(future.result())

df = pd.DataFrame(results)
df.to_csv("batch_energies.csv", index=False)
print(df)

Key Parameters

| Parameter | Module | Default | Range / Options | Effect |

|-----------|--------|---------|-----------------|--------|

| method | compute | required | "gfn2-xtb", "b3lyp", "wb97x-d", "mp2" | QC method; xTB is fastest, DFT is accurate, MP2 for correlation |

| basis_set | compute (DFT) | method-dependent | "6-31g*", "6-311+g**", "def2-svp", "def2-tzvp" | Basis set; larger = more accurate and slower |

| tasks | compute | required | ["optimize"], ["single_point"], ["conformers"], ["torsion_scan"] | What calculation to run |

| n_conformers | conformers task | 10 | 1100 | Number of conformers to generate and optimize |

| n_scan_points | torsion_scan | 36 | 1272 | Number of dihedral scan points (360/n gives step size) |

| solvent | compute | None | "water", "dmso", "methanol", etc. | Implicit SMD solvation model |

| torsion_atoms | torsion_scan | required | list of 4 atom indices | Defines the dihedral angle for the scan |

Best Practices

  • Use GFN2-xTB for screening, DFT for final characterization: xTB is 100–1000x faster than DFT and adequate for conformer ranking and geometry exploration. Switch to B3LYP or wB97X-D for accurate energetics, HOMO/LUMO gaps, and publishable results.
  • Always optimize geometry before computing properties: Single-point calculations on unrelaxed geometries (e.g., from SMILES 3D embedding) give unreliable energies and electronic properties. Run tasks=["optimize"] first.
  • Set solvent for biologically relevant molecules: Gas-phase energies often differ dramatically from solution-phase for charged or highly polar molecules. Use solvent="water" for drug candidates evaluated in aqueous conditions.
  • Poll job status for long DFT calculations: Use client.wait() with a timeout or poll with client.get_job(job_id).status in long-running batch workflows to avoid blocking.
  • Export optimized geometries as XYZ for reuse: Save the optimized geometry to avoid re-running costly DFT jobs when different property calculations are needed on the same structure.
   with open("optimized.xyz", "w") as f:
       f.write(result.geometry.to_xyz())

Common Workflows

Workflow 1: Conformer Search and Property Calculation

Goal: Find the lowest-energy conformer of a drug candidate and compute its electronic properties.

import rowan
import pandas as pd

client = rowan.RowanClient()
smiles = "CC(C)Cc1ccc(cc1)C(C)C(=O)O"   # ibuprofen

# Step 1: Generate and rank conformers at fast xTB level
conf_job = client.compute(
    smiles=smiles, method="gfn2-xtb", tasks=["conformers"], n_conformers=20
)
conf_result = client.wait(conf_job.id)
lowest_conf = min(conf_result.conformers, key=lambda c: c.energy)
print(f"Lowest conformer energy: {lowest_conf.energy:.6f} Hartree")

# Step 2: Refine with DFT and compute properties
dft_job = client.compute(
    xyz=lowest_conf.to_xyz(),      # use optimized xTB geometry as DFT start
    method="b3lyp",
    basis_set="6-31g*",
    tasks=["optimize", "partial_charges", "orbitals"],
    solvent="water",
)
dft_result = client.wait(dft_job.id)

print(f"B3LYP/6-31G* energy (water): {dft_result.energy:.6f} Hartree")
print(f"HOMO-LUMO gap: {dft_result.lumo_energy - dft_result.homo_energy:.4f} eV")
print(f"Dipole moment: {dft_result.dipole_moment:.3f} Debye")

Workflow 2: Relative Stability of Tautomers

Goal: Compare the energies of two tautomers to determine which is more stable in water.

import rowan

client = rowan.RowanClient()

tautomers = {
    "keto":   "CC(=O)CC(=O)C",     # acetylacetone keto form
    "enol":   "CC(=O)C=C(O)C",     # acetylacetone enol form
}

energies = {}
for name, smiles in tautomers.items():
    job = client.compute(
        smiles=smiles,
        method="b3lyp",
        basis_set="6-311+g**",
        tasks=["optimize"],
        solvent="water",
    )
    result = client.wait(job.id)
    energies[name] = result.energy
    print(f"{name}: {result.energy:.6f} Hartree")

delta_e_hartree = energies["enol"] - energies["keto"]
delta_e_kcal    = delta_e_hartree * 627.509
print(f"\nDelta E (enol - keto): {delta_e_kcal:.2f} kcal/mol")
print(f"More stable form: {'enol' if delta_e_kcal < 0 else 'keto'}")

Expected Outputs

  • result.energy — total electronic energy in Hartree
  • result.geometry — optimized 3D geometry (atoms + coordinates)
  • result.dipole_moment — scalar dipole moment in Debye
  • result.homo_energy, result.lumo_energy — frontier orbital energies in eV
  • result.partial_charges — list of per-atom charges in elementary charge units
  • result.conformers — list of conformer objects with individual energies
  • result.torsion_scan — list of (angle, energy) scan points

Common Recipes

Recipe: Quick Single-Point Energy

When to use: Compare relative energies of two conformers or reaction intermediates in one call.

import rowan

client = rowan.Client()

smiles_list = ["CC(=O)O", "C(=O)(O)C"]  # Acetic acid, two representations
jobs = []
for smi in smiles_list:
    job = client.compute(
        molecule=rowan.Molecule.from_smiles(smi),
        theory_level="gfn2-xtb",
        task="single_point",
    )
    jobs.append(job)

# Collect energies
for smi, job in zip(smiles_list, jobs):
    result = client.wait(job)
    print(f"{smi}: energy = {result.energy:.6f} Hartree")

Recipe: Check Running Job Status

When to use: Monitor a long-running optimization or conformer search without blocking.

import rowan, time

client = rowan.Client()
job = client.compute(
    molecule=rowan.Molecule.from_smiles("c1ccccc1"),
    theory_level="gfn2-xtb",
    task="optimize",
)
print(f"Job ID: {job.id}")

# Poll every 10 seconds (non-blocking)
for _ in range(30):
    status = client.status(job)
    print(f"Status: {status}")
    if status in ("completed", "failed"):
        break
    time.sleep(10)

result = client.get(job)
print(f"Final energy: {result.energy:.6f} Hartree")

Troubleshooting

| Problem | Cause | Solution |

|---------|-------|----------|

| AuthenticationError | API key not set or expired | Set ROWAN_API_KEY env variable; regenerate key at rowanquantum.com |

| Job stays in queued status | High server load on free tier | Wait or upgrade to paid tier; free tier may queue during peak hours |

| SCF not converged error | DFT self-consistent field failed | Try a smaller basis set; use method="gfn2-xtb" first to get a better starting geometry |

| ValueError: invalid SMILES | Malformed SMILES string | Validate with Chem.MolFromSmiles(smiles) using RDKit before submission |

| High energy after optimization | Geometry stuck in local minimum | Generate multiple conformers with tasks=["conformers"] and pick the lowest |

| Missing result.homo_energy | Orbital calculation not requested | Add "orbitals" to the tasks list |

References

How to use it

Copy the folder

Take jaechang-hits/rowan from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.

Install what it needs

The instructions reference pip. Without those the skill loads but fails at the first command.