PyOpenMagnetics 1.7.28__tar.gz → 1.7.29__tar.gz
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.
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/CMakeLists.txt +1 -1
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/PKG-INFO +1 -1
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/PyOpenMagnetics.pyi +3 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/pyproject.toml +1 -1
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/advisers.cpp +20 -1
- pyopenmagnetics-1.7.29/tests/test_losses_not_evaluable_catalogue.py +62 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/.github/workflows/ci.yml +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/.github/workflows/publish.yml +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/.gitignore +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/AGENTS.md +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/LICENSE +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/README.md +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/_packaging/__init__.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/_packaging/_build_info.py.in +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/api/MAS.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/api/mas_db_reader.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/api/validation.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/clear_cibuildwheel_cache.sh +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/docs/compatibility.md +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/docs/errors.md +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/docs/performance.md +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/README.md +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/buck_inductor.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/complete_simulation_example.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/converter_design_example.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/debug_bobbin.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/debug_coil.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/debug_core.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/debug_plotting.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/flyback_220v_12v_1a.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/flyback_220v_12v_2a_complete.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/flyback_bh_curve.png +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/flyback_core.png +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/flyback_design.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/flyback_summary.png +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/flyback_waveforms.png +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/list_plot_funcs.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/plot_flyback_design.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/plot_flyback_pyom.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/test_field_calc.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/examples/test_field_plot.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/force_fresh_build.sh +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/llms.txt +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/notebooks/01_getting_started.ipynb +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/notebooks/02_buck_inductor.ipynb +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/notebooks/03_core_losses.ipynb +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/notebooks/README.md +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/requirements.txt +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/advisers.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/bobbin.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/bobbin.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/cmc.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/cmc.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/common.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/converter.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/converter.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/core.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/core.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/crossref.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/crossref.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/database.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/database.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/logging.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/logging.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/losses.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/losses.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/module.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/plotting.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/plotting.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/settings.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/settings.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/simulation.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/simulation.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/utils.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/utils.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/winding.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/winding.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/wire.cpp +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/src/wire.h +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/test.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/__init__.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/conftest.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_converter_endpoints.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_core.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_core_adviser.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_datasheet_only_catalogue.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_examples_integration.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_inputs.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_logging.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_magnetic_adviser.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_magnetics_catalogue_load.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_mas_schema_walk.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_material_validator.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_plotting.py +0 -0
- {pyopenmagnetics-1.7.28 → pyopenmagnetics-1.7.29}/tests/test_winding.py +0 -0
|
@@ -142,7 +142,7 @@ if(NOT LOCAL_MKF_MAS)
|
|
|
142
142
|
set(MKF_GIT_TAG "main"
|
|
143
143
|
CACHE STRING "MKF git ref for the vendored PyOM build")
|
|
144
144
|
# Force fresh clone by using a unique timestamp - update this when the pin changes
|
|
145
|
-
set(MKF_FORCE_REFRESH "2026-09-30-mkf-
|
|
145
|
+
set(MKF_FORCE_REFRESH "2026-09-30-mkf-8b334ca7")
|
|
146
146
|
# Tell MKF to disable matplotplusplus and use SVG-based Painter instead
|
|
147
147
|
set(INCLUDE_PYMKF ON CACHE BOOL "Build Python interface" FORCE)
|
|
148
148
|
# GIT_SUBMODULES_RECURSE pulls in CAS/PEAS (added 2026-04 alongside the
|
|
@@ -676,6 +676,9 @@ def calculate_advised_magnetics_from_catalog(
|
|
|
676
676
|
- "mas": Mas object with magnetic data
|
|
677
677
|
- "scoring": Overall float score
|
|
678
678
|
- "scoringPerFilter": Object with individual scores per filter
|
|
679
|
+
- "lossesNotEvaluable" (only on such parts): why the part's core losses could not be
|
|
680
|
+
evaluated (its core material has no core-loss model); it is ranked without any
|
|
681
|
+
loss-based filter and returned without simulated outputs.
|
|
679
682
|
"""
|
|
680
683
|
...
|
|
681
684
|
|
|
@@ -195,6 +195,7 @@ json calculate_advised_magnetics_from_catalog(json inputsJson, json catalogJson,
|
|
|
195
195
|
auto masMagnetics = magneticAdviser.get_advised_magnetic(inputs, catalog, maximumNumberResults);
|
|
196
196
|
|
|
197
197
|
auto scoringsPerFilter = magneticAdviser.get_scorings();
|
|
198
|
+
const auto& lossesNotEvaluable = magneticAdviser.get_losses_not_evaluable();
|
|
198
199
|
|
|
199
200
|
json results = json();
|
|
200
201
|
results["data"] = json::array();
|
|
@@ -212,6 +213,11 @@ json calculate_advised_magnetics_from_catalog(json inputsJson, json catalogJson,
|
|
|
212
213
|
}
|
|
213
214
|
result["scoringPerFilter"] = filterScorings;
|
|
214
215
|
}
|
|
216
|
+
// A part whose core material has no core-loss model is ranked without the loss filters
|
|
217
|
+
// and returned without simulated outputs; this field says so, and why.
|
|
218
|
+
if (name && lossesNotEvaluable.count(*name)) {
|
|
219
|
+
result["lossesNotEvaluable"] = lossesNotEvaluable.at(*name);
|
|
220
|
+
}
|
|
215
221
|
results["data"].push_back(result);
|
|
216
222
|
}
|
|
217
223
|
|
|
@@ -247,6 +253,7 @@ json calculate_advised_magnetics_from_cache(json inputsJson, json filterFlowJson
|
|
|
247
253
|
: magneticAdviser.get_advised_magnetic(inputs, OpenMagnetics::magneticsCache.get(), filterFlow, maximumNumberResults);
|
|
248
254
|
|
|
249
255
|
auto scoringsPerFilter = magneticAdviser.get_scorings();
|
|
256
|
+
const auto& lossesNotEvaluable = magneticAdviser.get_losses_not_evaluable();
|
|
250
257
|
|
|
251
258
|
json results = json();
|
|
252
259
|
results["data"] = json::array();
|
|
@@ -264,6 +271,11 @@ json calculate_advised_magnetics_from_cache(json inputsJson, json filterFlowJson
|
|
|
264
271
|
}
|
|
265
272
|
result["scoringPerFilter"] = filterScorings;
|
|
266
273
|
}
|
|
274
|
+
// A part whose core material has no core-loss model is ranked without the loss filters
|
|
275
|
+
// and returned without simulated outputs; this field says so, and why.
|
|
276
|
+
if (name && lossesNotEvaluable.count(*name)) {
|
|
277
|
+
result["lossesNotEvaluable"] = lossesNotEvaluable.at(*name);
|
|
278
|
+
}
|
|
267
279
|
results["data"].push_back(result);
|
|
268
280
|
}
|
|
269
281
|
|
|
@@ -491,7 +503,10 @@ void register_adviser_bindings(py::module& m) {
|
|
|
491
503
|
- "mas": Mas object with magnetic data
|
|
492
504
|
- "scoring": Overall float score
|
|
493
505
|
- "scoringPerFilter": Object with individual scores per filter
|
|
494
|
-
|
|
506
|
+
- "lossesNotEvaluable" (only on such parts): why this part's core losses could
|
|
507
|
+
not be evaluated -- its core material carries no core-loss model. The part is
|
|
508
|
+
ranked without any loss-based filter and returned without simulated outputs.
|
|
509
|
+
|
|
495
510
|
Example:
|
|
496
511
|
>>> inputs = PyMKF.process_inputs(raw_inputs)
|
|
497
512
|
>>> catalog = [magnetic1, magnetic2, magnetic3]
|
|
@@ -531,6 +546,10 @@ void register_adviser_bindings(py::module& m) {
|
|
|
531
546
|
- "mas": Mas object with magnetic data
|
|
532
547
|
- "scoring": Overall float score
|
|
533
548
|
- "scoringPerFilter": Object with individual scores per filter
|
|
549
|
+
- "lossesNotEvaluable" (only on such parts): why this part's core losses could
|
|
550
|
+
not be evaluated -- its core material carries no core-loss model. The part is
|
|
551
|
+
ranked on the filters that apply to it, with no loss-based filter scored, and
|
|
552
|
+
is returned without simulated outputs.
|
|
534
553
|
|
|
535
554
|
Note:
|
|
536
555
|
Cache must be populated before calling this function.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A catalogue part whose core material carries no core-loss data any model can run
|
|
3
|
+
(`volumetricLosses: {}`, no `massLosses`) must neither abort the catalogue adviser nor vanish
|
|
4
|
+
from its results. Like a datasheet-only part, the loss-based filters do not apply to it (no score,
|
|
5
|
+
never a stand-in loss), it is ranked on the filters that do, and the result says why its losses
|
|
6
|
+
were not judged, in "lossesNotEvaluable".
|
|
7
|
+
"""
|
|
8
|
+
import json
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
import PyOpenMagnetics
|
|
13
|
+
|
|
14
|
+
from .test_datasheet_only_catalogue import buck_inputs, modelled_part, references_of
|
|
15
|
+
|
|
16
|
+
LOSSLESS_MATERIAL = "Test Ferrite Without Loss Data"
|
|
17
|
+
|
|
18
|
+
FLOW = [
|
|
19
|
+
{"filter": "Losses No Proximity", "invert": True, "log": False, "strictlyRequired": False, "weight": 1.0},
|
|
20
|
+
{"filter": "Volume", "invert": True, "log": False, "strictlyRequired": False, "weight": 1.0},
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def lossless_part(reference):
|
|
25
|
+
"""The modelled part, on N87 with its core-loss data removed, as MAS stores a material nobody
|
|
26
|
+
has measured losses for."""
|
|
27
|
+
material = PyOpenMagnetics.find_core_material_by_name("N87")
|
|
28
|
+
material["name"] = LOSSLESS_MATERIAL
|
|
29
|
+
material["volumetricLosses"] = {}
|
|
30
|
+
material.pop("massLosses", None)
|
|
31
|
+
part = modelled_part(reference)
|
|
32
|
+
part["core"]["functionalDescription"]["material"] = material
|
|
33
|
+
return part
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@pytest.fixture
|
|
37
|
+
def catalogue(tmp_path):
|
|
38
|
+
PyOpenMagnetics.clear_magnetic_cache()
|
|
39
|
+
path = tmp_path / "catalogue.ndjson"
|
|
40
|
+
parts = [modelled_part("NORMAL-A"), lossless_part("LOSSLESS"), modelled_part("NORMAL-B")]
|
|
41
|
+
path.write_text("\n".join(json.dumps(part) for part in parts) + "\n", encoding="utf-8")
|
|
42
|
+
PyOpenMagnetics.load_magnetics_from_file(str(path), True)
|
|
43
|
+
yield
|
|
44
|
+
PyOpenMagnetics.clear_magnetic_cache()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_a_part_without_a_core_loss_model_is_ranked_and_flagged(catalogue):
|
|
48
|
+
result = PyOpenMagnetics.calculate_advised_magnetics_from_cache(buck_inputs(), FLOW, 10)
|
|
49
|
+
|
|
50
|
+
assert set(references_of(result)) == {"NORMAL-A", "LOSSLESS", "NORMAL-B"}
|
|
51
|
+
by_reference = {item["mas"]["magnetic"]["manufacturerInfo"]["reference"]: item for item in result["data"]}
|
|
52
|
+
|
|
53
|
+
flagged = by_reference["LOSSLESS"]
|
|
54
|
+
assert LOSSLESS_MATERIAL in flagged["lossesNotEvaluable"]
|
|
55
|
+
assert "no core-loss data" in flagged["lossesNotEvaluable"]
|
|
56
|
+
# Ranked only on what applies to it: no loss score, never a stand-in.
|
|
57
|
+
assert "LOSSES_NO_PROXIMITY" not in flagged["scoringPerFilter"]
|
|
58
|
+
assert "VOLUME" in flagged["scoringPerFilter"]
|
|
59
|
+
|
|
60
|
+
for reference in ("NORMAL-A", "NORMAL-B"):
|
|
61
|
+
assert "lossesNotEvaluable" not in by_reference[reference]
|
|
62
|
+
assert "LOSSES_NO_PROXIMITY" in by_reference[reference]["scoringPerFilter"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|