-
Notifications
You must be signed in to change notification settings - Fork 5
INP manager refactor #143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
INP manager refactor #143
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
58d1498
Implement Card Set 2 (Element Information) for SAMMY INP files with p…
KedoKudo 7f5e564
Add Card Set 3 (Physical Constants) implementation and tests for SAMM…
KedoKudo 60b7792
Add Card03Density class and unit tests for sample density in SAMMY IN…
KedoKudo 28bcf32
Refactor InpManager to remove unused normalization parameters and upd…
KedoKudo fd91044
Update InpManager to use default values for title and reaction type i…
KedoKudo 0121cf6
update pixi lock file
KedoKudo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| #!/usr/bin/env python | ||
| """ | ||
| Card Set 2 (Element Information) for SAMMY INP files. | ||
|
|
||
| This module provides the Card02 class for parsing and generating the element | ||
| information line in SAMMY input files. This card appears early in the INP file | ||
| and defines the sample element, atomic weight, and energy range. | ||
|
|
||
| Format specification (Card Set 2): | ||
| Cols Format Variable Description | ||
| 1-10 A ELMNT Sample element's name (left-aligned) | ||
| 11-20 F AW Atomic weight (amu) | ||
| 21-30 F EMIN Minimum energy for dataset (eV) | ||
| 31-40 F EMAX Maximum energy (eV) | ||
|
|
||
| Example: | ||
| Si 27.976928 300000. 1800000. | ||
| """ | ||
|
|
||
| from typing import List | ||
|
|
||
| from pydantic import BaseModel, Field | ||
|
|
||
| from pleiades.utils.logger import loguru_logger | ||
|
|
||
| logger = loguru_logger.bind(name=__name__) | ||
|
|
||
| # Format specification for Card Set 2 | ||
| CARD02_FORMAT = { | ||
| "element": slice(0, 10), | ||
| "atomic_weight": slice(10, 20), | ||
| "min_energy": slice(20, 30), | ||
| "max_energy": slice(30, 40), | ||
| } | ||
|
|
||
|
|
||
| class ElementInfo(BaseModel): | ||
| """Pydantic model for element information in Card Set 2. | ||
|
|
||
| Attributes: | ||
| element: Sample element's name (up to 10 characters) | ||
| atomic_weight: Atomic weight in amu | ||
| min_energy: Minimum energy for dataset in eV | ||
| max_energy: Maximum energy in eV | ||
| """ | ||
|
|
||
| element: str = Field(..., description="Sample element's name", max_length=10) | ||
| atomic_weight: float = Field(..., description="Atomic weight (amu)", gt=0) | ||
| min_energy: float = Field(..., description="Minimum energy (eV)", ge=0) | ||
| max_energy: float = Field(..., description="Maximum energy (eV)", gt=0) | ||
|
|
||
| def model_post_init(self, __context) -> None: | ||
| """Validate that max_energy > min_energy.""" | ||
| if self.max_energy <= self.min_energy: | ||
| raise ValueError(f"max_energy ({self.max_energy}) must be greater than min_energy ({self.min_energy})") | ||
|
|
||
|
|
||
| class Card02(BaseModel): | ||
| """ | ||
| Class representing Card Set 2 (element information) in SAMMY INP files. | ||
|
|
||
| This card defines the sample element, atomic weight, and energy range for the analysis. | ||
| """ | ||
|
|
||
| @classmethod | ||
| def from_lines(cls, lines: List[str]) -> ElementInfo: | ||
| """Parse element information from Card Set 2 line. | ||
|
|
||
| Args: | ||
| lines: List of input lines (expects single line for Card 2) | ||
|
|
||
| Returns: | ||
| ElementInfo: Parsed element information | ||
|
|
||
| Raises: | ||
| ValueError: If format is invalid or required values missing | ||
| """ | ||
| if not lines or not lines[0].strip(): | ||
| message = "No valid Card 2 line provided" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| line = lines[0] | ||
| if len(line) < 40: | ||
| line = f"{line:<40}" | ||
|
|
||
| try: | ||
| element = line[CARD02_FORMAT["element"]].strip() | ||
| atomic_weight = float(line[CARD02_FORMAT["atomic_weight"]].strip()) | ||
| min_energy = float(line[CARD02_FORMAT["min_energy"]].strip()) | ||
| max_energy = float(line[CARD02_FORMAT["max_energy"]].strip()) | ||
| except (ValueError, IndexError) as e: | ||
| message = f"Failed to parse Card 2 line: {e}" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| if not element: | ||
| message = "Element name cannot be empty" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| return ElementInfo( | ||
| element=element, | ||
| atomic_weight=atomic_weight, | ||
| min_energy=min_energy, | ||
| max_energy=max_energy, | ||
| ) | ||
|
|
||
| @classmethod | ||
| def to_lines(cls, element_info: ElementInfo) -> List[str]: | ||
| """Convert element information to Card Set 2 formatted line. | ||
|
|
||
| Args: | ||
| element_info: ElementInfo object containing element data | ||
|
|
||
| Returns: | ||
| List containing single formatted line for Card Set 2 | ||
| """ | ||
| if not isinstance(element_info, ElementInfo): | ||
| message = "element_info must be an instance of ElementInfo" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| line = ( | ||
| f"{element_info.element:<10s}" | ||
| f"{element_info.atomic_weight:10.6f}" | ||
| f"{element_info.min_energy:10.3f}" | ||
| f"{element_info.max_energy:10.1f}" | ||
| ) | ||
|
|
||
| return [line] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| #!/usr/bin/env python | ||
| """ | ||
| Card Set 3 (Physical Constants) for SAMMY INP files. | ||
|
|
||
| This module provides the Card03 class for parsing and generating the physical | ||
| constants line in SAMMY input files. This card appears after the element information | ||
| and defines temperature, flight path, and resolution parameters. | ||
|
|
||
| Format specification (Card Set 3 - Physical Constants): | ||
| The line contains five floating-point values with variable spacing: | ||
| - TEMP: Temperature (K) | ||
| - FPL: Flight path length (m) | ||
| - DELTAL: Spread in flight-path length (m) | ||
| - DELTAG: Gaussian resolution width (μs) | ||
| - DELTAE: e-folding width of exponential resolution (μs) | ||
|
|
||
| Example: | ||
| 300. 200.0000 0.182233 0.0 0.002518 | ||
| """ | ||
|
|
||
| from typing import List | ||
|
|
||
| from pydantic import BaseModel, Field | ||
|
|
||
| from pleiades.utils.logger import loguru_logger | ||
|
|
||
| logger = loguru_logger.bind(name=__name__) | ||
|
|
||
|
|
||
| class PhysicalConstants(BaseModel): | ||
| """Pydantic model for physical constants in Card Set 3. | ||
|
|
||
| Attributes: | ||
| temperature: Temperature in Kelvin | ||
| flight_path_length: Flight path length in meters | ||
| delta_l: Spread in flight-path length in meters | ||
| delta_g: Gaussian resolution width in microseconds | ||
| delta_e: e-folding width of exponential resolution in microseconds | ||
| """ | ||
|
|
||
| temperature: float = Field(..., description="Temperature (K)", gt=0) | ||
| flight_path_length: float = Field(..., description="Flight path length (m)", gt=0) | ||
| delta_l: float = Field(default=0.0, description="Spread in flight-path length (m)", ge=0) | ||
| delta_g: float = Field(default=0.0, description="Gaussian resolution width (μs)", ge=0) | ||
| delta_e: float = Field(default=0.0, description="e-folding width of exponential resolution (μs)", ge=0) | ||
|
|
||
|
|
||
| class Card03(BaseModel): | ||
| """ | ||
| Class representing Card Set 3 (physical constants) in SAMMY INP files. | ||
|
|
||
| This card defines temperature, flight path, and resolution parameters for the analysis. | ||
| """ | ||
|
|
||
| @classmethod | ||
| def from_lines(cls, lines: List[str]) -> PhysicalConstants: | ||
| """Parse physical constants from Card Set 3 line. | ||
|
|
||
| Args: | ||
| lines: List of input lines (expects single line for Card 3) | ||
|
|
||
| Returns: | ||
| PhysicalConstants: Parsed physical constants | ||
|
|
||
| Raises: | ||
| ValueError: If format is invalid or required values missing | ||
| """ | ||
| if not lines or not lines[0].strip(): | ||
| message = "No valid Card 3 line provided" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| line = lines[0].strip() | ||
| fields = line.split() | ||
|
|
||
| if len(fields) < 2: | ||
| message = f"Card 3 line must have at least 2 fields (TEMP, FPL), got {len(fields)}" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| try: | ||
| temperature = float(fields[0]) | ||
| flight_path_length = float(fields[1]) | ||
| delta_l = float(fields[2]) if len(fields) > 2 else 0.0 | ||
| delta_g = float(fields[3]) if len(fields) > 3 else 0.0 | ||
| delta_e = float(fields[4]) if len(fields) > 4 else 0.0 | ||
| except (ValueError, IndexError) as e: | ||
| message = f"Failed to parse Card 3 line: {e}" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| return PhysicalConstants( | ||
| temperature=temperature, | ||
| flight_path_length=flight_path_length, | ||
| delta_l=delta_l, | ||
| delta_g=delta_g, | ||
| delta_e=delta_e, | ||
| ) | ||
|
|
||
| @classmethod | ||
| def to_lines(cls, constants: PhysicalConstants) -> List[str]: | ||
| """Convert physical constants to Card Set 3 formatted line. | ||
|
|
||
| Args: | ||
| constants: PhysicalConstants object containing parameter data | ||
|
|
||
| Returns: | ||
| List containing single formatted line for Card Set 3 | ||
| """ | ||
| if not isinstance(constants, PhysicalConstants): | ||
| message = "constants must be an instance of PhysicalConstants" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| line = ( | ||
| f" {constants.temperature:5.1f} " | ||
| f"{constants.flight_path_length:8.4f} " | ||
| f"{constants.delta_l:8.6f} " | ||
| f"{constants.delta_g:3.1f} " | ||
| f"{constants.delta_e:8.6f}" | ||
| ) | ||
KedoKudo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| return [line] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| #!/usr/bin/env python | ||
| """ | ||
| Sample Density for SAMMY INP files. | ||
|
|
||
| This module provides the Card03Density class for parsing and generating the sample | ||
| density line in SAMMY input files. This line appears after the physical constants | ||
| and defines the material density and number density. | ||
|
|
||
| Format specification (Sample Density): | ||
| The line contains two floating-point values: | ||
| - Density: Material density (g/cm³) | ||
| - Number density: Number density (atoms/barn-cm) | ||
|
|
||
| Example: | ||
| 4.20000 0.347162 | ||
| """ | ||
|
|
||
| from typing import List | ||
|
|
||
| from pydantic import BaseModel, Field | ||
|
|
||
| from pleiades.utils.logger import loguru_logger | ||
|
|
||
| logger = loguru_logger.bind(name=__name__) | ||
|
|
||
|
|
||
| class SampleDensity(BaseModel): | ||
| """Pydantic model for sample density parameters. | ||
|
|
||
| Attributes: | ||
| density: Material density in g/cm³ | ||
| number_density: Number density in atoms/barn-cm | ||
| """ | ||
|
|
||
| density: float = Field(..., description="Material density (g/cm³)", gt=0) | ||
| number_density: float = Field(..., description="Number density (atoms/barn-cm)", gt=0) | ||
|
|
||
|
|
||
| class Card03Density(BaseModel): | ||
| """ | ||
| Class representing sample density line in SAMMY INP files. | ||
|
|
||
| This line defines the material density and number density for the sample. | ||
| """ | ||
|
|
||
| @classmethod | ||
| def from_lines(cls, lines: List[str]) -> SampleDensity: | ||
| """Parse sample density from density line. | ||
|
|
||
| Args: | ||
| lines: List of input lines (expects single line) | ||
|
|
||
| Returns: | ||
| SampleDensity: Parsed sample density parameters | ||
|
|
||
| Raises: | ||
| ValueError: If format is invalid or required values missing | ||
| """ | ||
| if not lines or not lines[0].strip(): | ||
| message = "No valid density line provided" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| line = lines[0].strip() | ||
| fields = line.split() | ||
|
|
||
| if len(fields) < 2: | ||
| message = f"Density line must have 2 fields (density, number_density), got {len(fields)}" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| try: | ||
| density = float(fields[0]) | ||
| number_density = float(fields[1]) | ||
| except (ValueError, IndexError) as e: | ||
| message = f"Failed to parse density line: {e}" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| return SampleDensity( | ||
| density=density, | ||
| number_density=number_density, | ||
| ) | ||
|
|
||
| @classmethod | ||
| def to_lines(cls, sample_density: SampleDensity) -> List[str]: | ||
| """Convert sample density to formatted line. | ||
|
|
||
| Args: | ||
| sample_density: SampleDensity object containing density data | ||
|
|
||
| Returns: | ||
| List containing single formatted line | ||
| """ | ||
| if not isinstance(sample_density, SampleDensity): | ||
| message = "sample_density must be an instance of SampleDensity" | ||
| logger.error(message) | ||
| raise ValueError(message) | ||
|
|
||
| line = f" {sample_density.density:8.6f} {sample_density.number_density:.6e}" | ||
|
|
||
| return [line] |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.