carnopy 0.1.0a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. carnopy/__init__.py +59 -0
  2. carnopy/__main__.py +9 -0
  3. carnopy/_version.py +1 -0
  4. carnopy/api.py +30 -0
  5. carnopy/backends/__init__.py +29 -0
  6. carnopy/backends/base.py +42 -0
  7. carnopy/backends/coolprop.py +109 -0
  8. carnopy/cli.py +517 -0
  9. carnopy/config/__init__.py +18 -0
  10. carnopy/config/io.py +37 -0
  11. carnopy/config/models.py +99 -0
  12. carnopy/config/normalize.py +115 -0
  13. carnopy/config/outputs.py +28 -0
  14. carnopy/config/visualization.py +81 -0
  15. carnopy/domain/__init__.py +3 -0
  16. carnopy/domain/failures.py +58 -0
  17. carnopy/domain/phases.py +19 -0
  18. carnopy/domain/properties.py +151 -0
  19. carnopy/domain/units.py +75 -0
  20. carnopy/generation/__init__.py +11 -0
  21. carnopy/generation/common.py +219 -0
  22. carnopy/generation/property_table.py +57 -0
  23. carnopy/generation/saturation_table.py +127 -0
  24. carnopy/generation/vapor_mass_fraction_table.py +99 -0
  25. carnopy/outputs/__init__.py +27 -0
  26. carnopy/outputs/layout.py +62 -0
  27. carnopy/outputs/metadata.py +117 -0
  28. carnopy/outputs/reports.py +68 -0
  29. carnopy/outputs/schemas.py +56 -0
  30. carnopy/outputs/writers.py +90 -0
  31. carnopy/pipeline.py +234 -0
  32. carnopy/provenance.py +93 -0
  33. carnopy/py.typed +1 -0
  34. carnopy/results.py +53 -0
  35. carnopy/sampling/__init__.py +4 -0
  36. carnopy/sampling/generate.py +57 -0
  37. carnopy/sampling/models.py +98 -0
  38. carnopy/templates/__init__.py +80 -0
  39. carnopy/templates/property_table.yaml +34 -0
  40. carnopy/templates/saturation_table.yaml +25 -0
  41. carnopy/templates/vapor_mass_fraction_table.yaml +31 -0
  42. carnopy/visualization/__init__.py +72 -0
  43. carnopy/visualization/automation.py +272 -0
  44. carnopy/visualization/config_io.py +29 -0
  45. carnopy/visualization/configuration.py +326 -0
  46. carnopy/visualization/curves.py +368 -0
  47. carnopy/visualization/diagrams.py +157 -0
  48. carnopy/visualization/export.py +307 -0
  49. carnopy/visualization/fields.py +191 -0
  50. carnopy/visualization/heatmaps.py +244 -0
  51. carnopy/visualization/inspect.py +205 -0
  52. carnopy/visualization/io.py +261 -0
  53. carnopy/visualization/models.py +75 -0
  54. carnopy/visualization/plots.py +652 -0
  55. carnopy/visualization/render.py +108 -0
  56. carnopy/visualization/requests.py +295 -0
  57. carnopy/visualization/selection.py +288 -0
  58. carnopy/visualization/series.py +331 -0
  59. carnopy/visualization/xy.py +201 -0
  60. carnopy-0.1.0a1.dist-info/METADATA +826 -0
  61. carnopy-0.1.0a1.dist-info/RECORD +64 -0
  62. carnopy-0.1.0a1.dist-info/WHEEL +4 -0
  63. carnopy-0.1.0a1.dist-info/entry_points.txt +2 -0
  64. carnopy-0.1.0a1.dist-info/licenses/LICENSE +21 -0
carnopy/__init__.py ADDED
@@ -0,0 +1,59 @@
1
+ from __future__ import annotations
2
+
3
+ from importlib import import_module
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from carnopy._version import __version__
7
+
8
+ if TYPE_CHECKING:
9
+ from carnopy.api import generate_dataset, load_config, validate_config
10
+ from carnopy.config.models import CarnopyConfig, NormalizedConfig
11
+ from carnopy.config.outputs import OutputConfig
12
+ from carnopy.config.visualization import VisualizationConfig, VisualizationPlotConfig
13
+ from carnopy.results import RunResult, ValidationResult, VisualizationSummary
14
+
15
+ __all__ = [
16
+ "CarnopyConfig",
17
+ "NormalizedConfig",
18
+ "OutputConfig",
19
+ "RunResult",
20
+ "ValidationResult",
21
+ "VisualizationConfig",
22
+ "VisualizationPlotConfig",
23
+ "VisualizationSummary",
24
+ "__version__",
25
+ "generate_dataset",
26
+ "load_config",
27
+ "validate_config",
28
+ ]
29
+
30
+ _LAZY_EXPORTS = {
31
+ "CarnopyConfig": ("carnopy.config.models", "CarnopyConfig"),
32
+ "NormalizedConfig": ("carnopy.config.models", "NormalizedConfig"),
33
+ "OutputConfig": ("carnopy.config.outputs", "OutputConfig"),
34
+ "RunResult": ("carnopy.results", "RunResult"),
35
+ "ValidationResult": ("carnopy.results", "ValidationResult"),
36
+ "VisualizationConfig": ("carnopy.config.visualization", "VisualizationConfig"),
37
+ "VisualizationPlotConfig": (
38
+ "carnopy.config.visualization",
39
+ "VisualizationPlotConfig",
40
+ ),
41
+ "VisualizationSummary": ("carnopy.results", "VisualizationSummary"),
42
+ "generate_dataset": ("carnopy.api", "generate_dataset"),
43
+ "load_config": ("carnopy.api", "load_config"),
44
+ "validate_config": ("carnopy.api", "validate_config"),
45
+ }
46
+
47
+
48
+ def __getattr__(name: str) -> Any:
49
+ try:
50
+ module_name, attribute_name = _LAZY_EXPORTS[name]
51
+ except KeyError as exc:
52
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from exc
53
+ value = getattr(import_module(module_name), attribute_name)
54
+ globals()[name] = value
55
+ return value
56
+
57
+
58
+ def __dir__() -> list[str]:
59
+ return sorted(set(globals()) | set(__all__))
carnopy/__main__.py ADDED
@@ -0,0 +1,9 @@
1
+ from carnopy.cli import app
2
+
3
+
4
+ def main() -> None:
5
+ app()
6
+
7
+
8
+ if __name__ == "__main__":
9
+ main()
carnopy/_version.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0a1"
carnopy/api.py ADDED
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from carnopy.config.io import LoadedConfig, load_config_file
6
+ from carnopy.pipeline import run_generation, validate_loaded_config
7
+ from carnopy.results import RunResult, ValidationResult
8
+
9
+
10
+ def load_config(path: str | Path) -> LoadedConfig:
11
+ return load_config_file(path)
12
+
13
+
14
+ def validate_config(path: str | Path) -> ValidationResult:
15
+ loaded = load_config_file(path)
16
+ return validate_loaded_config(loaded).result
17
+
18
+
19
+ def generate_dataset(
20
+ path: str | Path,
21
+ *,
22
+ output_root: str | Path = "outputs",
23
+ figures_root: str | Path = "figures",
24
+ ) -> RunResult:
25
+ loaded = load_config_file(path)
26
+ return run_generation(
27
+ loaded,
28
+ Path(output_root),
29
+ Path(figures_root),
30
+ )
@@ -0,0 +1,29 @@
1
+ from __future__ import annotations
2
+
3
+ from importlib import import_module
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ if TYPE_CHECKING:
7
+ from carnopy.backends.base import PropertyBackend
8
+ from carnopy.backends.coolprop import CoolPropBackend
9
+
10
+ __all__ = ["CoolPropBackend", "PropertyBackend"]
11
+
12
+ _LAZY_EXPORTS = {
13
+ "CoolPropBackend": ("carnopy.backends.coolprop", "CoolPropBackend"),
14
+ "PropertyBackend": ("carnopy.backends.base", "PropertyBackend"),
15
+ }
16
+
17
+
18
+ def __getattr__(name: str) -> Any:
19
+ try:
20
+ module_name, attribute_name = _LAZY_EXPORTS[name]
21
+ except KeyError as exc:
22
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}") from exc
23
+ value = getattr(import_module(module_name), attribute_name)
24
+ globals()[name] = value
25
+ return value
26
+
27
+
28
+ def __dir__() -> list[str]:
29
+ return sorted(set(globals()) | set(__all__))
@@ -0,0 +1,42 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Protocol
4
+
5
+ from carnopy.domain.failures import BackendResult
6
+
7
+
8
+ class PropertyBackend(Protocol):
9
+ @property
10
+ def name(self) -> str: ...
11
+
12
+ @property
13
+ def version(self) -> str: ...
14
+
15
+ def list_fluids(self) -> list[str]: ...
16
+
17
+ def aliases_for(self, canonical_fluid: str) -> list[str]: ...
18
+
19
+ def canonicalize_fluid(self, fluid: str) -> str: ...
20
+
21
+ def initialize_reference_states(self, fluids: list[str]) -> None: ...
22
+
23
+ def phase(
24
+ self,
25
+ fluid: str,
26
+ input1: str,
27
+ value1: float,
28
+ input2: str,
29
+ value2: float,
30
+ ) -> BackendResult[str]: ...
31
+
32
+ def property(
33
+ self,
34
+ output: str,
35
+ fluid: str,
36
+ input1: str,
37
+ value1: float,
38
+ input2: str,
39
+ value2: float,
40
+ ) -> BackendResult[float]: ...
41
+
42
+ def fluid_constant(self, output: str, fluid: str) -> BackendResult[float]: ...
@@ -0,0 +1,109 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import cached_property
4
+
5
+ import CoolProp
6
+ import CoolProp.CoolProp as CP
7
+
8
+ from carnopy.domain.failures import BackendInitializationError, BackendResult
9
+
10
+
11
+ class CoolPropBackend:
12
+ @property
13
+ def name(self) -> str:
14
+ return "coolprop"
15
+
16
+ @property
17
+ def version(self) -> str:
18
+ return str(CoolProp.__version__)
19
+
20
+ @cached_property
21
+ def _aliases(self) -> dict[str, str]:
22
+ aliases: dict[str, str] = {}
23
+ for canonical in self.list_fluids():
24
+ raw_aliases = CP.get_fluid_param_string(canonical, "aliases")
25
+ names = [canonical, *raw_aliases.split(",")]
26
+ for name in names:
27
+ cleaned = name.strip()
28
+ if cleaned:
29
+ aliases[cleaned.casefold()] = canonical
30
+ return aliases
31
+
32
+ def list_fluids(self) -> list[str]:
33
+ return sorted(str(fluid) for fluid in CP.FluidsList())
34
+
35
+ def aliases_for(self, canonical_fluid: str) -> list[str]:
36
+ raw = CP.get_fluid_param_string(canonical_fluid, "aliases")
37
+ aliases = {canonical_fluid}
38
+ aliases.update(name.strip() for name in raw.split(",") if name.strip())
39
+ return sorted(aliases)
40
+
41
+ def canonicalize_fluid(self, fluid: str) -> str:
42
+ if any(token in fluid for token in ("::", "&", "[", "]")):
43
+ raise ValueError(
44
+ f"mixtures and backend-prefixed fluid strings are unsupported: {fluid!r}"
45
+ )
46
+ try:
47
+ return self._aliases[fluid.strip().casefold()]
48
+ except KeyError as exc:
49
+ raise ValueError(f"unsupported CoolProp pure fluid {fluid!r}") from exc
50
+
51
+ def initialize_reference_states(self, fluids: list[str]) -> None:
52
+ for fluid in fluids:
53
+ try:
54
+ CP.set_reference_state(fluid, "DEF")
55
+ except Exception as exc:
56
+ raise BackendInitializationError(
57
+ f"failed to set CoolProp DEF reference state for {fluid}: {exc}"
58
+ ) from exc
59
+
60
+ def phase(
61
+ self,
62
+ fluid: str,
63
+ input1: str,
64
+ value1: float,
65
+ input2: str,
66
+ value2: float,
67
+ ) -> BackendResult[str]:
68
+ try:
69
+ value = str(CP.PhaseSI(input1, value1, input2, value2, fluid))
70
+ except Exception as exc:
71
+ return BackendResult.failure(
72
+ layer="backend",
73
+ code="backend_phase_call_failed",
74
+ message="CoolProp phase evaluation failed",
75
+ error=exc,
76
+ )
77
+ return BackendResult.success(value)
78
+
79
+ def property(
80
+ self,
81
+ output: str,
82
+ fluid: str,
83
+ input1: str,
84
+ value1: float,
85
+ input2: str,
86
+ value2: float,
87
+ ) -> BackendResult[float]:
88
+ try:
89
+ value = float(CP.PropsSI(output, input1, value1, input2, value2, fluid))
90
+ except Exception as exc:
91
+ return BackendResult.failure(
92
+ layer="backend",
93
+ code="backend_property_call_failed",
94
+ message=f"CoolProp property evaluation failed for {output}",
95
+ error=exc,
96
+ )
97
+ return BackendResult.success(value)
98
+
99
+ def fluid_constant(self, output: str, fluid: str) -> BackendResult[float]:
100
+ try:
101
+ value = float(CP.PropsSI(output, fluid))
102
+ except Exception as exc:
103
+ return BackendResult.failure(
104
+ layer="backend",
105
+ code="backend_property_call_failed",
106
+ message=f"CoolProp fluid constant evaluation failed for {output}",
107
+ error=exc,
108
+ )
109
+ return BackendResult.success(value)