Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,16 @@ measurements, reporting per-point log-errors and RMSE.
- `idt_criterion: max_dOHdt` (configurable: `max_dTdt`, `max_radical_dt`)
- `idt_sa_method: adjoint` (`brute_force` or `adjoint` for Cantera built-in SA)
- `experimental_idt_path` pointing to a YAML file with experimental data
- Experimental YAML format with citation, T/P/phi/idt fields
- Legacy experimental YAML with citation and T/P/phi/idt fields remains supported
- `experimental_idt_v1.yaml` shows direct per-point states, explicit units, SMILES
mole fractions, apparatus, source ignition definitions, uncertainty, DOI, and
record locator

Version 1 maps each composition SMILES to the configured RMG species by T3's
structural `T3Species` identity, then uses the existing configured-label to
Cantera-label lookup. An unmappable composition species or an absent OH/OH*/CH/CH*
target produces a typed refusal for that point. RCM points represent only the
post-compression constant-pressure state; volume histories are not supported here.


## Input reference
Expand Down
11 changes: 11 additions & 0 deletions docs/input_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,17 @@ t3:
# comparison (not optimization). See examples/idt_with_experiment/.
# default: null

# An unversioned experimental file retains the legacy citation + data[{T, P, phi, idt}]
# format and nearest-grid comparison under idt_criterion. A version: 1 file instead contains
# points with explicit temperature/pressure/IDT units, a normalized list of SMILES mole
# fractions, apparatus ('shock tube' or 'rapid compression machine'), ignition_definition,
# optional uncertainty, and source {doi, record}. Each point is simulated directly at its
# own state. Supported targets: pressure, temperature, OH, OH*, CH, CH*. Supported types:
# 'd/dt max', 'max', '1/2 max', 'd/dt max extrapolated'. Missing target species are refused;
# no ground-state or radical proxy is substituted. A target event that has not resolved by
# the integration horizon is also refused rather than scored from a truncated trace. See
# experimental_idt_v1.yaml in the example directory for a complete file.

# uncertainty analysis (optional block, T3 can run w/o UA)
# either local or global UA type must be specified to execute an UA
uncertainty:
Expand Down
16 changes: 16 additions & 0 deletions examples/idt_with_experiment/experimental_idt_v1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Versioned experimental IDT: each point is simulated at its own initial state.
version: 1
points:
- temperature: {value: 1100, units: K}
pressure: {value: 2, units: bar}
composition:
- {smiles: '[H][H]', mole_fraction: 0.04}
- {smiles: '[O][O]', mole_fraction: 0.02}
- {smiles: '[Ar]', mole_fraction: 0.94}
apparatus: shock tube
ignition_definition: {target: pressure, type: d/dt max}
idt: {value: 0.95, units: ms}
uncertainty: {value: 0.05, units: ms}
source:
doi: 10.0000/replace-with-source-doi
record: Table 2, mixture 1, point 3
156 changes: 156 additions & 0 deletions t3/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,162 @@ class IDTSAMethodEnum(str, Enum):
adjoint = 'adjoint'


class TemperatureUnitEnum(str, Enum):
"""Temperature units accepted by versioned experimental IDT files."""
K = 'K'
degC = 'degC'


class PressureUnitEnum(str, Enum):
"""Pressure units accepted by versioned experimental IDT files."""
Pa = 'Pa'
kPa = 'kPa'
MPa = 'MPa'
bar = 'bar'
atm = 'atm'


class TimeUnitEnum(str, Enum):
"""Time units accepted by versioned experimental IDT files."""
s = 's'
ms = 'ms'
us = 'us'
micro_s = 'micro-s'


class ExperimentalApparatusEnum(str, Enum):
"""Apparatus models supported for versioned experimental IDT points."""
shock_tube = 'shock tube'
rapid_compression_machine = 'rapid compression machine'


class IgnitionTargetEnum(str, Enum):
"""Signals supported as source-defined experimental ignition targets."""
pressure = 'pressure'
temperature = 'temperature'
OH = 'OH'
OH_star = 'OH*'
CH = 'CH'
CH_star = 'CH*'


class IgnitionTypeEnum(str, Enum):
"""Source-defined methods supported for locating ignition on a target trace."""
derivative_max = 'd/dt max'
maximum = 'max'
half_max = '1/2 max'
derivative_max_extrapolated = 'd/dt max extrapolated'


class ExperimentalIDTRefusalReason(str, Enum):
"""Typed reasons why an otherwise valid experimental point was not scored."""
unmappable_species = 'unmappable species'
target_species_absent = 'target species absent'
ignition_not_resolved = 'ignition not resolved'
simulation_failed = 'simulation failed'


class ExperimentalTemperature(BaseModel):
"""A temperature with explicit units."""
value: Annotated[float, Field(gt=0, allow_inf_nan=False)]
units: TemperatureUnitEnum
Comment thread
alongd marked this conversation as resolved.

class Config:
extra = 'forbid'


class ExperimentalPressure(BaseModel):
"""A pressure with explicit units."""
value: Annotated[float, Field(gt=0, allow_inf_nan=False)]
units: PressureUnitEnum

class Config:
extra = 'forbid'


class ExperimentalTime(BaseModel):
"""A positive time with explicit units."""
value: Annotated[float, Field(gt=0, allow_inf_nan=False)]
units: TimeUnitEnum

class Config:
extra = 'forbid'


class ExperimentalUncertainty(BaseModel):
"""A non-negative IDT uncertainty with explicit time units."""
value: Annotated[float, Field(ge=0, allow_inf_nan=False)]
units: TimeUnitEnum

class Config:
extra = 'forbid'


class ExperimentalCompositionEntry(BaseModel):
"""One SMILES-identified component of an experimental mole-fraction mixture."""
smiles: Annotated[str, Field(min_length=1)]
mole_fraction: Annotated[float, Field(gt=0, le=1, allow_inf_nan=False)]

class Config:
extra = 'forbid'


class ExperimentalIgnitionDefinition(BaseModel):
"""The source's target signal and rule for defining ignition."""
target: IgnitionTargetEnum
type: IgnitionTypeEnum

class Config:
extra = 'forbid'


class ExperimentalSourceReference(BaseModel):
"""A DOI and free-text locator for the source record."""
doi: Annotated[str, Field(min_length=1)]
record: Annotated[str, Field(min_length=1)]

class Config:
extra = 'forbid'


class ExperimentalIDTPoint(BaseModel):
"""One independently simulated version-1 experimental ignition-delay point."""
temperature: ExperimentalTemperature
pressure: ExperimentalPressure
composition: list[ExperimentalCompositionEntry]
apparatus: ExperimentalApparatusEnum
ignition_definition: ExperimentalIgnitionDefinition
idt: ExperimentalTime
uncertainty: ExperimentalUncertainty | None = None
source: ExperimentalSourceReference

class Config:
extra = 'forbid'

@field_validator('composition')
@classmethod
def validate_composition(cls, value):
"""Require a non-empty, unique, normalized mole-fraction composition."""
if not value:
raise ValueError('composition must contain at least one species')
smiles = [entry.smiles for entry in value]
if len(set(smiles)) != len(smiles):
raise ValueError('composition SMILES entries must be unique')
total = sum(entry.mole_fraction for entry in value)
if abs(total - 1.0) > 1e-6:
raise ValueError(f'composition mole fractions must sum to 1.0, got {total}')
return value


class ExperimentalIDTFile(BaseModel):
"""Version-1 per-point experimental ignition-delay input file."""
version: Literal[1]
points: list[ExperimentalIDTPoint]

class Config:
extra = 'forbid'


class T3Sensitivity(BaseModel):
"""
A class for validating input.T3.sensitivity arguments
Expand Down
Loading
Loading