PyOpenMagnetics 1.3.10__tar.gz → 1.3.12__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 (84) hide show
  1. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/CMakeLists.txt +14 -2
  2. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/PKG-INFO +1 -1
  3. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/PyOpenMagnetics.pyi +36 -0
  4. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/pyproject.toml +1 -1
  5. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/converter.cpp +495 -3
  6. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/converter.h +11 -0
  7. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/.github/workflows/ci.yml +0 -0
  8. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/.github/workflows/publish.yml +0 -0
  9. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/.gitignore +0 -0
  10. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/AGENTS.md +0 -0
  11. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/LICENSE +0 -0
  12. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/README.md +0 -0
  13. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/api/MAS.py +0 -0
  14. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/api/mas_db_reader.py +0 -0
  15. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/api/validation.py +0 -0
  16. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/clear_cibuildwheel_cache.sh +0 -0
  17. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/docs/compatibility.md +0 -0
  18. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/docs/errors.md +0 -0
  19. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/docs/performance.md +0 -0
  20. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/README.md +0 -0
  21. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/buck_inductor.py +0 -0
  22. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/complete_simulation_example.py +0 -0
  23. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/converter_design_example.py +0 -0
  24. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/debug_bobbin.py +0 -0
  25. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/debug_coil.py +0 -0
  26. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/debug_core.py +0 -0
  27. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/debug_plotting.py +0 -0
  28. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/flyback_220v_12v_1a.py +0 -0
  29. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/flyback_220v_12v_2a_complete.py +0 -0
  30. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/flyback_bh_curve.png +0 -0
  31. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/flyback_core.png +0 -0
  32. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/flyback_design.py +0 -0
  33. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/flyback_summary.png +0 -0
  34. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/flyback_waveforms.png +0 -0
  35. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/list_plot_funcs.py +0 -0
  36. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/plot_flyback_design.py +0 -0
  37. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/plot_flyback_pyom.py +0 -0
  38. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/test_field_calc.py +0 -0
  39. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/examples/test_field_plot.py +0 -0
  40. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/force_fresh_build.sh +0 -0
  41. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/llms.txt +0 -0
  42. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/notebooks/01_getting_started.ipynb +0 -0
  43. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/notebooks/02_buck_inductor.ipynb +0 -0
  44. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/notebooks/03_core_losses.ipynb +0 -0
  45. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/notebooks/README.md +0 -0
  46. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/requirements.txt +0 -0
  47. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/advisers.cpp +0 -0
  48. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/advisers.h +0 -0
  49. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/bobbin.cpp +0 -0
  50. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/bobbin.h +0 -0
  51. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/common.h +0 -0
  52. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/core.cpp +0 -0
  53. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/core.h +0 -0
  54. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/database.cpp +0 -0
  55. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/database.h +0 -0
  56. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/logging.cpp +0 -0
  57. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/logging.h +0 -0
  58. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/losses.cpp +0 -0
  59. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/losses.h +0 -0
  60. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/module.cpp +0 -0
  61. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/plotting.cpp +0 -0
  62. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/plotting.h +0 -0
  63. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/settings.cpp +0 -0
  64. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/settings.h +0 -0
  65. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/simulation.cpp +0 -0
  66. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/simulation.h +0 -0
  67. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/utils.cpp +0 -0
  68. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/utils.h +0 -0
  69. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/winding.cpp +0 -0
  70. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/winding.h +0 -0
  71. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/wire.cpp +0 -0
  72. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/src/wire.h +0 -0
  73. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/test.py +0 -0
  74. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/tests/__init__.py +0 -0
  75. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/tests/conftest.py +0 -0
  76. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/tests/test_converter_endpoints.py +0 -0
  77. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/tests/test_core.py +0 -0
  78. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/tests/test_core_adviser.py +0 -0
  79. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/tests/test_examples_integration.py +0 -0
  80. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/tests/test_inputs.py +0 -0
  81. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/tests/test_logging.py +0 -0
  82. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/tests/test_magnetic_adviser.py +0 -0
  83. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/tests/test_plotting.py +0 -0
  84. {pyopenmagnetics-1.3.10 → pyopenmagnetics-1.3.12}/tests/test_winding.py +0 -0
@@ -232,7 +232,6 @@ add_custom_command(
232
232
  -S ${MAS_DIR}/schemas/inputs/topologies/currentTransformer.json
233
233
  -S ${MAS_DIR}/schemas/inputs/topologies/boost.json
234
234
  -S ${MAS_DIR}/schemas/inputs/topologies/buck.json
235
- -S ${MAS_DIR}/schemas/inputs/topologies/flybuck.json
236
235
  -S ${MAS_DIR}/schemas/inputs/topologies/forward.json
237
236
  -S ${MAS_DIR}/schemas/inputs/topologies/isolatedBuck.json
238
237
  -S ${MAS_DIR}/schemas/inputs/topologies/isolatedBuckBoost.json
@@ -240,7 +239,20 @@ add_custom_command(
240
239
  -S ${MAS_DIR}/schemas/inputs/topologies/dualActiveBridge.json
241
240
  -S ${MAS_DIR}/schemas/inputs/topologies/llcResonant.json
242
241
  -S ${MAS_DIR}/schemas/inputs/topologies/cllcResonant.json
243
- -S ${MAS_DIR}/schemas/inputs/topologies/phaseShiftFullBridge.json
242
+ -S ${MAS_DIR}/schemas/inputs/topologies/clllcResonant.json
243
+ -S ${MAS_DIR}/schemas/inputs/topologies/phaseShiftedFullBridge.json
244
+ -S ${MAS_DIR}/schemas/inputs/topologies/phaseShiftedHalfBridge.json
245
+ -S ${MAS_DIR}/schemas/inputs/topologies/powerFactorCorrection.json
246
+ -S ${MAS_DIR}/schemas/inputs/topologies/commonModeChoke.json
247
+ -S ${MAS_DIR}/schemas/inputs/topologies/differentialModeChoke.json
248
+ -S ${MAS_DIR}/schemas/inputs/topologies/asymmetricHalfBridge.json
249
+ -S ${MAS_DIR}/schemas/inputs/topologies/cuk.json
250
+ -S ${MAS_DIR}/schemas/inputs/topologies/sepic.json
251
+ -S ${MAS_DIR}/schemas/inputs/topologies/zeta.json
252
+ -S ${MAS_DIR}/schemas/inputs/topologies/weinberg.json
253
+ -S ${MAS_DIR}/schemas/inputs/topologies/fourSwitchBuckBoost.json
254
+ -S ${MAS_DIR}/schemas/inputs/topologies/seriesResonant.json
255
+ -S ${MAS_DIR}/schemas/inputs/topologies/vienna.json
244
256
  -o ${MAS_DIRECTORY}/MAS.hpp --namespace MAS --source-style single-source --type-style pascal-case --member-style underscore-case --enumerator-style upper-underscore-case --no-boost
245
257
  USES_TERMINAL)
246
258
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PyOpenMagnetics
3
- Version: 1.3.10
3
+ Version: 1.3.12
4
4
  Summary: Python wrapper for OpenMagnetics
5
5
  Author-Email: Alfonso Martinez <Alfonso_VII@hotmail.com>
6
6
  Classifier: Development Status :: 4 - Beta
@@ -960,3 +960,39 @@ def process_isolated_buck_boost(isolated_buck_boost: JsonDict) -> Inputs:
960
960
  def process_current_transformer(ct: JsonDict, turns_ratio: float, secondary_resistance: float = 0.0) -> Inputs:
961
961
  """Process Current Transformer specification to Inputs."""
962
962
  ...
963
+
964
+ def process_cuk(cuk: JsonDict) -> Inputs:
965
+ """Process Cuk converter specification to Inputs."""
966
+ ...
967
+
968
+ def process_sepic(sepic: JsonDict) -> Inputs:
969
+ """Process SEPIC converter specification to Inputs."""
970
+ ...
971
+
972
+ def process_zeta(zeta: JsonDict) -> Inputs:
973
+ """Process Zeta converter specification to Inputs."""
974
+ ...
975
+
976
+ def process_four_switch_buck_boost(converter: JsonDict) -> Inputs:
977
+ """Process Four-Switch Buck-Boost converter specification to Inputs."""
978
+ ...
979
+
980
+ def process_asymmetric_half_bridge(converter: JsonDict) -> Inputs:
981
+ """Process Asymmetric Half-Bridge converter specification to Inputs."""
982
+ ...
983
+
984
+ def process_weinberg(converter: JsonDict) -> Inputs:
985
+ """Process Weinberg converter specification to Inputs."""
986
+ ...
987
+
988
+ def process_vienna(converter: JsonDict) -> Inputs:
989
+ """Process Vienna Rectifier converter specification to Inputs."""
990
+ ...
991
+
992
+ def process_clllc(converter: JsonDict) -> Inputs:
993
+ """Process CLLLC Resonant converter specification to Inputs."""
994
+ ...
995
+
996
+ def process_src(converter: JsonDict) -> Inputs:
997
+ """Process Series Resonant Converter (SRC) specification to Inputs."""
998
+ ...
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "PyOpenMagnetics"
7
- version = "1.3.10"
7
+ version = "1.3.12"
8
8
  requires-python = ">=3.8"
9
9
  authors = [
10
10
  { name="Alfonso Martinez", email="Alfonso_VII@hotmail.com" },
@@ -17,9 +17,134 @@
17
17
  #include "converter_models/IsolatedBuckBoost.h"
18
18
  #include "converter_models/CurrentTransformer.h"
19
19
  #include "converter_models/PowerFactorCorrection.h"
20
+ #include "converter_models/Cuk.h"
21
+ #include "converter_models/Sepic.h"
22
+ #include "converter_models/Zeta.h"
23
+ #include "converter_models/FourSwitchBuckBoost.h"
24
+ #include "converter_models/AsymmetricHalfBridge.h"
25
+ #include "converter_models/Weinberg.h"
26
+ #include "converter_models/Vienna.h"
27
+ #include "converter_models/Clllc.h"
28
+ #include "converter_models/Src.h"
29
+ #include "constructive_models/MasMigration.h"
30
+
31
+ #include <set>
32
+ #include <unordered_map>
20
33
 
21
34
  namespace PyMKF {
22
35
 
36
+ // ------------------------------------------------------------------
37
+ // Topology name normalization.
38
+ //
39
+ // dispatch_converter() below uses legacy short forms ("flyback", "buck",
40
+ // ...). External callers may pass:
41
+ // * the same short form (canonical internal),
42
+ // * the MAS 1.0 camelCase enum value ("flybackConverter", ...),
43
+ // * or the pre-1.0 Title Case label ("Flyback Converter", ...).
44
+ //
45
+ // Normalize all three to the internal short form so process_converter()
46
+ // and design_magnetics_from_converter() transparently accept any of them.
47
+ // ------------------------------------------------------------------
48
+ static std::string normalize_topology_name(const std::string& s) {
49
+ static const std::set<std::string> short_forms = {
50
+ "flyback", "advanced_flyback",
51
+ "buck", "advanced_buck",
52
+ "boost", "advanced_boost",
53
+ "single_switch_forward",
54
+ "two_switch_forward",
55
+ "active_clamp_forward",
56
+ "push_pull",
57
+ "llc", "advanced_llc",
58
+ "cllc", "advanced_cllc",
59
+ "dab", "advanced_dab",
60
+ "phase_shifted_full_bridge", "psfb",
61
+ "phase_shifted_half_bridge", "pshb",
62
+ "isolated_buck",
63
+ "isolated_buck_boost",
64
+ "current_transformer",
65
+ "power_factor_correction", "pfc",
66
+ "cuk", "advanced_cuk",
67
+ "sepic", "advanced_sepic",
68
+ "zeta", "advanced_zeta",
69
+ "four_switch_buck_boost", "advanced_four_switch_buck_boost",
70
+ "asymmetric_half_bridge", "advanced_asymmetric_half_bridge",
71
+ "weinberg", "advanced_weinberg",
72
+ "vienna", "advanced_vienna",
73
+ "clllc", "advanced_clllc",
74
+ "src", "advanced_src"
75
+ };
76
+ if (short_forms.count(s)) return s;
77
+
78
+ static const std::unordered_map<std::string, std::string> aliases = {
79
+ // MAS 1.0 camelCase (canonical for designRequirements.topology)
80
+ {"flybackConverter", "flyback"},
81
+ {"buckConverter", "buck"},
82
+ {"boostConverter", "boost"},
83
+ {"singleSwitchForwardConverter", "single_switch_forward"},
84
+ {"twoSwitchForwardConverter", "two_switch_forward"},
85
+ {"activeClampForwardConverter", "active_clamp_forward"},
86
+ {"pushPullConverter", "push_pull"},
87
+ {"llcResonantConverter", "llc"},
88
+ {"llcConverter", "llc"},
89
+ {"cllcResonantConverter", "cllc"},
90
+ {"cllcConverter", "cllc"},
91
+ {"dualActiveBridgeConverter", "dab"},
92
+ {"phaseShiftedFullBridgeConverter", "phase_shifted_full_bridge"},
93
+ {"phaseShiftedHalfBridgeConverter", "phase_shifted_half_bridge"},
94
+ {"isolatedBuckConverter", "isolated_buck"},
95
+ {"isolatedBuckBoostConverter", "isolated_buck_boost"},
96
+ {"currentTransformer", "current_transformer"},
97
+ {"powerFactorCorrection", "power_factor_correction"},
98
+ {"cukConverter", "cuk"},
99
+ {"sepicConverter", "sepic"},
100
+ {"zetaConverter", "zeta"},
101
+ {"fourSwitchBuckBoostConverter", "four_switch_buck_boost"},
102
+ {"asymmetricHalfBridgeConverter", "asymmetric_half_bridge"},
103
+ {"weinbergConverter", "weinberg"},
104
+ {"viennaRectifierConverter", "vienna"},
105
+ {"clllcResonantConverter", "clllc"},
106
+ {"seriesResonantConverter", "src"},
107
+
108
+ // Pre-1.0 Title Case labels
109
+ {"Flyback Converter", "flyback"},
110
+ {"Buck Converter", "buck"},
111
+ {"Boost Converter", "boost"},
112
+ {"Single-Switch Forward Converter", "single_switch_forward"},
113
+ {"Two-Switch Forward Converter", "two_switch_forward"},
114
+ {"Active-Clamp Forward Converter", "active_clamp_forward"},
115
+ {"Push-Pull Converter", "push_pull"},
116
+ {"LLC Resonant Converter", "llc"},
117
+ {"LLC Converter", "llc"},
118
+ {"CLLC Resonant Converter", "cllc"},
119
+ {"Dual Active Bridge Converter", "dab"},
120
+ {"Phase-Shifted Full Bridge Converter", "phase_shifted_full_bridge"},
121
+ {"Phase-Shifted Half Bridge Converter", "phase_shifted_half_bridge"},
122
+ {"Isolated Buck Converter", "isolated_buck"},
123
+ {"Isolated Buck-Boost Converter", "isolated_buck_boost"},
124
+ {"Current Transformer", "current_transformer"},
125
+ {"Power Factor Correction", "power_factor_correction"},
126
+ {"Cuk Converter", "cuk"},
127
+ {"SEPIC Converter", "sepic"},
128
+ {"Sepic Converter", "sepic"},
129
+ {"Zeta Converter", "zeta"},
130
+ {"Four-Switch Buck-Boost Converter", "four_switch_buck_boost"},
131
+ {"Asymmetric Half-Bridge Converter", "asymmetric_half_bridge"},
132
+ {"Weinberg Converter", "weinberg"},
133
+ {"Vienna Rectifier Converter", "vienna"},
134
+ {"Vienna Rectifier", "vienna"},
135
+ {"CLLLC Resonant Converter", "clllc"},
136
+ {"Series Resonant Converter", "src"},
137
+ {"SRC", "src"}
138
+ };
139
+
140
+ auto it = aliases.find(s);
141
+ if (it != aliases.end()) return it->second;
142
+
143
+ // Pass through unchanged; dispatch_converter() will throw if it is
144
+ // truly unknown. We never silently substitute an unrelated topology.
145
+ return s;
146
+ }
147
+
23
148
  OpenMagnetics::Inputs process_flyback_internal(const json& converterJson, bool useNgspice) {
24
149
  OpenMagnetics::AdvancedFlyback converter(converterJson);
25
150
  converter._assertErrors = true;
@@ -363,6 +488,195 @@ OpenMagnetics::Inputs process_pfc_internal(const json& converterJson) {
363
488
  return converter.process();
364
489
  }
365
490
 
491
+ // ─────────────────────────────────────────────────────────────────────
492
+ // 9 new topology bindings (2026-05): Cuk, Sepic, Zeta,
493
+ // FourSwitchBuckBoost, AsymmetricHalfBridge, Weinberg, Vienna, Clllc,
494
+ // Src. All have first-class implementations in MKF's converter_models/
495
+ // — they were just not wired through PyMKF until now.
496
+ //
497
+ // Pattern groups:
498
+ // * Single-inductor non-isolated (Cuk, Sepic, Zeta, FSBB) follow the
499
+ // Buck/Boost pattern: AdvancedXxx::process() + simulate via inductance.
500
+ // * Isolated with vector turns ratios (AsymHB, Clllc) follow the LLC
501
+ // pattern.
502
+ // * Weinberg has scalar turns ratio (single-secondary topology) — its
503
+ // ngspice dispatch lives separately below.
504
+ // * Vienna and Src have AdvancedXxx classes that only override
505
+ // process_design_requirements(); the inherited Topology::process()
506
+ // handles them. They follow the PFC pattern (no useNgspice branch).
507
+ // ─────────────────────────────────────────────────────────────────────
508
+
509
+ OpenMagnetics::Inputs process_cuk_internal(const json& converterJson, bool useNgspice) {
510
+ OpenMagnetics::AdvancedCuk converter(converterJson);
511
+ converter._assertErrors = true;
512
+ if (useNgspice) {
513
+ auto designReqs = converter.process_design_requirements();
514
+ double inductance = OpenMagnetics::resolve_dimensional_values(designReqs.get_magnetizing_inductance());
515
+ auto operatingPoints = converter.simulate_and_extract_operating_points(inductance);
516
+ OpenMagnetics::Inputs result;
517
+ result.set_design_requirements(designReqs);
518
+ result.set_operating_points(operatingPoints);
519
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::CUK_CONVERTER);
520
+ return result;
521
+ } else {
522
+ OpenMagnetics::Inputs result = converter.process();
523
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::CUK_CONVERTER);
524
+ return result;
525
+ }
526
+ }
527
+
528
+ OpenMagnetics::Inputs process_sepic_internal(const json& converterJson, bool useNgspice) {
529
+ OpenMagnetics::AdvancedSepic converter(converterJson);
530
+ converter._assertErrors = true;
531
+ if (useNgspice) {
532
+ auto designReqs = converter.process_design_requirements();
533
+ double inductance = OpenMagnetics::resolve_dimensional_values(designReqs.get_magnetizing_inductance());
534
+ auto operatingPoints = converter.simulate_and_extract_operating_points(inductance);
535
+ OpenMagnetics::Inputs result;
536
+ result.set_design_requirements(designReqs);
537
+ result.set_operating_points(operatingPoints);
538
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::SEPIC_CONVERTER);
539
+ return result;
540
+ } else {
541
+ OpenMagnetics::Inputs result = converter.process();
542
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::SEPIC_CONVERTER);
543
+ return result;
544
+ }
545
+ }
546
+
547
+ OpenMagnetics::Inputs process_zeta_internal(const json& converterJson, bool useNgspice) {
548
+ OpenMagnetics::AdvancedZeta converter(converterJson);
549
+ converter._assertErrors = true;
550
+ if (useNgspice) {
551
+ auto designReqs = converter.process_design_requirements();
552
+ double inductance = OpenMagnetics::resolve_dimensional_values(designReqs.get_magnetizing_inductance());
553
+ auto operatingPoints = converter.simulate_and_extract_operating_points(inductance);
554
+ OpenMagnetics::Inputs result;
555
+ result.set_design_requirements(designReqs);
556
+ result.set_operating_points(operatingPoints);
557
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::ZETA_CONVERTER);
558
+ return result;
559
+ } else {
560
+ OpenMagnetics::Inputs result = converter.process();
561
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::ZETA_CONVERTER);
562
+ return result;
563
+ }
564
+ }
565
+
566
+ OpenMagnetics::Inputs process_four_switch_buck_boost_internal(const json& converterJson, bool useNgspice) {
567
+ OpenMagnetics::AdvancedFourSwitchBuckBoost converter(converterJson);
568
+ converter._assertErrors = true;
569
+ if (useNgspice) {
570
+ auto designReqs = converter.process_design_requirements();
571
+ double inductance = OpenMagnetics::resolve_dimensional_values(designReqs.get_magnetizing_inductance());
572
+ auto operatingPoints = converter.simulate_and_extract_operating_points(inductance);
573
+ OpenMagnetics::Inputs result;
574
+ result.set_design_requirements(designReqs);
575
+ result.set_operating_points(operatingPoints);
576
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::FOUR_SWITCH_BUCK_BOOST_CONVERTER);
577
+ return result;
578
+ } else {
579
+ OpenMagnetics::Inputs result = converter.process();
580
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::FOUR_SWITCH_BUCK_BOOST_CONVERTER);
581
+ return result;
582
+ }
583
+ }
584
+
585
+ OpenMagnetics::Inputs process_asymmetric_half_bridge_internal(const json& converterJson, bool useNgspice) {
586
+ OpenMagnetics::AdvancedAsymmetricHalfBridge converter(converterJson);
587
+ converter._assertErrors = true;
588
+ if (useNgspice) {
589
+ auto designReqs = converter.process_design_requirements();
590
+ std::vector<double> turnsRatios;
591
+ for (const auto& tr : designReqs.get_turns_ratios()) {
592
+ turnsRatios.push_back(OpenMagnetics::resolve_dimensional_values(tr));
593
+ }
594
+ double inductance = OpenMagnetics::resolve_dimensional_values(designReqs.get_magnetizing_inductance());
595
+ auto operatingPoints = converter.simulate_and_extract_operating_points(turnsRatios, inductance);
596
+ OpenMagnetics::Inputs result;
597
+ result.set_design_requirements(designReqs);
598
+ result.set_operating_points(operatingPoints);
599
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::ASYMMETRIC_HALF_BRIDGE_CONVERTER);
600
+ return result;
601
+ } else {
602
+ OpenMagnetics::Inputs result = converter.process();
603
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::ASYMMETRIC_HALF_BRIDGE_CONVERTER);
604
+ return result;
605
+ }
606
+ }
607
+
608
+ OpenMagnetics::Inputs process_weinberg_internal(const json& converterJson, bool useNgspice) {
609
+ OpenMagnetics::AdvancedWeinberg converter(converterJson);
610
+ converter._assertErrors = true;
611
+ if (useNgspice) {
612
+ auto designReqs = converter.process_design_requirements();
613
+ std::vector<double> turnsRatios;
614
+ for (const auto& tr : designReqs.get_turns_ratios()) {
615
+ turnsRatios.push_back(OpenMagnetics::resolve_dimensional_values(tr));
616
+ }
617
+ if (turnsRatios.empty()) {
618
+ throw std::runtime_error("Weinberg converter requires at least one turns ratio");
619
+ }
620
+ double inductance = OpenMagnetics::resolve_dimensional_values(designReqs.get_magnetizing_inductance());
621
+ auto operatingPoints = converter.simulate_and_extract_operating_points(turnsRatios[0], inductance);
622
+ OpenMagnetics::Inputs result;
623
+ result.set_design_requirements(designReqs);
624
+ result.set_operating_points(operatingPoints);
625
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::WEINBERG_CONVERTER);
626
+ return result;
627
+ } else {
628
+ OpenMagnetics::Inputs result = converter.process();
629
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::WEINBERG_CONVERTER);
630
+ return result;
631
+ }
632
+ }
633
+
634
+ OpenMagnetics::Inputs process_clllc_internal(const json& converterJson, bool useNgspice) {
635
+ OpenMagnetics::AdvancedClllc converter(converterJson);
636
+ converter._assertErrors = true;
637
+ if (useNgspice) {
638
+ auto designReqs = converter.process_design_requirements();
639
+ std::vector<double> turnsRatios;
640
+ for (const auto& tr : designReqs.get_turns_ratios()) {
641
+ turnsRatios.push_back(OpenMagnetics::resolve_dimensional_values(tr));
642
+ }
643
+ double inductance = OpenMagnetics::resolve_dimensional_values(designReqs.get_magnetizing_inductance());
644
+ auto operatingPoints = converter.simulate_and_extract_operating_points(turnsRatios, inductance);
645
+ OpenMagnetics::Inputs result;
646
+ result.set_design_requirements(designReqs);
647
+ result.set_operating_points(operatingPoints);
648
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::CLLLC_RESONANT_CONVERTER);
649
+ return result;
650
+ } else {
651
+ OpenMagnetics::Inputs result = converter.process();
652
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::CLLLC_RESONANT_CONVERTER);
653
+ return result;
654
+ }
655
+ }
656
+
657
+ // Vienna and Src follow the PFC pattern: AdvancedXxx overrides only
658
+ // process_design_requirements(); we invoke the inherited Topology::process()
659
+ // via the simple base class on the AdvancedXxx instance. useNgspice has
660
+ // no separate path here — process() already handles operating-point
661
+ // simulation through the topology pipeline.
662
+ OpenMagnetics::Inputs process_vienna_internal(const json& converterJson, bool useNgspice) {
663
+ (void)useNgspice;
664
+ OpenMagnetics::AdvancedVienna converter(converterJson);
665
+ converter._assertErrors = true;
666
+ OpenMagnetics::Inputs result = converter.process();
667
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::VIENNA_RECTIFIER_CONVERTER);
668
+ return result;
669
+ }
670
+
671
+ OpenMagnetics::Inputs process_src_internal(const json& converterJson, bool useNgspice) {
672
+ (void)useNgspice;
673
+ OpenMagnetics::AdvancedSrc converter(converterJson);
674
+ converter._assertErrors = true;
675
+ OpenMagnetics::Inputs result = converter.process();
676
+ result.get_mutable_design_requirements().set_topology(MAS::Topologies::SERIES_RESONANT_CONVERTER);
677
+ return result;
678
+ }
679
+
366
680
  OpenMagnetics::Inputs dispatch_converter(const std::string& topologyName, const json& converterJson, bool useNgspice) {
367
681
  if (topologyName == "flyback" || topologyName == "advanced_flyback") {
368
682
  return process_flyback_internal(converterJson, useNgspice);
@@ -412,6 +726,33 @@ OpenMagnetics::Inputs dispatch_converter(const std::string& topologyName, const
412
726
  else if (topologyName == "power_factor_correction" || topologyName == "pfc") {
413
727
  return process_pfc_internal(converterJson);
414
728
  }
729
+ else if (topologyName == "cuk" || topologyName == "advanced_cuk") {
730
+ return process_cuk_internal(converterJson, useNgspice);
731
+ }
732
+ else if (topologyName == "sepic" || topologyName == "advanced_sepic") {
733
+ return process_sepic_internal(converterJson, useNgspice);
734
+ }
735
+ else if (topologyName == "zeta" || topologyName == "advanced_zeta") {
736
+ return process_zeta_internal(converterJson, useNgspice);
737
+ }
738
+ else if (topologyName == "four_switch_buck_boost" || topologyName == "advanced_four_switch_buck_boost") {
739
+ return process_four_switch_buck_boost_internal(converterJson, useNgspice);
740
+ }
741
+ else if (topologyName == "asymmetric_half_bridge" || topologyName == "advanced_asymmetric_half_bridge") {
742
+ return process_asymmetric_half_bridge_internal(converterJson, useNgspice);
743
+ }
744
+ else if (topologyName == "weinberg" || topologyName == "advanced_weinberg") {
745
+ return process_weinberg_internal(converterJson, useNgspice);
746
+ }
747
+ else if (topologyName == "vienna" || topologyName == "advanced_vienna") {
748
+ return process_vienna_internal(converterJson, useNgspice);
749
+ }
750
+ else if (topologyName == "clllc" || topologyName == "advanced_clllc") {
751
+ return process_clllc_internal(converterJson, useNgspice);
752
+ }
753
+ else if (topologyName == "src" || topologyName == "advanced_src") {
754
+ return process_src_internal(converterJson, useNgspice);
755
+ }
415
756
  else {
416
757
  throw std::invalid_argument("Unknown topology: " + topologyName);
417
758
  }
@@ -432,12 +773,18 @@ json process_converter_internal(const std::string& topologyName, const json& con
432
773
  }
433
774
 
434
775
  json process_converter(const std::string& topologyName, json converterJson, bool useNgspice) {
435
- return process_converter_internal(topologyName, converterJson, useNgspice);
776
+ // Normalize topology name (accept MAS 1.0 camelCase, pre-1.0 Title Case,
777
+ // and the internal short form) and migrate any pre-1.0 enum strings
778
+ // embedded in the converter JSON (e.g. flyback "mode": "Continuous
779
+ // Conduction Mode" -> "continuousConductionMode") in-place.
780
+ std::string normalized = normalize_topology_name(topologyName);
781
+ OpenMagnetics::compat::migrate_pre_1_0(converterJson);
782
+ return process_converter_internal(normalized, converterJson, useNgspice);
436
783
  }
437
784
 
438
785
  // Simplified design_magnetics_from_converter using MKF template method
439
786
  json design_magnetics_from_converter(
440
- const std::string& topologyName,
787
+ const std::string& topologyNameRaw,
441
788
  json converterJson,
442
789
  int maxResults,
443
790
  json coreModeJson,
@@ -445,7 +792,11 @@ json design_magnetics_from_converter(
445
792
  json weightsJson) {
446
793
 
447
794
  (void)useNgspice; // Template method always uses ngspice
448
-
795
+
796
+ // Accept MAS 1.0 camelCase, pre-1.0 Title Case, or internal short form.
797
+ const std::string topologyName = normalize_topology_name(topologyNameRaw);
798
+ OpenMagnetics::compat::migrate_pre_1_0(converterJson);
799
+
449
800
  try {
450
801
  OpenMagnetics::CoreAdviser::CoreAdviserModes coreMode;
451
802
  from_json(coreModeJson, coreMode);
@@ -535,6 +886,69 @@ json design_magnetics_from_converter(
535
886
  ? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
536
887
  : magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
537
888
  }
889
+ else if (topologyName == "cuk" || topologyName == "advanced_cuk") {
890
+ OpenMagnetics::Cuk converter(converterJson);
891
+ converter._assertErrors = true;
892
+ masMagnetics = weights.empty()
893
+ ? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
894
+ : magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
895
+ }
896
+ else if (topologyName == "sepic" || topologyName == "advanced_sepic") {
897
+ OpenMagnetics::Sepic converter(converterJson);
898
+ converter._assertErrors = true;
899
+ masMagnetics = weights.empty()
900
+ ? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
901
+ : magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
902
+ }
903
+ else if (topologyName == "zeta" || topologyName == "advanced_zeta") {
904
+ OpenMagnetics::Zeta converter(converterJson);
905
+ converter._assertErrors = true;
906
+ masMagnetics = weights.empty()
907
+ ? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
908
+ : magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
909
+ }
910
+ else if (topologyName == "four_switch_buck_boost" || topologyName == "advanced_four_switch_buck_boost") {
911
+ OpenMagnetics::FourSwitchBuckBoost converter(converterJson);
912
+ converter._assertErrors = true;
913
+ masMagnetics = weights.empty()
914
+ ? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
915
+ : magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
916
+ }
917
+ else if (topologyName == "asymmetric_half_bridge" || topologyName == "advanced_asymmetric_half_bridge") {
918
+ OpenMagnetics::AsymmetricHalfBridge converter(converterJson);
919
+ converter._assertErrors = true;
920
+ masMagnetics = weights.empty()
921
+ ? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
922
+ : magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
923
+ }
924
+ else if (topologyName == "weinberg" || topologyName == "advanced_weinberg") {
925
+ OpenMagnetics::Weinberg converter(converterJson);
926
+ converter._assertErrors = true;
927
+ masMagnetics = weights.empty()
928
+ ? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
929
+ : magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
930
+ }
931
+ else if (topologyName == "vienna" || topologyName == "advanced_vienna") {
932
+ OpenMagnetics::Vienna converter(converterJson);
933
+ converter._assertErrors = true;
934
+ masMagnetics = weights.empty()
935
+ ? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
936
+ : magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
937
+ }
938
+ else if (topologyName == "clllc" || topologyName == "advanced_clllc") {
939
+ OpenMagnetics::Clllc converter(converterJson);
940
+ converter._assertErrors = true;
941
+ masMagnetics = weights.empty()
942
+ ? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
943
+ : magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
944
+ }
945
+ else if (topologyName == "src" || topologyName == "advanced_src") {
946
+ OpenMagnetics::Src converter(converterJson);
947
+ converter._assertErrors = true;
948
+ masMagnetics = weights.empty()
949
+ ? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
950
+ : magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
951
+ }
538
952
  else {
539
953
  // Fall back to old approach for other topologies
540
954
  json inputsJson = process_converter_internal(topologyName, converterJson, useNgspice);
@@ -629,6 +1043,16 @@ json process_current_transformer(json ctJson, double turnsRatio, double secondar
629
1043
  return process_converter("current_transformer", ctJson, true);
630
1044
  }
631
1045
 
1046
+ json process_cuk(json cukJson) { return process_converter("cuk", cukJson, true); }
1047
+ json process_sepic(json sepicJson) { return process_converter("sepic", sepicJson, true); }
1048
+ json process_zeta(json zetaJson) { return process_converter("zeta", zetaJson, true); }
1049
+ json process_four_switch_buck_boost(json j) { return process_converter("four_switch_buck_boost", j, true); }
1050
+ json process_asymmetric_half_bridge(json j) { return process_converter("asymmetric_half_bridge", j, true); }
1051
+ json process_weinberg(json j) { return process_converter("weinberg", j, true); }
1052
+ json process_vienna(json j) { return process_converter("vienna", j, true); }
1053
+ json process_clllc(json j) { return process_converter("clllc", j, true); }
1054
+ json process_src(json j) { return process_converter("src", j, true); }
1055
+
632
1056
  // ─────────────────────────────────────────────────────────────────────
633
1057
  // get_extra_components_inputs (MKF 2026-04-29 API)
634
1058
  //
@@ -713,6 +1137,25 @@ dispatch_extra_components(const std::string& topologyName,
713
1137
  return collect_extra_components<OpenMagnetics::IsolatedBuck>(converterJson, mode, magnetic);
714
1138
  if (topologyName == "isolated_buck_boost")
715
1139
  return collect_extra_components<OpenMagnetics::IsolatedBuckBoost>(converterJson, mode, magnetic);
1140
+ if (topologyName == "cuk" || topologyName == "advanced_cuk")
1141
+ return collect_extra_components<OpenMagnetics::Cuk>(converterJson, mode, magnetic);
1142
+ if (topologyName == "sepic" || topologyName == "advanced_sepic")
1143
+ return collect_extra_components<OpenMagnetics::Sepic>(converterJson, mode, magnetic);
1144
+ if (topologyName == "zeta" || topologyName == "advanced_zeta")
1145
+ return collect_extra_components<OpenMagnetics::Zeta>(converterJson, mode, magnetic);
1146
+ if (topologyName == "four_switch_buck_boost" || topologyName == "advanced_four_switch_buck_boost")
1147
+ return collect_extra_components<OpenMagnetics::FourSwitchBuckBoost>(converterJson, mode, magnetic);
1148
+ if (topologyName == "asymmetric_half_bridge" || topologyName == "advanced_asymmetric_half_bridge")
1149
+ return collect_extra_components<OpenMagnetics::AsymmetricHalfBridge>(converterJson, mode, magnetic);
1150
+ if (topologyName == "weinberg" || topologyName == "advanced_weinberg")
1151
+ return collect_extra_components<OpenMagnetics::Weinberg>(converterJson, mode, magnetic);
1152
+ if (topologyName == "clllc" || topologyName == "advanced_clllc")
1153
+ return collect_extra_components<OpenMagnetics::Clllc>(converterJson, mode, magnetic);
1154
+ if (topologyName == "src" || topologyName == "advanced_src")
1155
+ return collect_extra_components<OpenMagnetics::Src>(converterJson, mode, magnetic);
1156
+ // Vienna intentionally omitted: AdvancedVienna's MKF class does not
1157
+ // expose get_extra_components_inputs() — the rectifier brings no
1158
+ // detached design-requirement components beyond the boost inductor.
716
1159
  throw std::invalid_argument(
717
1160
  "get_extra_components_inputs: topology '" + topologyName +
718
1161
  "' has no extra-components dispatch (or hasn't been wired in PyMKF)."
@@ -760,6 +1203,21 @@ std::string generate_spice_inductor(const json& converterJson,
760
1203
  return topology.generate_ngspice_circuit(inductance, vinIdx, opIdx);
761
1204
  }
762
1205
 
1206
+ // Isolated topologies with a single secondary winding (Weinberg): the
1207
+ // generate_ngspice_circuit signature takes a scalar turns ratio rather
1208
+ // than a vector. We pass turnsRatios[0] if available, otherwise 1.0.
1209
+ template <typename TopologyT>
1210
+ std::string generate_spice_isolated_scalar(const json& converterJson,
1211
+ const std::vector<double>& turnsRatios,
1212
+ double magnetizingInductance,
1213
+ size_t vinIdx, size_t opIdx) {
1214
+ TopologyT topology(converterJson);
1215
+ topology._assertErrors = true;
1216
+ topology.process();
1217
+ double turnsRatio = turnsRatios.empty() ? 1.0 : turnsRatios[0];
1218
+ return topology.generate_ngspice_circuit(turnsRatio, magnetizingInductance, vinIdx, opIdx);
1219
+ }
1220
+
763
1221
  } // namespace
764
1222
 
765
1223
  json generate_ngspice_circuit(const std::string& topologyName,
@@ -793,6 +1251,27 @@ json generate_ngspice_circuit(const std::string& topologyName,
793
1251
  else if (topologyName == "phase_shifted_half_bridge" || topologyName == "pshb") spice = generate_spice_isolated<OpenMagnetics::Pshb>(converterJson, turnsRatios, magnetizingInductance, vinIdx, opIdx);
794
1252
  else if (topologyName == "isolated_buck") spice = generate_spice_isolated<OpenMagnetics::IsolatedBuck>(converterJson, turnsRatios, magnetizingInductance, vinIdx, opIdx);
795
1253
  else if (topologyName == "isolated_buck_boost") spice = generate_spice_isolated<OpenMagnetics::IsolatedBuckBoost>(converterJson, turnsRatios, magnetizingInductance, vinIdx, opIdx);
1254
+ // Single-inductor non-isolated (2026-05): Cuk, Sepic, Zeta, FSBB.
1255
+ else if (topologyName == "cuk" || topologyName == "advanced_cuk")
1256
+ spice = generate_spice_inductor<OpenMagnetics::Cuk>(converterJson, magnetizingInductance, vinIdx, opIdx);
1257
+ else if (topologyName == "sepic" || topologyName == "advanced_sepic")
1258
+ spice = generate_spice_inductor<OpenMagnetics::Sepic>(converterJson, magnetizingInductance, vinIdx, opIdx);
1259
+ else if (topologyName == "zeta" || topologyName == "advanced_zeta")
1260
+ spice = generate_spice_inductor<OpenMagnetics::Zeta>(converterJson, magnetizingInductance, vinIdx, opIdx);
1261
+ else if (topologyName == "four_switch_buck_boost" || topologyName == "advanced_four_switch_buck_boost")
1262
+ spice = generate_spice_inductor<OpenMagnetics::FourSwitchBuckBoost>(converterJson, magnetizingInductance, vinIdx, opIdx);
1263
+ // Isolated with vector turns ratios (2026-05): AsymHB, Clllc, Src, Vienna.
1264
+ else if (topologyName == "asymmetric_half_bridge" || topologyName == "advanced_asymmetric_half_bridge")
1265
+ spice = generate_spice_isolated<OpenMagnetics::AsymmetricHalfBridge>(converterJson, turnsRatios, magnetizingInductance, vinIdx, opIdx);
1266
+ else if (topologyName == "clllc" || topologyName == "advanced_clllc")
1267
+ spice = generate_spice_isolated<OpenMagnetics::Clllc>(converterJson, turnsRatios, magnetizingInductance, vinIdx, opIdx);
1268
+ else if (topologyName == "src" || topologyName == "advanced_src")
1269
+ spice = generate_spice_isolated<OpenMagnetics::Src>(converterJson, turnsRatios, magnetizingInductance, vinIdx, opIdx);
1270
+ else if (topologyName == "vienna" || topologyName == "advanced_vienna")
1271
+ spice = generate_spice_isolated<OpenMagnetics::Vienna>(converterJson, turnsRatios, magnetizingInductance, vinIdx, opIdx);
1272
+ // Isolated with scalar turns ratio (single secondary): Weinberg.
1273
+ else if (topologyName == "weinberg" || topologyName == "advanced_weinberg")
1274
+ spice = generate_spice_isolated_scalar<OpenMagnetics::Weinberg>(converterJson, turnsRatios, magnetizingInductance, vinIdx, opIdx);
796
1275
  else return json{{"error", "generate_ngspice_circuit: unknown topology '" + topologyName + "'"}};
797
1276
  return json{{"netlist", spice}};
798
1277
  } catch (const std::exception& exc) {
@@ -866,6 +1345,19 @@ void register_converter_bindings(py::module& m) {
866
1345
  m.def("process_current_transformer", &process_current_transformer, "Process Current Transformer.",
867
1346
  py::arg("ct"), py::arg("turns_ratio"), py::arg("secondary_resistance") = 0.0);
868
1347
 
1348
+ // 2026-05 additions: full coverage of MKF's 24 converter topologies.
1349
+ m.def("process_cuk", &process_cuk, "Process Cuk converter.", py::arg("cuk"));
1350
+ m.def("process_sepic", &process_sepic, "Process SEPIC converter.", py::arg("sepic"));
1351
+ m.def("process_zeta", &process_zeta, "Process Zeta converter.", py::arg("zeta"));
1352
+ m.def("process_four_switch_buck_boost", &process_four_switch_buck_boost,
1353
+ "Process Four-Switch Buck-Boost converter.", py::arg("converter"));
1354
+ m.def("process_asymmetric_half_bridge", &process_asymmetric_half_bridge,
1355
+ "Process Asymmetric Half-Bridge converter.", py::arg("converter"));
1356
+ m.def("process_weinberg", &process_weinberg, "Process Weinberg converter.", py::arg("converter"));
1357
+ m.def("process_vienna", &process_vienna, "Process Vienna Rectifier converter.", py::arg("converter"));
1358
+ m.def("process_clllc", &process_clllc, "Process CLLLC Resonant converter.", py::arg("converter"));
1359
+ m.def("process_src", &process_src, "Process Series Resonant converter (SRC).", py::arg("converter"));
1360
+
869
1361
  m.def("generate_ngspice_circuit", &generate_ngspice_circuit,
870
1362
  "Return the canonical ngspice SPICE deck for the topology at a "
871
1363
  "given operating point, sized from the magnetic design (turns "
@@ -28,6 +28,17 @@ json process_isolated_buck(json isolatedBuckJson);
28
28
  json process_isolated_buck_boost(json isolatedBuckBoostJson);
29
29
  json process_current_transformer(json ctJson, double turnsRatio, double secondaryResistance = 0.0);
30
30
 
31
+ // 2026-05 additions: full coverage of MKF's 24 converter topologies.
32
+ json process_cuk(json cukJson);
33
+ json process_sepic(json sepicJson);
34
+ json process_zeta(json zetaJson);
35
+ json process_four_switch_buck_boost(json converterJson);
36
+ json process_asymmetric_half_bridge(json converterJson);
37
+ json process_weinberg(json converterJson);
38
+ json process_vienna(json converterJson);
39
+ json process_clllc(json converterJson);
40
+ json process_src(json converterJson);
41
+
31
42
  void register_converter_bindings(py::module& m);
32
43
 
33
44
  } // namespace PyMKF