5.7 KiB
5.7 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Fortran stellar atmosphere modeling suite being refactored to Rust. Strategy: split Fortran into modules first, then incrementally rewrite in Rust.
- TLUSTY 208: Non-LTE stellar atmosphere calculator (~50,000 lines → 304 modules)
- SYNSPEC 54: Synthetic spectrum evaluator (~24,000 lines → 168 modules)
- Progress: ~318 Rust modules (290 in
tlusty/math, 28 insynspec/math)
Environment Variables
export TL208=/home/fmq/program/tlusty
export TLUSTY=$TL208/tl208-s54
export LINELIST=$TL208/linelist
export IRON=$TL208/irondata
export OPTABLES=$TL208/optables
Build Commands
Rust
cargo build # Debug build
cargo build --release # Release build
cargo test # Run all tests (includes Fortran comparison tests)
cargo test test_expo # Run specific test
Fortran
# Production (single file)
gfortran -O3 -fno-automatic -mcmodel=large -o tlusty/tlusty.exe tlusty/tlusty208.f
gfortran -O3 -fno-automatic -mcmodel=large -o synspec/synspec.exe synspec/synspec54.f
# Development (modular)
cd $TLUSTY/rust/tlusty/extracted && make # Output: build/tlusty_extracted
Fortran compile flags:
-mcmodel=large: Required for large COMMON blocks (>2GB address space)-fno-automatic: Static storage (old Fortran compatibility)- Never use
-ffixed-line-length-none: Breaks columns 73-80 handling
Rust Architecture
src/
├── lib.rs # Module exports
├── tlusty/ # TLUSTY implementation
│ ├── mod.rs # Module exports + runner
│ ├── data.rs # Static data arrays (BLOCK DATA)
│ ├── runner.rs # Main program skeleton (incomplete)
│ ├── math/ # Pure math functions (290 modules)
│ │ ├── ali/ # Accelerated Lambda Iteration
│ │ ├── atomic/ # Atomic physics
│ │ ├── continuum/ # Continuum opacity
│ │ ├── eos/ # Equation of state
│ │ ├── solvers/ # Linear equation solvers
│ │ ├── special/ # Special functions (expint, voigt, etc.)
│ │ └── ... # Other physics categories
│ ├── state/ # COMMON block translations as structs
│ │ ├── constants.rs # Physical/math constants, array dimensions
│ │ ├── config.rs # Runtime config
│ │ ├── atomic.rs # Atomic/ion/level data
│ │ ├── model.rs # Atmosphere model state (largest struct)
│ │ ├── arrays.rs # Main linear equation arrays
│ │ ├── iterat.rs # Iteration control
│ │ ├── alipar.rs # ALI arrays
│ │ └── odfpar.rs # ODF data
│ └── io/ # Fortran-compatible I/O
│ ├── reader.rs # Free-format input reader
│ ├── writer.rs # Formatted output
│ ├── model.rs # fort.7/fort.8 model files
│ ├── start.rs # Initialization
│ └── ... # Other I/O routines
└── synspec/ # SYNSPEC implementation
└── math/ # Math functions (28 modules)
Running Tests
Rust Tests
cargo test # All unit tests
cargo test --test fortran_comparison # Fortran comparison tests only
Fortran Integration Tests
# TLUSTY: H-He model test
cd $TLUSTY/tests/tlusty/hhe
$TLUSTY/tlusty/tlusty.exe < hhe35lt.5 > hhe35lt.6
cp fort.7 hhe35lt.7
diff hhe35lt.7 hhe35lt.7.bak
# SYNSPEC: spectrum test
cd $TLUSTY/tests/synspec/hhe
ln -sf $TLUSTY/data data
cp hhe35nl.7 fort.8
ln -sf fort.55.con fort.55
$TLUSTY/synspec/synspec.exe < hhe35nl.5
Refactoring Workflow
- Find pure functions: Check
$TLUSTY/rust/tlusty/extracted/_PURE_UNITS.txtfor units without COMMON dependencies - Choose category: Place in appropriate
src/tlusty/math/<category>/subdirectory - Translate: Create
<name>.rs, add to category'smod.rs - Verify: Add test case in
tests/fortran_comparison.rswith Fortran reference values
Key Architecture
TLUSTY COMMON blocks (mapped to src/tlusty/state/ structs):
BASICS.FOR→constants.rs: Array dimensions (MDEPTH=100,MFREQ=135000,MLEVEL=1134)ATOMIC.FOR→atomic.rs: Atomic masses, abundances, energy levelsMODELQ.FOR→model.rs: Temperature, density, populationsARRAY1.FOR→arrays.rs: Main linear equation arrays
SYNSPEC reads model atmosphere from fort.8, outputs spectrum to fort.7
File unit numbers (see src/tlusty/io/mod.rs):
- Unit 5: Standard input (fort.5)
- Unit 7: Model output (fort.7)
- Unit 8: Model input (fort.8)
Fortran → Rust Translation Notes
Critical patterns to avoid mistakes:
- Index conversion: Fortran 1-indexed → Rust 0-indexed.
arr(i)→arr[i-1],DO I=1,N→for i in 0..n - Expression precedence:
-LOG(X)is-(LOG(X)), notLOG(-X) - Decrementing loops: Use
isize/i32when loop variable may become negative - COMMON dependency: Check INCLUDE statements before assuming a function is pure
- Large structs: Functions with many COMMON dependencies use lifetime structs:
pub struct Params<'a> { pub input: &'a [f64], pub output: &'a mut [f64], } - Type inference:
(z1 - z2).powi(2)may fail; use(z1 - z2) * (z1 - z2) - Test tolerance: Polynomial approximations (Abramowitz-Stegun) need relaxed tolerance (~1e-7)