Skip to content

Commit

Permalink
Merge pull request #109 from upb-lea/split_improvement
Browse files Browse the repository at this point in the history
Split improvement
  • Loading branch information
gituser789 authored May 23, 2024
2 parents 0b68937 + 9242235 commit 0c51ceb
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- name: install femmt package
run: |
sudo apt-get update
# Problem with OSError: libGLU.so.1: connot open shared object file
# Problem with OSError: libGLU.so.1: cannot open shared object file
# Answer here: https://stackoverflow.com/questions/55313610/importerror-libgl-so-1-cannot-open-shared-object-file-no-such-file-or-directo
sudo apt install libsm6 libxext6 ffmpeg libfontconfig1 libxrender1 libglu1
# Unzip used for onelab
Expand Down
34 changes: 27 additions & 7 deletions .github/workflows/sphinx_render_docs.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
name: "Sphinx: Render docs"

on: push
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main]
pull_request:
branches: [ main ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
build:
Expand All @@ -13,15 +20,28 @@ jobs:
with:
python-version: '3.10'
- uses: actions/checkout@v4
- name: install femmt package
run: |
sudo apt-get update
# Problem with OSError: libGLU.so.1: cannot open shared object file
# Answer here: https://stackoverflow.com/questions/55313610/importerror-libgl-so-1-cannot-open-shared-object-file-no-such-file-or-directo
sudo apt install libsm6 libxext6 ffmpeg libfontconfig1 libxrender1 libglu1
# Unzip used for onelab
sudo apt install unzip
pip install --upgrade pip
pip install opencv-python
pip install -e .
- name: Install sphinx and build documentation with sphinx
run: |
python --version
pip install sphinx sphinx-multiversion sphinx_rtd_theme sphinxcontrib-email
pip install -e .
- name: Build HTML
uses: ammaraskar/sphinx-action@master
with:
docs-folder: "docs/"
pip install sphinx sphinx_rtd_theme sphinxcontrib-email
cd docs
make html
# - name: Build HTML
# uses: ammaraskar/sphinx-action@master
# with:
# docs-folder: "docs/"
# pre-build-command: "pip install sphinx_rtd_theme sphinxcontrib-email"
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
Expand Down
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0


## [Unreleased]

## [0.5.3] - 2024-05-23
### Added
- Conductor placing strategies

## [0.5.2] - 2024-04-30
### Added
Expand Down Expand Up @@ -138,7 +140,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- add femmt/SolidComp.py
- add femmt/CompRes.py

[Unreleased]: https://github.com/upb-lea/transistordatabase/compare/0.5.1...HEAD
[Unreleased]: https://github.com/upb-lea/transistordatabase/compare/0.5.3...HEAD
[0.5.3]: https://github.com/upb-lea/transistordatabase/compare/0.5.3...0.5.2
[0.5.2]: https://github.com/upb-lea/transistordatabase/compare/0.5.2...0.5.1
[0.5.1]: https://github.com/upb-lea/transistordatabase/compare/0.5.1...0.5.0
[0.5.0]: https://github.com/upb-lea/transistordatabase/compare/0.5.0...0.4.0
[0.4.0]: https://github.com/upb-lea/transistordatabase/compare/0.4.0...0.3.0
Expand Down
11 changes: 9 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Stable features
* `Center tapped transformer </femmt/examples/basic_transformer_center_tapped.py>`__
* `Magnetic shunt </femmt/examples/basic_transformer_integrated.py>`__ (transformer with integrated inductor)
* `Stacked core </femmt/examples/basic_transformer_stacked.py>`__ (transformer with integrated inductor)
* Round litz wire
* Round litz wire, implemented according to `Niyomsatian et al.: Frequency-domain homogenization for litz-wire bundles in finite element calculations <https://ieeexplore.ieee.org/document/9007233>`__
* Round and rectangular solid wires
* Different winding schemes (hexagonal, left/right, top/down, ...)
* Parallel connection of solid wires
Expand All @@ -45,7 +45,7 @@ Stable features
* Implemented using `ONELAB <https://onelab.info/>`__
* Current excitation
* Frequency domain solver
* Litz wire loss model for proximity and skin effect (Niyomsatian et al.: Frequency-domain homogenization for impedance characterization of litz-wire transformers in 2-D finite element models)
* Litz wire loss model for proximity and skin effect (`Niyomsatian et al.: Frequency-domain homogenization for impedance characterization of litz-wire transformers in 2-D finite element models <https://ieeexplore.ieee.org/document/7695378>`__)
* Core loss calculation for real materials (data from material database)
* Amplitude dependent loss angle (Local resolution of complex permeability)
* Equivalent permittivity data for eddy current calculations
Expand Down Expand Up @@ -98,6 +98,13 @@ Documentation
-------------------
Please have a look at the `documentation <https://upb-lea.github.io/FEM_Magnetics_Toolbox/intro.html>`__. You will find tutorials and a function description.

Literature
-------------------

* `An Open-Source FEM Magnetics Toolbox for Power Electronic Magnetic Components <https://ieeexplore.ieee.org/document/9862128>`__

* `An Open-Source FEM Magnetic Toolbox for Calculating Electric and Thermal Behavior of Power Electronic Magnetic Components <https://ieeexplore.ieee.org/document/9907554>`__

Installation
---------------

Expand Down
2 changes: 1 addition & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
author = 'LEA-UPB'

# The full version, including alpha/beta/rc tags
release = '0.5.2'
release = '0.5.3'

# -- General configuration ---------------------------------------------------

Expand Down
103 changes: 103 additions & 0 deletions femmt/examples/basic_split_windings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""Example how to use the split winding method. Run this file, to see the different winding orders."""
import femmt as fmt
import os

def run_transformer_vvw_split_examples(num_windings, onelab_folder: str = None, show_visual_outputs: bool = True, is_test: bool = False):
"""Run the example code for the transformer."""
example_results_folder = os.path.join(os.path.dirname(__file__), "example_results")
if not os.path.exists(example_results_folder):
os.mkdir(example_results_folder)

def setup_simulation(working_directory, horizontal_split_factors, vertical_split_factors):
geo = fmt.MagneticComponent(component_type=fmt.ComponentType.Transformer, working_directory=working_directory,
verbosity=fmt.Verbosity.Silent, is_gui=is_test)

# This line is for automated pytest running on GitHub only. Please ignore this line!
if onelab_folder is not None:
geo.file_data.onelab_folder_path = onelab_folder

core_dimensions = fmt.dtos.SingleCoreDimensions(window_h=16.1e-3, window_w=(22.5 - 12) / 2 * 1e-3,
core_inner_diameter=12e-3, core_h=22e-3)
core = fmt.Core(core_dimensions=core_dimensions, material=fmt.Material.N95, temperature=60, frequency=100000,
permeability_datasource=fmt.MaterialDataSource.Measurement,
permeability_datatype=fmt.MeasurementDataType.ComplexPermeability,
permeability_measurement_setup=fmt.MeasurementSetup.LEA_LK,
permittivity_datasource=fmt.MaterialDataSource.Measurement,
permittivity_datatype=fmt.MeasurementDataType.ComplexPermittivity,
permittivity_measurement_setup=fmt.MeasurementSetup.LEA_LK)
geo.set_core(core)

air_gaps = fmt.AirGaps(fmt.AirGapMethod.Percent, core)
air_gaps.add_air_gap(fmt.AirGapLegPosition.CenterLeg, 0.00016, 50)
geo.set_air_gaps(air_gaps)

insulation = fmt.Insulation()
insulation.add_core_insulations(0.0008, 0.0008, 0.0001, 0.00001)
iso_self = 0.0001
iso_against = 0.0002
insulation.add_winding_insulations(
[[iso_self, iso_against, iso_against, iso_against, iso_against, iso_against, iso_against],
[iso_against, iso_self, iso_against, iso_against, iso_against, iso_against, iso_against],
[iso_against, iso_against, iso_self, iso_against, iso_against, iso_against, iso_against],
[iso_against, iso_against, iso_against, iso_self, iso_against, iso_against, iso_against],
[iso_against, iso_against, iso_against, iso_against, iso_self, iso_against, iso_against],
[iso_against, iso_against, iso_against, iso_against, iso_against, iso_self, iso_against],
[iso_against, iso_against, iso_against, iso_against, iso_against, iso_against, iso_self]])
geo.set_insulation(insulation)

winding_window = fmt.WindingWindow(core, insulation)

cells = winding_window.flexible_split(
horizontal_split_factors=horizontal_split_factors,
vertical_split_factors=vertical_split_factors
)

windings = []
for i in range(num_windings):
winding = fmt.Conductor(i, fmt.Conductivity.Copper)
winding.set_litz_round_conductor(0.85e-3 / 2, 40, 0.1e-3 / 2, None, fmt.ConductorArrangement.Square)
windings.append(winding)

for i in range(num_windings):
cells[i].set_winding(windings[i], 7 - i, fmt.WindingType.Single, fmt.Align.ToEdges,
fmt.ConductorDistribution.VerticalUpward_HorizontalRightward)

geo.set_winding_windows([winding_window])

geo.create_model(freq=100000, pre_visualize_geometry=show_visual_outputs)

return geo

if num_windings == 2:
# Run with vertical split
working_directory = os.path.join(example_results_folder, "2-windings-vertical-split-only")
setup_simulation(working_directory, horizontal_split_factors=[], vertical_split_factors=[[0.5]])

# Run with horizontal split
working_directory = os.path.join(example_results_folder, "2-windings-horizontal-split-only")
setup_simulation(working_directory, horizontal_split_factors=[0.5], vertical_split_factors=[])

elif num_windings == 3:
working_directory = os.path.join(example_results_folder, "3-windings-vertical-split-only")
setup_simulation(working_directory, horizontal_split_factors=[], vertical_split_factors=[[0.33, 0.66]])

working_directory = os.path.join(example_results_folder, "3-windings-horizontal-split-only")
setup_simulation(working_directory, horizontal_split_factors=[0.33, 0.66], vertical_split_factors=[])

elif num_windings == 5:
working_directory = os.path.join(example_results_folder, "5-windings")
setup_simulation(working_directory, horizontal_split_factors=[0.48, 0.75], vertical_split_factors=[[0.5], [0.5], None])

elif num_windings == 6:
working_directory = os.path.join(example_results_folder, "6-windings")
setup_simulation(working_directory, horizontal_split_factors=[0.48, 0.75], vertical_split_factors=[[0.5], [0.5], [0.5]])

else:
raise ValueError("Unsupported number of windings")


if __name__ == "__main__":
# Run simulations for different numbers of windings
for num_windings in [2, 3, 5, 6]:
print(f"Running simulation for {num_windings} windings")
run_transformer_vvw_split_examples(num_windings, show_visual_outputs=True)
77 changes: 77 additions & 0 deletions femmt/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,83 @@ def NCellsSplit(self, split_distance: float = 0, horizontal_split_factors: List[
# we return the combined list of all virtual winding windows.
return self.virtual_winding_windows

def flexible_split(self, split_distance: float = 0,
horizontal_split_factors: Optional[List[float]] = None,
vertical_split_factors: Optional[List[List[float]]] = None) -> List[VirtualWindingWindow]:
"""
Flexible split function to divide a window into sections based on provided horizontal and vertical split factors.
:param split_distance: Distance between split sections.
:param horizontal_split_factors: Relative positions for horizontal splits (0-1 range).
:param vertical_split_factors: Nested list of relative positions for vertical splits (0-1 range).
Each sublist corresponds to the vertical splits for each horizontal section.
:return: List of VirtualWindingWindow instances.
"""
if horizontal_split_factors is None:
horizontal_split_factors = []

if vertical_split_factors is None:
vertical_split_factors = [[]]

if self.stray_path is not None and self.air_gaps is not None and self.air_gaps.number > self.stray_path.start_index:
air_gap_1_position = self.air_gaps.midpoints[self.stray_path.start_index][1]
air_gap_2_position = self.air_gaps.midpoints[self.stray_path.start_index + 1][1]
max_pos = max(air_gap_2_position, air_gap_1_position)
min_pos = min(air_gap_2_position, air_gap_1_position)
distance = max_pos - min_pos # TODO: this is set in accordance to the midpoint of the air gap:
# TODO: should be changed to the core-cond isolation
horizontal_splits = min_pos + distance / 2
vertical_splits = self.max_left_bound + (self.max_right_bound - self.max_left_bound) * vertical_split_factors
split_distance = distance # here, the distance between the two vwws is set automatically
else:

horizontal_splits = np.array(horizontal_split_factors)
horizontal_splits = np.sort(np.clip(horizontal_splits, 0, 1))
horizontal_splits = self.max_bot_bound + (self.max_top_bound - self.max_bot_bound) * horizontal_splits
horizontal_splits = np.concatenate(([self.max_bot_bound], horizontal_splits, [self.max_top_bound]))

cells = []

if len(horizontal_split_factors) == 0 and any(vertical_split_factors): # Only vertical splits
for i in range(len(vertical_split_factors)):
vertical_splits = np.array(vertical_split_factors[i]) if vertical_split_factors[i] else []
vertical_splits = np.sort(np.clip(vertical_splits, 0, 1))
vertical_splits = self.max_left_bound + (self.max_right_bound - self.max_left_bound) * vertical_splits
vertical_splits = np.concatenate(([self.max_left_bound], vertical_splits, [self.max_right_bound]))

for j in range(len(vertical_splits) - 1):
cells.append(VirtualWindingWindow(
bot_bound=self.max_bot_bound,
top_bound=self.max_top_bound,
left_bound=vertical_splits[j],
right_bound=vertical_splits[j + 1]
))
elif len(vertical_split_factors) == 0 and len(horizontal_split_factors) > 0: # Only horizontal splits
for i in range(len(horizontal_splits) - 1):
cells.append(VirtualWindingWindow(
bot_bound=horizontal_splits[i],
top_bound=horizontal_splits[i + 1],
left_bound=self.max_left_bound,
right_bound=self.max_right_bound
))
else: # Both horizontal and vertical splits or no splits
for i in range(len(horizontal_splits) - 1):
vertical_splits = np.array(vertical_split_factors[i]) if vertical_split_factors[i] else []
vertical_splits = np.sort(np.clip(vertical_splits, 0, 1))
vertical_splits = self.max_left_bound + (self.max_right_bound - self.max_left_bound) * vertical_splits
vertical_splits = np.concatenate(([self.max_left_bound], vertical_splits, [self.max_right_bound]))

for j in range(len(vertical_splits) - 1):
cells.append(VirtualWindingWindow(
bot_bound=horizontal_splits[i],
top_bound=horizontal_splits[i + 1],
left_bound=vertical_splits[j],
right_bound=vertical_splits[j + 1]
))

self.virtual_winding_windows = cells
return self.virtual_winding_windows

def split_with_stack(self, stack: ConductorStack):
"""
Split the winding window according to a ConductorStack dataclass.
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
"Documentation": "https://upb-lea.github.io/FEM_Magnetics_Toolbox/main/intro.html",
"Source Code": "https://github.com/upb-lea/FEM_Magnetics_Toolbox",
},
version='0.5.2',
version='0.5.3',
zip_safe=False,
data_files=[('', ['CHANGELOG.md'])]
)
9 changes: 9 additions & 0 deletions tests/integration/test_femmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import femmt.examples.component_study.transformer_component_study
import femmt.examples.basic_transformer_excitation_sweep
import femmt.examples.basic_inductor_excitation_sweep
import femmt.examples.basic_split_windings
import materialdatabase as mdb


Expand Down Expand Up @@ -2442,3 +2443,11 @@ def test_transformer_excitation_sweep(temp_folder):
femmt.examples.basic_transformer_excitation_sweep.basic_example_transformer_excitation_sweep(onelab_folder=onelab_folder,
show_visual_outputs=False,
is_test=True)

def test_split_windings(temp_folder):
"""Integration test to the basic example file."""
temp_folder_path, onelab_folder = temp_folder
for num_windings in [2, 3, 5, 6]:
print(f"Running simulation for {num_windings} windings")
femmt.examples.basic_split_windings.run_transformer_vvw_split_examples(num_windings, onelab_folder=onelab_folder,
show_visual_outputs=False, is_test=True)

0 comments on commit 0c51ceb

Please sign in to comment.