重构6
This commit is contained in:
@@ -0,0 +1,427 @@
|
||||
# Fortran I/O 兼容层设计
|
||||
|
||||
## 目标
|
||||
|
||||
1. 读取与 Fortran 相同格式的输入文件
|
||||
2. 生成与 Fortran 相同格式的输出文件
|
||||
3. 便于 A/B 测试对比
|
||||
|
||||
## TLUSTY I/O 模式分析
|
||||
|
||||
### 单元号映射
|
||||
|
||||
| Fortran 单元 | 文件 | 用途 | 格式 |
|
||||
|-------------|------|------|------|
|
||||
| 5 | stdin | 输入命令 | 格式化 |
|
||||
| 6 | stdout | 进度/结果输出 | 格式化 |
|
||||
| 7 | fort.7 | 模型输出 | 格式化 |
|
||||
| 8 | fort.8 | 模型输入 | 格式化 |
|
||||
| 9 | fort.9 | 频率网格 | 格式化 |
|
||||
| 91-93 | 临时 | 内部暂存 | UNFORMATTED |
|
||||
|
||||
### 输入格式特点
|
||||
|
||||
```fortran
|
||||
! 自由格式读取(list-directed)
|
||||
READ(IBUFF,*) TEFF, GRAV ! 35000. 4.0
|
||||
|
||||
! 字符串用单引号
|
||||
READ(IBUFF,*) TYPION ! ' H 1'
|
||||
|
||||
! 行内注释用 !
|
||||
35000. 4.0 ! TEFF, GRAV
|
||||
```
|
||||
|
||||
### 输出格式特点
|
||||
|
||||
```fortran
|
||||
! FORMAT 语句控制
|
||||
WRITE(6,604) ION,TYPION(ION),N0I,N1I,NKI,IZ(ION)
|
||||
604 FORMAT(1H ,I3,2X,A4,6I6,1PD15.3)
|
||||
|
||||
! 科学计数法
|
||||
3.289007E+04 3.010526E+08 5.839922E-16
|
||||
```
|
||||
|
||||
## Rust 架构设计
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
src/
|
||||
├── io/
|
||||
│ ├── mod.rs # I/O 模块入口
|
||||
│ ├── reader.rs # Fortran 格式输入解析
|
||||
│ ├── writer.rs # Fortran 格式输出
|
||||
│ ├── units.rs # 单元号管理
|
||||
│ └── format.rs # FORMAT 语句模拟
|
||||
├── math/ # 纯计算(已有)
|
||||
└── main.rs # 入口点
|
||||
```
|
||||
|
||||
### 核心设计
|
||||
|
||||
#### 1. 输入解析器 (reader.rs)
|
||||
|
||||
```rust
|
||||
/// Fortran 风格的自由格式读取器
|
||||
pub struct FortranReader<R: BufRead> {
|
||||
inner: R,
|
||||
current_line: String,
|
||||
line_number: usize,
|
||||
}
|
||||
|
||||
impl<R: BufRead> FortranReader<R> {
|
||||
/// 读取一行,处理注释
|
||||
pub fn read_line(&mut self) -> io::Result<&str> {
|
||||
loop {
|
||||
self.current_line.clear();
|
||||
self.inner.read_line(&mut self.current_line)?;
|
||||
self.line_number += 1;
|
||||
|
||||
// 去除行内注释
|
||||
if let Some(pos) = self.current_line.find('!') {
|
||||
self.current_line.truncate(pos);
|
||||
}
|
||||
|
||||
let trimmed = self.current_line.trim();
|
||||
if !trimmed.is_empty() {
|
||||
return Ok(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 读取值(模拟 READ(*,*))
|
||||
pub fn read_values<T: FromFortran>(&mut self) -> io::Result<T> {
|
||||
let line = self.read_line()?;
|
||||
T::from_fortran_str(line)
|
||||
}
|
||||
}
|
||||
|
||||
/// 从 Fortran 字符串解析的 trait
|
||||
pub trait FromFortran: Sized {
|
||||
fn from_fortran_str(s: &str) -> io::Result<Self>;
|
||||
}
|
||||
|
||||
impl FromFortran for f64 {
|
||||
fn from_fortran_str(s: &str) -> io::Result<Self> {
|
||||
// 处理 Fortran 的 'D' 和 'E' 指数符号
|
||||
let s = s.to_uppercase().replace('D', "E");
|
||||
s.trim().parse().map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromFortran for bool {
|
||||
fn from_fortran_str(s: &str) -> io::Result<Self> {
|
||||
match s.trim().to_uppercase().as_str() {
|
||||
"T" | ".TRUE." => Ok(true),
|
||||
"F" | ".FALSE." => Ok(false),
|
||||
_ => Err(io::Error::new(io::ErrorKind::InvalidData, "invalid boolean")),
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 输出格式化器 (writer.rs)
|
||||
|
||||
```rust
|
||||
/// Fortran 格式输出写入器
|
||||
pub struct FortranWriter<W: Write> {
|
||||
inner: W,
|
||||
}
|
||||
|
||||
impl<W: Write> FortranWriter<W> {
|
||||
/// 按 FORMAT 规范写入
|
||||
pub fn write_formatted(&mut self, format: &FormatSpec, values: &[Value]) -> io::Result<()> {
|
||||
let output = format.apply(values);
|
||||
write!(self.inner, "{}", output)
|
||||
}
|
||||
|
||||
/// 写入科学计数法(模拟 1PD15.3)
|
||||
pub fn write_exp(&mut self, val: f64, width: usize, decimals: usize) -> io::Result<()> {
|
||||
let s = format_exp_fortran(val, width, decimals);
|
||||
write!(self.inner, "{}", s)
|
||||
}
|
||||
}
|
||||
|
||||
/// Fortran 风格的科学计数法
|
||||
fn format_exp_fortran(val: f64, width: usize, decimals: usize) -> String {
|
||||
if val == 0.0 {
|
||||
return format!("{:>width$}", "0.0", width = width);
|
||||
}
|
||||
|
||||
let abs_val = val.abs();
|
||||
let exp = abs_val.log10().floor() as i32;
|
||||
|
||||
// Fortran 格式: ±0.XXXXE±YY 或 ±0.XXXXD±YY
|
||||
let mantissa = val / 10f64.powi(exp);
|
||||
let sign = if val >= 0.0 { " " } else { "" };
|
||||
|
||||
format!("{sign}{mantissa:width$.decimals$}E{exp:+03}")
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. 单元号管理 (units.rs)
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter, Read, Write};
|
||||
|
||||
/// 文件单元管理器(模拟 Fortran 单元号)
|
||||
pub struct FortranUnits {
|
||||
units: HashMap<u8, Box<dyn UnitFile>>,
|
||||
}
|
||||
|
||||
trait UnitFile {
|
||||
fn as_reader(&mut self) -> Option<&mut dyn BufRead>;
|
||||
fn as_writer(&mut self) -> Option<&mut dyn Write>;
|
||||
}
|
||||
|
||||
impl FortranUnits {
|
||||
pub fn new() -> Self {
|
||||
let mut units = HashMap::new();
|
||||
|
||||
// 默认单元
|
||||
units.insert(5, Box::new(StdinUnit::new()) as Box<dyn UnitFile>);
|
||||
units.insert(6, Box::new(StdoutUnit::new()) as Box<dyn UnitFile>);
|
||||
|
||||
Self { units }
|
||||
}
|
||||
|
||||
/// 打开文件到指定单元
|
||||
pub fn open(&mut self, unit: u8, path: &str, status: OpenStatus) -> io::Result<()> {
|
||||
let file = File::open(path)?;
|
||||
let reader = BufReader::new(file);
|
||||
self.units.insert(unit, Box::new(FileReader { inner: reader }));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 读取
|
||||
pub fn read_line(&mut self, unit: u8) -> io::Result<String> {
|
||||
if let Some(u) = self.units.get_mut(&unit) {
|
||||
if let Some(reader) = u.as_reader() {
|
||||
let mut line = String::new();
|
||||
reader.read_line(&mut line)?;
|
||||
return Ok(line);
|
||||
}
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "unit not found"))
|
||||
}
|
||||
|
||||
/// 写入
|
||||
pub fn write(&mut self, unit: u8, data: &str) -> io::Result<()> {
|
||||
if let Some(u) = self.units.get_mut(&unit) {
|
||||
if let Some(writer) = u.as_writer() {
|
||||
return writer.write_all(data.as_bytes());
|
||||
}
|
||||
}
|
||||
Err(io::Error::new(io::ErrorKind::NotFound, "unit not found"))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. FORMAT 解析器 (format.rs)
|
||||
|
||||
```rust
|
||||
/// Fortran FORMAT 规范
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FormatSpec {
|
||||
items: Vec<FormatItem>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FormatItem {
|
||||
Integer { width: usize },
|
||||
Float { width: usize, decimals: usize, exponential: bool },
|
||||
String { width: usize },
|
||||
Char(char),
|
||||
Newline,
|
||||
Skip,
|
||||
}
|
||||
|
||||
impl FormatSpec {
|
||||
/// 解析 FORMAT 字符串
|
||||
/// 例如: "(I3,2X,A4,6I6,1PD15.3)"
|
||||
pub fn parse(s: &str) -> Result<Self, FormatError> {
|
||||
// 移除外层括号
|
||||
let s = s.trim_start_matches('(').trim_end_matches(')');
|
||||
|
||||
let mut items = Vec::new();
|
||||
let mut chars = s.chars().peekable();
|
||||
|
||||
while let Some(&c) = chars.peek() {
|
||||
match c {
|
||||
'I' | 'i' => items.push(Self::parse_int(&mut chars)?),
|
||||
'F' | 'f' => items.push(Self::parse_float(&mut chars)?),
|
||||
'E' | 'e' | 'D' | 'd' => items.push(Self::parse_exp(&mut chars)?),
|
||||
'A' | 'a' => items.push(Self::parse_string(&mut chars)?),
|
||||
'X' | 'x' => { chars.next(); items.push(FormatItem::Skip); }
|
||||
'/' => { chars.next(); items.push(FormatItem::Newline); }
|
||||
'1'..='9' => {
|
||||
let repeat = Self::parse_number(&mut chars)?;
|
||||
// 处理重复计数
|
||||
}
|
||||
_ => { chars.next(); }
|
||||
}
|
||||
}
|
||||
|
||||
Ok(FormatSpec { items })
|
||||
}
|
||||
|
||||
/// 应用格式到值
|
||||
pub fn apply(&self, values: &[Value]) -> String {
|
||||
let mut output = String::new();
|
||||
let mut val_idx = 0;
|
||||
|
||||
for item in &self.items {
|
||||
match item {
|
||||
FormatItem::Integer { width } => {
|
||||
if let Some(Value::Int(v)) = values.get(val_idx) {
|
||||
output.push_str(&format!("{:>width$}", v));
|
||||
val_idx += 1;
|
||||
}
|
||||
}
|
||||
FormatItem::Float { width, decimals, exponential } => {
|
||||
if let Some(Value::Float(v)) = values.get(val_idx) {
|
||||
if *exponential {
|
||||
output.push_str(&format_exp_fortran(*v, *width, *decimals));
|
||||
} else {
|
||||
output.push_str(&format!("{:>width$.decimals$}", v));
|
||||
}
|
||||
val_idx += 1;
|
||||
}
|
||||
}
|
||||
FormatItem::String { width } => {
|
||||
if let Some(Value::Str(s)) = values.get(val_idx) {
|
||||
output.push_str(&format!("{:<width$}", s));
|
||||
val_idx += 1;
|
||||
}
|
||||
}
|
||||
FormatItem::Char(c) => output.push(*c),
|
||||
FormatItem::Newline => output.push('\n'),
|
||||
FormatItem::Skip => output.push(' '),
|
||||
}
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 使用示例
|
||||
|
||||
```rust
|
||||
use tlusty::io::{FortranReader, FortranWriter, FortranUnits};
|
||||
use tlusty::math::some_calculation;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
// 初始化单元
|
||||
let mut units = FortranUnits::new();
|
||||
units.open(8, "model_input.dat", OpenStatus::Old)?;
|
||||
units.open(7, "model_output.dat", OpenStatus::Replace)?;
|
||||
|
||||
// 读取输入
|
||||
let reader = FortranReader::new(stdin().lock());
|
||||
let teff: f64 = reader.read_values()?;
|
||||
let grav: f64 = reader.read_values()?;
|
||||
|
||||
// 调用纯计算函数
|
||||
let result = some_calculation(teff, grav);
|
||||
|
||||
// 写入输出(Fortran 格式)
|
||||
let mut writer = FortranWriter::new(units.get_writer(7)?);
|
||||
writer.write_exp(result.temperature, 15, 3)?;
|
||||
writer.write_exp(result.pressure, 15, 3)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 1. 单元测试
|
||||
|
||||
```rust
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_format_exp() {
|
||||
assert_eq!(
|
||||
format_exp_fortran(3.289e4, 15, 3),
|
||||
" 3.289E+04"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_values() {
|
||||
let input = "35000. 4.0 ! TEFF, GRAV\n";
|
||||
let mut reader = FortranReader::new(input.as_bytes());
|
||||
|
||||
let teff: f64 = reader.read_values().unwrap();
|
||||
let grav: f64 = reader.read_values().unwrap();
|
||||
|
||||
assert_relative_eq!(teff, 35000.0);
|
||||
assert_relative_eq!(grav, 4.0);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 集成测试
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn test_hhe_model() {
|
||||
// 运行 Rust 版本
|
||||
let rust_output = run_tlusty_rust("tests/hhe/hhe35lt.5");
|
||||
|
||||
// 读取 Fortran 参考输出
|
||||
let fortran_output = fs::read_to_string("tests/hhe/hhe35lt.7.bak").unwrap();
|
||||
|
||||
// 对比
|
||||
assert_outputs_match(&rust_output, &fortran_output, tolerance=1e-6);
|
||||
}
|
||||
```
|
||||
|
||||
## 重构策略
|
||||
|
||||
对于有 I/O 的模块:
|
||||
|
||||
1. **分离 I/O 和计算**
|
||||
```rust
|
||||
// ❌ 混合
|
||||
pub fn read_and_calculate() -> Result {
|
||||
let input = read_from_file()?; // I/O
|
||||
let result = calculate(input); // 计算
|
||||
write_to_file(result)?; // I/O
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
// ✅ 分离
|
||||
pub fn calculate(input: Input) -> Output { ... } // 纯函数,可测试
|
||||
|
||||
pub fn run() -> Result {
|
||||
let input = read_from_file()?;
|
||||
let result = calculate(input);
|
||||
write_to_file(result)?;
|
||||
Ok(result)
|
||||
}
|
||||
```
|
||||
|
||||
2. **保持格式兼容**
|
||||
- 输入解析器必须接受 Fortran 格式
|
||||
- 输出必须与 Fortran 输出字节级兼容(用于 diff)
|
||||
|
||||
3. **渐进式重构**
|
||||
- 先实现纯计算部分
|
||||
- 后实现 I/O 包装层
|
||||
- 最后集成测试
|
||||
|
||||
## 实现优先级
|
||||
|
||||
1. **Phase 1**: 实现 `FortranReader`(输入解析)
|
||||
2. **Phase 2**: 实现 `FortranWriter`(输出格式化)
|
||||
3. **Phase 3**: 实现 `FortranUnits`(文件管理)
|
||||
4. **Phase 4**: 集成测试框架
|
||||
@@ -0,0 +1,185 @@
|
||||
# SYNSPEC 输入输出文件完整文档
|
||||
|
||||
## 概述
|
||||
|
||||
SYNSPEC 是光谱合成程序,使用 TLUSTY 计算的大气模型计算理论光谱。
|
||||
本文档记录 SYNSPEC 所有文件单元的用途、格式和内容。
|
||||
|
||||
**相关文档**: TLUSTY I/O 文件见 `docs/TLUSTY_IO_FILES.md`
|
||||
|
||||
---
|
||||
|
||||
## 第一部分:核心输入/输出
|
||||
|
||||
| 单元号 | 文件名 | 用途 | 方向 | 格式 | 说明 |
|
||||
|--------|--------|------|------|------|------|
|
||||
| **5** | stdin | 主输入 | 输入 | 格式化 | fort.55.lin 或 fort.55.con |
|
||||
| **6** | stdout | 标准输出 | 输出 | 格式化 | 进度和诊断信息 |
|
||||
| **7** | fort.7 | 光谱输出 | 输出 | 格式化 | 计算的谱 flux |
|
||||
| **8** | fort.8 / bfactors | 模型输入 | 输入 | 格式化 | 大气模型或 NLTE 系数 |
|
||||
|
||||
---
|
||||
|
||||
## 第二部分:谱线数据文件
|
||||
|
||||
| 单元号 | 文件名 | 用途 | 方向 | 格式 | 说明 |
|
||||
|--------|--------|------|------|------|------|
|
||||
| **3** | fort.3 | 分子线列表 | 输入 | 格式化 | 分子谱线列表文件名 |
|
||||
| **11** | fort.11 | Kurucz 线输出 | 输出 | 格式化 | 谱线数据输出 |
|
||||
| **12** | fort.12 | 二进制光谱 | 输出 | 格式化 | 谱线数据(二进制/格式化) |
|
||||
| **14** | fort.14 | 调试输出 | 输出 | 格式化 | 详细调试信息 |
|
||||
| **17** | fort.17 | 谱线选择 | 输出 | 格式化 | 选中的谱线列表 |
|
||||
| **19** | fort.19 | 原子线列表 | 输入 | 格式化 | 默认原子谱线列表 |
|
||||
|
||||
---
|
||||
|
||||
## 第三部分:轮廓/加宽文件
|
||||
|
||||
| 单元号 | 文件名 | 用途 | 方向 | 格式 | 说明 |
|
||||
|--------|--------|------|------|------|------|
|
||||
| **50** | fort.50 | Stark 轮廓 | 输出 | 格式化 | 氢 Stark 加宽数据 |
|
||||
| **56** | fort.56 | He 轮廓 | 输出 | 格式化 | 氦线轮廓数据 |
|
||||
| **57** | fort.57 | 分子线 | 输入 | 格式化 | 分子谱线列表 |
|
||||
|
||||
---
|
||||
|
||||
## 第四部分:控制/诊断文件
|
||||
|
||||
| 单元号 | 文件名 | 用途 | 方向 | 格式 | 说明 |
|
||||
|--------|--------|------|------|------|------|
|
||||
| **4** | fort.4 | 参数文件 | 输入 | 格式化 | 非标准参数文件 (NST) |
|
||||
| **55** | fort.55.lin/.con | 输入参数 | 输入 | 格式化 | 谱线/连续谱计算参数 |
|
||||
| **69** | fort.69 | 计时 | 输出 | 格式化 | 计算时间统计 |
|
||||
| **84** | fort.84 | 参数值 | I/O | 格式化 | 优化参数值 |
|
||||
| **95** | fort.95 | 线标识 | 输出 | 格式化 | 谱线标识信息 |
|
||||
|
||||
---
|
||||
|
||||
## 第五部分:原子数据文件
|
||||
|
||||
| 文件名 | 用途 | 说明 |
|
||||
|--------|------|------|
|
||||
| `./data/hydprf.dat` | 氢线轮廓 | H I Stark 加宽轮廓 |
|
||||
| `./data/he1prf.dat` | He I 轮廓 | He I 线轮廓数据 |
|
||||
| `./data/he2prf.dat` | He II 轮廓 | He II 线轮廓数据 |
|
||||
| `./data/h1.dat` | H I 能级 | 氢原子能级数据 |
|
||||
| `./data/he1.dat` | He I 能级 | 中性氦能级数据 |
|
||||
| `./data/he2.dat` | He II 能级 | 氦离子能级数据 |
|
||||
| `bfactors` | NLTE 系数 | NLTE 出发系数(替代 fort.8) |
|
||||
| `RBF.DAT` | 辐射场边界 | 辐射 bracketing 数据 |
|
||||
|
||||
---
|
||||
|
||||
## 第六部分:文件格式详解
|
||||
|
||||
### 6.1 fort.55.lin (谱线计算输入)
|
||||
|
||||
```fortran
|
||||
! Line 1: IFREQ=0, NFREQ, INLTE
|
||||
0 50 0
|
||||
! Line 2: IHYDPR, IHE1PR, IHE2PR (轮廓开关)
|
||||
1 0 0 0
|
||||
! Line 3: 不透明度开关
|
||||
0 0 0 0 0
|
||||
! Line 4: 其他开关
|
||||
1 1 0 0 0
|
||||
! Line 5: 分子开关
|
||||
0 0 0
|
||||
! Line 6: 波长范围和步长
|
||||
20 100000 10 0 0.0001 4
|
||||
! Line 7-8: 角度/通量选项
|
||||
0 0
|
||||
```
|
||||
|
||||
### 6.2 fort.55.con (连续谱计算输入)
|
||||
|
||||
```fortran
|
||||
! 与 fort.55.lin 结构相同,但 IFREQ=0 表示连续谱
|
||||
0 50 1
|
||||
1 0 0 0
|
||||
...
|
||||
```
|
||||
|
||||
### 6.3 fort.7 (光谱输出)
|
||||
|
||||
```fortran
|
||||
! 波长 flux
|
||||
3500.00 1.234E+14
|
||||
3501.00 1.235E+14
|
||||
...
|
||||
```
|
||||
|
||||
### 6.4 fort.8 / bfactors (模型输入)
|
||||
|
||||
与 TLUSTY fort.7 格式相同,包含:
|
||||
- 深度点数和参数
|
||||
- 质量深度数组
|
||||
- 温度、电子密度、质量密度、布居数
|
||||
|
||||
---
|
||||
|
||||
## 第七部分:有 I/O 的模块分析
|
||||
|
||||
| 模块 | 主要 I/O 操作 | 复杂度 |
|
||||
|------|--------------|--------|
|
||||
| **START** | 读取 fort.55 参数 | 中 |
|
||||
| **INIBL0** | 初始化输入 | 中 |
|
||||
| **NSTPAR** | 非标准参数 | 中 |
|
||||
| **HYDINI** | 氢线轮廓 | 低 |
|
||||
| **HE1INI** | He I 轮廓 | 低 |
|
||||
| **HE2INI** | He II 轮廓 | 低 |
|
||||
| **INPBF** | 读取 bfactors | 低 |
|
||||
| **MOLEQ** | 分子线列表 | 中 |
|
||||
| **OPDATA** | 不透明度数据 | 低 |
|
||||
| **RDATA** | 原子数据 | 低 |
|
||||
| **SIGAVS** | Stark 数据 | 低 |
|
||||
|
||||
---
|
||||
|
||||
## 第八部分:重构优先级
|
||||
|
||||
### 高优先级
|
||||
|
||||
| 文件 | 单元 | 用途 |
|
||||
|------|------|------|
|
||||
| fort.55.lin | 5 | 谱线计算参数 |
|
||||
| fort.55.con | 5 | 连续谱计算参数 |
|
||||
| fort.7 | 7 | 光谱输出 |
|
||||
| fort.8 | 8 | 模型输入 |
|
||||
|
||||
### 中优先级
|
||||
|
||||
| 文件 | 单元 | 用途 |
|
||||
|------|------|------|
|
||||
| fort.11 | 11 | Kurucz 线输出 |
|
||||
| fort.12 | 12 | 二进制光谱 |
|
||||
| fort.17 | 17 | 谱线选择 |
|
||||
|
||||
### 低优先级
|
||||
|
||||
| 文件 | 单元 | 用途 |
|
||||
|------|------|------|
|
||||
| fort.14 | 14 | 调试 |
|
||||
| fort.50 | 50 | Stark 轮廓 |
|
||||
| fort.56 | 56 | He 轮廓 |
|
||||
| fort.69 | 69 | 计时 |
|
||||
| fort.95 | 95 | 线标识 |
|
||||
|
||||
---
|
||||
|
||||
## 附录:测试文件清单 (tests/synspec/hhe/)
|
||||
|
||||
| 文件 | 大小 | 说明 |
|
||||
|------|------|------|
|
||||
| fort.55.lin | 231 B | 谱线计算参数 |
|
||||
| fort.55.con | 229 B | 连续谱计算参数 |
|
||||
| fort.7 | 56 B | 光谱输出 |
|
||||
| fort.8 | 45 KB | 模型输入 |
|
||||
| fort.11 | 307 B | Kurucz 线 |
|
||||
| fort.12 | 2.4 KB | 二进制光谱 |
|
||||
| fort.14 | 6.8 KB | 调试输出 |
|
||||
| fort.17 | 56 B | 谱线选择 |
|
||||
| fort.57 | 0 B | 分子线(空)|
|
||||
| fort.69 | 37 B | 计时 |
|
||||
| fort.84 | 352 B | 参数值 |
|
||||
| fort.95 | 1.6 KB | 线标识 |
|
||||
@@ -0,0 +1,249 @@
|
||||
# TLUSTY 输入输出文件完整文档
|
||||
|
||||
## 概述
|
||||
|
||||
TLUSTY 使用 Fortran 风格的文件单元号(Unit Numbers)进行 I/O 操作。
|
||||
本文档记录 TLUSTY 所有文件单元的用途、格式和内容。
|
||||
|
||||
**相关文档**: SYNSPEC I/O 文件见 `docs/SYNSPEC_IO_FILES.md`
|
||||
|
||||
---
|
||||
|
||||
## 第一部分:核心输入/输出
|
||||
|
||||
| 单元号 | 文件名 | 用途 | 方向 | 格式 | 说明 |
|
||||
|--------|--------|------|------|------|------|
|
||||
| **5** | stdin | 主输入文件 | 输入 | 格式化 | 命令行输入,包含所有模型参数 |
|
||||
| **6** | stdout | 标准输出 | 输出 | 格式化 | 进度信息、警告、错误消息 |
|
||||
| **7** | fort.7 | 模型输出 | 输出 | 格式化 | 最终模型数据(温度、密度、布居数) |
|
||||
| **8** | fort.8 | 模型输入 | 输入 | 格式化 | 初始模型或重启模型数据 |
|
||||
|
||||
---
|
||||
|
||||
## 第二部分:迭代输出
|
||||
|
||||
| 单元号 | 文件名 | 用途 | 方向 | 格式 | 说明 |
|
||||
|--------|--------|------|------|------|------|
|
||||
| **9** | fort.9 | 收敛历史 | 输出 | 格式化 | 每次迭代的温度、电子密度变化 |
|
||||
| **10** | fort.10 | 警告/慢收敛 | 输出 | 格式化 | 收敛问题诊断信息 |
|
||||
| **11** | fort.11 | 辐射压力 | 输出 | 格式化 | 深度点辐射压力数据 |
|
||||
| **12** | fort.12 | 模型快照 | 输出 | 格式化 | 迭代中间状态的模型数据 |
|
||||
| **13** | fort.13 | 通量输出 | 输出 | 格式化 | 频率点通量数据 |
|
||||
| **14** | fort.14 | 角度分布 | 输出 | 格式化 | 辐射强度角度分布 |
|
||||
|
||||
---
|
||||
|
||||
## 第三部分:状态/调试输出
|
||||
|
||||
| 单元号 | 文件名 | 用途 | 方向 | 格式 | 说明 |
|
||||
|--------|--------|------|------|------|------|
|
||||
| **16** | fort.16 | 能级布居详情 | 输出 | 格式化 | 详细布居数变化信息 |
|
||||
| **17** | fort.17 | 迭代模型 | 输出 | 格式化 | 迭代过程中的模型状态 |
|
||||
| **18** | fort.18 | 迭代日志 | 输出 | 格式化 | 迭代步骤日志(调试用) |
|
||||
| **20** | fort.20 | 备份模型 | 输出 | 格式化 | 模型备份(用于重启) |
|
||||
| **22** | fort.22 | 模型快照 | 输出 | 格式化 | 另一种格式的模型快照 |
|
||||
|
||||
---
|
||||
|
||||
## 第四部分:ODF/不透明度文件
|
||||
|
||||
| 单元号 | 文件名 | 用途 | 方向 | 格式 | 说明 |
|
||||
|--------|--------|------|------|------|------|
|
||||
| **40** | RBF.DAT | 辐射bracketing | 输入 | 格式化 | 辐射场参数文件 |
|
||||
| **82** | fort.82 | 谱线统计 | 输出 | 格式化 | 谱线频率范围统计 |
|
||||
| **84** | fort.84 | 参数值 | I/O | 格式化 | 参数优化值 |
|
||||
| **86** | fort.86 | 冷却率 | 输出 | 格式化 | 各深度点冷却率 |
|
||||
| **87** | fort.87 | 冷却分解 | 输出 | 格式化 | 按离子分解的冷却率 |
|
||||
| **88** | fort.88 | 冷却对比 | 输出 | 格式化 | 冷却率对比数据 |
|
||||
|
||||
---
|
||||
|
||||
## 第五部分:控制参数文件
|
||||
|
||||
| 单元号 | 文件名 | 用途 | 方向 | 格式 | 说明 |
|
||||
|--------|--------|------|------|------|------|
|
||||
| **44** | fort.44 | 收敛控制 | 输入 | 格式化 | 自定义收敛参数 |
|
||||
| **57** | (动态) | 准静态线数据 | 输入 | 格式化 | ALLARD 准静态线 |
|
||||
| **58** | (动态) | He 数据 | 输入 | 格式化 | 氦原子数据表 |
|
||||
| **59** | (动态) | He 数据 | 输入 | 格式化 | 氦原子数据表 |
|
||||
| **69** | fort.69 | 计时信息 | 输出 | 格式化 | 性能计时数据 |
|
||||
|
||||
---
|
||||
|
||||
## 第六部分:临时/暂存文件
|
||||
|
||||
| 单元号 | 文件名 | 用途 | 方向 | 格式 | 说明 |
|
||||
|--------|--------|------|------|------|------|
|
||||
| **91** | (SCRATCH) | 暂存1 | I/O | **无格式** | 二进制暂存 |
|
||||
| **92** | (SCRATCH) | 暂存2 | I/O | **无格式** | 二进制暂存 |
|
||||
| **93** | (SCRATCH) | 暂存3 | I/O | **无格式** | 二进制暂存 |
|
||||
|
||||
---
|
||||
|
||||
## 第七部分:原子数据文件
|
||||
|
||||
### 7.1 能级数据文件 (*.dat)
|
||||
|
||||
| 模式 | 示例文件 | 说明 |
|
||||
|------|---------|------|
|
||||
| `[元素][离子].dat` | h1.dat, he1.dat, c1.dat | 原子能级数据 |
|
||||
| `[元素][离子]_[n]+[m]lev.dat` | al2_20+9lev.dat | 自定义能级数 |
|
||||
| `[元素][离子]hyd.dat` | al4hyd.dat | 氢化物数据 |
|
||||
|
||||
### 7.2 光谱数据文件 (*.t)
|
||||
|
||||
| 模式 | 示例文件 | 说明 |
|
||||
|------|---------|------|
|
||||
| `[元素][离子].t` | c1.t, ca1.t, al1.t | Kurucz 光谱线数据 |
|
||||
|
||||
### 7.3 CIA 数据 (碰撞诱导吸收)
|
||||
|
||||
| 文件名 | 说明 |
|
||||
|--------|------|
|
||||
| `CIA_H2H.dat` | H₂-H 碰撞吸收 |
|
||||
| `CIA_H2H2.dat` | H₂-H₂ 碰撞吸收 |
|
||||
| `CIA_H2He.dat` | H₂-He 碰撞吸收 |
|
||||
| `CIA_HHe.dat` | H-He 碰撞吸收 |
|
||||
|
||||
### 7.4 Stark 加宽数据
|
||||
|
||||
| 文件名 | 说明 |
|
||||
|--------|------|
|
||||
| `lemke.dat` | Lemke H Stark 线宽 |
|
||||
| `tremblay.dat` | Tremblay H Stark 线宽 |
|
||||
| `laquasi.dat` | Lyman-α 准静态轮廓 |
|
||||
| `lbquasi.dat` | Lyman-β 准静态轮廓 |
|
||||
| `lgquasi.dat` | Lyman-γ 准静态轮廓 |
|
||||
| `lhquasi.dat` | Lyman 系其他线 |
|
||||
|
||||
### 7.5 其他数据文件
|
||||
|
||||
| 文件名 | 说明 |
|
||||
|--------|------|
|
||||
| `absopac.dat` | 吸收不透明度 |
|
||||
| `ioniz.dat` | 电离数据 |
|
||||
| `irwin_bc.dat` | Irwin 边界条件 |
|
||||
| `irwin_orig.dat` | Irwin 原始数据 |
|
||||
| `ptab.dat` | 压力表 |
|
||||
| `stab.dat` | 自由能表 |
|
||||
| `xenomorph.blue.dat` | XENOMORPH 蓝端 |
|
||||
| `xenomorph.red.dat` | XENOMORPH 红端 |
|
||||
| `RBF.DAT` | 辐射场边界 |
|
||||
|
||||
---
|
||||
|
||||
## 第八部分:文件格式详解
|
||||
|
||||
### 8.1 fort.5 (主输入)
|
||||
|
||||
```fortran
|
||||
35000. 4.0 ! TEFF, GRAV (有效温度K, log g)
|
||||
T T ! LTE, LTGRAY (LTE开关, 灰大气开关)
|
||||
'' ! 可选参数文件名(空=无)
|
||||
*-----------------------------------------------------------------
|
||||
* frequencies
|
||||
50 ! NFREAD (频率点数)
|
||||
*-----------------------------------------------------------------
|
||||
* data for atoms
|
||||
8 ! NATOMS (原子种类数)
|
||||
* mode abn modpf
|
||||
2 0 0 ! 模式, 丰度, 配分函数模式
|
||||
...
|
||||
*-----------------------------------------------------------------
|
||||
* data for ions
|
||||
*iat iz nlevs ilast ilvlin nonstd typion filei
|
||||
1 0 9 0 100 0 ' H 1' './data/h1.dat'
|
||||
...
|
||||
```
|
||||
|
||||
### 8.2 fort.7/fort.8 (模型文件)
|
||||
|
||||
```fortran
|
||||
! 头部: ND, NUMPAR
|
||||
70 3
|
||||
! 质量深度数组
|
||||
1.000E+00 9.500E-01 ... 1.000E-10
|
||||
! 每个深度点
|
||||
! TEMP(ID) ELEC(ID) DENS(ID) [TOTN(ID)] [POPUL(1..NLEVEL)]
|
||||
```
|
||||
|
||||
### 8.3 fort.9 (收敛历史)
|
||||
|
||||
```fortran
|
||||
RELATIVE CHANGES OF VECTOR PSI
|
||||
ITER ID TEMP NE POP RAD MAXIMUM ilev ifr
|
||||
1 70 1.23E-02 2.45E-01 1.00E+00 0.00E+00 2.45E-01 5 10
|
||||
...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 第九部分:有 I/O 的模块分析
|
||||
|
||||
| 模块 | 主要 I/O 操作 | 复杂度 |
|
||||
|------|--------------|--------|
|
||||
| **INITIA** | 打开所有输入文件 | 高 |
|
||||
| **OUTPUT** | 写入 fort.7, fort.12, fort.22 | 中 |
|
||||
| **READBF** | 读取原子数据文件 | 低 |
|
||||
| **PRSENT** | 打印进度到 fort.6 | 低 |
|
||||
| **TIMING** | 写入 fort.69 | 低 |
|
||||
| **OPFRAC** | 读取 ODF 文件 | 中 |
|
||||
| **INILAM** | 初始化谱线数据 | 高 |
|
||||
| **KURUCZ** | 读取 Kurucz 格式模型 | 中 |
|
||||
| **NSTPAR** | 读取非标准参数 | 中 |
|
||||
| **MOLEQ** | 分子数据处理 | 中 |
|
||||
| **OPDATA** | 读取不透明度数据 | 中 |
|
||||
| **RDATA** | 读取原子数据 | 低 |
|
||||
| **SIGAVE** | Stark 加宽数据 | 低 |
|
||||
|
||||
---
|
||||
|
||||
## 第十部分:重构优先级
|
||||
|
||||
### 高优先级(核心 I/O,必须实现)
|
||||
|
||||
| 文件 | 单元 | 用途 |
|
||||
|------|------|------|
|
||||
| fort.5 | 5 | 主输入 |
|
||||
| fort.6 | 6 | 标准输出 |
|
||||
| fort.7 | 7 | 模型输出 |
|
||||
| fort.8 | 8 | 模型输入 |
|
||||
|
||||
### 中优先级(诊断/中间文件)
|
||||
|
||||
| 文件 | 单元 | 用途 |
|
||||
|------|------|------|
|
||||
| fort.9 | 9 | 收敛历史 |
|
||||
| fort.11 | 11 | 辐射压力 |
|
||||
| fort.12 | 12 | 模型快照 |
|
||||
|
||||
### 低优先级(调试/可选)
|
||||
|
||||
| 文件 | 单元 | 用途 |
|
||||
|------|------|------|
|
||||
| fort.10 | 10 | 警告 |
|
||||
| fort.14 | 14 | 角度分布 |
|
||||
| fort.16-18 | 16-18 | 调试 |
|
||||
| fort.69 | 69 | 计时 |
|
||||
| fort.82,84,86-88 | | ODF 诊断 |
|
||||
|
||||
---
|
||||
|
||||
## 附录:测试文件清单 (tests/tlusty/hhe/)
|
||||
|
||||
| 文件 | 大小 | 说明 |
|
||||
|------|------|------|
|
||||
| hhe35lt.5 | 984 B | 输入文件 |
|
||||
| fort.7 | 45 KB | 模型输出 |
|
||||
| fort.8 | 45 KB | 模型输入 |
|
||||
| fort.9 | 139 KB | 收敛历史 |
|
||||
| fort.10 | 1.2 KB | 警告 |
|
||||
| fort.11 | 8 KB | 辐射压力 |
|
||||
| fort.12 | 45 KB | 模型快照 |
|
||||
| fort.14 | 96 KB | 角度分布 |
|
||||
| fort.17 | 4.7 KB | 迭代模型 |
|
||||
| fort.18 | 480 KB | 详细日志 |
|
||||
| fort.22 | 45 KB | 模型快照 |
|
||||
| fort.69 | 3.3 KB | 计时 |
|
||||
| fort.82 | 4.5 KB | 谱线统计 |
|
||||
| fort.84 | 1.9 KB | 参数值 |
|
||||
Reference in New Issue
Block a user