Validation¶
validation
¶
Validation module for PyFDS.
This module provides comprehensive validation for FDS simulations, including input sanitization, simulation-level validation, cross-reference checking, and execution configuration validation.
Examples:
>>> from pyfds.validation import validate_simulation
>>> result = validate_simulation(sim)
>>> if not result.is_valid:
... for error in result.errors:
... print(error)
Classes¶
BuiltinSpecies
¶
Bases: StrEnum
Built-in FDS species that don't require explicit definition.
These species IDs are predefined by FDS and can be referenced without creating a corresponding SPEC namelist.
BuiltinSurface
¶
Bases: StrEnum
Built-in FDS surfaces that don't require explicit definition.
These surface IDs are predefined by FDS and can be referenced without creating a corresponding SURF namelist.
Severity
¶
Bases: StrEnum
Validation issue severity levels.
Issue
dataclass
¶
A validation issue.
| ATTRIBUTE | DESCRIPTION |
|---|---|
severity |
Issue severity level (ERROR, WARNING, INFO)
TYPE:
|
message |
Human-readable description of the issue
TYPE:
|
namelist |
FDS namelist name where issue was found
TYPE:
|
field |
Field name where issue was found
TYPE:
|
ValidationResult
dataclass
¶
CrossReferenceValidator
¶
Validates cross-references between FDS namelists.
Provides more detailed reference checking than the main SimulationValidator, including: - RAMP references from SURF and MATL - BURN_AWAY surface configurations - HT3D configurations
| RETURNS | DESCRIPTION |
|---|---|
ValidationResult
|
Result containing all validation issues found. |
Source code in src/pyfds/validation/cross_references.py
Functions¶
validate
¶
Run all cross-reference validations.
| RETURNS | DESCRIPTION |
|---|---|
ValidationResult
|
Validation result containing all issues found. |
Source code in src/pyfds/validation/cross_references.py
ExecutionValidator
¶
Validates parallel execution configuration.
Checks MPI process count, OpenMP thread count, and provides recommendations for optimal performance.
Based on FDS User Guide Chapter 3 "Running FDS" guidelines for optimal parallel performance.
Source code in src/pyfds/validation/execution.py
Functions¶
validate
¶
Validate parallel configuration.
| PARAMETER | DESCRIPTION |
|---|---|
simulation
|
Simulation to validate
TYPE:
|
n_mpi
|
Number of MPI processes
TYPE:
|
n_threads
|
Number of OpenMP threads per process
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
ValidationResult
|
Validation result containing any issues found. |
Source code in src/pyfds/validation/execution.py
suggest_config
¶
Suggest optimal parallel configuration.
| PARAMETER | DESCRIPTION |
|---|---|
simulation
|
Simulation to analyze
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict
|
Suggested n_mpi and n_threads values with rationale |
Source code in src/pyfds/validation/execution.py
SimulationValidator
¶
Validates complete simulation configurations.
Validation is performed in order: 1. Required components (HEAD, TIME, MESH) 2. Cross-reference validation (SURF_ID, MATL_ID, etc.) 3. Geometry quality checks 4. Physical reasonableness checks
Source code in src/pyfds/validation/simulation.py
Functions¶
validate
¶
Run all validations.
| RETURNS | DESCRIPTION |
|---|---|
ValidationResult
|
Result containing all validation issues |
Source code in src/pyfds/validation/simulation.py
Functions¶
safe_read_text
¶
Safely read a text file with size validation.
| PARAMETER | DESCRIPTION |
|---|---|
file_path
|
Path to file to read
TYPE:
|
max_size
|
Maximum allowed file size in bytes, by default MAX_OUTPUT_FILE_SIZE
TYPE:
|
encoding
|
Text encoding, by default "utf-8"
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
File contents |
| RAISES | DESCRIPTION |
|---|---|
ValidationError
|
If file is too large or cannot be read |
Source code in src/pyfds/validation/input.py
validate_chid
¶
Validate and sanitize a CHID (case identifier).
CHID must be: - Non-empty - 60 characters or less - Contain only letters, numbers, underscores, and hyphens - Not contain path separators or path traversal sequences
| PARAMETER | DESCRIPTION |
|---|---|
chid
|
Case identifier to validate
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
str
|
Validated CHID (unchanged if valid) |
| RAISES | DESCRIPTION |
|---|---|
ValidationError
|
If CHID is invalid |
Examples:
>>> validate_chid("my_simulation")
'my_simulation'
>>> validate_chid("test-case-123")
'test-case-123'
Source code in src/pyfds/validation/input.py
validate_file_size
¶
Validate that a file is not too large to read safely.
| PARAMETER | DESCRIPTION |
|---|---|
file_path
|
Path to file to check
TYPE:
|
max_size
|
Maximum allowed file size in bytes, by default MAX_OUTPUT_FILE_SIZE (100 MB)
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Path
|
The file path (unchanged if valid) |
| RAISES | DESCRIPTION |
|---|---|
ValidationError
|
If file is too large |
Source code in src/pyfds/validation/input.py
validate_non_negative_number
¶
Validate that a number is non-negative (>= 0).
| PARAMETER | DESCRIPTION |
|---|---|
value
|
Number to validate
TYPE:
|
name
|
Name of the parameter (for error messages), by default "value"
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
int or float
|
The value (unchanged if valid) |
| RAISES | DESCRIPTION |
|---|---|
ValidationError
|
If value is negative |
Source code in src/pyfds/validation/input.py
validate_path
¶
Validate and resolve a file system path.
| PARAMETER | DESCRIPTION |
|---|---|
path
|
Path to validate
TYPE:
|
must_exist
|
If True, path must already exist, by default False
TYPE:
|
must_be_file
|
If True, path must be a file (not a directory), by default False
TYPE:
|
must_be_dir
|
If True, path must be a directory (not a file), by default False
TYPE:
|
allow_create
|
If True, allow paths that don't exist yet (for output files), by default True
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Path
|
Validated, resolved absolute path |
| RAISES | DESCRIPTION |
|---|---|
ValidationError
|
If path validation fails |
Source code in src/pyfds/validation/input.py
validate_positive_number
¶
Validate that a number is positive (> 0).
| PARAMETER | DESCRIPTION |
|---|---|
value
|
Number to validate
TYPE:
|
name
|
Name of the parameter (for error messages), by default "value"
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
int or float
|
The value (unchanged if valid) |
| RAISES | DESCRIPTION |
|---|---|
ValidationError
|
If value is not positive |
Source code in src/pyfds/validation/input.py
validate_fds_file
¶
Validate an existing FDS input file.
| PARAMETER | DESCRIPTION |
|---|---|
filepath
|
Path to FDS input file
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
bool
|
True if file is valid |
| RAISES | DESCRIPTION |
|---|---|
ValidationError
|
If validation fails |
Source code in src/pyfds/validation/simulation.py
validate_simulation
¶
Validate a complete simulation configuration.
This is the main entry point for simulation validation. Runs all validation checks including required components, cross-references, geometry quality, and physical bounds.
| PARAMETER | DESCRIPTION |
|---|---|
simulation
|
Simulation to validate
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
ValidationResult
|
Validation result with all issues |
Examples:
>>> sim = Simulation(chid="test")
>>> sim.add(Mesh(...), Time(...))
>>> result = validate_simulation(sim)
>>> if result.is_valid:
... print("Simulation is valid!")
Source code in src/pyfds/validation/__init__.py
Overview¶
The validation module provides comprehensive validation for FDS simulations, including input sanitization, simulation-level validation, cross-reference checking, and execution configuration validation.
Core Classes¶
Validator¶
Main validation class for checking simulation configurations.
from pyfds import Simulation, Mesh, Time
from pyfds.core.geometry import Bounds3D, Grid3D
from pyfds.validation import Validator
sim = Simulation(chid="test")
sim.add(Time(t_end=600.0))
sim.add(Mesh(ijk=Grid3D.of(50, 50, 25), xb=Bounds3D.of(0, 5, 0, 5, 0, 2.5)))
# Validate simulation
validator = Validator()
result = validator.validate(sim)
if result.is_valid:
print("Simulation is valid!")
else:
for error in result.errors:
print(f"Error: {error}")
ValidationResult¶
Container for validation results with errors, warnings, and info messages.
from pyfds.validation import validate_simulation
sim = Simulation(chid="test")
# ... build simulation ...
result = validate_simulation(sim)
print(f"Valid: {result.is_valid}")
print(f"Errors: {len(result.errors)}")
print(f"Warnings: {len(result.warnings)}")
print(f"Info: {len(result.info)}")
# Get all issues
for issue in result.all_issues:
print(f"[{issue.severity}] {issue.message}")
Issue¶
Represents a single validation issue with severity, message, and context.
from pyfds.validation import Issue, Severity
# Issues are created by validators
issue = Issue(
severity=Severity.ERROR,
message="Missing required parameter",
field="t_end",
value=None
)
print(f"{issue.severity}: {issue.message}")
Severity¶
Enumeration of validation issue severity levels.
from pyfds.validation import Severity
# Severity levels
Severity.ERROR # Critical issues that prevent FDS from running
Severity.WARNING # Issues that may cause problems
Severity.INFO # Informational messages
Validation Functions¶
validate_simulation()¶
Main entry point for validating a complete simulation.
from pyfds import Simulation, Mesh, Time
from pyfds.core.geometry import Bounds3D, Grid3D
from pyfds.validation import validate_simulation
sim = Simulation(chid="test")
sim.add(Time(t_end=600.0))
sim.add(Mesh(ijk=Grid3D.of(50, 50, 25), xb=Bounds3D.of(0, 5, 0, 5, 0, 2.5)))
result = validate_simulation(sim)
if not result.is_valid:
for error in result.errors:
print(f"Error: {error.message}")
else:
sim.write("test.fds")
validate_fds_file()¶
Validate an existing FDS input file.
from pyfds.validation import validate_fds_file
result = validate_fds_file("simulation.fds")
if result.is_valid:
print("FDS file is valid")
else:
print("Validation errors found:")
for error in result.errors:
print(f" - {error.message}")
Input Validators¶
validate_chid()¶
Validate simulation CHID (case ID).
from pyfds.validation import validate_chid, CHID_MAX_LENGTH
# Valid CHID
try:
validate_chid("my_simulation")
except ValueError as e:
print(f"Invalid CHID: {e}")
# Too long
try:
validate_chid("a" * (CHID_MAX_LENGTH + 1))
except ValueError as e:
print(f"CHID too long: {e}")
# Invalid characters
try:
validate_chid("my simulation") # Spaces not allowed
except ValueError as e:
print(f"Invalid characters: {e}")
validate_path()¶
Validate file paths for safety and existence.
from pyfds.validation import validate_path
from pathlib import Path
# Check if path exists
try:
validate_path("/path/to/file.fds", must_exist=True)
except ValueError as e:
print(f"Path validation failed: {e}")
# Check if parent directory exists
try:
validate_path("/path/to/output.fds", check_parent=True)
except ValueError as e:
print(f"Parent directory doesn't exist: {e}")
validate_positive_number()¶
Ensure a number is positive.
from pyfds.validation import validate_positive_number
# Valid
validate_positive_number(10.0, "t_end") # OK
# Invalid
try:
validate_positive_number(0, "t_end")
except ValueError as e:
print(f"Error: {e}") # "t_end must be positive"
try:
validate_positive_number(-5.0, "dt")
except ValueError as e:
print(f"Error: {e}") # "dt must be positive"
validate_non_negative_number()¶
Ensure a number is non-negative (zero allowed).
from pyfds.validation import validate_non_negative_number
# Valid
validate_non_negative_number(0, "t_begin") # OK
validate_non_negative_number(10.0, "t_begin") # OK
# Invalid
try:
validate_non_negative_number(-1.0, "t_begin")
except ValueError as e:
print(f"Error: {e}") # "t_begin must be non-negative"
validate_file_size()¶
Check if a file size is within acceptable limits.
from pyfds.validation import validate_file_size, MAX_INPUT_FILE_SIZE
from pathlib import Path
fds_file = Path("large_simulation.fds")
try:
validate_file_size(fds_file, MAX_INPUT_FILE_SIZE)
except ValueError as e:
print(f"File too large: {e}")
safe_read_text()¶
Safely read text files with size and encoding validation.
from pyfds.validation import safe_read_text
try:
content = safe_read_text("simulation.fds")
print(f"Read {len(content)} characters")
except ValueError as e:
print(f"Failed to read file: {e}")
Specialized Validators¶
SimulationValidator¶
Comprehensive validation for complete simulations.
from pyfds.validation import SimulationValidator
sim = Simulation(chid="test")
# ... build simulation ...
validator = SimulationValidator(sim)
result = validator.validate()
# Check specific aspects
result.check_required_components()
result.check_cross_references()
result.check_geometry_quality()
result.check_physical_bounds()
CrossReferenceValidator¶
Validates ID references between namelists.
from pyfds.validation import CrossReferenceValidator
validator = CrossReferenceValidator(sim)
issues = validator.validate()
for issue in issues:
if "surf_id" in issue.message.lower():
print(f"Surface reference issue: {issue.message}")
ExecutionValidator¶
Validates execution configuration.
from pyfds.validation import ExecutionValidator
from pyfds.config import RunConfig
config = RunConfig(n_threads=4, timeout=3600)
validator = ExecutionValidator()
issues = validator.validate_config(config)
if issues:
for issue in issues:
print(f"Config issue: {issue.message}")
Validation Constants¶
from pyfds.validation import (
CHID_MAX_LENGTH, # Maximum CHID length
CHID_PATTERN, # Regex pattern for valid CHIDs
MAX_INPUT_FILE_SIZE, # Maximum input file size
MAX_OUTPUT_FILE_SIZE, # Maximum output file size
)
print(f"Max CHID length: {CHID_MAX_LENGTH}")
print(f"Max input file: {MAX_INPUT_FILE_SIZE / 1024 / 1024} MB")
Built-in Enums¶
BuiltinSpecies¶
Enumeration of FDS built-in species.
from pyfds.validation import BuiltinSpecies
# Check if species is built-in
if "OXYGEN" in [s.value for s in BuiltinSpecies]:
print("OXYGEN is a built-in species")
# List all built-in species
for species in BuiltinSpecies:
print(species.value)
BuiltinSurface¶
Enumeration of FDS built-in surfaces.
from pyfds.validation import BuiltinSurface
# Check if surface is built-in
if "INERT" in [s.value for s in BuiltinSurface]:
print("INERT is a built-in surface")
# List all built-in surfaces
for surface in BuiltinSurface:
print(surface.value)
Usage Patterns¶
Pre-Write Validation¶
from pyfds import Simulation
from pyfds.validation import validate_simulation
sim = Simulation(chid="test")
# ... build simulation ...
# Validate before writing
result = validate_simulation(sim)
if result.is_valid:
sim.write("test.fds")
else:
print("Fix these errors before writing:")
for error in result.errors:
print(f" - {error.message}")
Progressive Validation¶
from pyfds import Simulation
from pyfds.validation import SimulationValidator
sim = Simulation(chid="test")
validator = SimulationValidator(sim)
# Add components and validate incrementally
sim.add(Time(t_end=600.0))
if not validator.check_required_components():
print("Still missing required components")
sim.add(Mesh(...))
if validator.validate().is_valid:
print("Simulation is now valid!")
Custom Validation¶
from pyfds.validation import Validator, Issue, Severity
class CustomValidator(Validator):
"""Custom validator with project-specific rules."""
def validate_custom(self, sim):
"""Check custom requirements."""
issues = []
# Example: require at least one device
if not sim.get_all(Device):
issues.append(Issue(
severity=Severity.WARNING,
message="No devices defined - results may be limited",
))
return issues
See Also¶
- Exceptions - Validation and other exceptions
- Validation Reference - Complete validation rules
- Troubleshooting - Common validation issues
- Simulation - Main simulation class