PyOpenMagnetics 1.7.16__tar.gz → 1.7.18__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.
Files changed (91) hide show
  1. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/CMakeLists.txt +6 -2
  2. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/PKG-INFO +1 -1
  3. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/pyproject.toml +1 -1
  4. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/winding.cpp +52 -0
  5. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/winding.h +3 -0
  6. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/test_winding.py +55 -0
  7. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/.github/workflows/ci.yml +0 -0
  8. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/.github/workflows/publish.yml +0 -0
  9. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/.gitignore +0 -0
  10. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/AGENTS.md +0 -0
  11. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/LICENSE +0 -0
  12. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/PyOpenMagnetics.pyi +0 -0
  13. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/README.md +0 -0
  14. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/_packaging/__init__.py +0 -0
  15. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/_packaging/_build_info.py.in +0 -0
  16. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/api/MAS.py +0 -0
  17. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/api/mas_db_reader.py +0 -0
  18. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/api/validation.py +0 -0
  19. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/clear_cibuildwheel_cache.sh +0 -0
  20. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/docs/compatibility.md +0 -0
  21. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/docs/errors.md +0 -0
  22. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/docs/performance.md +0 -0
  23. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/README.md +0 -0
  24. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/buck_inductor.py +0 -0
  25. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/complete_simulation_example.py +0 -0
  26. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/converter_design_example.py +0 -0
  27. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/debug_bobbin.py +0 -0
  28. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/debug_coil.py +0 -0
  29. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/debug_core.py +0 -0
  30. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/debug_plotting.py +0 -0
  31. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/flyback_220v_12v_1a.py +0 -0
  32. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/flyback_220v_12v_2a_complete.py +0 -0
  33. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/flyback_bh_curve.png +0 -0
  34. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/flyback_core.png +0 -0
  35. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/flyback_design.py +0 -0
  36. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/flyback_summary.png +0 -0
  37. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/flyback_waveforms.png +0 -0
  38. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/list_plot_funcs.py +0 -0
  39. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/plot_flyback_design.py +0 -0
  40. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/plot_flyback_pyom.py +0 -0
  41. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/test_field_calc.py +0 -0
  42. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/examples/test_field_plot.py +0 -0
  43. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/force_fresh_build.sh +0 -0
  44. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/llms.txt +0 -0
  45. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/notebooks/01_getting_started.ipynb +0 -0
  46. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/notebooks/02_buck_inductor.ipynb +0 -0
  47. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/notebooks/03_core_losses.ipynb +0 -0
  48. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/notebooks/README.md +0 -0
  49. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/requirements.txt +0 -0
  50. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/advisers.cpp +0 -0
  51. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/advisers.h +0 -0
  52. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/bobbin.cpp +0 -0
  53. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/bobbin.h +0 -0
  54. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/cmc.cpp +0 -0
  55. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/cmc.h +0 -0
  56. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/common.h +0 -0
  57. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/converter.cpp +0 -0
  58. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/converter.h +0 -0
  59. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/core.cpp +0 -0
  60. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/core.h +0 -0
  61. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/crossref.cpp +0 -0
  62. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/crossref.h +0 -0
  63. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/database.cpp +0 -0
  64. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/database.h +0 -0
  65. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/logging.cpp +0 -0
  66. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/logging.h +0 -0
  67. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/losses.cpp +0 -0
  68. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/losses.h +0 -0
  69. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/module.cpp +0 -0
  70. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/plotting.cpp +0 -0
  71. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/plotting.h +0 -0
  72. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/settings.cpp +0 -0
  73. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/settings.h +0 -0
  74. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/simulation.cpp +0 -0
  75. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/simulation.h +0 -0
  76. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/utils.cpp +0 -0
  77. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/utils.h +0 -0
  78. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/wire.cpp +0 -0
  79. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/src/wire.h +0 -0
  80. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/test.py +0 -0
  81. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/__init__.py +0 -0
  82. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/conftest.py +0 -0
  83. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/test_converter_endpoints.py +0 -0
  84. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/test_core.py +0 -0
  85. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/test_core_adviser.py +0 -0
  86. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/test_examples_integration.py +0 -0
  87. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/test_inputs.py +0 -0
  88. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/test_logging.py +0 -0
  89. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/test_magnetic_adviser.py +0 -0
  90. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/test_magnetics_catalogue_load.py +0 -0
  91. {pyopenmagnetics-1.7.16 → pyopenmagnetics-1.7.18}/tests/test_plotting.py +0 -0
@@ -464,11 +464,15 @@ cmrc_add_resource_library(insulation_standards ALIAS data::insulation_standards
464
464
  target_link_libraries(PyOpenMagnetics PUBLIC data::insulation_standards)
465
465
 
466
466
 
467
- # Only embed essential data files to reduce binary size
468
- # Skip large optional datasets like cores_stock.ndjson
467
+ # The MAS catalogues MKF reads at runtime. cores_stock.ndjson is NOT optional: it is the SMALL one
468
+ # (1573 cores vs 18943) and it is what load_cores() reads under settings.useOnlyCoresInStock, the
469
+ # default. Without it MKF used to fall back silently to the full cores.ndjson -- ~2.4 GB resident
470
+ # after load_all_databases(), and an available-cores advise that grew past 16 GB (ABT #1328).
471
+ # MKF now refuses that setting when the stock catalogue is missing, so it must be embedded.
469
472
  cmrc_add_resource_library(data ALIAS data::data NAMESPACE data WHENCE ${MAS_DIR} PREFIX MAS
470
473
  ${MAS_DIR}/data/core_materials.ndjson
471
474
  ${MAS_DIR}/data/core_shapes.ndjson
475
+ ${MAS_DIR}/data/cores_stock.ndjson
472
476
  ${MAS_DIR}/data/cores.ndjson
473
477
  ${MAS_DIR}/data/bobbins.ndjson
474
478
  ${MAS_DIR}/data/insulation_materials.ndjson
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PyOpenMagnetics
3
- Version: 1.7.16
3
+ Version: 1.7.18
4
4
  Summary: Python wrapper for OpenMagnetics
5
5
  Author-Email: Alfonso Martinez <Alfonso_VII@hotmail.com>
6
6
  Classifier: Development Status :: 4 - Beta
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "PyOpenMagnetics"
7
- version = "1.7.16"
7
+ version = "1.7.18"
8
8
  requires-python = ">=3.8"
9
9
  authors = [
10
10
  { name="Alfonso Martinez", email="Alfonso_VII@hotmail.com" },
@@ -500,6 +500,32 @@ json get_isolation_side_from_index(size_t index) {
500
500
  return OpenMagnetics::get_isolation_side_from_index(index);
501
501
  }
502
502
 
503
+ json guess_round_wire_from_dc_resistance(json coilJson, json dcResistancesJson, double maxError) {
504
+ if (!dcResistancesJson.is_array()) {
505
+ throw std::invalid_argument("guess_round_wire_from_dc_resistance: dc_resistances must be a list of DC resistances in Ohm, one per winding");
506
+ }
507
+ std::vector<double> dcResistances = dcResistancesJson.get<std::vector<double>>();
508
+ OpenMagnetics::Coil coil(coilJson);
509
+ if (dcResistances.size() != coil.get_functional_description().size()) {
510
+ throw std::invalid_argument("guess_round_wire_from_dc_resistance: got " + std::to_string(dcResistances.size()) +
511
+ " DC resistances for a coil with " + std::to_string(coil.get_functional_description().size()) + " windings");
512
+ }
513
+ for (size_t index = 0; index < dcResistances.size(); ++index) {
514
+ if (!(dcResistances[index] > 0)) {
515
+ throw std::invalid_argument("guess_round_wire_from_dc_resistance: DC resistance of winding " + std::to_string(index) +
516
+ " must be positive, got " + std::to_string(dcResistances[index]));
517
+ }
518
+ }
519
+
520
+ json result = json::array();
521
+ for (auto& wire : coil.guess_round_wire_from_dc_resistance(dcResistances, maxError)) {
522
+ json aux;
523
+ to_json(aux, wire);
524
+ result.push_back(aux);
525
+ }
526
+ return result;
527
+ }
528
+
503
529
  json set_interlayer_insulation(json coilJson, double layerThickness) {
504
530
  OpenMagnetics::Coil coil(coilJson, false);
505
531
  coil.set_interlayer_insulation(layerThickness);
@@ -868,6 +894,32 @@ void register_winding_bindings(py::module& m) {
868
894
  py::arg("index"),
869
895
  py::call_guard<py::gil_scoped_release>());
870
896
 
897
+ m.def("guess_round_wire_from_dc_resistance", &guess_round_wire_from_dc_resistance,
898
+ R"pbdoc(
899
+ Guess the round wire of each winding from its measured DC resistance.
900
+
901
+ Winds the coil, then iteratively replaces each winding's wire with the
902
+ round wire whose DC resistance per meter matches the target over the
903
+ wound wire length, re-winding until every winding is within max_error
904
+ (or the chosen wires stop changing).
905
+
906
+ Args:
907
+ coil_json: JSON Coil with bobbin and functionalDescription (any
908
+ initial wire; it is replaced).
909
+ dc_resistances: DC resistance in Ohm per winding, same order as
910
+ functionalDescription.
911
+ max_error: Maximum relative DC-resistance error (default 0.05).
912
+
913
+ Returns:
914
+ JSON array of Wire objects, one per winding.
915
+
916
+ Raises:
917
+ EngineError if dc_resistances is not a list, its length differs from
918
+ the number of windings, or any value is not positive.
919
+ )pbdoc",
920
+ py::arg("coil_json"), py::arg("dc_resistances"), py::arg("max_error") = 0.05,
921
+ py::call_guard<py::gil_scoped_release>());
922
+
871
923
  m.def("set_interlayer_insulation", &set_interlayer_insulation,
872
924
  R"pbdoc(
873
925
  Set interlayer insulation for a coil.
@@ -39,6 +39,9 @@ json set_interlayer_insulation(json coilJson, double layerThickness);
39
39
  json set_intersection_insulation(json coilJson, double layerThickness, int numberInsulationLayers);
40
40
  json get_solid_insulation_requirements_for_wires(json inputsJson, json patternJson, int repetitions);
41
41
 
42
+ // Wire estimation
43
+ json guess_round_wire_from_dc_resistance(json coilJson, json dcResistancesJson, double maxError);
44
+
42
45
  void register_winding_bindings(py::module& m);
43
46
 
44
47
  } // namespace PyMKF
@@ -99,3 +99,58 @@ class TestInsulationMaterials:
99
99
  if len(names) > 0:
100
100
  material = PyOpenMagnetics.find_insulation_material_by_name(names[0])
101
101
  assert isinstance(material, dict)
102
+
103
+
104
+ class TestGuessRoundWireFromDcResistance:
105
+ """Round-wire estimation from measured per-winding DC resistance."""
106
+
107
+ @staticmethod
108
+ def _current_transformer_coil(sample_toroidal_core, primary_wire, secondary_wire):
109
+ core = PyOpenMagnetics.calculate_core_data(sample_toroidal_core, False)
110
+ bobbin = PyOpenMagnetics.create_basic_bobbin(core, True)
111
+ return {
112
+ "bobbin": bobbin,
113
+ "functionalDescription": [
114
+ {"name": "primary", "numberTurns": 1, "numberParallels": 1,
115
+ "isolationSide": PyOpenMagnetics.get_isolation_side_from_index(0), "wire": primary_wire},
116
+ {"name": "secondary", "numberTurns": 50, "numberParallels": 1,
117
+ "isolationSide": PyOpenMagnetics.get_isolation_side_from_index(1), "wire": secondary_wire},
118
+ ],
119
+ }
120
+
121
+ def test_round_trip_recovers_dc_resistance(self, sample_toroidal_core):
122
+ """Wires guessed from a known coil's DC resistances reproduce those resistances."""
123
+ reference = self._current_transformer_coil(sample_toroidal_core, "Round 0.90 - Grade 1", "Round 0.212 - Grade 1")
124
+ wound = PyOpenMagnetics.wind(reference, 1, [0.5, 0.5], [0, 1], [])
125
+ dc_resistances = PyOpenMagnetics.calculate_dc_resistance_per_winding(wound, 25)
126
+
127
+ # Start from the thinnest wire, as heimdall's current-transformer translator does.
128
+ guess = self._current_transformer_coil(sample_toroidal_core, "Round 0.01 - Grade 1", "Round 0.01 - Grade 1")
129
+ wires = PyOpenMagnetics.guess_round_wire_from_dc_resistance(guess, dc_resistances)
130
+
131
+ assert isinstance(wires, list)
132
+ assert len(wires) == 2
133
+ for wire in wires:
134
+ assert wire["type"] == "round"
135
+
136
+ # A 1-turn primary needs a far thicker conductor than a 50-turn secondary.
137
+ assert wires[0]["conductingDiameter"]["nominal"] > wires[1]["conductingDiameter"]["nominal"]
138
+
139
+ guess["functionalDescription"][0]["wire"] = wires[0]
140
+ guess["functionalDescription"][1]["wire"] = wires[1]
141
+ rewound = PyOpenMagnetics.wind(guess, 1, [0.5, 0.5], [0, 1], [])
142
+ recovered = PyOpenMagnetics.calculate_dc_resistance_per_winding(rewound, 25)
143
+ for target, value in zip(dc_resistances, recovered):
144
+ assert abs(value - target) / target < 0.05
145
+
146
+ def test_rejects_resistance_count_mismatch(self, sample_toroidal_core):
147
+ """One DC resistance per winding is required."""
148
+ coil = self._current_transformer_coil(sample_toroidal_core, "Round 0.01 - Grade 1", "Round 0.01 - Grade 1")
149
+ with pytest.raises(PyOpenMagnetics.EngineError):
150
+ PyOpenMagnetics.guess_round_wire_from_dc_resistance(coil, [0.001])
151
+
152
+ def test_rejects_non_positive_resistance(self, sample_toroidal_core):
153
+ """A zero DC resistance has no wire and must not be silently mapped to one."""
154
+ coil = self._current_transformer_coil(sample_toroidal_core, "Round 0.01 - Grade 1", "Round 0.01 - Grade 1")
155
+ with pytest.raises(PyOpenMagnetics.EngineError):
156
+ PyOpenMagnetics.guess_round_wire_from_dc_resistance(coil, [0.001, 0.0])