Skip to content
Open
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
14 changes: 14 additions & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
81d65dae23119d7626c1280868064fd6d83adf98
b8bf10e010ce4c2dad1bc0c85367f573a5d0b881
6f2eee122c42eee8306b29491e85118d1c0ff81d
d87f9dfec164991649fc6a33a9a25e387ae4fa5b
245d5ffe2b07a6c6b59afe0f18520297d2ebf776
a9cc5f3393cf87713155e8c6582a2724748185da
21c334c5d2d7438382cd6b18cfc0080b93db905b
5b123eb06e941570e20292d72a27b978a8ea0315
4c6aac5ba123b770c44a86fe0008fd8e63755432
f4017e4911d8ef9cd49315a5a86fb22f5f75ef95
b7472c592e028533850d953905290f6e6a3014f4
2c4e08432d06ceec2faebd82243a2a5bced96d0a
e6458e20673d8385d85bcfe8e552a403734326a7
0d71d450598d0a399794ab3621cab74fb064f95c
28 changes: 28 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This workflow will install Python dependencies and run the linter
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: Lint

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
ruff:
name: Lint with Ruff
runs-on: ubuntu-latest

steps:
- name: Check out repository
uses: actions/checkout@v6

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install --editable .[dev]

- name: Run linter check
run: |
python -m ruff check --output-format=github src/ tests/
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/

# Abstra
# Abstra is an AI-powered process automation framework.
Expand Down
49 changes: 47 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
[project]
name = "zdPlasmaPy"
version = "0.1.0"
requires-python = ">=3.12"
license-files = ["LICEN[CS]E*"]
dynamic = ["version"]
dependencies = [
"h5py>=3.16.0",
"ipykernel>=7.3.0",
"jsonschema>=4.26.0",
"matplotlib>=3.11.0",
"numpy<2.0.0",
"pytest>=9.1.0",
"pyyaml>=6.0.3",
"scipy>=1.17.1",
"streamlit>=1.58.0",
]

[project.optional-dependencies]
dev = [
"ruff>=0.15.17",
]

[project.scripts]
zdplasmapy = "main:main"
Expand All @@ -12,6 +30,33 @@ build-backend = "setuptools.build_meta"
[tool.setuptools]
py-modules = ["main"]

[tool.setuptools_scm]

[tool.setuptools.packages.find]
where = ["."]
include = ["src*"]
include = ["src*"]

[tool.ruff.lint]
select = [
"F", # Pyflakes
"E", # pycodestyle error
"W", # pycodestyle warning
"I", # isort
"B", # flake8-bugbear
"A", # flake8-builtins
"C4", # flake8-comprehensions
"T10", # flake8-debugger
"SIM", # flake8-simplify
"TCH", # flake8-type-checking
"UP", # pyupgrade
"FURB", # refurb
"PERF", # perflint
"NPY", # NumPy specific
]
ignore = [
"B904", # `except` clause raise
"E401", # Multiple imports on one line
"E501", # Line too long
"E701", # Multiple statements on one line
"E741", # Ambiguous variable name
]
19 changes: 10 additions & 9 deletions src/build_model_dict.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
# src/build_model_dict.py

from .config_loader import load_config
from .chemistry_parser import load_chemistry
from .config_loader import load_config


def build_model_definition(config_path):
"""
Builds the model_definition dictionary that GlobalModel expects.

Args:
config_path: Path to config.yml

Returns:
dict: Complete model definition for GlobalModel
"""
# Load config
config = load_config(config_path)

# Load chemistry
species, reactions, mass_dict = load_chemistry(config['chemistry']['absolute_path'])

# --- Item 3: Extract ion species masses for generalized wall loss ---
ion_species = {}
for sp in species:
if '+' in sp.get('name', '') and sp.get('name') != 'e':
ion_species[sp['name']] = sp.get('mass_amu', 1.0)

# Build the model definition dictionary
model_def = {
'name': config.get('name', 'Unnamed Model'),
Expand Down Expand Up @@ -61,19 +62,19 @@ def build_model_definition(config_path):
'transport_model': config.get('transport_model', 'none'),
'declarations_func': lambda p: {} # Empty for now, transport models will populate
}

# --- Item 2: Dynamic Gas Density from pressure + composition ---
k_B = 1.380649e-23
P = config['parameters']['pressure_Pa']
Tg = config['parameters']['gas_temp_K']
N_total = P / (k_B * Tg)

gas_composition = config['parameters'].get('gas_composition', {})
for gas_species, fraction in gas_composition.items():
# Only inject if NOT explicitly set in species_densities (override wins)
if gas_species not in config['initial_conditions'].get('species_densities', {}):
model_def['initial_values'][gas_species] = fraction * N_total
print(f"INFO: Auto-computed {gas_species} density = {fraction} × {N_total:.3e} = {fraction * N_total:.3e} m⁻³")

return model_def

29 changes: 15 additions & 14 deletions src/case_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,37 @@
"""
import os


def discover_cases(cases_dir='cases'):
"""
Discover all valid case folders in the cases/ directory.
A valid case has a config.yml file.

Returns:
list: List of case names (subdirectory names)
"""
if not os.path.isdir(cases_dir):
return []

cases = []
for entry in os.listdir(cases_dir):
case_path = os.path.join(cases_dir, entry)
if os.path.isdir(case_path):
config_path = os.path.join(case_path, 'config.yml')
if os.path.isfile(config_path):
cases.append(entry)

return sorted(cases)


def get_case_config_path(case_name, cases_dir='cases'):
"""
Get the full path to a case's config.yml file.

Args:
case_name (str): Name of the case folder
cases_dir (str): Base cases directory

Returns:
str: Full path to config.yml
"""
Expand All @@ -43,43 +44,43 @@ def get_case_config_path(case_name, cases_dir='cases'):
def group_parameters(params, species_list, geometry_dict, constants_dict):
"""
Group flat parameter dictionary into structured groups for cleaner access.

Args:
params (dict): Flat parameter dictionary
species_list (list): List of species names
geometry_dict (dict): Geometry parameters
constants_dict (dict): Physical constants

Returns:
dict: Grouped parameters with keys: constants, variables, geometry, species
"""
# Extract known variable keys
variable_keys = ['Te_eV', 'Th_eV', 'na', 'ne', 'Ti_eV', 'Tg_K', 'Th_K']

# Extract known species-specific keys (concentrations, mass, sigma, etc.)
# Start with existing species dict if provided (to avoid double-grouping loss)
species_keys = params.get('species', {}).copy()
for key in params.keys():
for key in params:
if key.startswith('mass_') or key.startswith('sigma_') or key in species_list:
species_keys[key] = params[key]

# Also add geometry parameters that might be in params but should be in geometry
for key in ['R', 'L', 'radius_m', 'length_m', 'Reff', 'volume', 'area']:
if key in params:
geometry_dict[key] = params[key]

grouped = {
'constants': constants_dict.copy(),
'variables': {k: params[k] for k in variable_keys if k in params},
'geometry': geometry_dict.copy(),
'species': species_keys.copy()
}

# Add any remaining params to variables (fallback)
for key, value in params.items():
if key not in variable_keys and key not in species_keys and key not in constants_dict and key not in ['R', 'L', 'radius_m', 'length_m', 'Reff', 'volume', 'area', 't']:
grouped['variables'][key] = value

# Explicitly pull 't' to the top-level as many declarations expect it there
if 't' in params:
grouped['t'] = params['t']
Expand All @@ -88,5 +89,5 @@ def group_parameters(params, species_list, geometry_dict, constants_dict):
grouped.update(grouped['constants'])
grouped.update(grouped['geometry'])
grouped.update(grouped['variables'])

return grouped
6 changes: 3 additions & 3 deletions src/chemistry.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ def __init__(self, name, mass_amu=0.0):

class Reaction:
"""A class to hold data about a single reaction, including its compiled functions."""
def __init__(self, formula, rate_coeff_func, energy_loss_func, type, reference):
def __init__(self, formula, rate_coeff_func, energy_loss_func, type_, reference):
self.formula = formula
self.rate_coeff_func = rate_coeff_func
self.energy_loss_func = energy_loss_func
self.type = type
self.reference = reference
self.type = type_
self.reference = reference
Loading