peslite-core 0.5.0__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 (53) hide show
  1. peslite/__init__.py +42 -0
  2. peslite/addons/__init__.py +75 -0
  3. peslite/addons/_discovery.py +19 -0
  4. peslite/addons/components/__init__.py +22 -0
  5. peslite/addons/control/__init__.py +23 -0
  6. peslite/addons/functions/__init__.py +20 -0
  7. peslite/assembly/__init__.py +76 -0
  8. peslite/assembly/circuit.py +2634 -0
  9. peslite/assembly/conduction.py +362 -0
  10. peslite/assembly/cpp.py +7872 -0
  11. peslite/assembly/events.py +218 -0
  12. peslite/assembly/exporter.py +84 -0
  13. peslite/assembly/imperix.py +667 -0
  14. peslite/assembly/imperix_build.py +129 -0
  15. peslite/assembly/params.py +1811 -0
  16. peslite/assembly/protection.py +232 -0
  17. peslite/assembly/system.py +824 -0
  18. peslite/assembly/types.py +59 -0
  19. peslite/assembly/unit.py +1055 -0
  20. peslite/assembly/validate.py +645 -0
  21. peslite/components/__init__.py +36 -0
  22. peslite/components/adc.py +429 -0
  23. peslite/components/converter.py +1176 -0
  24. peslite/components/network.py +873 -0
  25. peslite/components/onnx.py +322 -0
  26. peslite/components/pwm.py +1093 -0
  27. peslite/components/wpt.py +678 -0
  28. peslite/control/__init__.py +42 -0
  29. peslite/control/blocks.py +492 -0
  30. peslite/control/controller.py +1939 -0
  31. peslite/control/loops.py +1405 -0
  32. peslite/control/modulation.py +169 -0
  33. peslite/control/profiles.py +153 -0
  34. peslite/solver/__init__.py +20 -0
  35. peslite/solver/energy.py +752 -0
  36. peslite/solver/implicit.py +573 -0
  37. peslite/solver/integrators.py +804 -0
  38. peslite/solver/linearization.py +143 -0
  39. peslite/solver/model.py +1894 -0
  40. peslite/solver/multirate.py +726 -0
  41. peslite/solver/netlist.py +4050 -0
  42. peslite/solver/simulation.py +2233 -0
  43. peslite/solver/splitbound.py +245 -0
  44. peslite/solver/timing.py +46 -0
  45. peslite_core-0.5.0.data/data/share/peslite/examples/templates/component.py +27 -0
  46. peslite_core-0.5.0.data/data/share/peslite/examples/templates/controller.py +32 -0
  47. peslite_core-0.5.0.data/data/share/peslite/examples/templates/template.pes +35 -0
  48. peslite_core-0.5.0.dist-info/METADATA +142 -0
  49. peslite_core-0.5.0.dist-info/RECORD +53 -0
  50. peslite_core-0.5.0.dist-info/WHEEL +5 -0
  51. peslite_core-0.5.0.dist-info/entry_points.txt +2 -0
  52. peslite_core-0.5.0.dist-info/licenses/LICENSE +661 -0
  53. peslite_core-0.5.0.dist-info/top_level.txt +1 -0
peslite/__init__.py ADDED
@@ -0,0 +1,42 @@
1
+ """Power-electronics converter simulation on a port-Hamiltonian model kernel.
2
+
3
+ The package has five parts: :mod:`.components` (power circuit and converter hardware),
4
+ :mod:`.control` (the converter's controller), :mod:`.assembly` (a system built from a simulation
5
+ file), :mod:`.solver` (the model kernel, integrators and run), and :mod:`.addons` (custom extension
6
+ entry points and optional functions). Plant quantities are in SI; controllers work in each unit's
7
+ pu bases.
8
+ """
9
+
10
+ from . import solver, control, components, assembly
11
+ from .solver import (AdaptiveSolver, BlackBoxSubsystem, DormandPrince45, FixedStepSolver, Model,
12
+ MultirateSolver, make_solver)
13
+ from .control import OutputStage, VSCController, make_controller, register_loop_type
14
+ from .components import (ADC, ADCSample, PWM, PWMAveragingModel, ZOH, AveragingModel, SwitchingModel,
15
+ ThreePhaseBridge, CarrierComparison, FullBridge, HalfBridge,
16
+ MeasurementPorts, make_bridge,
17
+ make_modulator, register_component_type)
18
+ from .assembly import (DCConverter, Params, Protection, ProtectionSample,
19
+ SourceScenario, System, Unit, VSC,
20
+ dump, dumps, load, register_event_type)
21
+ from .solver.simulation import Simulation, SimulationResult, main
22
+ from .assembly.exporter import ExportResult, export
23
+ from . import addons
24
+ from .assembly.params import _register_load_preparer
25
+
26
+ _register_load_preparer(addons._discover_for)
27
+
28
+ __version__ = "0.5.0"
29
+
30
+ __all__ = [
31
+ "solver", "control", "components", "assembly", "addons",
32
+ "Params", "load", "dump", "dumps", "System", "Unit", "VSC",
33
+ "DCConverter", "Protection", "ProtectionSample", "MeasurementPorts", "Model", "BlackBoxSubsystem",
34
+ "SourceScenario",
35
+ "Simulation", "SimulationResult", "ExportResult", "export", "VSCController", "main", "make_controller", "make_modulator", "make_solver",
36
+ "register_loop_type", "register_component_type", "register_event_type",
37
+ "OutputStage", "ADC", "ADCSample", "PWM", "SwitchingModel", "PWMAveragingModel", "AveragingModel",
38
+ "ThreePhaseBridge", "make_bridge",
39
+ "HalfBridge", "FullBridge",
40
+ "CarrierComparison", "ZOH",
41
+ "FixedStepSolver", "AdaptiveSolver", "DormandPrince45", "MultirateSolver", "__version__",
42
+ ]
@@ -0,0 +1,75 @@
1
+ """Optional functions and automatically discovered custom PESLite types."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib import import_module, invalidate_caches
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from . import components, control
10
+ from ._discovery import discover_modules
11
+
12
+ # These imports happen once when PESLite starts. They populate the existing registries; no
13
+ # directory search or add-on dispatch remains in the simulation hot path.
14
+ control.discover()
15
+ components.discover()
16
+
17
+ __all__ = ["control", "components", "functions", "energy_closure", "plot_csv", "plot_result"]
18
+
19
+
20
+ def _merge_path(package, directory: Path) -> bool:
21
+ """Append one real directory to a package search path, once."""
22
+ if not directory.is_dir():
23
+ return False
24
+ resolved = str(directory.resolve())
25
+ if resolved not in package.__path__:
26
+ package.__path__.append(resolved)
27
+ return True
28
+
29
+
30
+ def _discover_for(simulation_file: str | Path) -> tuple[Any, ...]:
31
+ """Merge and discover ``PESaddons`` beside one simulation file.
32
+
33
+ The installed add-on packages remain the first search locations. A sibling ``PESaddons``
34
+ contributes the same ``control``, ``components`` and ``functions`` package paths without
35
+ changing the process-wide ``sys.path``. Controller and component decorators must run before
36
+ the simulation file is parsed; functions remain lazy and are imported only when requested.
37
+ """
38
+ root = Path(simulation_file).resolve().parent / "PESaddons"
39
+ if not root.is_dir():
40
+ return ()
41
+
42
+ _merge_path(import_module(__name__), root)
43
+ locations = []
44
+ for package, name in ((control, "control"), (components, "components")):
45
+ directory = root / name
46
+ if _merge_path(package, directory):
47
+ locations.append((package, directory))
48
+
49
+ # Import the existing functions package only when this project contributes that namespace.
50
+ # Optional third-party implementations remain lazy; this merely makes project-local function
51
+ # modules importable from the same path.
52
+ function_directory = root / "functions"
53
+ if function_directory.is_dir():
54
+ functions = import_module(f"{__name__}.functions")
55
+ _merge_path(functions, function_directory)
56
+ invalidate_caches()
57
+
58
+ imported = []
59
+ for package, directory in locations:
60
+ imported.extend(discover_modules(package.__name__, (str(directory),)))
61
+ return tuple(imported)
62
+
63
+
64
+ def __getattr__(name: str) -> Any:
65
+ """Load optional function implementations only when their API is requested."""
66
+ if name == "functions":
67
+ module = import_module(f"{__name__}.functions")
68
+ globals()[name] = module
69
+ return module
70
+ if name in {"energy_closure", "plot_csv", "plot_result"}:
71
+ module = import_module(f"{__name__}.functions")
72
+ globals().update({public: getattr(module, public)
73
+ for public in ("energy_closure", "plot_csv", "plot_result")})
74
+ return globals()[name]
75
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,19 @@
1
+ """Import modules placed in one add-on search package."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from importlib import import_module
6
+ from pkgutil import iter_modules
7
+ from types import ModuleType
8
+ from typing import Iterable
9
+
10
+
11
+ def discover_modules(package: str, paths: Iterable[str]) -> tuple[ModuleType, ...]:
12
+ """Import every module directly contained in ``paths`` in deterministic order.
13
+
14
+ Importing a controller or component module executes its normal PESLite registration
15
+ decorators. Python's module cache makes repeated discovery safe and inexpensive.
16
+ """
17
+ prefix = f"{package}."
18
+ names = sorted(info.name for info in iter_modules(paths, prefix))
19
+ return tuple(import_module(name) for name in names)
@@ -0,0 +1,22 @@
1
+ """Entry point for optional and custom PESLite component modules.
2
+
3
+ Place modules in this package and register their parameter dataclasses with
4
+ ``register_component_type``. PESLite imports each module during package initialisation, so its
5
+ types enter the same registry and configuration search path as built-in circuit elements.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from types import ModuleType
11
+
12
+ from ... import components as _components
13
+ from .._discovery import discover_modules
14
+
15
+ # Add-on components use the exact public component API and the exact built-in element registry.
16
+ globals().update({name: getattr(_components, name) for name in _components.__all__})
17
+ __all__ = [*_components.__all__, "discover"]
18
+
19
+
20
+ def discover() -> tuple[ModuleType, ...]:
21
+ """Import component add-ons found on this package's search path."""
22
+ return discover_modules(__name__, __path__)
@@ -0,0 +1,23 @@
1
+ """Entry point for optional and custom PESLite control-loop modules.
2
+
3
+ Place modules in this package and register their loop classes with
4
+ ``register_loop_type``. PESLite imports each module during package initialisation, so its types
5
+ enter the same registry and configuration search path as built-in control loops.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from types import ModuleType
11
+
12
+ from ... import control as _control
13
+ from .._discovery import discover_modules
14
+
15
+ # An add-on control module gets the same public construction surface as a built-in control module.
16
+ # Keeping this list tied to ``control.__all__`` prevents the two entry points drifting.
17
+ globals().update({name: getattr(_control, name) for name in _control.__all__})
18
+ __all__ = [*_control.__all__, "discover"]
19
+
20
+
21
+ def discover() -> tuple[ModuleType, ...]:
22
+ """Import control add-ons found on this package's search path."""
23
+ return discover_modules(__name__, __path__)
@@ -0,0 +1,20 @@
1
+ """Standard namespace for lazily loaded built-in and project-local functions."""
2
+
3
+ from importlib import import_module
4
+
5
+ _EXPORTS = {
6
+ "energy_closure": ("energy_audit", "energy_closure"),
7
+ "plot_csv": ("plotting", "plot_csv"),
8
+ "plot_result": ("plotting", "plot_result"),
9
+ }
10
+ __all__ = list(_EXPORTS)
11
+
12
+
13
+ def __getattr__(name):
14
+ """Load a public function from its implementation module when requested."""
15
+ if name not in _EXPORTS:
16
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
17
+ module_name, attribute = _EXPORTS[name]
18
+ value = getattr(import_module(f"{__name__}.{module_name}"), attribute)
19
+ globals()[name] = value
20
+ return value
@@ -0,0 +1,76 @@
1
+ """Assembly of a system from a simulation file.
2
+
3
+ ``params``: the file parameters, including runtime changes; ``validate``: cross-section checks;
4
+ ``events``: event types and scenarios; ``protection``: the unified protection subsystem;
5
+ ``unit``: a converter unit; ``system``: the network, registered elements and event operations as
6
+ one model.
7
+ """
8
+
9
+ from .params import (BaseValues, ConfigError, ControlParams, LCCLinkParams, LCCSLinkParams,
10
+ MultiSSLinkParams, Params, SCCParams, SSLinkParams, UnitParams,
11
+ dump, dumps, from_dict, load,
12
+ read_initial, to_dict)
13
+ from .events import (EVENT_TYPES, Event, Scenario, SourceScenario,
14
+ register_event_type)
15
+ from .protection import Protection, ProtectionSample
16
+ from .unit import DCConverter, Unit, VSC
17
+ from .system import System
18
+ from .params import _DCConverterUnitFields, _VSCUnitFields, _WPTUnitFields
19
+ from .system import _assemble_dc_converter, _assemble_vsc, _assemble_wpt
20
+ from .types import register_unit_type
21
+ from .validate import _dc_converter, _unit, _wpt
22
+ from ..control.profiles import control_type
23
+ from . import circuit as _circuit
24
+ from ..solver.netlist import _install_device_runtime
25
+
26
+ _install_device_runtime(_circuit.STANDALONE_RUNTIME)
27
+
28
+ register_unit_type(
29
+ "vsc",
30
+ params=_VSCUnitFields,
31
+ default_bridge="three_phase_bridge",
32
+ default_port="dc",
33
+ ports=("dc", "power"),
34
+ phases=3,
35
+ bridge_types=frozenset(("three_phase_bridge",)),
36
+ measurement_channels=frozenset(("u_g", "i_c", "u_dc")),
37
+ current_channel="i_c",
38
+ protection_criteria=frozenset((
39
+ "overcurrent", "rms_current", "undervoltage", "overvoltage", "frequency", "dc_voltage", "rocof",
40
+ )),
41
+ defaults_grid_frequency=True,
42
+ validator=_unit,
43
+ assembler=_assemble_vsc,
44
+ )
45
+ register_unit_type(
46
+ "dc_converter",
47
+ params=_DCConverterUnitFields,
48
+ default_bridge=lambda control: control_type(control.type).default_bridge,
49
+ default_port="dc",
50
+ ports=("dc", "power"),
51
+ phases=1,
52
+ bridge_types=frozenset(("half_bridge", "full_bridge")),
53
+ measurement_channels=frozenset(("current", "voltage", "vin", "power")),
54
+ current_channel="current",
55
+ protection_criteria=frozenset((
56
+ "overcurrent", "rms_current", "undervoltage", "overvoltage", "dc_voltage",
57
+ )),
58
+ validator=_dc_converter,
59
+ assembler=_assemble_dc_converter,
60
+ )
61
+ register_unit_type(
62
+ "wpt",
63
+ params=_WPTUnitFields,
64
+ children=("primary", "secondary"),
65
+ default_port="primary",
66
+ phases=1,
67
+ validator=_wpt,
68
+ assembler=_assemble_wpt,
69
+ )
70
+
71
+ __all__ = ["Params", "BaseValues", "ConfigError", "load", "dump", "dumps", "from_dict", "to_dict", "read_initial",
72
+ "Event", "EVENT_TYPES", "register_event_type", "Scenario",
73
+ "SourceScenario", "Protection", "ProtectionSample", "Unit", "VSC", "DCConverter",
74
+ "UnitParams", "ControlParams",
75
+ "SSLinkParams", "LCCLinkParams", "LCCSLinkParams", "MultiSSLinkParams", "SCCParams",
76
+ "System"]