├── .github └── workflows │ ├── python-package.yml │ └── python-publish.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── docs ├── Makefile ├── _templates │ ├── custom-class-template.rst │ └── custom-module-template.rst ├── afpm │ ├── S1R1.svg │ ├── S1R2.svg │ └── S2R1.svg ├── amela.rst ├── api.rst ├── bchreader.rst ├── conf.py ├── dakota.rst ├── dxfsl-converter │ ├── BspStator.png │ ├── BspWindings.png │ ├── airgap.png │ ├── dxf-orig.png │ ├── dxfsl-converter-manual.tex │ ├── femag-model.png │ ├── mesh.png │ ├── semafor.png │ ├── step1.png │ ├── step2.png │ └── step4.png ├── engine.rst ├── femag.rst ├── femagtools │ ├── airgap.rst │ ├── dxfsl.rst │ ├── femag.rst │ ├── machine.rst │ ├── machine │ │ ├── afpm.rst │ │ ├── im.rst │ │ ├── pm.rst │ │ └── sm.rst │ ├── mcv.rst │ ├── moo.rst │ ├── parstudy.rst │ ├── plot.rst │ └── poc.rst ├── forcedens.rst ├── img │ ├── airgapinduc.png │ ├── femagtools-dakota.drawio │ ├── femagtools-dakota.png │ ├── femagtools.png │ ├── fluxdens.png │ ├── geom.png │ ├── loss.png │ ├── mcv.png │ ├── mesh.png │ ├── mmf.png │ ├── mmf_fft.png │ ├── ncformat.dot │ ├── ncformat.dot.png │ ├── ncformat.png │ ├── plot.png │ ├── shortcircuit.png │ ├── spel.png │ ├── spoke-diagram.png │ ├── spoke.png │ ├── winding.png │ └── zoneplan.png ├── index.rst ├── intro.rst ├── models.rst ├── models │ ├── afpm.rst │ ├── dxf.rst │ ├── machine.rst │ ├── magnet.rst │ ├── material.rst │ ├── rotor.rst │ ├── simulation.rst │ ├── stator.rst │ ├── userspec.rst │ └── windings.rst ├── ncisa.rst ├── pyplots │ ├── example.PLT1 │ ├── forcedens.py │ ├── pmchar.py │ └── pmfieldweak.py ├── requirements.txt ├── sizing.rst ├── slot-parameters │ ├── FEMAG-FSL.jrn │ ├── FEMAG-FSL.log │ ├── afm_rotor.svg │ ├── afm_stator.svg │ ├── asynRotor.svg │ ├── magnetIron.svg │ ├── magnetIron3.svg │ ├── magnetIron4.svg │ ├── magnetIron5.svg │ ├── magnetIronV.svg │ ├── magnetSector.svg │ ├── magntype1.png │ ├── magntype2.png │ ├── magntype3.png │ ├── magntype4.png │ ├── magntype5.png │ ├── magv.PROT │ ├── rot_hsm.svg │ ├── rotorKS2.svg │ ├── srm.svg │ ├── stat1.PROT │ ├── stator1.svg │ ├── stator4.svg │ └── statorRotor3.svg ├── tspost.rst ├── userspec.fsl └── windings.rst ├── examples ├── README ├── amela │ ├── magnetfsl.mako │ ├── pm_sym_fast_amela.py │ └── statorfsl.mako ├── analytical-model │ ├── fieldweakening.py │ └── pmchar.py ├── bch-erg │ ├── TEST_001.BCH │ ├── TEST_002.BCH │ ├── erg-torque-mtpa.py │ ├── ldlq.erg │ ├── phasor_plot.py │ ├── read_ldq-bch-plot-torque.py │ └── read_pm_sim-bch-plot-torque.py ├── calculation │ ├── afpm-24-20.py │ ├── asyn_motor.py │ ├── cogg_calc_mcv.py │ ├── fieldcalc.mako │ ├── fieldcalc.py │ ├── ld_lq_fast.py │ ├── pm_sym_fast.py │ ├── pm_sym_fast_linear.py │ ├── pm_sym_fast_shortcircuit.py │ ├── pm_sym_loss.py │ ├── psd_psq_fast.py │ ├── torq_calc.py │ └── torq_calc_linear.py ├── dakota │ └── moat.py ├── docker-zmq │ ├── README │ └── cogg_calc_mcv.py ├── magnetcurves │ ├── BM38H.MC │ ├── BM38H.MCV │ ├── M270-35A.MC │ ├── M270-35A.MCV │ ├── M330-35A.MCV │ ├── M330-50A.MC │ ├── M330-50A.MCV │ ├── M400_50A.MC │ ├── M400_50A.MCV │ ├── M800-65A.MC │ ├── M800-65A.MCV │ ├── Stahl37.MC │ ├── Stahl37.MCV │ ├── V800-50A_aniso.MC │ └── V800-50A_aniso.MCV ├── mcv │ ├── plot_mcv.py │ └── write_mcv.py ├── modal-analysis │ ├── magnetfsl.mako │ ├── modal_analysis_me.py │ └── statorfsl.mako ├── model-creation │ ├── createall.py │ ├── cust-wdg.py │ ├── dualairgap │ │ ├── dualairg.py │ │ ├── magnet.mako │ │ └── stator.mako │ ├── dxf │ │ ├── dxf-ipm.py │ │ └── ipm4.dxf │ ├── fsl-fml │ │ ├── ipmfml.mako │ │ ├── spokefml.mako │ │ ├── stator1-spoke.py │ │ ├── statorRotor3-ipm-fml.py │ │ ├── statorfsl-ringmagnet.py │ │ └── statorfsl.mako │ ├── stator1-magnetIron3.py │ ├── stator1-magnetIron4.py │ ├── stator1-magnetIron5.py │ ├── stator1-magnetIronV.py │ ├── stator1-magnetSector-pm-sym-fast.py │ ├── stator2-magnetSector.py │ ├── stator4-magnetSector.py │ ├── statorBG-magnetSector.py │ └── statorRotor3-magnetIron.py ├── optimization │ └── pmopt.py ├── parameter-ident-characteristics │ ├── README │ ├── afpm │ │ ├── char.py │ │ ├── effmap.py │ │ ├── machine.py │ │ └── parident.py │ ├── eesm │ │ ├── char.py │ │ ├── eesm.dxf │ │ ├── effmap.py │ │ ├── lamination │ │ │ ├── M270-35A.json │ │ │ ├── M330-35A.json │ │ │ ├── M400-50A.json │ │ │ ├── M530-50A.json │ │ │ └── M800-65A.json │ │ ├── machine.py │ │ └── parident.py │ ├── im │ │ ├── char.py │ │ ├── effmap.py │ │ ├── im.dxf │ │ ├── machine.py │ │ └── parident.py │ └── vmag │ │ ├── char.py │ │ ├── effmap.py │ │ ├── machine.py │ │ ├── parident.py │ │ └── vmag.dxf ├── parameter-variation │ ├── parvar.py │ ├── psidq-magntemp-list.py │ └── torq_calc_linear.py └── ts │ ├── machine.py │ ├── pmts.py │ └── templates │ ├── simplemagnet.mako │ └── simplestator.mako ├── notebooks ├── 0-Introduction.ipynb ├── 1-ModelsAndFemag.ipynb ├── 2-MaterialHandling.ipynb ├── 3-Windings.ipynb ├── 4-BchFileReader.ipynb ├── 5-MachineCharacteristicsEfficiencyMaps.ipynb ├── 6-MagnetLosses.ipynb ├── 7-ParameterVariationAndOptimization.ipynb ├── 8-IronLosses.ipynb ├── 9-Eccentricity-Analysis.ipynb ├── M400-50A.MC ├── M400-50A.MCV ├── PM270L8.vtu ├── Run_amela.ipynb ├── TEST_001.BCH ├── TKS_M270-50_A.txt ├── TKS_M_330-35_A.txt ├── VTK-Postprocessing.ipynb ├── femag │ ├── LDQ-0-90.BCH │ ├── PM_130_L10.BATCH │ ├── PM_270_L8_001.BATCH │ ├── TEST_002.BCH │ ├── ldlq.erg │ └── xxx.BCH ├── femagtools.png ├── laminations │ ├── M270-35A.MC │ ├── M270-35A.MCV │ └── TKS-M400-65A.txt └── templates │ ├── magnetfsl.mako │ ├── spokefml.mako │ └── statorfsl.mako ├── pyproject.toml ├── requirements.txt ├── src ├── femagtools │ ├── __init__.py │ ├── airgap.py │ ├── amazon.py │ ├── amela.py │ ├── asm.py │ ├── bch.py │ ├── bchxml.py │ ├── condor.py │ ├── conductor.py │ ├── config.py │ ├── convert.py │ ├── dakota.py │ ├── dakota_femag.py │ ├── dakotaout.py │ ├── docker.py │ ├── dxfsl │ │ ├── __init__.py │ │ ├── area.py │ │ ├── areabuilder.py │ │ ├── concat.py │ │ ├── conv.py │ │ ├── converter.py │ │ ├── corner.py │ │ ├── dumprenderer.py │ │ ├── dxfparser.py │ │ ├── femparser.py │ │ ├── fslrenderer.py │ │ ├── functions.py │ │ ├── geom.py │ │ ├── journal.py │ │ ├── machine.py │ │ ├── plotrenderer.py │ │ ├── shape.py │ │ ├── svgparser.py │ │ └── symmetry.py │ ├── ecloss.py │ ├── erg.py │ ├── femag.py │ ├── forcedens.py │ ├── fsl.py │ ├── getset.py │ ├── gmsh.py │ ├── google.py │ ├── grid.py │ ├── heat_source_network.py │ ├── hxy.py │ ├── isa7.py │ ├── jhb.py │ ├── job.py │ ├── leakinduc.py │ ├── losscoeffs.py │ ├── machine │ │ ├── __init__.py │ │ ├── afpm.py │ │ ├── effloss.py │ │ ├── im.py │ │ ├── pm.py │ │ ├── sizing.py │ │ ├── sm.py │ │ └── utils.py │ ├── magnet.py │ ├── mcv.py │ ├── me.py │ ├── model.py │ ├── moo │ │ ├── __init__.py │ │ ├── algorithm.py │ │ ├── population.py │ │ ├── problem.py │ │ └── test │ │ │ ├── AlgorithmTest.py │ │ │ ├── PopulationTest.py │ │ │ └── ProblemTest.py │ ├── moproblem.py │ ├── multiproc.py │ ├── mxw2msh.py │ ├── nc.py │ ├── netlist.py │ ├── ntib.py │ ├── opt.py │ ├── parstudy.py │ ├── plot │ │ ├── __init__.py │ │ ├── bch.py │ │ ├── char.py │ │ ├── fieldlines.py │ │ ├── fluxdens.py │ │ ├── forcedens.py │ │ ├── machine.py │ │ ├── mcv.py │ │ ├── nc.py │ │ ├── phasor.py │ │ └── wdg.py │ ├── poc.py │ ├── semi_fea.py │ ├── shortcircuit.py │ ├── svgfsl │ │ └── converter.py │ ├── templates │ │ ├── FE-losses.mako │ │ ├── afm_rotor.mako │ │ ├── afm_stator.mako │ │ ├── airgapinduc.mako │ │ ├── asyn_motor.mako │ │ ├── basic_modpar.mako │ │ ├── bertotti.mako │ │ ├── calc_field_ts.mako │ │ ├── calc_therm_field.mako │ │ ├── cogg_calc.mako │ │ ├── colorgrad.mako │ │ ├── com_motor_sim.mako │ │ ├── conduct-data.mako │ │ ├── connect_models.mako │ │ ├── cu_losses.mako │ │ ├── dakota │ │ │ └── moga.mako │ │ ├── displ_stator_rotor.mako │ │ ├── ec-rotorbar.mako │ │ ├── fe-contr.mako │ │ ├── fieldcalc.mako │ │ ├── gen_hairpin_winding.mako │ │ ├── gen_winding.mako │ │ ├── inductances.mako │ │ ├── ld_lq_fast.mako │ │ ├── leak_dist_wind.mako │ │ ├── leak_evol_wind.mako │ │ ├── leak_tooth_wind.mako │ │ ├── magnet-data.mako │ │ ├── magnetFC2.mako │ │ ├── magnetIron.mako │ │ ├── magnetIron2.mako │ │ ├── magnetIron3.mako │ │ ├── magnetIron4.mako │ │ ├── magnetIron5.mako │ │ ├── magnetIronV.mako │ │ ├── magnetSector.mako │ │ ├── magnetSectorLinear.mako │ │ ├── magnetShell.mako │ │ ├── magnetShell2.mako │ │ ├── mesh-airgap.mako │ │ ├── modal_analysis.mako │ │ ├── modified_steinmetz.mako │ │ ├── mult_cal_fast.mako │ │ ├── new_model.mako │ │ ├── noloadflux-rot.mako │ │ ├── noloadflux.mako │ │ ├── noloadfluxdc.mako │ │ ├── open.mako │ │ ├── plots.mako │ │ ├── pm_sym_f_cur.mako │ │ ├── pm_sym_fast.mako │ │ ├── pm_sym_loss.mako │ │ ├── prepare_thermal.mako │ │ ├── psd_psq_fast.mako │ │ ├── psi-torq-rem-rot.mako │ │ ├── psi-torq-rem.mako │ │ ├── psi-torq-rot.mako │ │ ├── ring.mako │ │ ├── rot_hsm.mako │ │ ├── rotorAsyn.mako │ │ ├── rotorKs2.mako │ │ ├── rotor_msh.mako │ │ ├── rotor_winding.mako │ │ ├── shortcircuit.mako │ │ ├── srm.mako │ │ ├── stator1.mako │ │ ├── stator2.mako │ │ ├── stator3Linear.mako │ │ ├── stator4.mako │ │ ├── statorBG.mako │ │ ├── statorRing.mako │ │ ├── statorRotor3.mako │ │ ├── stator_msh.mako │ │ ├── therm-dynamic.mako │ │ ├── therm_static.mako │ │ └── torq_calc.mako │ ├── tks.py │ ├── ts.py │ ├── utils.py │ ├── vbf.py │ ├── vtu.py │ ├── windings.py │ └── zmq.py └── tests │ ├── __init__.py │ ├── data │ ├── AMELA │ ├── AMELA.bat │ ├── FERRIT_20gC.MCV │ ├── IPM-130-4.dxf │ ├── M270-50A_1000Hz_L.jhb │ ├── Mode_001.txt │ ├── PLT.0 │ ├── PM-4p-distleak.BATCH │ ├── PM-with-asterisks_001.BATCH │ ├── PMREL-4p-skewed.BATCH │ ├── PM_270_L8_001.BATCH │ ├── TKM270-50A-LOSS.MCV │ ├── TKS-M400-65A.txt │ ├── TKS_NO_20.MCV │ ├── V800-50A_aniso.MCV │ ├── aniso.jhb │ ├── bag.dat │ ├── bag2.dat │ ├── char.BATCH │ ├── cogging.BATCH │ ├── convert │ │ ├── Designer.jplot │ │ ├── quads.ISA7 │ │ ├── quads.nas │ │ ├── superelements.nas │ │ ├── triangles.ISA7 │ │ └── triangles.nas │ ├── demag-vtu │ │ └── PM_130_L10_0000.vtu │ ├── dq.BATCH │ ├── hxy │ │ └── PM270L8_011.hxy │ ├── ldlq.erg │ ├── ldlq_outer_rotor.BATCH │ ├── ldq-losses.BATCH │ ├── ldq.BATCH │ ├── ldqlosses-2024b2.BATCH │ ├── linearForce.BATCH │ ├── linmot_z.BATCH │ ├── m270_35.vbf │ ├── magnsec.AUX7 │ ├── magnsec.ISA7 │ ├── minimal.AUX7 │ ├── minimal.ISA7 │ ├── minimal.nc │ ├── parident │ │ ├── bar.dat │ │ ├── noloadbag-1.dat │ │ ├── noloadbag-2.dat │ │ ├── noloadbag-3.dat │ │ ├── noloadbag-4.dat │ │ ├── noloadbag-5.dat │ │ └── psi-rot-mag.dat │ ├── pm_data.nc │ ├── pm_data │ │ ├── pm_data_se38.json │ │ └── pm_data_se38 │ │ │ └── EClosses.tab │ ├── pm_sym_fast_outer_rotor.BATCH │ ├── pmsim-9.BATCH │ ├── pmsim-external.BATCH │ ├── pmsim.BATCH │ ├── psdqlosses-2024b2.BATCH │ ├── psidpsiq.BATCH │ ├── psidq-losses.BATCH │ ├── rel-felosses.BATCH │ ├── relsim.BATCH │ ├── sctest.BATCH │ ├── temp_model.hsn │ ├── test.ASM │ ├── test.poc │ ├── test_disp_stat.ISA7 │ ├── test_disp_stat.nc │ ├── test_func.poc │ ├── zzz_pm_model_ts.nc │ └── zzz_pm_model_ts_results_1 │ │ ├── zzz_pm_model_ts_0000.vtu │ │ ├── zzz_pm_model_ts_0001.vtu │ │ ├── zzz_pm_model_ts_0002.vtu │ │ ├── zzz_pm_model_ts_0003.vtu │ │ ├── zzz_pm_model_ts_0004.vtu │ │ ├── zzz_pm_model_ts_0005.vtu │ │ ├── zzz_pm_model_ts_0006.vtu │ │ ├── zzz_pm_model_ts_0007.vtu │ │ ├── zzz_pm_model_ts_0008.vtu │ │ ├── zzz_pm_model_ts_0009.vtu │ │ ├── zzz_pm_model_ts_0010.vtu │ │ ├── zzz_pm_model_ts_0011.vtu │ │ ├── zzz_pm_model_ts_0012.vtu │ │ ├── zzz_pm_model_ts_0013.vtu │ │ ├── zzz_pm_model_ts_0014.vtu │ │ ├── zzz_pm_model_ts_0015.vtu │ │ ├── zzz_pm_model_ts_0016.vtu │ │ ├── zzz_pm_model_ts_0017.vtu │ │ ├── zzz_pm_model_ts_0018.vtu │ │ ├── zzz_pm_model_ts_0019.vtu │ │ ├── zzz_pm_model_ts_0020.vtu │ │ ├── zzz_pm_model_ts_0021.vtu │ │ ├── zzz_pm_model_ts_0022.vtu │ │ ├── zzz_pm_model_ts_0023.vtu │ │ ├── zzz_pm_model_ts_0024.vtu │ │ ├── zzz_pm_model_ts_0025.vtu │ │ ├── zzz_pm_model_ts_0026.vtu │ │ ├── zzz_pm_model_ts_0027.vtu │ │ ├── zzz_pm_model_ts_0028.vtu │ │ ├── zzz_pm_model_ts_0029.vtu │ │ ├── zzz_pm_model_ts_0030.vtu │ │ ├── zzz_pm_model_ts_0031.vtu │ │ ├── zzz_pm_model_ts_0032.vtu │ │ ├── zzz_pm_model_ts_0033.vtu │ │ ├── zzz_pm_model_ts_0034.vtu │ │ ├── zzz_pm_model_ts_0035.vtu │ │ ├── zzz_pm_model_ts_0036.vtu │ │ ├── zzz_pm_model_ts_0037.vtu │ │ ├── zzz_pm_model_ts_0038.vtu │ │ └── zzz_pm_model_ts_0039.vtu │ ├── engines │ ├── __init__.py │ ├── config.ini │ ├── data │ │ └── cloud_init.txt │ ├── test_amazon.py │ └── test_config.py │ ├── geom │ ├── __init__.py │ ├── test_functions.py │ └── test_point_inside.py │ ├── mcvwriter │ ├── moo │ ├── __init__.py │ ├── test_algorithm.py │ ├── test_population.py │ └── test_problem.py │ ├── test_afpm.py │ ├── test_airgap_induction.py │ ├── test_amela.py │ ├── test_asm.py │ ├── test_bchreader.py │ ├── test_conductor.py │ ├── test_convert.py │ ├── test_dxfsl.py │ ├── test_effloss.py │ ├── test_erg.py │ ├── test_femag.py │ ├── test_forcedens.py │ ├── test_fsl.py │ ├── test_heat_source_network.py │ ├── test_hxy.py │ ├── test_im.py │ ├── test_isa7.py │ ├── test_jhb.py │ ├── test_job.py │ ├── test_losscoeffs.py │ ├── test_machine.py │ ├── test_magncurv.py │ ├── test_magnet.py │ ├── test_mcv.py │ ├── test_mcvreader.py │ ├── test_me.py │ ├── test_model.py │ ├── test_nc.py │ ├── test_parident.py │ ├── test_parstudy.py │ ├── test_pocfile.py │ ├── test_sizing.py │ ├── test_sm.py │ ├── test_tksreader.py │ ├── test_ts.py │ ├── test_vbfreader.py │ ├── test_vtu.py │ └── test_windings.py └── tox.ini /.github/workflows/python-package.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Python package 5 | 6 | on: 7 | push: 8 | branches: [ master, development ] 9 | pull_request: 10 | branches: [ master, development ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | python-version: ["3.10", "3.11", "3.12"] 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Set up Python ${{ matrix.python-version }} 24 | uses: actions/setup-python@v5 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | python -m pip install flake8 pytest 31 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 32 | # - name: Lint with flake8 33 | # run: | 34 | # # stop the build if there are Python syntax errors or undefined names 35 | # flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 36 | # # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 37 | # flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 38 | - name: Test with pytest 39 | run: | 40 | python -m pytest 41 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | name: Upload Python Package 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | deploy: 12 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') 13 | name: Build Python distribution and publish to PyPI 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - name: Set up Python 19 | uses: actions/setup-python@v2 20 | with: 21 | python-version: '3.x' 22 | - name: Install dependencies 23 | run: | 24 | python -m pip install --upgrade pip 25 | pip install build 26 | - name: Build package 27 | run: python -m build 28 | - name: Publish package 29 | uses: pypa/gh-action-pypi-publish@release/v1 30 | with: 31 | user: __token__ 32 | password: ${{ secrets.PYPI_API_TOKEN }} 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | build/ 3 | *egg-info/ 4 | docs/_build/ 5 | dist/ 6 | __pycache__/ 7 | .cache/ 8 | .coverage 9 | 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2023, Semafor Informatik & Energie AG, Basel 2 | Copyright (c) 2023-2024, Gamma Technology LLC 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions 7 | are met: 8 | 9 | Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 | THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include src/femagtools/templates/*.mako -------------------------------------------------------------------------------- /docs/_templates/custom-class-template.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. autoclass:: {{ objname }} 6 | :members: 7 | :show-inheritance: 8 | :inherited-members: 9 | :special-members: __call__, __add__, __mul__ 10 | 11 | {% block methods %} 12 | {% if methods %} 13 | .. rubric:: {{ _('Methods') }} 14 | 15 | .. autosummary:: 16 | :nosignatures: 17 | {% for item in methods %} 18 | {%- if not item.startswith('_') %} 19 | ~{{ name }}.{{ item }} 20 | {%- endif -%} 21 | {%- endfor %} 22 | {% endif %} 23 | {% endblock %} 24 | 25 | {% block attributes %} 26 | {% if attributes %} 27 | .. rubric:: {{ _('Attributes') }} 28 | 29 | .. autosummary:: 30 | {% for item in attributes %} 31 | ~{{ name }}.{{ item }} 32 | {%- endfor %} 33 | {% endif %} 34 | {% endblock %} 35 | -------------------------------------------------------------------------------- /docs/_templates/custom-module-template.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. automodule:: {{ fullname }} 4 | 5 | {% block attributes %} 6 | {% if attributes %} 7 | .. rubric:: Module attributes 8 | 9 | .. autosummary:: 10 | :toctree: 11 | {% for item in attributes %} 12 | {{ item }} 13 | {%- endfor %} 14 | {% endif %} 15 | {% endblock %} 16 | 17 | {% block functions %} 18 | {% if functions %} 19 | .. rubric:: {{ _('Functions') }} 20 | 21 | .. autosummary:: 22 | :toctree: 23 | :nosignatures: 24 | {% for item in functions %} 25 | {{ item }} 26 | {%- endfor %} 27 | {% endif %} 28 | {% endblock %} 29 | 30 | {% block classes %} 31 | {% if classes %} 32 | .. rubric:: {{ _('Classes') }} 33 | 34 | .. autosummary:: 35 | :toctree: 36 | :template: custom-class-template.rst 37 | :nosignatures: 38 | {% for item in classes %} 39 | {{ item }} 40 | {%- endfor %} 41 | {% endif %} 42 | {% endblock %} 43 | 44 | {% block exceptions %} 45 | {% if exceptions %} 46 | .. rubric:: {{ _('Exceptions') }} 47 | 48 | .. autosummary:: 49 | :toctree: 50 | {% for item in exceptions %} 51 | {{ item }} 52 | {%- endfor %} 53 | {% endif %} 54 | {% endblock %} 55 | 56 | {% block modules %} 57 | {% if modules %} 58 | .. autosummary:: 59 | :toctree: 60 | :template: custom-module-template.rst 61 | :recursive: 62 | {% for item in modules %} 63 | {{ item }} 64 | {%- endfor %} 65 | {% endif %} 66 | {% endblock %} 67 | -------------------------------------------------------------------------------- /docs/amela.rst: -------------------------------------------------------------------------------- 1 | Amela 2 | ***** 3 | 4 | AMELA can be executed as a batch process in femagtools. Amela object will search the 5 | AMELA batch file and the FEMAG model file in the given directories. The magnet data 6 | for the loss calculation will be extracted from the FEMAG model file. 7 | 8 | * If the FEMAG model file (nc file) is located in the same directory as AMELA. 9 | Only the workdir is needed. 10 | 11 | Example:: 12 | 13 | amela = Amela(workdir, dict(name='example')) 14 | r = amela() 15 | loss = r['pm_data_se38']['total_loss'] 16 | print(f'loss in the superelement 38 is: {loss} W') 17 | 18 | * If the FEMAG model file (nc file) is located in a different directory as AMELA. 19 | Both the workdir (nc file) and amela_dir (AMELA.bat or AMELA.sh) need to be input. 20 | 21 | Example:: 22 | 23 | amela = Amela(workdir, dict(name='example'), \ 24 | amela_dir) 25 | r = amela() 26 | loss = r['pm_data_se38']['total_loss'] 27 | print(f'loss in the superelement 38 is: {loss} W') 28 | 29 | The circumferential and axial segmentation are optional parameters and can be 30 | passed in the same dictionary. 31 | 32 | Example:: 33 | 34 | magnet_data = dict(name='example', 35 | nseglen=3) 36 | amela = Amela(workdir, magnet_data, \ 37 | amela_dir) 38 | 39 | list of all the optional parameters: 40 | 41 | ========= =================================== 42 | speed rotational speed (1/min) 43 | sigma electrical conductivity (S/m) 44 | nsegwid number of circumferential segments 45 | nseglen number of axial segments 46 | ========= =================================== 47 | 48 | The return values of the Amela object is a dictionary that contains the loss data: 49 | 50 | ========== ======================================================== 51 | loss_data time dependable loss value 52 | total_loss total loss in the superelement (averaged over time step) 53 | ========== ======================================================== 54 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | .. 2 | DO NOT DELETE THIS FILE! It contains the all-important `.. autosummary::` directive with `:recursive:` option, without 3 | which API documentation wouldn't get extracted from docstrings by the `sphinx.ext.autosummary` engine. It is hidden 4 | (not declared in any toctree) to remove an unnecessary intermediate page; index.rst instead points directly to the 5 | package page. DO NOT REMOVE THIS FILE! 6 | 7 | .. autosummary:: 8 | :toctree: _autosummary 9 | :template: custom-module-template.rst 10 | :recursive: 11 | 12 | femagtools 13 | -------------------------------------------------------------------------------- /docs/dxfsl-converter/BspStator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/dxfsl-converter/BspStator.png -------------------------------------------------------------------------------- /docs/dxfsl-converter/BspWindings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/dxfsl-converter/BspWindings.png -------------------------------------------------------------------------------- /docs/dxfsl-converter/airgap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/dxfsl-converter/airgap.png -------------------------------------------------------------------------------- /docs/dxfsl-converter/dxf-orig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/dxfsl-converter/dxf-orig.png -------------------------------------------------------------------------------- /docs/dxfsl-converter/femag-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/dxfsl-converter/femag-model.png -------------------------------------------------------------------------------- /docs/dxfsl-converter/mesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/dxfsl-converter/mesh.png -------------------------------------------------------------------------------- /docs/dxfsl-converter/semafor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/dxfsl-converter/semafor.png -------------------------------------------------------------------------------- /docs/dxfsl-converter/step1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/dxfsl-converter/step1.png -------------------------------------------------------------------------------- /docs/dxfsl-converter/step2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/dxfsl-converter/step2.png -------------------------------------------------------------------------------- /docs/dxfsl-converter/step4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/dxfsl-converter/step4.png -------------------------------------------------------------------------------- /docs/femagtools/airgap.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.airgap 2 | :members: 3 | -------------------------------------------------------------------------------- /docs/femagtools/dxfsl.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.dxfsl 2 | :members: 3 | -------------------------------------------------------------------------------- /docs/femagtools/femag.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.femag 2 | :members: Femag, ZmqFemag 3 | -------------------------------------------------------------------------------- /docs/femagtools/machine.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.machine 2 | :members: 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | machine/pm 8 | machine/sm 9 | machine/im 10 | machine/afpm 11 | -------------------------------------------------------------------------------- /docs/femagtools/machine/afpm.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.machine.afpm 2 | :members: 3 | -------------------------------------------------------------------------------- /docs/femagtools/machine/im.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.machine.im 2 | :members: parident, InductionMachine 3 | -------------------------------------------------------------------------------- /docs/femagtools/machine/pm.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.machine.pm 2 | :members: 3 | -------------------------------------------------------------------------------- /docs/femagtools/machine/sm.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.machine.sm 2 | :members: 3 | -------------------------------------------------------------------------------- /docs/femagtools/mcv.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.mcv 2 | :members: MagnetizingCurve, read 3 | -------------------------------------------------------------------------------- /docs/femagtools/moo.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.moo 2 | :members: 3 | -------------------------------------------------------------------------------- /docs/femagtools/parstudy.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.parstudy 2 | :members: 3 | -------------------------------------------------------------------------------- /docs/femagtools/plot.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.plot 2 | :members: 3 | -------------------------------------------------------------------------------- /docs/femagtools/poc.rst: -------------------------------------------------------------------------------- 1 | .. automodule:: femagtools.poc 2 | :members: 3 | -------------------------------------------------------------------------------- /docs/forcedens.rst: -------------------------------------------------------------------------------- 1 | ForceDensity 2 | ************ 3 | 4 | The ForceDensity object contains the PLT file results. It has 5 | following attributes which mostly correspond to the text sections in the file: 6 | 7 | ================ ======================================================= 8 | Attribute Description 9 | ================ ======================================================= 10 | project Name of model file 11 | filename Name of PLT file 12 | date calculation date 13 | version FEMAG version 14 | nodes number of nodes 15 | elements number of elements 16 | quality meshing quality 17 | positions Position properties 18 | ================ ======================================================= 19 | 20 | Positions 21 | ========= 22 | 23 | list of dictionaries for each position 24 | 25 | ========= ======================================================= 26 | position rotor position 27 | X list of angles 28 | FN list of normal component of force 29 | FT list tangential component of force 30 | Radius list of radius 31 | B_N list normal component of flux density 32 | B_T list tangential component of flux density 33 | ========= ======================================================= 34 | 35 | Example:: 36 | 37 | fdens = ForceDensity() 38 | fdens.read('example.PLT0') 39 | pl.title('{}, Rotor Position {}'.format( 40 | fdens.title, fdens.positions[0]['position'])) 41 | pl.plot(fdens.positions[0]['X'], fdens.positions[0]['FT']) 42 | 43 | .. plot:: pyplots/forcedens.py 44 | 45 | -------------------------------------------------------------------------------- /docs/img/airgapinduc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/airgapinduc.png -------------------------------------------------------------------------------- /docs/img/femagtools-dakota.drawio: -------------------------------------------------------------------------------- 1 | 7Vpbc+MmFP41foxHd8uPsZMm2zY72abd7uaNSFhWIwsPQo6dX1+Q0AWBZa0txUm3zkwGDhfBdy6cc2BkzlfbGwzWyzvkw2hkaP52ZF6NDMM1TPqfEXY5wTHtnBDg0M9JekV4CF8hJ2qcmoY+TISOBKGIhGuR6KE4hh4RaABj9CJ2W6BI/OoaBFAiPHggkql/hz5Z8m3ZWkW/hWGwLL6sa7xlBYrOnJAsgY9eaiTzemTOMUIkL622cxgx7Apc8nG/7GktF4ZhTLoMmEE/xp6/WzxvFt5duvnjq4sudCefZgOilO+Yr5bsCggwSmMfslm0kTl7WYYEPqyBx1pfKM8pbUlWEa3ptCivii90AzGB2xqJr/IGohUkeEe78FZH5yJSiAwH8KXC3yhQXtaxtzgRcJ4H5dQVLLTAkVGj9Hi59O6/eL9+fY0/fzFuFuZu4124EibQp1LCqwiTJQpQDKLrijoTUav6/I7QmmP1DyRkx0UepASJSMJtSL7Vyt/ZVGOb1662fOassisqMd3ut3qlNopVq2FZrRiX749taq9wcVKCUuzBNoniSgpwAElbP0stBBhGgIQbcSG9c1Q3T2KpfiRLB2dPHXb1xrUTYedD71FIP13qbGmvuc7aDVXMxYYPqhupxjy2Kc7TVOl8f9I8mQyUu+kkFm3CW7OGC7gCATtxktPs4iKMojmKEM7Gmj6A7sKj9IRg9AxrLY7nwqdFP5a0PIw4mqZsSXV9KEuqBNiY/Bym9BjLaXW1nI7SHpzLlDrn5GjFxe+1lkMcHTsiTzXTPMDVrHYPcUgxg7j/U7Mz7803YnXbKmvm0QfPiICLzEp+QANpWaKrWVrDQxZyMFfT/oDaZNiCOr2dr+l01Jq3cjXbFllTGrpVsErGYSzxmsaIa1ZkPaIIRiigPSlm65rlEdpqJumwgm1hEWD3FKlZhuhfOLasPapIzRzKvZhKWJ9mlHrAyLFEjFwFRoYCI2cojApz9q5AskWQpmcHSY4Ezg+SI4Kka2dHyZBQyjyBCy8CSRJ6vXoEUPdtOFF5BFNnYgKnJ5AnDZD1c4NcnobnSVXowtk+nhyKf0pf4gdireM9gCKPI7kTw+efsqGXGINdrcOaZSaS2syN/EbzxNT5cbAvHyL1F5O8tJCvQD3anFri6LdOp5iSfcAwSSOSjFFKJLH+aN6P2QgeJorgYSj3R53cOy0WP9ZUKLMrRheV7yfj3DV4dk7U+NPOSjl4HhlORNc7e6KFgBXyaLog08+ULb2epAub/Slj6+zHRqCY1Oj5rx+1MdxG0CBrzVShNO5gTsxEYswdNVGhhzAcGXRObR6h1M+Lt3+yOop9ioyhjccSXygIRARfBDlGMWxwhJNAFAYxrXoU2syiMUhDD0SXvGEV+n6msSpui/LQA5vsqWjdLJlNhsoPMnrg02+f57ep83r7OPvr8RN5+pRs0I0iN5+ry38gji4D5+IkUQXSKrD7OEmUYKuMVfNkif1LdsHORJa7+w25B5hwnPJ8q1+r8QuhAnYGdxgHtNGljdwtUTeqj5vJe8vmK/zQNrE+mMyviYKtkISCduI9niXdGB15kWc1InrpRnCP6/mjDrXR+I5utjvUUn+3xaE+wg9W8lg+Yd6PNlVpXCGLqx9QDHXKWGtVwk7K1KYkHYO6/7XphEBOHVgoBPYtn0vU0g7DXTG0vJd4R3cMrausWZhV/hLv9Jyl5MYogNzvRTZiZMULBEehf4Ndr+muDBTwlmHMXf0kXKWMYUj2KWXPvrvHjmESvoKnbCoGPD/V6Lz2bGRfsbmo9CeVU9k1aOiBRc2nO6pHItZAjr6aR/ItDt3NBuCfhyVa81pajgdUanMES2i1eoKaHxfVO17z+l8= -------------------------------------------------------------------------------- /docs/img/femagtools-dakota.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/femagtools-dakota.png -------------------------------------------------------------------------------- /docs/img/femagtools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/femagtools.png -------------------------------------------------------------------------------- /docs/img/fluxdens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/fluxdens.png -------------------------------------------------------------------------------- /docs/img/geom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/geom.png -------------------------------------------------------------------------------- /docs/img/loss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/loss.png -------------------------------------------------------------------------------- /docs/img/mcv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/mcv.png -------------------------------------------------------------------------------- /docs/img/mesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/mesh.png -------------------------------------------------------------------------------- /docs/img/mmf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/mmf.png -------------------------------------------------------------------------------- /docs/img/mmf_fft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/mmf_fft.png -------------------------------------------------------------------------------- /docs/img/ncformat.dot: -------------------------------------------------------------------------------- 1 | digraph g { 2 | graph [ 3 | rankdir = "LR" 4 | ]; 5 | node [ 6 | fontsize = "16" 7 | shape = "record" 8 | ]; 9 | 10 | #general [ 11 | # label="FC_RADIUS | pole_pairs, poles_sim | delta_node_angle | num_slots | arm_length | pos_el_fe_induction" 12 | #]; 13 | 14 | node0 [ 15 | label="Node | key | x, y, r, phi | bndcnd | pernod | vpot" 16 | ]; 17 | 18 | element [ 19 | label="Element | key | area | center | reluc | mag | permeability() | flux_density() | demagnetization() | iron_loss_density() | mag_loss_density() | wdg_loss_density()" 20 | ]; 21 | 22 | superelement [ 23 | label = "SuperElement | key | length | mcvtype | condtype | curd" 24 | ]; 25 | 26 | nodechain [ 27 | label = "NodeChain | key | node1, nodmid, node2" 28 | ]; 29 | 30 | subregion [ 31 | label="Subregion | key | name | curdir | num_turns " 32 | ]; 33 | winding [ 34 | label="Winding | key | name | cur | flux | volt" 35 | ]; 36 | nodechain -> node0 37 | element -> node0 38 | element -> superelement 39 | superelement -> element 40 | superelement -> nodechain 41 | superelement -> subregion 42 | subregion -> superelement 43 | subregion -> nodechain 44 | winding -> subregion 45 | subregion -> winding 46 | 47 | } 48 | -------------------------------------------------------------------------------- /docs/img/ncformat.dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/ncformat.dot.png -------------------------------------------------------------------------------- /docs/img/ncformat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/ncformat.png -------------------------------------------------------------------------------- /docs/img/plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/plot.png -------------------------------------------------------------------------------- /docs/img/shortcircuit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/shortcircuit.png -------------------------------------------------------------------------------- /docs/img/spel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/spel.png -------------------------------------------------------------------------------- /docs/img/spoke-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/spoke-diagram.png -------------------------------------------------------------------------------- /docs/img/spoke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/spoke.png -------------------------------------------------------------------------------- /docs/img/winding.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/winding.png -------------------------------------------------------------------------------- /docs/img/zoneplan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/img/zoneplan.png -------------------------------------------------------------------------------- /docs/models.rst: -------------------------------------------------------------------------------- 1 | Models 2 | ****** 3 | 4 | The models are dictionaries with the properties of a material, a machine or a simulation. 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | models/machine 10 | models/material 11 | models/simulation 12 | -------------------------------------------------------------------------------- /docs/models/afpm.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _afpm: 3 | 4 | Axial Flux Machines (AFPM) 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | 7 | Axial flux machines have an airgap between stator and rotor that 8 | is aligned parallel with the axis of rotation. Three types of 9 | configurations are distinguished which are defined by the parameter afmtype: 10 | 11 | +-----------------------------+-----------------------------+-----------------------------+ 12 | | S1R1 | S2R1 | S1R2 | 13 | | | | | 14 | | .. image:: ../afpm/S1R1.svg | .. image:: ../afpm/S1R1.svg | .. image:: ../afpm/S1R2.svg | 15 | | :width: 200 | :width: 200 | :width: 200 | 16 | +-----------------------------+-----------------------------+-----------------------------+ 17 | 18 | For the simulation the AFPM is split into a number of slices (usually 3) each of which is treated as a linear machine. 19 | 20 | .. Note:: 21 | 22 | Machine models with any of the above listed types must use the models :ref:`afm_stator` 23 | and :ref:`afm_rotor`. 24 | -------------------------------------------------------------------------------- /docs/models/dxf.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _model_creation_with_dxf: 3 | 4 | Model Creation with DXF 5 | ======================= 6 | 7 | The goal of the dxfsl modules is to create a complete FE model for rotating PM and Reluctance Machines on the basis of a DXF file with 8 | as little restrictions as possible. 9 | This has the consequence that symmetries, subregions, magnets, windings, boundary conditions need to be identified. 10 | 11 | The procedure is as follows: 12 | 13 | 1. Read the DXF file and create a graph object with nodes and edges. 14 | 2. Identify the areas stator, rotor and airgap and their symmetry axis. 15 | 3. Add auxiliary lines if required by the meshing process. 16 | 4. Convert the graph object into FSL code including the identified subregions. 17 | 18 | For monitoring and trouble-shooting purposes it is possible to create plots that display the intermediate results. 19 | 20 | Example with a single dxf file motor.dxf:: 21 | 22 | machine = dict( 23 | name="Motor", 24 | lfe=0.001, 25 | 26 | dxffile=dict( 27 | name='motor.dxf' 28 | ), 29 | stator=dict( 30 | mcvkey_yoke='dummy', 31 | mcvkey_shaft="dummy" 32 | ), 33 | magnet=dict( 34 | mcvkey_yoke="dummy", 35 | mcvkey_shaft="dummy" 36 | ), 37 | ... 38 | 39 | .. Note:: 40 | * The parameters *poles*, *outer_diam*, *bore_diam* and *airgap* as well as *num_slots* and *num_slots_gen* will be set automatically 41 | * for additional keys of dxffile see :ref:`stator_slots_dxf`. 42 | 43 | Example with two separate dxf files for stator and rotor:: 44 | 45 | machine = dict( 46 | name="Motor", 47 | lfe=0.001, 48 | 49 | stator=dict( 50 | mcvkey_yoke='dummy', 51 | dxffile=dict( 52 | name='mystator.dxf', 53 | position='out' 54 | ) 55 | ), 56 | magnet=dict( 57 | mcvkey_yoke="dummy", 58 | mcvkey_shaft="dummy", 59 | dxffile=dict( 60 | name='myrotor.dxf', 61 | position='in' 62 | ) 63 | ), 64 | ... 65 | -------------------------------------------------------------------------------- /docs/models/machine.rst: -------------------------------------------------------------------------------- 1 | .. _machine-model: 2 | 3 | Machine 4 | ======= 5 | 6 | Three different types of machines are supported: 7 | 8 | * RFM: Radial Flux Machines, 9 | * LM: Linear Machines, 10 | * AFPM: Axial Flux Machine. 11 | 12 | Machines have a set of basic parameters, a stator, a magnet and a winding: 13 | 14 | ============== ====================================== ====== 15 | Parameter Description Unit 16 | ============== ====================================== ====== 17 | name Name of machine 18 | lfe Lenght of iron m 19 | afmtype (AFPM only, see :ref:`afpm`) 20 | poles Number of poles 21 | outer_diam Outer diameter (yoke side) m 22 | bore_diam Bore diameter (airgap side) m 23 | inner_diam Inner diameter (yoke or shaft) m 24 | shaft_diam Shaft diameter m 25 | airgap airgap width m 26 | external_rotor True, False False 27 | ffactor processing factor for iron losses 28 | coord_system 1 (x/y) or 2 (r/z) 0 29 | dxffile (see :ref:`model_creation_with_dxf`) 30 | ============== ====================================== ====== 31 | 32 | .. Note:: 33 | 34 | depending on the type (RFM, AFM, LM) not all combinations are useful. 35 | A LM for example does not have a diameter. 36 | 37 | .. toctree:: 38 | :maxdepth: 2 39 | 40 | stator 41 | windings 42 | magnet 43 | rotor 44 | dxf 45 | afpm 46 | -------------------------------------------------------------------------------- /docs/pyplots/forcedens.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import femagtools.forcedens 4 | import matplotlib.pylab as pl 5 | 6 | fdens = femagtools.forcedens.read('example.PLT1') 7 | 8 | f, (ax1, ax2) = pl.subplots(2, sharex=True) 9 | ax1.set_title('{}, Rotor position {}'.format( 10 | fdens.title, fdens.positions[0]['position'])) 11 | ax1.plot(fdens.positions[0]['X'], [1e-3*ft 12 | for ft in fdens.positions[0]['FT']], 13 | label='F tang') 14 | ax1.plot(fdens.positions[0]['X'], [1e-3*ft 15 | for ft in fdens.positions[0]['FN']], 16 | label='F norm') 17 | ax1.legend() 18 | ax2.plot(fdens.positions[0]['X'], fdens.positions[0]['B_T'], 19 | label='B tang') 20 | ax2.plot(fdens.positions[0]['X'], fdens.positions[0]['B_N'], 21 | label='B norm') 22 | ax1.set_ylabel('kN/m²') 23 | ax2.set_ylabel('T') 24 | pl.xlabel('Position / deg') 25 | ax2.legend() 26 | pl.show() 27 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | sphinx-autodoc-typehints 3 | nbsphinx 4 | ipython 5 | jupytext 6 | jupyter 7 | matplotlib 8 | numpy 9 | lmfit 10 | mako 11 | netCDF4 12 | networkx 13 | meshio 14 | dxfgrabber 15 | vtk 16 | -------------------------------------------------------------------------------- /docs/slot-parameters/FEMAG-FSL.jrn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/slot-parameters/FEMAG-FSL.jrn -------------------------------------------------------------------------------- /docs/slot-parameters/FEMAG-FSL.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/slot-parameters/FEMAG-FSL.log -------------------------------------------------------------------------------- /docs/slot-parameters/magntype1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/slot-parameters/magntype1.png -------------------------------------------------------------------------------- /docs/slot-parameters/magntype2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/slot-parameters/magntype2.png -------------------------------------------------------------------------------- /docs/slot-parameters/magntype3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/slot-parameters/magntype3.png -------------------------------------------------------------------------------- /docs/slot-parameters/magntype4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/slot-parameters/magntype4.png -------------------------------------------------------------------------------- /docs/slot-parameters/magntype5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/docs/slot-parameters/magntype5.png -------------------------------------------------------------------------------- /docs/slot-parameters/magv.PROT: -------------------------------------------------------------------------------- 1 | New File open 8:23. 5 2 | -------------------------------------------------------------------------------- /docs/slot-parameters/stat1.PROT: -------------------------------------------------------------------------------- 1 | New File open 8:10.50 2 | -------------------------------------------------------------------------------- /docs/tspost.rst: -------------------------------------------------------------------------------- 1 | FEMAG TS Postcalculation 2 | ************************ 3 | 4 | \femagCommand{import femagtools\_ts as ftts} 5 | 6 | FEMAG-TS erstellt für die vtu-Files ein Verzeichnis mit dem Modellname und angegängtem "\_results\_x". 7 | Beim Initialisieren des ts\_vtu-Moduls muss der Modellname und das Verzeichnis der vtu-Files angegeben werden. 8 | \vspace{3mm} \\ 9 | \femagParameter{modelname = "model"} \\ 10 | \femagParameter{directory = modelname+"\_results\_1/"} 11 | \smalllineskip 12 | \femagCommand{vtu\_data = ftts.ts\_vtu(modelname,directory)} 13 | -------------------------------------------------------------------------------- /docs/userspec.fsl: -------------------------------------------------------------------------------- 1 | User Specified Magnet Geometries 2 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | 4 | Magnet geometries not coverd by the built in models can be specified by fsl code. Here is a example: 5 | 6 | -- figure:: img/spoke.fsl 7 | 8 | example of a user specified geometry 9 | 10 | FSL Magnet:: 11 | 12 | .. 13 | magnet=dict( 14 | mcvkey_yoke="dummy", 15 | spoke=dict( 16 | magn_height=0.012, 17 | shaft_diam=0.01, 18 | slot_width=0.006, 19 | magn_width=0.022 20 | ) 21 | .. 22 | 23 | The following values can be referenced: 24 | 25 | ============== ======================== 26 | mcvkey_yoke 27 | mcvkey_shaft 28 | agndst Node distance in airgap 29 | ============== ======================== 30 | -------------------------------------------------------------------------------- /docs/windings.rst: -------------------------------------------------------------------------------- 1 | Windings 2 | ******** 3 | 4 | The windings module provides utility functions and the class 5 | Windings to define and analyze windings. 6 | 7 | Example of a symmetric 3-phase, 2-layer Winding with 54 slots and 6 pole pairs:: 8 | 9 | w = femagtools.windings.Winding(dict(Q=54, p=6, m=3, l=2)) 10 | 11 | assert wdg.yd == 4 12 | assert wdg.zoneplan() == ( 13 | [[1, 2, -6], [4, 5, -9], [-3, 7, 8]], 14 | [[1, -5, -6], [4, -8, -9], [-2, -3, 7]]) 15 | 16 | femagtools.plot.zoneplan(w) 17 | 18 | .. figure:: img/zoneplan.png 19 | 20 | Zone plan:: 21 | 22 | femagtools.plot.winding(w) 23 | 24 | .. figure:: img/winding.png 25 | 26 | MMF:: 27 | 28 | mmf = w.mmf() 29 | femagtools.plot.mmf(mmf) 30 | femagtools.plot.mmf_fft(mmf) 31 | 32 | .. figure:: img/mmf.png 33 | 34 | .. figure:: img/mmf_fft.png 35 | 36 | Custom Windings 37 | =============== 38 | 39 | Example of a custom defined winding:: 40 | 41 | w = femagtools.windings.Winding(dict( 42 | Q=12, p=5, m=3, 43 | 1: {'N': [10, 10, 10, 10], 44 | 'layer': [1, 2, 1, 2], 45 | 'slots': [1, 1, -2, 6]}, 46 | 2: {'N': [10, 10, 10, 10], 47 | 'layer': [2, 1, 2, 1], 48 | 'slots': [-4, 5, 5, -6]}, 49 | 3: {'N': [10, 10, 10, 10], 50 | 'layer': [2, 1, 2, 1], 51 | 'slots': [2, -3, -3, 4]}}) 52 | )) 53 | -------------------------------------------------------------------------------- /examples/README: -------------------------------------------------------------------------------- 1 | Examples: 2 | 3 | mcv: 4 | write_mcv.py: 5 | create MC/MCV files from BH curve data 6 | plot_mcv.py: 7 | read MC file and show BH and Mue plot 8 | 9 | model-creation: 10 | various combinations of stator and magnet models 11 | 12 | bch-erg: 13 | read_ldq_bch-plot-torque.py: read BCH file from a Ld-Lq-identification 14 | and create surface plot of the torque 15 | read_pm_sim-bch-plot-torque.py: read BCH file from a PM/Rel Simulation 16 | and plot the torque vs rotor position 17 | erg-torque-mtpa.py: read ERG file and create surface plot with MTPA curve 18 | 19 | analytical-model: 20 | fieldweakening.py: calculate the frequency and current using an analytical model 21 | pmchar.py: calculate speed-torque characteristics and show plot 22 | 23 | calculation: 24 | ld_lq_fast.py: execute a ld-lq identification and calculate 25 | the frequency and current at given voltage and torque 26 | f1 222.5 Hz, I1 76.3 A, Beta -38.7 ° 27 | 28 | psd_psq_fast.py: same with Psid-Psiq-Identification 29 | f1 230.0 Hz, I1 76.2 A, Beta -38.5 ° 30 | 31 | cogg_calc_mcv.py: build model with magnetic curve data, 32 | execute a cogging calculation and print the fft 33 | spectrum of the torque 34 | 35 | pm_sym_fast.py: 36 | execute a PM/Rel machine simulation and print the torque and losses 37 | torq_calc.py: 38 | execute a Torq/Force calculation and print the torque and losses 39 | pm_sym_loss.py: 40 | execute a PM/Rel machine loss simulation and print losses 41 | 42 | parameter-variation: 43 | parvar.py: execute a parameter variation 44 | 45 | optimization: 46 | pmopt.py: execute a multi objective optimization 47 | 48 | -------------------------------------------------------------------------------- /examples/amela/pm_sym_fast_amela.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | import femagtools.poc 3 | import femagtools.amela 4 | import pathlib 5 | import logging 6 | import math 7 | 8 | machine = dict( 9 | name="PM130L4", 10 | lfe=30e-3, 11 | poles=10, 12 | outer_diam=0.1, 13 | bore_diam=0.055, 14 | inner_diam=0.035, 15 | airgap=0.001, 16 | stator=dict( 17 | num_slots=12, 18 | statorfsl=dict( 19 | sw=0.005, 20 | tw=0.007, 21 | slot_h1=0.0017, 22 | slot_h2=0.002) 23 | ), 24 | magnet=dict( 25 | magnetfsl=dict( 26 | hm=3e-3, 27 | bm=11.205e-3 28 | ) 29 | ), 30 | 31 | winding=dict( 32 | num_phases=3, 33 | num_wires=10, 34 | coil_span=1, 35 | num_layers=2) 36 | ) 37 | 38 | logging.basicConfig(level=logging.INFO, 39 | format='%(asctime)s %(message)s') 40 | 41 | workdir = pathlib.Path().home() / 'femag' 42 | workdir.mkdir(parents=True, exist_ok=True) 43 | 44 | femag = femagtools.Femag(workdir) 45 | 46 | simulation = dict( 47 | angl_i_up=0.0, 48 | calculationMode="pm_sym_fast", 49 | wind_temp=60.0, 50 | magn_temp=20.0, 51 | current=30.0/math.sqrt(2), 52 | speed=8000/60, 53 | num_move_steps=-73, 54 | period_frac=1, 55 | plots=['field_lines', ['Babs', 0.5, 3.2, 'Babs.svg']]) 56 | 57 | r = femag(machine, 58 | simulation) 59 | 60 | # amela directory can be specified separately 61 | amela_dir = '../../amela_interface' 62 | amela = femagtools.amela.Amela(workdir, dict(name=machine['name']), amela_dir) 63 | # magnet_loss is a python dict that contains the loss data 64 | magnet_loss = amela() 65 | -------------------------------------------------------------------------------- /examples/bch-erg/erg-torque-mtpa.py: -------------------------------------------------------------------------------- 1 | 2 | import femagtools.erg 3 | import femagtools.machine 4 | import femagtools.plot 5 | 6 | import matplotlib.pylab as pl 7 | 8 | res = femagtools.erg.read('ldlq.erg') 9 | 10 | lfe = 350 11 | 12 | pm = femagtools.machine.create(res, r1=0, ls=0, lfe=lfe) 13 | 14 | femagtools.plot.mtpa(pm, res['i1'][-1]) 15 | pl.show() 16 | -------------------------------------------------------------------------------- /examples/bch-erg/ldlq.erg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/bch-erg/ldlq.erg -------------------------------------------------------------------------------- /examples/bch-erg/phasor_plot.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | import femagtools.plot 3 | import matplotlib.pylab as pl 4 | 5 | r = femagtools.read_bchfile('TEST_002.BCH') 6 | 7 | femagtools.plot.phasor(r) 8 | pl.show() 9 | 10 | #w1 = r.dqPar['npoles']*r.dqPar['speed']*math.pi 11 | #femagtools.plot.phasor(r.dqPar['up'], r.dqPar['i1'][-1], 12 | # r.dqPar['beta'][-1], 0, 13 | # w1*r.dqPar['ld'][-1], 14 | # w1*r.dqPar['lq'][-1]) 15 | -------------------------------------------------------------------------------- /examples/bch-erg/read_ldq-bch-plot-torque.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import femagtools 3 | import matplotlib.pylab as pl 4 | import femagtools.plot 5 | import femagtools.machine 6 | 7 | bch = femagtools.read_bchfile('TEST_001.BCH') 8 | 9 | beta = bch.ldq['beta'] 10 | i1 = bch.ldq['i1'] 11 | torque = bch.ldq['torque'] 12 | 13 | pm = femagtools.machine.create(bch, r1=0, ls=0) 14 | femagtools.plot.mtpa(pm, i1[-1]) 15 | pl.show() 16 | 17 | -------------------------------------------------------------------------------- /examples/bch-erg/read_pm_sim-bch-plot-torque.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | import femagtools 4 | import matplotlib.pylab as pl 5 | import numpy as np 6 | import scipy.interpolate as ip 7 | 8 | bch = femagtools.read_bchfile('TEST_002.BCH') 9 | 10 | pos = bch.torque[-1]['angle'] 11 | torque = bch.torque[-1]['torque'] 12 | 13 | fig = pl.figure() 14 | ax = fig.add_subplot(111) 15 | ax.set_title(bch.project) 16 | ax.set_xlabel(u'Position [°]') 17 | ax.set_ylabel(u'Torque [Nm]') 18 | ax.plot(pos, torque, 'go', label='Calculated') 19 | 20 | k = 20 21 | posip = np.linspace(0, pos[-1], k*len(torque)) 22 | 23 | f = ip.interp1d(pos, torque, kind='cubic') 24 | 25 | ax.plot(posip, f(posip), label='Interpolated') 26 | ax.plot(pos, [np.average(torque)] * len(pos), label='Average') 27 | ax.legend() 28 | 29 | pl.grid() 30 | pl.show() 31 | -------------------------------------------------------------------------------- /examples/calculation/fieldcalc.mako: -------------------------------------------------------------------------------- 1 | 2 | -- demo template for custom calculations 3 | --- 4 | maxit=300 5 | du_u0=1e-3 6 | 7 | m.num_par_wdgs = ${model.get('num_par_wdgs', 1)} 8 | phi = ${model.get('phi')} 9 | I1 = ${model.get('current')}*math.sqrt(2.0)/m.num_par_wdgs 10 | k = 0 11 | for ii=1,3 do 12 | cur = I1*math.cos(phi/180.0*math.pi+k*math.pi/3.0) 13 | def_curr_wdg(1,cur) 14 | k = k+2 15 | end 16 | 17 | calc_field_single(maxit, reset, du_u0) 18 | 19 | post_models("induct(x)","b") -- Calculate field distribution 20 | 21 | data=io.open("bag.dat","w") -- Output in data file 22 | N = table.getn(b) -- Number of elements in array 23 | i = 1 24 | repeat 25 | data:write(string.format("%g %g %g\n",b[i],b[i+1],b[i+2])) 26 | i = i+3 27 | until i>=N 28 | io.close(data) 29 | -------------------------------------------------------------------------------- /examples/docker-zmq/README: -------------------------------------------------------------------------------- 1 | This directory includes a cogging calculation example 2 | with FEMAG running as a service. This can be done 3 | either by starting a docker container: 4 | 5 | docker run -p 5555:5555 -p 5556:5556 --name femag -d \ 6 | hub.semafor.ch/profemag/femag:9 7 | 8 | or as an operating system process with a port number argument 9 | 10 | xfemag64 -b 5555 11 | 12 | -------------------------------------------------------------------------------- /examples/magnetcurves/BM38H.MC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/BM38H.MC -------------------------------------------------------------------------------- /examples/magnetcurves/BM38H.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/BM38H.MCV -------------------------------------------------------------------------------- /examples/magnetcurves/M270-35A.MC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/M270-35A.MC -------------------------------------------------------------------------------- /examples/magnetcurves/M270-35A.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/M270-35A.MCV -------------------------------------------------------------------------------- /examples/magnetcurves/M330-35A.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/M330-35A.MCV -------------------------------------------------------------------------------- /examples/magnetcurves/M330-50A.MC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/M330-50A.MC -------------------------------------------------------------------------------- /examples/magnetcurves/M330-50A.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/M330-50A.MCV -------------------------------------------------------------------------------- /examples/magnetcurves/M400_50A.MC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/M400_50A.MC -------------------------------------------------------------------------------- /examples/magnetcurves/M400_50A.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/M400_50A.MCV -------------------------------------------------------------------------------- /examples/magnetcurves/M800-65A.MC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/M800-65A.MC -------------------------------------------------------------------------------- /examples/magnetcurves/M800-65A.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/M800-65A.MCV -------------------------------------------------------------------------------- /examples/magnetcurves/Stahl37.MC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/Stahl37.MC -------------------------------------------------------------------------------- /examples/magnetcurves/Stahl37.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/Stahl37.MCV -------------------------------------------------------------------------------- /examples/magnetcurves/V800-50A_aniso.MC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/V800-50A_aniso.MC -------------------------------------------------------------------------------- /examples/magnetcurves/V800-50A_aniso.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/examples/magnetcurves/V800-50A_aniso.MCV -------------------------------------------------------------------------------- /examples/mcv/plot_mcv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # read mc file with filename given as command line argument and 3 | # sho BH and Mue plot 4 | # 5 | # Usage: 6 | # plot.mcv.py 7 | # 8 | import matplotlib.pylab as pl 9 | import femagtools.mcv 10 | import femagtools.plot 11 | import sys 12 | 13 | mcv = femagtools.mcv.read(sys.argv[1]) 14 | 15 | if mcv['mc1_type'] in (femagtools.mcv.MAGCRV, femagtools.mcv.ORIENT_CRV): 16 | ncols = 2 17 | else: # Permanent Magnet 18 | ncols = 1 19 | 20 | fig, ax = pl.subplots(nrows=1, ncols=ncols) 21 | if ncols > 1: 22 | pl.subplot(1, ncols, 1) 23 | femagtools.plot.mcv_hbj(mcv) 24 | pl.subplot(1, ncols, 2) 25 | femagtools.plot.mcv_muer(mcv) 26 | else: 27 | pl.subplot(1, ncols, 1) 28 | femagtools.plot.mcv_hbj(mcv, log=False) 29 | 30 | fig.tight_layout() 31 | fig.subplots_adjust(top=0.94) 32 | pl.show() 33 | -------------------------------------------------------------------------------- /examples/modal-analysis/modal_analysis_me.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | import femagtools.plot 3 | import matplotlib.pyplot as plt 4 | import pathlib 5 | import logging 6 | 7 | machine = dict( 8 | name="PM130L4", 9 | lfe=30e-3, 10 | poles=10, 11 | outer_diam=0.1, 12 | bore_diam=0.055, 13 | inner_diam=0.035, 14 | airgap=0.001, 15 | stator=dict( 16 | num_slots=12, 17 | num_slots_gen=12, 18 | statorfsl=dict( 19 | sw=0.005, 20 | tw=0.007, 21 | slot_h1=0.0017, 22 | slot_h2=0.002) 23 | ), 24 | magnet=dict( 25 | magnetfsl=dict( 26 | hm=3e-3, 27 | bm=11.205e-3 28 | ) 29 | ), 30 | 31 | winding=dict( 32 | num_phases=3, 33 | num_wires=10, 34 | coil_span=1, 35 | num_layers=2) 36 | ) 37 | 38 | logging.basicConfig(level=logging.INFO, 39 | format='%(asctime)s %(message)s') 40 | 41 | workdir = pathlib.Path().home() / 'femag' 42 | workdir.mkdir(parents=True, exist_ok=True) 43 | 44 | # remove old results (if any) 45 | for i in workdir.glob('*_Mode_*'): 46 | i.unlink() 47 | 48 | femag = femagtools.Femag(workdir) 49 | 50 | # mechanical material can be passed in a list: 51 | # [mass_density, Young's Modulus, Possion's number] 52 | # kg/m3, Gpa, # 53 | simulation = dict( 54 | num_modes=15, 55 | calculationMode="modal_analysis", 56 | stator_material=[7700, 210, 0.3], 57 | slot_material=[5000, 1.5, 0.3], 58 | export_figure=True 59 | ) 60 | # return eigenfrequency, eigenvectors 61 | r = femag(machine, 62 | simulation) 63 | 64 | if simulation['export_figure']: 65 | femagtools.plot.eigenmode(r) 66 | plt.show() 67 | -------------------------------------------------------------------------------- /examples/model-creation/createall.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | import importlib 3 | import os 4 | import logging 5 | logging.basicConfig(level=logging.INFO, 6 | format='%(asctime)s %(message)s') 7 | 8 | models = ['statorBG-magnetSector', 9 | 'stator1-magnetIron3', 10 | 'stator1-magnetIron4', 11 | 'stator1-magnetIron5', 12 | 'stator1-magnetIronV', 13 | 'stator2-magnetSector', 14 | 'stator4-magnetSector', 15 | 'statorRotor3-magnetIron' ] 16 | 17 | logger = logging.getLogger("fslcreator") 18 | workdir = os.path.join(os.path.expanduser('~'), 'femag') 19 | try: 20 | os.mkdir(workdir) 21 | except FileExistsError: 22 | pass 23 | logger.info("Femagtools Version %s Working Dir %s", 24 | femagtools.__version__, workdir) 25 | for m in models: 26 | mod = importlib.import_module(m) 27 | logger.info("--> %s <--", m) 28 | with open(os.path.join(workdir, m+'.fsl'), 'w') as f: 29 | f.write('\n'.join(getattr(mod, 'create_fsl')())) 30 | -------------------------------------------------------------------------------- /examples/model-creation/dualairgap/dualairg.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | 3 | machine = dict( 4 | name="DASSW", 5 | description="Dual Airgap, Single Stator Winding", 6 | lfe=0.023, 7 | poles=4, 8 | outer_diam=0.072, 9 | bore_diam=[0.025, 0.0558], 10 | inner_diam=0.015, 11 | airgap=[0.001,0.001], 12 | external_rotor=True, 13 | 14 | stator=dict( 15 | num_slots=4, 16 | stator=dict( 17 | beta_s=0.3, 18 | nodepitch1=1.0, 19 | nodepitch2=0.5) 20 | ), 21 | magnet=dict( 22 | remancenc=0.415, 23 | relperm=1.09, 24 | magnet=dict( 25 | hm=5e-3, 26 | alpha_m=0.98) 27 | ), 28 | windings=dict( 29 | num_phases=1, 30 | num_layers=2, 31 | num_wires=500, 32 | coil_span=1) 33 | ) 34 | 35 | with open(machine['name'] +'.fsl', 'w') as fp: 36 | fp.write('\n'.join(femagtools.create_fsl(machine))) 37 | -------------------------------------------------------------------------------- /examples/model-creation/dxf/dxf-ipm.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | 3 | def create_fsl(): 4 | machine = dict( 5 | name="IPM4", 6 | desc="DXF Demo", 7 | lfe=0.08356, 8 | ffactor=1.1, 9 | 10 | dxffile=dict( 11 | name='ipm4.dxf' 12 | ), 13 | 14 | stator=dict( 15 | mcvkey_yoke='M270-35A', 16 | mcvkey_teeth='M270-35A' 17 | ), 18 | magnet=dict( 19 | mcvkey_yoke="M270-35A" 20 | ), 21 | 22 | windings=dict( 23 | num_phases=3, 24 | num_layers=2, 25 | num_wires=10, 26 | coil_span=8 27 | ) 28 | ) 29 | return femagtools.create_fsl(machine) 30 | 31 | if __name__ == '__main__': 32 | import os 33 | import logging 34 | logging.basicConfig(level=logging.INFO, 35 | format='%(asctime)s %(message)s') 36 | modelname = os.path.split(__file__)[-1].split('.')[0] 37 | logger = logging.getLogger(modelname) 38 | workdir = os.path.join(os.path.expanduser('~'), 'femag') 39 | try: 40 | os.mkdir(workdir) 41 | except FileExistsError: 42 | pass 43 | with open(os.path.join(workdir, modelname+'.fsl'), 'w') as f: 44 | f.write('\n'.join(create_fsl())) 45 | 46 | logger.info("FSL %s created", 47 | os.path.join(workdir, modelname+'.fsl')) 48 | -------------------------------------------------------------------------------- /examples/model-creation/fsl-fml/stator1-spoke.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | 3 | 4 | def create_fsl(): 5 | machine = dict( 6 | name="example2", 7 | lfe=0.1, 8 | poles=4, 9 | outer_diam=0.143, 10 | bore_diam=0.07, 11 | inner_diam=0.015, 12 | airgap=0.001, 13 | 14 | stator=dict( 15 | num_slots=12, 16 | mcvkey_yoke="dummy", 17 | rlength=1.0, 18 | stator1=dict( 19 | slot_rf1=0.057, 20 | tip_rh1=0.037, 21 | tip_rh2=0.037, 22 | tooth_width=0.011, 23 | slot_width=0.003) 24 | ), 25 | 26 | magnet=dict( 27 | mcvkey_yoke="dummy", 28 | spokefml=dict( 29 | magn_height=0.008, 30 | shaft_diam=0.01, 31 | slot_width=0.004, 32 | magn_width=0.024 33 | ) 34 | ), 35 | 36 | winding=dict( 37 | num_phases=3, 38 | num_wires=100, 39 | coil_span=3.0, 40 | num_layers=1) 41 | ) 42 | 43 | return femagtools.create_fsl(machine) 44 | 45 | 46 | if __name__ == '__main__': 47 | import os 48 | import logging 49 | logging.basicConfig(level=logging.INFO, 50 | format='%(asctime)s %(message)s') 51 | modelname = os.path.split(__file__)[-1].split('.')[0] 52 | logger = logging.getLogger(modelname) 53 | workdir = os.path.join(os.path.expanduser('~'), 'femag') 54 | try: 55 | os.mkdir(workdir) 56 | except FileExistsError: 57 | pass 58 | 59 | with open(os.path.join(workdir, modelname+'.fsl'), 'w') as f: 60 | f.write('\n'.join(create_fsl())) 61 | 62 | logger.info("FSL %s created", 63 | os.path.join(workdir, modelname+'.fsl')) 64 | -------------------------------------------------------------------------------- /examples/model-creation/fsl-fml/statorfsl-ringmagnet.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | 3 | 4 | def create_fsl(): 5 | machine = dict( 6 | name="statorfsl", 7 | desc="Stator FSL Demo", 8 | poles=10, 9 | outer_diam=0.1, 10 | bore_diam=0.055, 11 | inner_diam=0.033, 12 | airgap=0.001, 13 | lfe=0.15, 14 | stator=dict( 15 | num_slots=12, 16 | mcvkey_yoke='M270-35A', 17 | statorfsl=dict( 18 | yoke_height=0.008, 19 | slot_h1=0.0015, 20 | slot_h2=0.002, 21 | slot_width=0.003, 22 | tooth_width=0.007) 23 | ), 24 | magnet=dict( 25 | mcvkey_yoke="M270-35A", 26 | ring=dict( 27 | magn_height=0.005) 28 | ), 29 | winding=dict( 30 | num_phases=3, 31 | num_layers=2, 32 | num_wires=100, 33 | coil_span=1, 34 | cufilfact=0.4, 35 | culength=1.4) 36 | ) 37 | return femagtools.create_fsl(machine, templatedir='templ') 38 | 39 | 40 | if __name__ == '__main__': 41 | import os 42 | import logging 43 | logging.basicConfig(level=logging.INFO, 44 | format='%(asctime)s %(message)s') 45 | modelname = os.path.split(__file__)[-1].split('.')[0] 46 | logger = logging.getLogger(modelname) 47 | workdir = os.path.join(os.path.expanduser('~'), 'femag') 48 | try: 49 | os.mkdir(workdir) 50 | except FileExistsError: 51 | pass 52 | 53 | with open(os.path.join(workdir, modelname+'.fsl'), 'w') as f: 54 | f.write('\n'.join(create_fsl())) 55 | 56 | logger.info("FSL %s created", 57 | os.path.join(workdir, modelname+'.fsl')) 58 | -------------------------------------------------------------------------------- /examples/model-creation/stator1-magnetIron4.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | 3 | def create_fsl(): 4 | machine = dict( 5 | name="PM 130 L4", 6 | lfe=0.1, 7 | poles=4, 8 | outer_diam=0.13, 9 | bore_diam=0.07, 10 | inner_diam=0.015, 11 | airgap=0.001, 12 | 13 | stator=dict( 14 | num_slots=12, 15 | stator1=dict( 16 | slot_rf1=0.057, 17 | tip_rh1=0.037, 18 | tip_rh2=0.037, 19 | tooth_width=0.009, 20 | slot_width=0.003) 21 | ), 22 | 23 | magnet=dict( 24 | magnetIron4=dict( 25 | magn_height=4e-3, 26 | magn_width=36e-3, 27 | gap_ma_iron=1e-3, 28 | air_space_h=3e-3, 29 | iron_bfe=2.5e-3, 30 | magn_di_ra=8e-3, 31 | corner_r=2e-3, 32 | air_sp_ori=0.0, 33 | condshaft_r=7e-3, 34 | magn_ori=1, 35 | magn_num=2, 36 | iron_shape=0) 37 | ), 38 | 39 | winding=dict( 40 | num_phases=3, 41 | num_wires=100, 42 | coil_span=3.0, 43 | num_layers=1) 44 | ) 45 | return femagtools.create_fsl(machine) 46 | 47 | 48 | if __name__ == '__main__': 49 | import os 50 | import logging 51 | logging.basicConfig(level=logging.INFO, 52 | format='%(asctime)s %(message)s') 53 | modelname = os.path.split(__file__)[-1].split('.')[0] 54 | logger = logging.getLogger(modelname) 55 | workdir = os.path.join(os.path.expanduser('~'), 'femag') 56 | 57 | with open(os.path.join(workdir, modelname+'.fsl'), 'w') as f: 58 | f.write('\n'.join(create_fsl())) 59 | 60 | logger.info("FSL %s created", 61 | os.path.join(workdir, modelname+'.fsl')) 62 | -------------------------------------------------------------------------------- /examples/model-creation/stator1-magnetIron5.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | 3 | def create_fsl(): 4 | machine = dict( 5 | name="PM 130 L4", 6 | lfe=0.1, 7 | poles=4, 8 | outer_diam=0.13, 9 | bore_diam=0.07, 10 | inner_diam=0.015, 11 | airgap=0.001, 12 | 13 | stator=dict( 14 | num_slots=12, 15 | stator1=dict( 16 | slot_rf1=0.057, 17 | tip_rh1=0.037, 18 | tip_rh2=0.037, 19 | tooth_width=0.009, 20 | slot_width=0.003) 21 | ), 22 | 23 | magnet=dict( 24 | magnetIron5=dict( 25 | magn_height=4e-3, 26 | magn_width=36e-3, 27 | gap_ma_iron=1e-3, 28 | air_space_h=3e-3, 29 | air_space_b=3e-3, 30 | iron_bfe=2.5e-3, 31 | magn_di_ra=8e-3, 32 | corner_r=2e-3, 33 | air_sp_ori=0.0, 34 | magn_num=2, 35 | iron_shape=0) 36 | ), 37 | 38 | winding=dict( 39 | num_phases=3, 40 | num_wires=100, 41 | coil_span=3.0, 42 | num_layers=1) 43 | ) 44 | return femagtools.create_fsl(machine) 45 | 46 | 47 | if __name__ == '__main__': 48 | import os 49 | import logging 50 | logging.basicConfig(level=logging.INFO, 51 | format='%(asctime)s %(message)s') 52 | modelname = os.path.split(__file__)[-1].split('.')[0] 53 | logger = logging.getLogger(modelname) 54 | workdir = os.path.join(os.path.expanduser('~'), 'femag') 55 | 56 | with open(os.path.join(workdir, modelname+'.fsl'), 'w') as f: 57 | f.write('\n'.join(create_fsl())) 58 | 59 | logger.info("FSL %s created", 60 | os.path.join(workdir, modelname+'.fsl')) 61 | -------------------------------------------------------------------------------- /examples/model-creation/stator1-magnetIronV.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | 3 | 4 | def create_fsl(): 5 | machine = dict( 6 | name="PM 130 L4", 7 | lfe=0.1, 8 | poles=4, 9 | outer_diam=0.13, 10 | bore_diam=0.07, 11 | inner_diam=0.015, 12 | airgap=0.001, 13 | 14 | stator=dict( 15 | num_slots=12, 16 | stator1=dict( 17 | slot_rf1=0.057, 18 | tip_rh1=0.037, 19 | tip_rh2=0.037, 20 | tooth_width=0.009, 21 | slot_width=0.003) 22 | ), 23 | 24 | magnet=dict( 25 | magnetIronV=dict( 26 | magn_height=4e-3, 27 | magn_width=18e-3, 28 | magn_angle=130, 29 | iron_hs=1e-3, 30 | iron_height=2e-3, 31 | gap_ma_iron=1e-3, 32 | air_triangle=1, 33 | condshaft_r=12e-3, 34 | magn_rem=1.2, 35 | magn_num=2, 36 | iron_shape=0) 37 | ), 38 | 39 | winding=dict( 40 | num_phases=3, 41 | num_wires=100, 42 | coil_span=3.0, 43 | num_layers=1) 44 | ) 45 | 46 | return femagtools.create_fsl(machine) 47 | 48 | 49 | if __name__ == '__main__': 50 | import os 51 | import logging 52 | logging.basicConfig(level=logging.INFO, 53 | format='%(asctime)s %(message)s') 54 | modelname = os.path.split(__file__)[-1].split('.')[0] 55 | logger = logging.getLogger(modelname) 56 | workdir = os.path.join(os.path.expanduser('~'), 'femag') 57 | 58 | with open(os.path.join(workdir, modelname+'.fsl'), 'w') as f: 59 | f.write('\n'.join(create_fsl())) 60 | 61 | logger.info("FSL %s created", 62 | os.path.join(workdir, modelname+'.fsl')) 63 | -------------------------------------------------------------------------------- /examples/model-creation/stator2-magnetSector.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | 3 | 4 | def create_fsl(): 5 | machine = dict( 6 | name="PM 130 L4", 7 | lfe=0.1, 8 | poles=4, 9 | outer_diam=0.13, 10 | bore_diam=0.07, 11 | inner_diam=0.015, 12 | airgap=0.001, 13 | 14 | stator=dict( 15 | num_slots=12, 16 | num_slots_gen=12, 17 | stator2=dict( 18 | slot_t1=0.001, 19 | slot_t2=0.0005, 20 | slot_t3=0.0005, 21 | slot_depth=0.020, 22 | slot_width=0.009, 23 | corner_width=0.01) 24 | ), 25 | 26 | magnet=dict( 27 | magnetSector=dict( 28 | magn_num=1, 29 | magn_width_pct=0.8, 30 | magn_height=0.004, 31 | magn_shape=0.0, 32 | bridge_height=0.0, 33 | magn_type=1, 34 | condshaft_r=0.02, 35 | magn_ori=8, 36 | magn_rfe=0.0, 37 | bridge_width=0.0, 38 | magn_len=1.0) 39 | ), 40 | 41 | winding=dict( 42 | num_phases=3, 43 | num_wires=100, 44 | coil_span=3.0, 45 | num_layers=1) 46 | ) 47 | 48 | return femagtools.create_fsl(machine) 49 | 50 | 51 | if __name__ == '__main__': 52 | import os 53 | import logging 54 | logging.basicConfig(level=logging.INFO, 55 | format='%(asctime)s %(message)s') 56 | modelname = os.path.split(__file__)[-1].split('.')[0] 57 | logger = logging.getLogger(modelname) 58 | workdir = os.path.join(os.path.expanduser('~'), 'femag') 59 | 60 | with open(os.path.join(workdir, modelname+'.fsl'), 'w') as f: 61 | f.write('\n'.join(create_fsl())) 62 | 63 | logger.info("FSL %s created", 64 | os.path.join(workdir, modelname+'.fsl')) 65 | -------------------------------------------------------------------------------- /examples/model-creation/statorBG-magnetSector.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | 3 | def create_fsl(): 4 | machine = dict( 5 | name="PM 130 L4", 6 | lfe=0.1, 7 | poles=4, 8 | outer_diam=0.04, 9 | bore_diam=0.022, 10 | inner_diam=0.005, 11 | airgap=0.001, 12 | 13 | stator=dict( 14 | num_slots=12, 15 | statorBG=dict( 16 | yoke_diam_ins=0.0344, 17 | slot_h1=0.0005, 18 | slot_h3=0.004, 19 | slot_width=0.00395, 20 | slot_r1=0.0008, 21 | slot_r2=0.0007, 22 | tooth_width=0.0032, 23 | middle_line=1, 24 | tip_rad=-0.03, 25 | slottooth=0) 26 | ), 27 | 28 | magnet=dict( 29 | magnetSector=dict( 30 | magn_num=1, 31 | magn_width_pct=0.8, 32 | magn_height=0.002, 33 | magn_shape=0.0, 34 | bridge_height=0.0, 35 | magn_type=1, 36 | condshaft_r=0.005, 37 | magn_ori=2, 38 | magn_rfe=0.0, 39 | bridge_width=0.0, 40 | magn_len=1.0) 41 | ), 42 | 43 | winding=dict( 44 | num_phases=3, 45 | num_wires=10, 46 | coil_span=1, 47 | num_layers=2) 48 | ) 49 | 50 | return femagtools.create_fsl(machine) 51 | 52 | 53 | if __name__ == '__main__': 54 | import os 55 | import logging 56 | logging.basicConfig(level=logging.INFO, 57 | format='%(asctime)s %(message)s') 58 | modelname = os.path.split(__file__)[-1].split('.')[0] 59 | logger = logging.getLogger(modelname) 60 | workdir = os.path.join(os.path.expanduser('~'), 'femag') 61 | 62 | with open(os.path.join(workdir, modelname+'.fsl'), 'w') as f: 63 | f.write('\n'.join(create_fsl())) 64 | 65 | logger.info("FSL %s created", 66 | os.path.join(workdir, modelname+'.fsl')) 67 | -------------------------------------------------------------------------------- /examples/model-creation/statorRotor3-magnetIron.py: -------------------------------------------------------------------------------- 1 | import femagtools 2 | 3 | 4 | def create_fsl(): 5 | machine = dict( 6 | name="PM 130 L4", 7 | lfe=0.1, 8 | poles=4, 9 | outer_diam=0.13, 10 | bore_diam=0.07, 11 | inner_diam=0.015, 12 | airgap=0.001, 13 | 14 | stator=dict( 15 | num_slots=12, 16 | statorRotor3=dict( 17 | slot_height=0.02, 18 | slot_h1=0.002, 19 | slot_h2=0.004, 20 | slot_r1=0.0, 21 | slot_r2=0.0, 22 | wedge_width1=0, 23 | wedge_width2=0, 24 | middle_line=0, 25 | tooth_width=0.009, 26 | slot_top_sh=0.0, 27 | slot_width=0.003) 28 | ), 29 | 30 | magnet=dict( 31 | magnetIron=dict( 32 | magn_width=39e-3, 33 | magn_height=4e-3, 34 | gap_ma_iron=0.0, 35 | air_triangle=1, 36 | iron_height=0.8e-3, 37 | magn_rem=1.2, 38 | condshaft_r=5e-3, 39 | bridge_height=0, 40 | magn_ori=1, 41 | bridge_width=0.0, 42 | iron_shape=33.5e-3) 43 | ), 44 | 45 | winding=dict( 46 | num_phases=3, 47 | num_wires=100, 48 | coil_span=3.0, 49 | num_layers=1) 50 | ) 51 | 52 | return femagtools.create_fsl(machine) 53 | 54 | 55 | if __name__ == '__main__': 56 | import os 57 | import logging 58 | logging.basicConfig(level=logging.INFO, 59 | format='%(asctime)s %(message)s') 60 | modelname = os.path.split(__file__)[-1].split('.')[0] 61 | logger = logging.getLogger(modelname) 62 | workdir = os.path.join(os.path.expanduser('~'), 'femag') 63 | 64 | with open(os.path.join(workdir, modelname+'.fsl'), 'w') as f: 65 | f.write('\n'.join(create_fsl())) 66 | 67 | logger.info("FSL %s created", 68 | os.path.join(workdir, modelname+'.fsl')) 69 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/README: -------------------------------------------------------------------------------- 1 | 2 | Parameter Identification, Characteristics and Efficiency Map 3 | ============================================================ 4 | 5 | For machine types: vmag (PMSM), eesm (WFSM), im (Induction Machine) 6 | 7 | To run the examples change to the machine type directory and 8 | follow these steps: 9 | 10 | 1. Create EEC parameters from machine (dqpars.json): 11 | 12 | $ python parident.py 13 | 14 | 2. Create speed characteristics plot (speedchar.pdf) 15 | 16 | $ python char.py 17 | 18 | 3. Create efficiency map (effmap.pdf) 19 | 20 | $ python effmap.py 21 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/afpm/char.py: -------------------------------------------------------------------------------- 1 | """ 2 | Speed characteristics of Axialflux PM 3 | Ronald Tanner 4 | """ 5 | import logging 6 | import json 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import femagtools.plot 10 | import femagtools.machine 11 | from femagtools.machine.utils import betai1 12 | 13 | 14 | if __name__ == '__main__': 15 | logging.basicConfig(level=logging.INFO, 16 | format='%(asctime)s %(message)s') 17 | 18 | with open('dqpar.json') as fp: 19 | dqpars = json.load(fp) 20 | 21 | temp = [90, 90] 22 | pm = femagtools.machine.create_from_eecpars(temp, dqpars) 23 | 24 | i1max = 80 25 | Udc = 800 26 | u1max = round(0.9*Udc/np.sqrt(2)/np.sqrt(3)) 27 | 28 | rep = [] 29 | w1, T = pm.w1_imax_umax(i1max, u1max) 30 | iq, id = pm.iqd_tmech(T, w1/2/np.pi/pm.p) 31 | uq, ud = pm.uqd(w1, iq, id) 32 | u1 = np.linalg.norm((ud, uq))/np.sqrt(2) 33 | beta, i1 = betai1(iq, id) 34 | rep.append((w1/2/np.pi*60/pm.p, T, i1, beta/np.pi*180, u1)) 35 | 36 | nmax = 4000/60 37 | w1 = 2*np.pi*nmax*pm.p 38 | iq, id, tq = pm.iqd_imax_umax(i1max, w1, u1max, T) 39 | beta, i1 = betai1(iq, id) 40 | uq, ud = pm.uqd(w1, iq, id) 41 | u1 = np.linalg.norm((ud, uq))/np.sqrt(2) 42 | rep.append((w1/2/np.pi*60/pm.p, tq, i1, beta/np.pi*180, u1)) 43 | 44 | print(""" 45 | n/rpm T/Nm I1/A beta/° U1/V 46 | ------------------------------- 47 | """) 48 | for r in rep: 49 | print(f" {r[0]:5.0f} {r[1]:5.1f} {r[2]:5.1f} {r[3]:5.1f} {r[4]:5.1f}") 50 | print() 51 | 52 | r = pm.characteristics(T, nmax, u1max) 53 | fig = femagtools.plot.characteristics(r) 54 | fig.savefig('speedchar.pdf') 55 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/afpm/effmap.py: -------------------------------------------------------------------------------- 1 | """ 2 | Create Efficiency Map of a Axialflux PM 3 | Ronald Tanner 4 | """ 5 | import logging 6 | import json 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import femagtools.plot 10 | import femagtools.machine 11 | import femagtools.machine.effloss 12 | 13 | if __name__ == '__main__': 14 | logging.basicConfig(level=logging.INFO, 15 | format='%(asctime)s %(message)s') 16 | 17 | with open('dqpar.json') as fp: 18 | dqpars = json.load(fp) 19 | 20 | temp = [90, 90] 21 | m = femagtools.machine.create_from_eecpars(temp, dqpars) 22 | 23 | i1max = 80 24 | Udc = 800 25 | u1max = round(0.9*Udc/np.sqrt(2)/np.sqrt(3)) 26 | w1, T = m.w1_imax_umax(i1max, u1max) 27 | 28 | nmax = 4000/60 29 | fig, ax = plt.subplots(figsize=(12,12)) 30 | ax.set_title('') 31 | effmap = femagtools.machine.effloss.efficiency_losses_map( 32 | m, u1max, T, [], nmax) 33 | contf = femagtools.plot.efficiency_map(effmap, ax, title='') 34 | fig.tight_layout() 35 | fig.savefig('effmap.pdf') 36 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/afpm/parident.py: -------------------------------------------------------------------------------- 1 | # Axial Flux Machine (AFM) demo 2 | # 3 | from machine import machine 4 | 5 | if __name__ == '__main__': 6 | import logging 7 | import pathlib 8 | import json 9 | from femagtools.machine.afpm import parident 10 | from femagtools.multiproc import Engine 11 | 12 | logging.basicConfig(level=logging.INFO, 13 | format='%(asctime)s %(message)s') 14 | 15 | workdir = pathlib.Path('dqpar') 16 | workdir.mkdir(exist_ok=True) 17 | 18 | engine = Engine() 19 | temp = [60, 90] 20 | r = parident(workdir, engine, temp, machine, 21 | magnetizingCurves='', 22 | magnetMat=[], condMat=[], 23 | speed=4000/60, 24 | beta_min=-90, 25 | num_beta_steps=4, num_cur_steps=3) 26 | with open('dqpar.json', 'w') as fp: 27 | json.dump(r, fp) 28 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/eesm/char.py: -------------------------------------------------------------------------------- 1 | """ 2 | speed characteristics of EESM 3 | Ronald Tanner 4 | """ 5 | import logging 6 | import numpy as np 7 | import json 8 | import femagtools.plot 9 | import femagtools.machine 10 | from femagtools.machine.utils import betai1 11 | import matplotlib.pyplot as plt 12 | 13 | logging.basicConfig(level=logging.INFO, 14 | format='%(asctime)s %(message)s') 15 | 16 | with open('eecpars.json') as fp: 17 | eecpars = json.load(fp) 18 | 19 | temp = [90, 90] 20 | eesm = femagtools.machine.create_from_eecpars(temp, eecpars) 21 | 22 | i1max = 275 23 | udc = 400 24 | u1max = 0.9*udc/np.sqrt(3)/np.sqrt(2) 25 | w1, Tmax = eesm.w1_imax_umax(i1max, u1max) 26 | 27 | speed = w1/2/np.pi/eesm.p 28 | iq, id, iex = eesm.iqd_tmech(Tmax, speed) 29 | uq, ud = eesm.uqd(w1, iq, id, iex) 30 | u1 = np.linalg.norm((ud, uq))/np.sqrt(2) 31 | 32 | print(""" 33 | n/rpm T/Nm I1/A Iex/A U1/V 34 | ----------------------------------- 35 | """) 36 | for n, T in zip([2000/60, speed, 6000/60, 10000/60], 37 | [120, Tmax, 100, 60]): 38 | w1 = 2*np.pi*n*eesm.p 39 | iq, id, iex, tqx = eesm.iqd_tmech_umax(T, w1, u1max) 40 | beta, i1 = betai1(iq, id) 41 | uq, ud = eesm.uqd(w1, iq, id, iex) 42 | u1 = np.linalg.norm((ud, uq))/np.sqrt(2) 43 | print(f" {60*n:6.0f} {T:5.1f} {i1:5.1f} {iex:4.1f} {u1:5.1f}") 44 | print() 45 | nmax = 12000/60 46 | r = eesm.characteristics(Tmax, nmax, u1max) 47 | fig = femagtools.plot.characteristics(r) 48 | fig.savefig('speedchar.pdf') 49 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/eesm/effmap.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | import pathlib 6 | import femagtools.plot 7 | import femagtools.machine 8 | import femagtools.machine.effloss 9 | 10 | 11 | logging.basicConfig(level=logging.INFO, 12 | format='%(asctime)s %(message)s') 13 | 14 | with open('eecpars.json') as fp: 15 | dqpars = json.load(fp) 16 | 17 | temp = [90, 90] 18 | m = femagtools.machine.create_from_eecpars(temp, dqpars) 19 | 20 | i1max = 275 21 | udc = 400 22 | u1max = 0.9*udc/np.sqrt(3)/np.sqrt(2) 23 | w1, Tmax = m.w1_imax_umax(i1max, u1max) 24 | nmax = 12000/60 25 | 26 | effmap = femagtools.machine.effloss.efficiency_losses_map( 27 | m, u1max, Tmax, [], nmax, num_proc=4) 28 | 29 | fig, ax = plt.subplots(figsize=(12,12)) 30 | ax.set_title('') 31 | contf = femagtools.plot.efficiency_map(effmap, ax, title='') 32 | fig.tight_layout() 33 | 34 | fig.savefig('effmap.pdf') 35 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/eesm/lamination/M270-35A.json: -------------------------------------------------------------------------------- 1 | {"name": "M270-35A", 2 | "desc": "for demo purposes only", 3 | "ctype": 1, 4 | "fillfac": 1.0, 5 | "fo": 50.0, 6 | "Bo": 1.5, 7 | "ch": 0.0, 8 | "ch_freq": 1.0, 9 | "cw": 3.0, 10 | "cw_freq": 1.45, 11 | "b_coeff": 1.85, 12 | "rho": 7.65, 13 | "fe_sat_mag": 2.15, 14 | "curve": [{ 15 | "hi": [0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 16 | 70.0, 80.0, 90.0, 100.0, 200.0, 300.0, 400.0, 17 | 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, 2000.0, 18 | 3000.0, 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 19 | 9000.0, 10000.0, 20000.0, 30000.0, 40000.0, 50000.0, 20 | 60000.0, 70000.0, 80000.0, 90000.0, 100000.0, 200000.0, 21 | 500000.0], 22 | "bi": [0.0, 0.10174000263214111, 0.2011370062828064, 23 | 0.29615598917007446, 0.38528698682785034, 0.4676159918308258, 24 | 0.5427759885787964, 0.6108270287513733, 0.6721190214157104, 25 | 0.7271659970283508, 0.7765570282936096, 1.0706720352172852, 26 | 1.19780695438385, 1.2671619653701782, 1.3110430240631104, 27 | 1.3416420221328735, 1.3644800186157227, 1.382403016090393, 28 | 1.3970229625701904, 1.4093159437179565, 1.4805519580841064, 29 | 1.5231300592422485, 1.558081030845642, 1.589516043663025, 30 | 1.6187200546264648, 1.646183967590332, 1.672116994857788, 31 | 1.6966110467910767, 1.7197109460830688, 1.8815209865570068, 32 | 1.9547009468078613, 1.9886070489883423, 2.0083839893341064, 33 | 2.023422956466675, 2.0368940830230713, 2.049838066101074, 34 | 2.062593936920166, 2.0752789974212646, 2.2013800144195557, 35 | 2.5786280632019043], 36 | "angle": 0.0}] 37 | } 38 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/eesm/lamination/M330-35A.json: -------------------------------------------------------------------------------- 1 | {"name": "M330-35A", 2 | "desc": "for demo purposes only", 3 | "ctype": 1, 4 | "fillfac": 1.0, 5 | "fo": 50.0, 6 | "Bo": 1.5, 7 | "ch": 0.0, 8 | "ch_freq": 0.0, 9 | "cw": 3.25, 10 | "cw_freq": 1.44, 11 | "b_coeff": 1.82, 12 | "rho": 7.65, 13 | "fe_sat_mag": 1.85325241, 14 | "curve": [{ 15 | "hi": [0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 16 | 80.0, 90.0, 100.0, 200.0, 300.0, 400.0, 500.0, 17 | 600.0, 700.0, 800.0, 900.0, 1000.0, 2000.0, 18 | 3000.0, 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 19 | 9000.0, 10000.0, 20000.0, 30000.0, 40000.0, 20 | 50000.0, 60000.0, 70000.0, 80000.0, 90000.0, 21 | 100000.0, 200000.0, 500000.0], 22 | "bi": [0.0, 0.07722435891628265, 0.15325646102428436, 23 | 0.2270091325044632, 0.29758957028388977, 0.3643421232700348, 24 | 0.4268576204776764, 0.4849509298801422, 0.5386165380477905, 25 | 0.5879855155944824, 0.6332783699035645, 0.9237410426139832, 26 | 1.0597389936447144, 1.1359325647354126, 1.1846184730529785, 27 | 1.2186754941940308, 1.2440956830978394, 1.264011025428772, 28 | 1.280210256576538, 1.293785810470581, 1.3710200786590576, 29 | 1.4157471656799316, 1.4518680572509766, 1.484082818031311, 30 | 1.5138740539550781, 1.5418201684951782, 1.5681712627410889, 31 | 1.5930418968200684, 1.6164904832839966, 1.7810873985290527, 32 | 1.8559958934783936, 1.8907582759857178, 1.9109141826629639, 33 | 1.9261165857315063, 1.9396638870239258, 1.9526455402374268, 34 | 1.9654245376586914, 1.9781244993209839, 2.1042869091033936, 35 | 2.4815709590911865], 36 | "angle": 0.0}]} 37 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/eesm/lamination/M400-50A.json: -------------------------------------------------------------------------------- 1 | {"name": "M400-50A", 2 | "desc": "for demo purposes only", 3 | "ctype": 1, 4 | "fillfac": 1.0, 5 | "fo": 50.0, 6 | "Bo": 1.5, 7 | "ch": 4.0, 8 | "ch_freq": 1.0, 9 | "cw": 0.8, 10 | "cw_freq": 1.0, 11 | "b_coeff": 1.0, 12 | "rho": 7.65, 13 | "fe_sat_mag": 2.15, 14 | "curve": [{ 15 | "hi": [0.0, 28.0, 50.0, 62.0, 70.0, 76.0, 85.0, 94.0, 16 | 105.0, 119.0, 138.0, 152.0, 165.0, 187.0, 209.0, 17 | 255.0, 300.0, 400.0, 540.0, 900.0, 1330.0, 3300.0, 18 | 6600.0, 11600.0, 18800.0, 29000.0, 46000.0, 98000.0, 19 | 175000.0, 254000.0], 20 | "bi": [0.0, 0.1, 0.2, 21 | 0.3, 0.4, 0.5, 22 | 0.6, 0.7, 0.8, 23 | 0.9, 1.0, 1.05, 24 | 1.1, 1.15, 1.2, 25 | 1.25, 1.3, 1.35, 1.4, 26 | 1.45, 1.5, 1.6, 1.7, 27 | 1.8, 1.9, 2.0, 2.1, 28 | 2.2, 2.3, 2.4], 29 | "angle": 0.0}]} 30 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/eesm/lamination/M530-50A.json: -------------------------------------------------------------------------------- 1 | {"name": "M530_50A", 2 | "desc": "for demo purposes only", 3 | "ctype": 1, 4 | "fillfac": 1.0, 5 | "fo": 50.0, 6 | "Bo": 1.5, 7 | "ch": 0.0, 8 | "ch_freq": 1, 9 | "cw": 3.0, 10 | "cw_freq": 1.45, 11 | "rho": 7.54, 12 | "fe_sat_mag": 2.0, 13 | "curve": [{ 14 | "hi": [0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 15 | 80.0, 90.0, 100.0, 200.0, 300.0, 400.0, 500.0, 16 | 600.0, 700.0, 800.0, 900.0, 1000.0, 2000.0, 3000.0, 17 | 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 9000.0, 18 | 10000.0, 20000.0, 30000.0, 40000.0, 50000.0, 60000.0, 19 | 70000.0, 80000.0, 90000.0, 100000.0, 200000.0, 500000.0], 20 | "bi": [0.0, 0.060812, 0.121207, 21 | 0.180751, 0.239071, 0.295837, 0.350773, 0.403664, 22 | 0.454353, 0.502741, 0.548778, 0.890678, 1.082872, 23 | 1.198796, 1.274945, 1.328566, 1.368405, 24 | 1.399268, 1.423987, 1.444324, 1.54869795, 25 | 1.597807, 1.632702, 1.661675, 1.687457, 26 | 1.711187, 1.733412, 1.754415, 1.774355, 1.926546, 27 | 2.012048, 2.058275, 2.085491, 2.104347, 2.11966, 28 | 2.133483, 2.146672, 2.1595831, 2.2862, 2.6637], 29 | "angle": 0.0}]} 30 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/eesm/lamination/M800-65A.json: -------------------------------------------------------------------------------- 1 | {"name": "M800-65A", 2 | "desc": "for demo purposes only", 3 | "ctype": 1, 4 | "fillfac": 1.0, 5 | "fo": 50.0, 6 | "Bo": 1.5, 7 | "ch": 0.0, 8 | "ch_freq": 1, 9 | "cw": 3, 10 | "cw_freq": 1.45, 11 | "b_coeff": 1.0, 12 | "rho": 7.65, 13 | "curve": [ 14 | {"hi": [0.0, 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 15 | 80.0, 90.0, 100.0, 200.0, 300.0, 400.0, 500.0, 16 | 600.0, 700.0, 800.0, 900.0, 1000.0, 2000.0, 17 | 3000.0, 4000.0, 5000.0, 6000.0, 7000.0, 8000.0, 18 | 9000.0, 10000.0, 20000.0, 30000.0, 40000.0, 50000.0, 19 | 60000.0, 70000.0, 80000.0, 90000.0, 100000.0, 200000.0, 20 | 500000.0], 21 | "bi": [0.0, 0.056587, 0.112851, 0.168478, 0.223178, 0.2766881, 0.328783, 22 | 0.379275, 0.428017, 0.474904, 0.519865, 0.866555, 1.072363, 23 | 1.2, 1.285121, 1.345424, 1.39036, 1.4252, 1.453078, 1.475977, 24 | 1.591754, 1.644, 1.68, 1.71, 1.735142, 1.758716, 1.78075, 1.80158, 25 | 1.82141, 1.9778, 2.0735, 2.129, 2.162473, 2.184886, 2.2021, 26 | 2.2169, 2.2306, 2.243757, 2.37071, 2.7482841], 27 | "angle": 0.0}] 28 | } 29 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/eesm/parident.py: -------------------------------------------------------------------------------- 1 | """ 2 | Parameter Identification of a EESM 3 | Ronald Tanner 4 | """ 5 | import logging 6 | import json 7 | import pathlib 8 | from machine import machine, laminations, condMat 9 | import femagtools.machine.sm 10 | import femagtools.mcv 11 | from femagtools.multiproc import Engine 12 | 13 | if __name__ == '__main__': 14 | logging.basicConfig(level=logging.INFO, 15 | format='%(asctime)s %(message)s') 16 | 17 | workdir = pathlib.Path('work') 18 | workdir.mkdir(exist_ok=True) 19 | 20 | engine = Engine() 21 | r = femagtools.machine.sm.parident(workdir, engine, machine, 22 | magnetizingCurves=laminations, 23 | condMat=condMat) 24 | r['zeta1'] = 0.3 # skin effect factor of winding resistance 25 | with open('eecpars.json', 'w') as fp: 26 | json.dump(r, fp) 27 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/im/char.py: -------------------------------------------------------------------------------- 1 | """ 2 | speed characteristics of IM 3 | Ronald Tanner 4 | """ 5 | import logging 6 | import json 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import femagtools.plot 10 | import femagtools.machine 11 | 12 | logging.basicConfig(level=logging.INFO, 13 | format='%(asctime)s %(message)s') 14 | 15 | 16 | with open('impar.json') as fp: 17 | impars = json.load(fp) 18 | 19 | temp = [90, 80] 20 | im = femagtools.machine.create_from_eecpars(temp, impars) 21 | 22 | T = 57 23 | u1max = 230 24 | nmax = 100 25 | 26 | print(""" 27 | n/rpm T/Nm I1/A U1/V cosphi f/Hz 28 | ----------------------------------------- 29 | """) 30 | 31 | wm = im.wmfweak(u1max, im.psiref, T) 32 | for tq, n in zip([T, 32.9, 20], 33 | [wm/2/np.pi, 1450/60, 2900/60]): 34 | r = im.operating_point(T, n, u1max) 35 | print(f" {n*60:6.0f} {tq:5.1f} {r['i1']:5.1f} {r['u1']:4.1f} {r['cosphi']:6.3f} {r['f1']:5.1f}") 36 | print() 37 | 38 | r = im.characteristics(T, nmax, u1max) 39 | fig = femagtools.plot.characteristics(r) 40 | fig.savefig('speedchar.pdf') 41 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/im/effmap.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import json 3 | import matplotlib.pyplot as plt 4 | import femagtools.plot 5 | import femagtools.machine 6 | import femagtools.machine.effloss 7 | 8 | 9 | logging.basicConfig(level=logging.INFO, 10 | format='%(asctime)s %(message)s') 11 | 12 | 13 | with open('impar.json') as fp: 14 | impars = json.load(fp) 15 | 16 | temp = [90, 80] 17 | T = 57 18 | u1max = 230 19 | nmax = 100 20 | 21 | r = femagtools.machine.effloss.efficiency_losses_map( 22 | impars, u1max, T, temp, nmax, npoints=(50, 40)) 23 | 24 | fig, axs = plt.subplots(figsize=(12,10)) 25 | femagtools.plot.efficiency_map(r, ax=axs, title='') 26 | fig.tight_layout() 27 | fig.savefig('effmap.pdf') 28 | 29 | # plt.show() 30 | 31 | fig, axs = plt.subplots() 32 | femagtools.plot.losses_map(r, ax=axs) 33 | fig.savefig('lossmap.pdf') 34 | # plt.show() 35 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/im/parident.py: -------------------------------------------------------------------------------- 1 | """ 2 | Parameter Identification of a IM 3 | Ronald Tanner 4 | """ 5 | import logging 6 | import femagtools.machine 7 | import femagtools.mcv 8 | import pathlib 9 | import json 10 | from machine import machine, magnetizingCurves, condMat 11 | from femagtools.multiproc import Engine 12 | 13 | if __name__ == '__main__': 14 | logging.basicConfig(level=logging.INFO, 15 | format='%(asctime)s %(message)s') 16 | 17 | workdir = pathlib.Path('work') 18 | workdir.mkdir(exist_ok=True) 19 | 20 | engine = Engine() 21 | f1 = 50 22 | u1 = 400 23 | wdgcon = 'star' 24 | results = femagtools.machine.im.parident( 25 | workdir, engine, f1, u1, wdgcon, 26 | machine=machine, 27 | magnetizingCurves=magnetizingCurves, 28 | condMat=condMat) 29 | with open('impar.json', 'w') as fp: 30 | json.dump(results, fp) 31 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/vmag/char.py: -------------------------------------------------------------------------------- 1 | """ 2 | Speed characteristics of VMAG PM 3 | Ronald Tanner 4 | """ 5 | import logging 6 | import json 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import femagtools.plot 10 | import femagtools.machine 11 | from femagtools.machine.utils import betai1 12 | 13 | 14 | if __name__ == '__main__': 15 | logging.basicConfig(level=logging.INFO, 16 | format='%(asctime)s %(message)s') 17 | 18 | with open('dqpar.json') as fp: 19 | dqpars = json.load(fp) 20 | 21 | temp = [90, 90] 22 | pm = femagtools.machine.create_from_eecpars(temp, dqpars) 23 | 24 | i1max = 250 25 | Udc = 420 26 | u1max = round(0.9*Udc/np.sqrt(2)/np.sqrt(3)) 27 | 28 | rep = [] 29 | w1, T = pm.w1_imax_umax(i1max, u1max) 30 | iq, id = pm.iqd_tmech(T, w1/2/np.pi/pm.p) 31 | uq, ud = pm.uqd(w1, iq, id) 32 | u1 = np.linalg.norm((ud, uq))/np.sqrt(2) 33 | beta, i1 = betai1(iq, id) 34 | rep.append((w1/2/np.pi*60/pm.p, T, i1, beta/np.pi*180, u1)) 35 | 36 | nmax = 6000/60 37 | w1 = 2*np.pi*nmax*pm.p 38 | iq, id, tq = pm.iqd_imax_umax(i1max, w1, u1max, T) 39 | beta, i1 = betai1(iq, id) 40 | uq, ud = pm.uqd(w1, iq, id) 41 | u1 = np.linalg.norm((ud, uq))/np.sqrt(2) 42 | rep.append((w1/2/np.pi*60/pm.p, tq, i1, beta/np.pi*180, u1)) 43 | 44 | print(""" 45 | n/rpm T/Nm I1/A beta/° U1/V 46 | ------------------------------- 47 | """) 48 | for r in rep: 49 | print(f" {r[0]:5.0f} {r[1]:5.1f} {r[2]:5.1f} {r[3]:5.1f} {r[4]:5.1f}") 50 | print() 51 | 52 | r = pm.characteristics(T, nmax, u1max) 53 | fig = femagtools.plot.characteristics(r) 54 | fig.savefig('speedchar.pdf') 55 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/vmag/effmap.py: -------------------------------------------------------------------------------- 1 | """ 2 | Create Efficiency Map of a VMAG PM 3 | Ronald Tanner 4 | """ 5 | import logging 6 | import json 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import femagtools.plot 10 | import femagtools.machine 11 | import femagtools.machine.effloss 12 | 13 | if __name__ == '__main__': 14 | logging.basicConfig(level=logging.INFO, 15 | format='%(asctime)s %(message)s') 16 | 17 | with open('dqpar.json') as fp: 18 | dqpars = json.load(fp) 19 | 20 | temp = [90, 90] 21 | m = femagtools.machine.create_from_eecpars(temp, dqpars) 22 | 23 | i1max = 250 24 | Udc = 420 25 | u1max = round(0.9*Udc/np.sqrt(2)/np.sqrt(3)) 26 | w1, T = m.w1_imax_umax(i1max, u1max) 27 | 28 | nmax = 6000/60 29 | fig, ax = plt.subplots(figsize=(12,12)) 30 | ax.set_title('') 31 | effmap = femagtools.machine.effloss.efficiency_losses_map( 32 | m, u1max, T, [], nmax) 33 | contf = femagtools.plot.efficiency_map(effmap, ax, title='') 34 | fig.tight_layout() 35 | fig.savefig('effmap.pdf') 36 | -------------------------------------------------------------------------------- /examples/parameter-ident-characteristics/vmag/parident.py: -------------------------------------------------------------------------------- 1 | """ 2 | DQ Parameter Identification of a VMAG PM 3 | Ronald Tanner 4 | """ 5 | import logging 6 | import pathlib 7 | import json 8 | import femagtools.machine 9 | import femagtools.mcv 10 | from machine import machine, laminations, magnetMat, condMat 11 | from femagtools.multiproc import Engine 12 | 13 | if __name__ == '__main__': 14 | logging.basicConfig(level=logging.INFO, 15 | format='%(asctime)s %(message)s') 16 | 17 | workdir = pathlib.Path('work') 18 | workdir.mkdir(exist_ok=True) 19 | 20 | engine = Engine() 21 | dqpars = femagtools.machine.pm.parident( 22 | workdir, engine, temp=[60, 90], 23 | i1_max=300, 24 | machine=machine, 25 | magnetizingCurves=laminations, 26 | magnetMat=magnetMat, condMat=condMat) 27 | dqpars['zeta1'] = 0.3 # skin effect factor of winding resistance 28 | with open('dqpar.json', 'w') as fp: 29 | json.dump(dqpars, fp) 30 | -------------------------------------------------------------------------------- /examples/ts/machine.py: -------------------------------------------------------------------------------- 1 | machine = { 2 | 'name': "PM 130 L4", 3 | 'lfe': 0.05, 4 | 'poles': 4, 5 | 'outer_diam': 0.11, 6 | 'bore_diam': 0.057, 7 | 'inner_diam': 0.015, 8 | 'airgap': 0.0015, 9 | 'stator': { 10 | 'num_slots': 6, 11 | 'mcvkey_yoke': 'M400_50A', 12 | 'rlength': 1, 13 | 'simplestator': { 14 | 'slot_height': 16e-3, 15 | 'slot_width': 16e-3, 16 | }, 17 | }, 18 | 'magnet': { 19 | 'mcvkey_yoke': 'Stahl37', 20 | 'rlength': 1, 21 | 'simplemagnet': { 22 | 'magnet_height': 5e-3, 23 | 'magnet_width': 30e-3 24 | } 25 | }, 26 | 'winding': { 27 | 'num_phases': 3, 28 | 'num_wires': 10, 29 | 'coil_span': 3, 30 | 'num_layers': 1 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/ts/pmts.py: -------------------------------------------------------------------------------- 1 | # FEMAG DC PM/Rel-Simulation 2 | # 3 | import logging 4 | import femagtools 5 | import pathlib 6 | from machine import machine 7 | import matplotlib.pyplot as plt 8 | 9 | simulation = dict( 10 | calculationMode="calc_field_ts", 11 | src_ampl=10.0, 12 | src_type='current', 13 | freq=100.0, 14 | speed=50.0, 15 | sim_time=[0.01, 0.02], 16 | store_time=0.01/20, 17 | dtmin=0.01/20, 18 | dtmax=0.01/20, 19 | resmin=1e-5, 20 | resmax=1e-4, 21 | vtu_movie=True) 22 | 23 | logging.basicConfig(level=logging.INFO, 24 | format='%(asctime)s %(message)s') 25 | modelname = machine['name'].replace(' ', '_') 26 | workdir = pathlib.Path.home() / 'femag' 27 | 28 | femag = femagtools.Femag(workdir, magnetizingCurves='../magnetcurves', 29 | cmd='tsfemag64', 30 | templatedirs=['templates']) 31 | 32 | r = femag(machine, simulation) 33 | 34 | fig, axs = plt.subplots(2, 2, sharex=True) 35 | axs[0, 0].plot(r['time'], r['I1']) 36 | axs[0, 0].plot(r['time'], r['I2']) 37 | axs[0, 0].plot(r['time'], r['I3']) 38 | axs[0, 0].set_title('Current / A') 39 | axs[0, 0].grid() 40 | axs[0, 1].plot(r['time'], r['U1']) 41 | axs[0, 1].plot(r['time'], r['U2']) 42 | axs[0, 1].plot(r['time'], r['U3']) 43 | axs[0, 1].set_title('Voltage / V') 44 | axs[0, 1].grid() 45 | axs[1, 0].plot(r['time'], r['angle']) 46 | axs[1, 0].set_title('Angle / °') 47 | axs[1, 0].grid() 48 | axs[1, 0].set_xlabel('Time / s') 49 | axs[1, 1].plot(r['time'], r['torque']) 50 | axs[1, 1].set_title('Torque / Nm') 51 | axs[1, 1].grid() 52 | axs[1, 1].set_xlabel('Time / s') 53 | fig.tight_layout() 54 | plt.show() 55 | -------------------------------------------------------------------------------- /notebooks/M400-50A.MC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/notebooks/M400-50A.MC -------------------------------------------------------------------------------- /notebooks/M400-50A.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/notebooks/M400-50A.MCV -------------------------------------------------------------------------------- /notebooks/femag/ldlq.erg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/notebooks/femag/ldlq.erg -------------------------------------------------------------------------------- /notebooks/femagtools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/notebooks/femagtools.png -------------------------------------------------------------------------------- /notebooks/laminations/M270-35A.MC: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/notebooks/laminations/M270-35A.MC -------------------------------------------------------------------------------- /notebooks/laminations/M270-35A.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/notebooks/laminations/M270-35A.MCV -------------------------------------------------------------------------------- /notebooks/laminations/TKS-M400-65A.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/notebooks/laminations/TKS-M400-65A.txt -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.0"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "femagtools" 7 | authors = [ 8 | {name = "Ronald Tanner", email = "tar@semafor.ch"}, 9 | {name = "Dapu Zhang", email = "dzhang@gtisoft.com"}, 10 | {name = "Beat Holm", email = "hob@semafor.ch"}, 11 | {name = "Günther Amsler", email = "amg@semafor.ch"}, 12 | {name = "Nicolas Mauchle", email = "mau@semafor.ch"} 13 | ] 14 | description = "Python API for FEMAG" 15 | readme = "README.md" 16 | requires-python = ">=3.7" 17 | license = {file = "LICENSE"} 18 | classifiers = [ 19 | "Programming Language :: Python :: 3", 20 | "Intended Audience :: Science/Research", 21 | "License :: OSI Approved :: BSD License", 22 | "Topic :: Scientific/Engineering" 23 | ] 24 | dependencies = [ 25 | 'numpy', 26 | 'scipy', 27 | 'mako', 28 | 'six', 29 | 'lmfit', 30 | 'netCDF4>=1.6.5', # >=1.6.5 to mitigate CVE-2023-38545 31 | ] 32 | dynamic = ["version"] 33 | 34 | [project.optional-dependencies] 35 | rdp = ['rdp'] # reduce nodes in dxf/svg fsl conversion 36 | dxfsl = ['dxfgrabber', 'networkx'] 37 | svgfsl = ['dxfgrabber', 'networkx', 'lxml'] 38 | mplot = ['matplotlib'] 39 | meshio = ['meshio'] 40 | vtk = ['vtk'] 41 | zmq = ['pyzmq'] 42 | test = ['pytest'] 43 | all = ['femagtools[dxfsl,svgfsl,mplot,meshio,vtk,zmq,test]'] # add new dependency groups here as well 44 | 45 | [project.scripts] 46 | femagtools-plot = "femagtools.plot.bch:main" 47 | femagtools-convert = "femagtools.convert:main" 48 | femagtools-bchxml = "femagtools.bchxml:main" 49 | femagtools-dxfsl = "femagtools.dxfsl.conv:main" 50 | femagtools-svgfsl = "femagtools.svgfsl.converter:main" 51 | 52 | [tool.setuptools.dynamic] 53 | version = {attr = "femagtools.__version__"} 54 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | mako 4 | networkx 5 | vtk 6 | meshio 7 | matplotlib 8 | lxml 9 | netCDF4 10 | lmfit 11 | dxfgrabber 12 | rdp 13 | -------------------------------------------------------------------------------- /src/femagtools/__init__.py: -------------------------------------------------------------------------------- 1 | """Python API for FEMAG 2 | 3 | """ 4 | __title__ = 'femagtools' 5 | __version__ = '1.8.15' 6 | __author__ = 'Ronald Tanner' 7 | __license__ = 'BSD' 8 | __copyright__ = 'Copyright 2023-2025 Gamma Technology' 9 | 10 | from .asm import read 11 | from .bch import Reader 12 | from .model import MachineModel 13 | from .fsl import Builder 14 | from .magnet import Magnet 15 | from .femag import Femag, ZmqFemag 16 | from .conductor import Conductor 17 | 18 | 19 | def read_bchfile(filename): 20 | """Read BCH/BATCH results from file *filename*.""" 21 | import io 22 | bchresults = Reader() 23 | with io.open(filename, encoding='latin1', errors='ignore') as f: 24 | bchresults.read(f.readlines()) 25 | return bchresults 26 | 27 | 28 | def create_fsl(machine, 29 | operatingconditions={}, 30 | magnetmat=[], 31 | condMat=[], 32 | templatedirs=[]): 33 | """create FSL command list from model and operating parameters 34 | 35 | Args: 36 | machine: dict with parameters (model) 37 | operatingConditions: dict with parameters (simulation) 38 | magnetmat: list fo dict with parameters (magnet material) 39 | templatedir: additional template directory 40 | """ 41 | model = MachineModel(machine) 42 | 43 | builder = Builder(templatedirs) 44 | magnets = [] 45 | if magnetmat: 46 | magnets = Magnet(magnetmat) 47 | if condMat: 48 | if not isinstance(condMat, Conductor): 49 | condMat = Conductor(condMat) 50 | 51 | if operatingconditions: 52 | return builder.create(model, operatingconditions, magnets) 53 | return builder.create_model(model, 54 | condMat=condMat, 55 | magnets=magnets) + ['save_model("cont")'] 56 | -------------------------------------------------------------------------------- /src/femagtools/conductor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | femagtools.conductor 4 | ~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Creating and managing coonductor material 7 | 8 | 9 | """ 10 | 11 | 12 | class Conductor: 13 | def __init__(self, clist=[]): 14 | """initialize this object from a list of conductor objects""" 15 | self.conductors = {} 16 | for c in clist: 17 | if 'id' in c: 18 | self.conductors[str(c['id'])] = c 19 | elif 'name' in c: 20 | self.conductors[c['name']] = c 21 | 22 | def find(self, id): 23 | """find conductor by id or name""" 24 | try: 25 | return self.conductors[id] 26 | except ValueError: 27 | pass # not found 28 | except KeyError: 29 | pass 30 | return self.find_by_name(id) 31 | 32 | def find_by_name(self, name): 33 | """find conductor by name""" 34 | for k in self.conductors.keys(): 35 | if self.conductors[k]['name'] == name: 36 | return self.conductors[k] 37 | # not found 38 | return None 39 | 40 | def __str__(self): 41 | return str([self.conductors[c] 42 | for c in self.conductors]) 43 | -------------------------------------------------------------------------------- /src/femagtools/dxfsl/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | femagtools.dxfsl 3 | ~~~~~~~~~~~~~~~~ 4 | 5 | convert dxf to fsl 6 | 7 | 8 | """ 9 | -------------------------------------------------------------------------------- /src/femagtools/dxfsl/corner.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | femagtools.dxfsl.corner 4 | ~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Authors: Ronald Tanner, beat Holm 7 | """ 8 | from __future__ import print_function 9 | import numpy as np 10 | import logging 11 | from .functions import distance 12 | 13 | logger = logging.getLogger('femagtools.corner') 14 | 15 | 16 | class Corner(object): 17 | def __init__(self, center, p): 18 | self.__p = p 19 | self.__dist = distance(center, p) 20 | self.__keep = False 21 | self.is_new_point = False 22 | 23 | def point(self): 24 | return self.__p 25 | 26 | def is_equal(self, p, rtol=1e-04, atol=1e-04): 27 | return (np.isclose(self.__p[0], p[0], rtol=rtol, atol=atol) and 28 | np.isclose(self.__p[1], p[1], rtol=rtol, atol=atol)) 29 | 30 | def is_same_corner(self, c): 31 | return self.is_equal(c.__p) 32 | 33 | def set_keep_node(self): 34 | self.__keep = True 35 | 36 | def keep_node(self): 37 | return self.__keep 38 | 39 | def node(self): 40 | return self.__p 41 | 42 | def __eq__(self, c): 43 | return (np.isclose(self.__p[0], c.__p[0], rtol=1e-04, atol=1e-04) and 44 | np.isclose(self.__p[1], c.__p[1], rtol=1e-04, atol=1e-04)) 45 | 46 | def __lt__(self, c): 47 | if self.__dist < c.__dist: 48 | return 1 49 | else: 50 | return 0 51 | 52 | def __str__(self): 53 | return "Corner: p={}, keep={}".format(self.__p, self.__keep) 54 | -------------------------------------------------------------------------------- /src/femagtools/dxfsl/dumprenderer.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | dxfsl 4 | ~~~~~ 5 | 6 | renders geometry 7 | 8 | 9 | """ 10 | import numpy as np 11 | import logging 12 | 13 | logger = logging.getLogger(__name__) 14 | 15 | 16 | ############################# 17 | # DumpRenderer # 18 | ############################# 19 | 20 | class DumpRenderer(object): 21 | def __init__(self, name): 22 | self.model = name 23 | 24 | def circle(self, center, radius): 25 | self.content.append(u'Crcle({}, {}, {})'.format(center[0], 26 | center[1], 27 | radius)) 28 | 29 | def arc(self, startangle, endangle, center, radius): 30 | p1 = (center[0] + radius*np.cos(startangle), 31 | center[1] + radius*np.sin(startangle)) 32 | p2 = (center[0] + radius*np.cos(endangle), 33 | center[1] + radius*np.sin(endangle)) 34 | self.content.append( 35 | u"Arc({}, {}, {}, {}, {}, {})".format( 36 | p1[0], p1[1], p2[0], p2[1], 37 | center[0], center[1])) 38 | 39 | def line(self, p1, p2): 40 | self.content.append( 41 | u"Line({}, {}, {}, {})".format( 42 | p1[0], p1[1], p2[0], p2[1])) 43 | 44 | def render(self, geom): 45 | '''create file with elements''' 46 | incl_bnd = True 47 | self.content = [] 48 | handled = set() 49 | 50 | # collect all areas 51 | for i, area in enumerate(geom.areas(incl_bnd)): 52 | self.content.append('-- {}'.format(i)) 53 | for e in area: 54 | if e not in handled: 55 | e.render(self) 56 | handled.add(e) 57 | self.content.append('--') 58 | geom.remove_areas(incl_bnd) 59 | # and all remaining edges and circles 60 | for circle in geom.circles(): 61 | circle.render(self) 62 | 63 | for e1, e2, attr in geom.g.edges(data=True): 64 | attr['object'].render(self) 65 | 66 | return self.content 67 | -------------------------------------------------------------------------------- /src/femagtools/erg.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | femagtools.erg 4 | ~~~~~~~~~~~~~~ 5 | 6 | Reading ERG files 7 | 8 | 9 | 10 | """ 11 | import re 12 | import numpy as np 13 | import io 14 | 15 | 16 | head_pattern = re.compile(r'([A-Za-z_0-9]+)') 17 | unit_pattern = re.compile(r'\[([A-Za-z/0-9 ]+)\]') 18 | num_pattern = re.compile(r'([+-]?\d+(?:\.\d+)?(?:[eE][+-]\d+)?)\s*') 19 | 20 | 21 | def read(filename): 22 | """read ERG file 23 | returns dict with array values 24 | """ 25 | head = [] 26 | units = [] 27 | m = [] 28 | with io.open(filename, 29 | errors='ignore') as f: 30 | for l in f: 31 | if head and units: 32 | n = num_pattern.findall(l) 33 | if n: 34 | m.append([float(x) for x in n]) 35 | elif head: 36 | u = unit_pattern.findall(l) 37 | if u: 38 | units = u 39 | elif l.find('|') > 0: 40 | h = head_pattern.findall(l) 41 | if h: 42 | head = h 43 | 44 | m = np.array(m).T 45 | ncols = len(set(m[1])) 46 | i1 = np.reshape(m[0], (-1, ncols)).T[0] 47 | nrows = len(i1) 48 | 49 | res = {k: (np.reshape(x, (nrows, ncols)).T[::-1]).tolist() 50 | for k, x in zip(head[2:], m[2:])} 51 | res['i1'] = i1.tolist() 52 | res['beta'] = m[1][:ncols][::-1].tolist() 53 | return res 54 | -------------------------------------------------------------------------------- /src/femagtools/grid.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | femagtools.grid 4 | ~~~~~~~~~~~~~~~ 5 | 6 | Parameter range calculation using Grid sampling 7 | 8 | 9 | 10 | """ 11 | import logging 12 | import femagtools.parstudy 13 | import numpy as np 14 | 15 | logger = logging.getLogger(__name__) 16 | 17 | 18 | def create_parameter_range(domain): 19 | """returns the transposed array of the combined domain values""" 20 | L = [len(d) for d in domain] 21 | LS = np.prod(L) 22 | s = [] 23 | e = 1 24 | for d in domain: 25 | LS = LS//len(d) 26 | s.append(np.repeat(d*LS, e)) 27 | e = e*L[0] 28 | L = L[1:] 29 | return np.array(s).T 30 | 31 | 32 | class Grid(femagtools.parstudy.ParameterStudy): 33 | """Grid Parameter variation calculation""" 34 | 35 | def __init__(self, workdir, 36 | magnetizingCurves=None, magnets=None, condMat=[], 37 | result_func=None): # tasktype='Task'): 38 | super().__init__(workdir, 39 | magnetizingCurves, magnets, condMat, 40 | result_func) 41 | 42 | def _get_names_and_range(self, dvars, num_samples): 43 | if isinstance(dvars, dict): 44 | dvarnames = dvars['columns'] 45 | par_range = dvars['list'] 46 | domain = [r for r in zip(*par_range)] 47 | else: 48 | dvarnames = [d['name'] for d in dvars] 49 | domain = [list(np.linspace(d['bounds'][0], 50 | d['bounds'][1], 51 | d['steps'])) if 'bounds' in d else d['values'] 52 | for d in dvars] 53 | 54 | par_range = create_parameter_range(domain) 55 | return dvarnames, domain, par_range 56 | -------------------------------------------------------------------------------- /src/femagtools/jhb.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | import sys 5 | import os 6 | import femagtools.mcv as mcv 7 | import logging 8 | 9 | logger = logging.getLogger(__name__) 10 | 11 | 12 | class Reader(object): 13 | def __init__(self, filename): 14 | self.mc1_type = mcv.MAGCRV 15 | 16 | with open(filename) as f: 17 | self.name = os.path.splitext( 18 | os.path.basename(f.readline().strip()))[0] 19 | r = f.readline().split() 20 | self.angle = [float(a) for a in r[1:]] 21 | self.curve = [dict(hi=[], bi=[]) 22 | for i in range(int(r[0])-1)] 23 | for l in f: 24 | r = l.split() 25 | if len(r) > 1: 26 | bh = [float(x.replace(',', '.')) for x in r] 27 | if bh[1] > 0: 28 | b = bh[0] 29 | for i, h in enumerate(bh[1:]): 30 | self.curve[i]['hi'].append(h) 31 | self.curve[i]['bi'].append(b) 32 | if len(self.curve) > 1: 33 | self.mc1_type = mcv.ORIENT_CRV 34 | logger.info("JHB %s curves %d sizes %s", self.name, len(self.curve), 35 | [len(c['bi']) for c in self.curve]) 36 | 37 | def __getitem__(self, index): 38 | return self.__getattribute__(index) 39 | 40 | def getValues(self): 41 | """return values as mcv dict""" 42 | return { 43 | 'name': self.name, 44 | 'ctype': self.mc1_type, 45 | 'curve': self.curve} 46 | 47 | 48 | def read(filename): 49 | """read JHB File and return mc dict""" 50 | jhb = Reader(filename) 51 | return jhb.getValues() 52 | 53 | 54 | if __name__ == "__main__": 55 | if len(sys.argv) == 2: 56 | filename = sys.argv[1] 57 | else: 58 | filename = sys.stdin.readline().strip() 59 | 60 | jhb = Reader(filename) 61 | print(jhb.getValues()) 62 | -------------------------------------------------------------------------------- /src/femagtools/leakinduc.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | '''Calculate leakage inductances''' 3 | import numpy as np 4 | import logging 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | 9 | def end_wdg_leak_ind_round_wires(l_ew, p, q, m, y, taup, w1, layers, num_par_wdgs, slot_height): 10 | '''returns end winding leakage inductance per phase per end winding side (DE or NDE)''' 11 | mue0 = 4*np.pi*1e-7 12 | if layers == 2: 13 | lambda_ew = 0.34*q*(1 - 2*y*taup/(np.pi*l_ew*m*q)) 14 | if layers == 1: 15 | lambda_ew = q*(0.67 - 0.43*(taup + slot_height*np.pi/(2*p))/l_ew) 16 | L_ew = mue0*2/(p*q)*(w1/num_par_wdgs)**2*l_ew*lambda_ew 17 | return L_ew 18 | 19 | 20 | def end_wdg_leak_ind_hairpin_wires(): #TODO 21 | L_ew = 0 22 | return L_ew 23 | 24 | 25 | def harm_leak_ind(E_fft, order_fft, freq, Ia): # needs to be validated 26 | '''returns harmonic leakage inductance per phase''' 27 | L_harm = [] 28 | for ii in range(1, len(order_fft)): # skip 1st order 29 | L_harm.append(E_fft[ii] / Ia / (2*np.pi*freq*order_fft[ii])) 30 | 31 | return sum(L_harm) 32 | 33 | -------------------------------------------------------------------------------- /src/femagtools/magnet.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | femagtools.magnet 4 | ~~~~~~~~~~~~~~~~~ 5 | 6 | Creating and managing magnet material 7 | 8 | 9 | 10 | """ 11 | 12 | 13 | class Magnet: 14 | def __init__(self, mlist=[]): 15 | """initialize this object from a list of magnet objects""" 16 | self.magnets = {} 17 | for m in mlist: 18 | if 'id' in m: 19 | self.magnets[str(m['id'])] = m 20 | elif 'name' in m: 21 | self.magnets[m['name']] = m 22 | 23 | def find(self, id): 24 | """find magnet by id or name""" 25 | try: 26 | return self.magnets[id] 27 | except ValueError: 28 | pass # not found 29 | except KeyError: 30 | pass 31 | return self.find_by_name(id) 32 | 33 | def find_by_name(self, name): 34 | """find magnet by name""" 35 | try: 36 | for k in self.magnets.keys(): 37 | if self.magnets[k]['name'] == name: 38 | return self.magnets[k] 39 | # not found 40 | except KeyError: 41 | pass 42 | return {} 43 | 44 | def __str__(self): 45 | return str([self.magnets[m] 46 | for m in self.magnets]) 47 | -------------------------------------------------------------------------------- /src/femagtools/me.py: -------------------------------------------------------------------------------- 1 | """ 2 | Postprocessing FEMAG-ME results 3 | """ 4 | __author__ = 'dapu zhang' 5 | 6 | import re 7 | import numpy as np 8 | import matplotlib.pyplot as plt 9 | import logging 10 | 11 | # set logging 12 | logger = logging.getLogger(__name__) 13 | 14 | def get_eigenvectors(filelist, psfiles): 15 | """return eigenfrequency and eigenvectors (raw data and psfiles)""" 16 | eigenvecs = {} 17 | eigenfreq = [] 18 | ps_data = [] 19 | temp = [] 20 | temp_arr = [] 21 | read_fig = False 22 | 23 | if len(psfiles) > 0: read_fig = True 24 | if len(filelist) == 0: return [] 25 | 26 | for k, kk in zip(filelist, range(len(filelist))): 27 | # read ps file 28 | if read_fig: ps_data.append(plt.imread(psfiles[kk])) 29 | eigenvecs[str(kk)] = {} 30 | with open(k, 'r') as f: 31 | data = f.read().split('\n') 32 | eigenval = float(re.split(r'\s+', data[0].strip())[2]) 33 | eigenfreq.append(eigenval/2/np.pi) 34 | 35 | for i in range(len(data[1:-1])): 36 | for j in data[2+i].strip().split(' '): 37 | if j != '': 38 | temp.append(float(j)) 39 | 40 | temp_arr = np.array(temp).reshape(-1, 5) 41 | idx_collect = [] 42 | # remove the index, at which the dof equals zero 43 | for c in range(temp_arr.shape[0]): 44 | if np.abs(temp_arr[c, 1]) < 1e-15 and \ 45 | np.abs(temp_arr[c, 2]) < 1e-15: 46 | idx_collect.append(c) 47 | # prepare the data from the further calculation 48 | temp_arr = np.delete(temp_arr, np.array(idx_collect), axis=0) 49 | temp_arr = np.insert(temp_arr, 3, np.zeros((temp_arr.shape[0], )), axis=1) 50 | temp_arr = np.hstack((temp_arr, np.zeros((temp_arr.shape[0], 1)))) 51 | eigenvecs[str(kk)].update({'eigenvecs': temp_arr[:, 1:4]}) 52 | # return node position 53 | if kk == 0: eigenvecs.update({'node_pos': temp_arr[:, 4::]}) 54 | 55 | return [ps_data, eigenfreq, eigenvecs] 56 | -------------------------------------------------------------------------------- /src/femagtools/moo/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Multi objective Optimizer 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | 7 | 8 | 9 | 10 | """ 11 | from .population import Population, Individual 12 | from .problem import Problem 13 | from .algorithm import Nsga2 14 | -------------------------------------------------------------------------------- /src/femagtools/moo/test/ProblemTest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | import unittest 4 | import sys 5 | sys.path.insert(0, '../..') 6 | from moo.problem import Problem 7 | 8 | 9 | class ProblemTest(unittest.TestCase): 10 | def test_compare_fc(self): 11 | prob = Problem(0, 0, 2) 12 | f1 = (0, 0) 13 | f2 = (1, 1) 14 | c1 = [] 15 | c2 = [] 16 | self.assertTrue(prob.compare_fc(f1, c1, f2, c2)) 17 | self.assertFalse(prob.compare_fc(f2, c2, f1, c1)) 18 | self.assertFalse(prob.compare_fc(f2, c2, f2, c2)) 19 | 20 | if __name__ == '__main__': 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /src/femagtools/plot/__init__.py: -------------------------------------------------------------------------------- 1 | """Creating plots 2 | 3 | """ 4 | from .machine import machine 5 | from .fluxdens import airgap, airgap_fft 6 | from .bch import torque, torque_fft, force, force_fft, \ 7 | fluxdens_surface, winding_current, winding_flux, \ 8 | voltage, voltage_fft, \ 9 | pmrelsim, multcal, fasttorque, cogging, transientsc, \ 10 | transientsc_demag, i1beta_torque, i1beta_ld, i1beta_lq, i1beta_psid, \ 11 | i1beta_psiq, i1beta_psim, i1beta_up, \ 12 | idq_ld, idq_lq, idq_psid, idq_psim, idq_psiq, idq_torque 13 | from .char import mtpa, mtpv, characteristics, efficiency_map, losses_map 14 | from .forcedens import forcedens, forcedens_surface, forcedens_contour, forcedens_fft 15 | from .nc import spel, mesh, demag, demag_pos, \ 16 | flux_density, flux_density_eccentricity, \ 17 | airgap_flux_density_pos, loss_density 18 | from .mcv import mcv_hbj, mcv_muer, felosses 19 | from .phasor import i1beta_phasor, iqd_phasor, phasor 20 | from .wdg import mmf, mmf_fft, zoneplan, winding_factors, winding, currdist 21 | from .fieldlines import fieldlines 22 | -------------------------------------------------------------------------------- /src/femagtools/plot/fieldlines.py: -------------------------------------------------------------------------------- 1 | import re 2 | import xml.etree.ElementTree as ET 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | import matplotlib.lines as mpl 6 | 7 | rgbpat = re.compile(r'rgb\((\d+),(\d+),(\d+)\)') 8 | 9 | def fieldlines(svgfilename, ax=0): 10 | """plot fieldlines from svg file""" 11 | lines = [] 12 | cols = [] 13 | tree = ET.parse(svgfilename) 14 | root = tree.getroot() 15 | for line in root.findall('svg:line', 16 | {'svg': 'http://www.w3.org/2000/svg'}): 17 | lines.append( 18 | ((float(line.attrib['x1']), float(line.attrib['x2'])), 19 | (float(line.attrib['y1']), float(line.attrib['y2'])))) 20 | cols.append( 21 | [int(x)/256 22 | for x in rgbpat.findall(line.attrib['stroke'])[0]]) 23 | a = np.array(lines) 24 | xmax, xmin = np.max(a[:, 0]), np.min(a[:, 0]) 25 | ymax, ymin = np.max(a[:, 1]), np.min(a[:, 1]) 26 | 27 | if ax == 0: 28 | ax = plt.gca() 29 | ax.set_frame_on(False) 30 | ax.set_aspect(1) 31 | ax.set_xlim((xmin, xmax)) 32 | ax.set_ylim((ymax, ymin)) # upside down 33 | ax.set_yticks([]) 34 | ax.set_xticks([]) 35 | 36 | for l, c in zip(lines, cols): 37 | ax.add_line(mpl.Line2D(l[0], l[1], color=c)) 38 | -------------------------------------------------------------------------------- /src/femagtools/plot/fluxdens.py: -------------------------------------------------------------------------------- 1 | """ Create airgap flux density plots 2 | 3 | """ 4 | import numpy as np 5 | import matplotlib.pyplot as plt 6 | 7 | 8 | def airgap(airgap, ax=0): 9 | """creates plot of flux density in airgap""" 10 | if ax == 0: 11 | ax = plt.gca() 12 | ax.set_title('Airgap Flux Density / T') 13 | ax.plot(airgap['pos'], airgap['B'], 14 | label='Max {:4.2f} T'.format(max(np.abs(airgap['B'])))) 15 | ax.plot(airgap['pos'], airgap['B_fft'], 16 | label='Base Ampl {:4.2f} T'.format(airgap['Bamp'])) 17 | ax.set_xlabel('Position/°') 18 | ax.legend() 19 | ax.grid(True) 20 | 21 | 22 | def airgap_fft(airgap, bmin=1e-2, ax=0): 23 | """plot airgap harmonics""" 24 | unit = 'T' 25 | if ax == 0: 26 | ax = plt.gca() 27 | ax.set_title('Airgap Flux Density Harmonics / {}'.format(unit)) 28 | ax.grid(True) 29 | order, fluxdens = np.array([(n, b) for n, b in zip(airgap['nue'], 30 | airgap['B_nue']) if b > bmin]).T 31 | try: 32 | markerline1, stemlines1, _ = ax.stem(order, fluxdens, '-.', basefmt=" ") 33 | ax.set_xticks(order) 34 | except ValueError: # empty sequence 35 | pass 36 | -------------------------------------------------------------------------------- /src/femagtools/templates/FE-losses.mako: -------------------------------------------------------------------------------- 1 | 2 | -- FE-Losses 3 | m.basfreq = ${model.get('basfreq', 50.0)} 4 | m.basind = ${model.get('basind', 1.5)} 5 | m.ch = ${model.get('ch', 4.0)} 6 | m.cw = ${model.get('cw', 2.0)} 7 | m.hyscoef = ${model.get('hyscoef', 1.0)} 8 | m.edycoef = ${model.get('edycoef', 2.0)} 9 | m.indcoef = ${model.get('indcoef', 2.0)} 10 | m.ffactor = ${model.get('ffactor', 1.0)} 11 | m.spweight = ${model.get('spweight', 7.65)} 12 | m.fillfact = ${model.get('fillfact', 1.0)} 13 | m.emodul = ${model.get('emodul', 210e9)} 14 | m.poison = ${model.get('poison', 0.3)} 15 | m.dampfact = ${model.get('dampfact', 0.0)} 16 | m.thcond = ${model.get('thcond', 30.0)} 17 | m.thcap = ${model.get('thcap', 480.0)} 18 | -------------------------------------------------------------------------------- /src/femagtools/templates/airgapinduc.mako: -------------------------------------------------------------------------------- 1 | post_models("induct(x)","bagx") -- Calculate field distribution 2 | data=io.open("bag.dat","w") -- Output in data file 3 | for i = 1, #bagx, 3 do 4 | data:write(string.format("%g %g %g\n",bagx[i],bagx[i+1],bagx[i+2])) 5 | end 6 | io.close(data) 7 | -------------------------------------------------------------------------------- /src/femagtools/templates/bertotti.mako: -------------------------------------------------------------------------------- 1 | 2 | function pfe(Bx,By,kh,fnu,km,z,d) 3 | 4 | -- Bx flux density x component 5 | -- By flux density y component 6 | -- kh Hysterese Factor 7 | -- fnu frequency 8 | -- km material factor 9 | -- ph return for hysterese losses 10 | -- pw return for eddy current losses 11 | -- iret status 12 | 13 | -- Parameter 14 | 15 | basfrq=${model['base_frequency']} -- Base Frequency for ch and cw [Hz] 16 | basind=${model['base_induction']} -- Base Induction (Peak) [T] 17 | ch=${model['ch']} -- Fe Hysteresis Coefficient ch [W/kg] 18 | cw=${model['cw']} -- Fe Eddy Current Coefficient cw [W/kg] 19 | ce=${model['ce']} -- Fe Excess Coefficient cw [W/kg] 20 | hyscoef=${model['alpha']} -- Hysteresis Frequency Coefficient 21 | spweight= ${model['special_weight']} -- Specific Weight Iron [gr/m3] 22 | fillfact=${model['fillfac']} -- Fillfactor Iron <= 1 23 | 24 | -- Bertotti Iron Loss Model 25 | -- pvfe = ch*f*(b**alpha) + cw*f**2*(b**2) + ce*f**1.5*(b**1.5) 26 | hxx = Bx/fillfact -- Bx 27 | hyy = By/fillfact -- By 28 | b21 = math.sqrt(hxx*hxx+hyy*hyy) 29 | b = b21/basind 30 | 31 | hi = fnu/basfrq 32 | hcw = hi^2 33 | hce = hi^1.5 34 | 35 | ph = kh*spweight*km*ch*hi*(b^hyscoef) -- [W/m3] 36 | pw = spweight*km*cw*hcw*(b^2) -- [W/m3] 37 | pe = spweight*km*ce*hce*(b^1.5) 38 | iret=1 39 | return ph, pw, pe, iret 40 | end -------------------------------------------------------------------------------- /src/femagtools/templates/calc_therm_field.mako: -------------------------------------------------------------------------------- 1 | -- Stator aussen 2 | -- Waermeuebergange einer längsangestroemten Platte 3 | -- 10m/s => 57.0W/m2.K 4 | -- 20m/s => 95.3W/m2.K 5 | -- 30m/s => 130.0W/m2.K 6 | dy1 = 269.24 7 | da1 = 161.92 8 | dy2 = 110.64 9 | heat_trans = 57.0 10 | area_factor = 10 11 | rau = (dy1+0.5)/2. 12 | xau,yau = pr2c(rau,math.pi/num_slots) -- Luft aussen gegen Umgebung 13 | def_heat_transfer(xau,yau,skyblue,heat_trans,area_factor) 14 | 15 | rau = (dy2-0.5)/2. 16 | area_factor = 1 17 | xau,yau = pr2c(rau,math.pi/num_slots) -- Luft innen gegen Umgebung 18 | def_heat_transfer(xau,yau,skyblue,heat_trans/5,area_factor) 19 | 20 | --------------------------------------------- 21 | -- set boundary conditions ------------------- 22 | del_bcond() 23 | 24 | beta = 2*math.pi*slots_gen/num_slots 25 | h = 3.8 26 | r1 = dy1/2 + h 27 | r2 = dy2/2 - h 28 | x0, y0 = pr2c(r1, beta) 29 | x1, y1 = pr2c(r2, beta) 30 | x2, y2 = r2, 0 31 | x3, y3 = r1, 0 32 | def_bcond_tp(x0, y0, x1, y1, x2, y2, x3, y3, 4) 33 | def_bcond_to(x1, y1, x2, y2) 34 | def_bcond_to(x3, y3, x0, y0) 35 | --[[ 36 | ag = 0.75 37 | da2 = da1 - 2*ag 38 | r1 = da2/2+ag/2 -- Inner airgap nodechain 39 | r2 = da2/2+ag -- Outer airgap nodechain 40 | 41 | x0, y0 = r1, 0 -- pr2c(r1, beta) 42 | x1, y1 = pr2c(r1, beta) 43 | 44 | def_nccond_to(x0,y0, x1,y1) 45 | 46 | x0, y0 = r2, 0 47 | x1, y1 = pr2c(r2, beta) 48 | def_nccond_to(r2,0, 0,r2) 49 | --]] 50 | --------------------------------------------- 51 | -- Verluste import losses 52 | --------------------------------------------- 53 | import_losses_from_femag_dc() 54 | color_gradation_th(0,0,tot,Losses,0,0,model.."_losses.svg") 55 | 56 | --------------------------------------------- 57 | -- Temperatur berechnen --------------------- 58 | --------------------------------------------- 59 | calc_therm_field() 60 | color_gradation_th(0,0,tot,Temp,0.0,0,model.."_temp.svg") 61 | -------------------------------------------------------------------------------- /src/femagtools/templates/colorgrad.mako: -------------------------------------------------------------------------------- 1 | % if model.get('colorgrad_babs',None): 2 | bmin = ${model.get('bmin', 0.0)} 3 | bmax = ${model.get('bmax', 0.0)} 4 | color_gradation( 0,0, 'tot', 'Babs', bmin, bmax, '${model['colorgrad_babs']}') 5 | % endif 6 | % if model.get('colorgrad_demag',None): 7 | hmin = ${model.get('hmin', 0.0)} 8 | hmax = ${model.get('hmax', 0.0)} 9 | color_gradation( 0,0, 'tot', 'demag', hmin, hmax, '${model['colorgrad_demag']}') 10 | % endif 11 | 12 | -------------------------------------------------------------------------------- /src/femagtools/templates/com_motor_sim.mako: -------------------------------------------------------------------------------- 1 | 2 | -- Commutator-Motor-Simulation 3 | m.curr_step = ${model.get('curr_step',1)} --Number of current steps 4 | m.current = ${model.get('current',1)} --Nominal winding current [peak] IN [A] 5 | m.brush_angl = ${model.get('brush_angl',0)} 6 | m.skew_angle = ${model.get('skew_angle',0)} 7 | m.num_skew_st = ${model.get('num_skew_st',0)} --Number of skew sections: 0=infinite 8 | m.brush_width = ${model.get('brush_width',1e-2)} -- Rel. brush width (Ref:taupe:piD/2 9 | 10 | m.num_arm_bar = ${model.get('num_arm_bar',0)} --ZA : number of armature bars 11 | m.num_fi_turn = ${model.get('num_fi_turn',0)} --ZF : number of field windings 12 | m.num_par_wdgs = ${model.get('num_par_wdgs',2)} --N.par.arm.circ: LapW:2a=2p WaveW:2a=2 13 | m.ex_condition = ${model.get('ex_condition',1)} 14 | m.speed = ${model.get('speed',25)*60} 15 | m.magn_temp = ${model.get('magn_temp',20)} 16 | m.calc_noload = ${model.get('calc_noload',1)} 17 | m.forcedens = ${model.get('forcedens',0)} 18 | m.calc_react = ${model.get('calc_react',0)} 19 | m.calc_fe_los = ${model.get('calc_fe_los',0)} 20 | m.delta_br_an = ${model.get('delta_br_an',0)} 21 | m.nu_move_steps = ${model.get('num_move_steps',49)} 22 | m.cmmfilename = model .. "_" .. m.num_poles .."p.cmm" 23 | m.range_phi = ${model.get('range_phi',0)} 24 | m.phi_start = 0 25 | 26 | run_models("com-motor_sim") 27 | -------------------------------------------------------------------------------- /src/femagtools/templates/conduct-data.mako: -------------------------------------------------------------------------------- 1 | 2 | -- conductor properties 3 | m.conduct = ${model.get('elconduct', 10e6)} -- el. conductivity S/m 4 | m.conrelperm = ${model.get('relperm', 100)} -- rel permeability 5 | m.contemp = ${model.get('contemp', 20)} -- conductor temperature °C 6 | m.contecoef = ${model.get('tempcoef', 0)} -- conduct. temperature coeff 1/K 7 | m.spconweight = ${model.get('spmaweight', 7.6)} -- mass density g/cm³ 8 | m.relconlength = ${model.get('relconlength', 100)} -- rel cond length % 9 | 10 | pre_models('conduct-data') -------------------------------------------------------------------------------- /src/femagtools/templates/connect_models.mako: -------------------------------------------------------------------------------- 1 | % if model.stator['num_slots'] > model.stator['num_slots_gen']: 2 | connect_models() 3 | % else: 4 | x0, y0 = pr2c(da1/2-ag/6, math.pi/2) 5 | create_mesh_se(x0, y0) 6 | x0, y0 = pr2c(da2/2+ag/6, math.pi/2) 7 | create_mesh_se(x0, y0) 8 | 9 | x0, y0 = pr2c(m.fc_radius, math.pi/2) 10 | create_mesh_se(x0, y0) 11 | 12 | x0,y0 = pd2c(dy1/2,0) 13 | def_bcond_vpo(x0, 0,-x0,0,0) 14 | def_bcond_vpo(-x0,0,x0,0,0) 15 | x0,y0 = pd2c(dy2/2,0) 16 | def_bcond_vpo(x0, 0,-x0,0,0) 17 | def_bcond_vpo(-x0,0,x0,0,0) 18 | % endif 19 | 20 | -- thermal properties 21 | ag_cond = 0.063 22 | --[[ 23 | if speed < 1.0 then 24 | -- Waermeleitfähigkeit von Luft 25 | ag_cond = 0.0262 26 | end 27 | --]] 28 | xai, yai = pr2c((da1+da2)/4, math.pi/m.npols_gen) 29 | def_mat_therm(xai,yai,cyan,1.19,ag_cond,1007,1) 30 | -------------------------------------------------------------------------------- /src/femagtools/templates/cu_losses.mako: -------------------------------------------------------------------------------- 1 | 2 | -- CU-Losses- 3 | m.cufilfact = ${model.get('cufilfact', 0.45)} 4 | m.culength = ${model.get('culength', 1.4)*100} -- rel wire length % 5 | m.cuconduct = ${model.get('cuconduct', 56e6)} -- el. conductivity S/m 6 | m.numlayers = ${model.get('num_layers', 1)} 7 | m.conheight = ${model.get('conheight', 0.0)} 8 | m.contemp = ${model.get('wind_temp',20.0)} -- conductor temperature °C 9 | m.emodul = ${model.get('emodul', 210e9)} 10 | m.poison = ${model.get('poisson', 0.3)} 11 | m.dampfact = ${model.get('dampfact', 0.0)} 12 | m.thcond = ${model.get('thcond', 30.)} 13 | m.thcap = ${model.get('thcap', 480.0)} 14 | m.slot_indul = ${model.get('slot_indul',0.0)*1e3} 15 | m.dia_wire = ${model.get('dia_wire',0.0)*1e3} -- wire diameter mm 16 | m.num_wire = ${model.get('num_wire',0.0)} 17 | % if model.get('winding_inside', False): 18 | -- conductor properties 19 | m.conduct = m.cuconduct 20 | m.conrelperm = ${model.get('relperm', 100)} -- rel permeability 21 | m.contecoef = ${model.get('tempcoef', 0)} -- conduct. temperature coeff 1/K 22 | m.spconweight = ${model.get('spmaweight', 7.6)} -- mass density g/cm³ 23 | m.relconlength = ${model.get('rlen', 1)*100} -- rel cond length % 24 | pre_models('conduct-data') 25 | pre_models("CU-Losses-2") -- inside 26 | % else: 27 | pre_models("CU-Losses-1") 28 | % endif 29 | -------------------------------------------------------------------------------- /src/femagtools/templates/dakota/moga.mako: -------------------------------------------------------------------------------- 1 | # Dakota Input Template File 2 | 3 | environment 4 | tabular_data 5 | tabular_data_file = 'femag.dat' 6 | 7 | method 8 | moga 9 | % if set(('num_generations', 'percent_change')).intersection(study.keys()): 10 | convergence_type metric_tracker 11 | % if 'num_generations' in study: 12 | num_generations = ${study['num_generations']} 13 | % endif 14 | % if 'percent_change' in study: 15 | percent_change = ${study['percent_change']} 16 | % endif 17 | % endif 18 | #final_solutions = 3 19 | print_each_pop 20 | # fitness_type domination_count 21 | # niching_type distance 0.05 0.05 22 | # replacement_type below_limit = 6 23 | # replacement_type roulette_wheel 24 | # postprocessor_type orthogonal_distance 0.05 0.05 25 | # max_function_evaluations = ${study.get('max_function_evaluations', 1000)} 26 | 27 | variables 28 | % if [d['bounds'] for d in study['decision_vars']]: 29 | continuous_design = ${len(study['decision_vars'])} 30 | lower_bounds ${' '.join([str(d['bounds'][0]) for d in study['decision_vars']])} 31 | upper_bounds ${' '.join([str(d['bounds'][1]) for d in study['decision_vars']])} 32 | descriptors ${' '.join([f"\"{d['name']}\"" for d in study['decision_vars']])} 33 | % endif 34 | 35 | interface 36 | id_interface = 'FEMAG' 37 | analysis_driver = 'python -m femagtools.dakota_femag' 38 | fork batch 39 | parameters_file = 'params.in' 40 | results_file = 'results.out' 41 | file_save 42 | 43 | responses 44 | objective_functions = ${len(study['objective_vars'])} 45 | descriptors ${' '.join([f"\"{o['name']}\"" for o in study['objective_vars']])} 46 | # sense 'max' 'min' .. 47 | no_gradients 48 | no_hessians 49 | -------------------------------------------------------------------------------- /src/femagtools/templates/displ_stator_rotor.mako: -------------------------------------------------------------------------------- 1 | -- calculate static or dynamic eccentricity 2 | -- NOTE: requires full model 3 | -- 4 | static = 0 5 | dynamic = 1 6 | m.disp_info = ${model.get('type', 'static')} -- Displace: Stator: 0, Rotor: 1 7 | 8 | da1 = ${model.get('bore_diam',0)*1e3} 9 | ag = ${model.get('airgap',0)*1e3} 10 | 11 | if m.b_min == 0 then -- move inside: outer stator 12 | if m.disp_info == static then 13 | m.fc_radius = da1/2 - ag/6 14 | else 15 | m.fc_radius = da1/2 - 5*ag/6 16 | end 17 | else 18 | if m.disp_info == static then 19 | m.fc_radius = da1/2 + ag/6 20 | else 21 | m.fc_radius = da1/2 + 5*ag/6 22 | end 23 | end 24 | m.disp_radius = ${model.get('ecc', 0)*1e3} -- Displacement: r [mm] 25 | m.disp_phi = 0.0 -- Displacement: phi [Degr] 26 | 27 | pre_models("Displ_Stat/Rot") 28 | -- must correct fc_radius 29 | if m.b_min == 0 then -- move inside: outer stator 30 | m.fc_radius = da1/2 - ag/2 31 | else 32 | m.fc_radius = da1/2 + ag/2 33 | end -------------------------------------------------------------------------------- /src/femagtools/templates/ec-rotorbar.mako: -------------------------------------------------------------------------------- 1 | -- eddy current simulation of a rotor bar 2 | -- 3 | -- set rotor bar 4 | xb, yb = 0, da2/2 - m.slot_height/2 - m.slot_h1 5 | muer = 1 6 | rel = 100 7 | cur = {1, 0} 8 | sigma1, sigma2 = get_dev_data( "cond_conduct" ) 9 | rotorbar = def_new_bar(xb,yb, "green", "U", cur[1],cur[2], "wi", 10 | sigma2, muer, rel, "polar", 0, 0) 11 | Abar = get_sreg_data("area",rotorbar) 12 | 13 | maxit = m.num_nonl_it 14 | permode = 'restore' 15 | du_u0 = m.error_perm/5 16 | 17 | psi={} 18 | L={} 19 | 20 | % if model.get('bar_len', 0): 21 | barlen = ${model.get('bar_len')*1e3} 22 | % else: 23 | p = m.num_poles/2 24 | Dr = da2-m.slot_height 25 | barlen = m.arm_length+math.pi*Dr/Q2/math.sin(math.pi*p/Q2) 26 | % endif 27 | 28 | state_of_problem('mag_dynamic') 29 | file_bar = io.open("bar.dat","w") 30 | dfreq = 8 31 | f0 = 2 32 | bag = {} 33 | pos = {} 34 | leakind = {} 35 | currdens={1, 2, 3, 4} -- factor for current variation (Current densities A/mm²) 36 | Nfreqs = 15 -- 37 | for i= 1, Nfreqs do 38 | freq = f0 + (i-1)*dfreq 39 | for k = 1, #currdens do 40 | cur = Abar*currdens[k] 41 | def_curr_wdg(rotorbar, cur, 0) 42 | 43 | calc_field_single({maxit=maxit, maxcop=du_u0, 44 | permode=permode, freq=freq}) 45 | if k==1 then 46 | u_re, u_im = get_wdg_data("volt", rotorbar) 47 | rbar = u_re*barlen/cur 48 | end 49 | i_re, i_im = get_wdg_data("cur", rotorbar) 50 | flx1_re, flx1_im = get_wdg_data("flux", rotorbar) 51 | flx2_re, flx2_im = get_wdg_data("flux", stator) 52 | 53 | print(string.format("%g: %g %g %g", 54 | freq, i_re, flx1_re*m.arm_length, flx2_re*m.arm_length)) 55 | 56 | leakind[k] = (flx1_re-flx2_re)*m.arm_length/cur 57 | end 58 | file_bar:write(string.format("%g %g ", 59 | freq, rbar)) 60 | for k=1, #currdens do 61 | file_bar:write(string.format("%g ", leakind[k])) 62 | end 63 | file_bar:write("\n") 64 | end 65 | file_bar:close() 66 | -------------------------------------------------------------------------------- /src/femagtools/templates/fe-contr.mako: -------------------------------------------------------------------------------- 1 | m.hc_min = ${'%12.3f' % model.get('hc_min', 95.0)} -- Limit demagnetisa > 0:[%]Hc,<0:[kA/m] 2 | m.con_hdcopy = ${'%12.3f' % model.get('con_hdcopy', 0)} -- Hc-copy:Name:auto:0,intact:1, none:-1 3 | m.b_max = ${'%12.3f' % model.get('b_max', 2.4)} -- Max Induction [T] in colorgradation 4 | m.b_min = ${'%12.3f' % model.get('move_inside')} -- Move inside: 0 , Move outside: > 0 5 | m.calc_fe_loss = ${model.get('calc_fe_loss', 1)} -- Calc. FE-Loss:0:no, 1:yes, 2:m-output 6 | m.eval_force = ${'%12.3f' % model.get('eval_force', 0)} -- Eval. force density > 0, no <= 0 7 | m.allow_draw = ${'%12.3f' % model.get('allow_draw', 1)} -- Draw Graphics :> 0: yes, 0: no 8 | m.fline_dens = ${'%12.3f' % model.get('fline_dens', 4)} -- F-Lines: 1: small, 2: medium, 3:thick 9 | m.num_flines = ${'%12.3f' % model.get('num_flines', 20)} -- Number of Field-lines: < 100 > 2 10 | m.name_bch_log = ${'%12.3f' % model.get('name_bch_log', 0)} -- Name bch-file in Logfile:> 0:yes,0:no 11 | m.st_size_move = ${'%12.3f' % model.get('st_size_move', 0)} -- Step size move: r/ph:[degr], x/y:[mm] 12 | m.num_nonl_it = ${'%12.3f' % model.get('num_nonl_it', 300)} -- Number of nonlinear Iterations < 99 13 | m.perm_mode = ${'%12.3f' % model.get('perm_mode', 0)} -- Permeability mode:>0:restore,0:actual 14 | m.error_perm = ${'%12.3f' % model.get('error_perm', 0.005)} -- Rel. Permeability error < 0.1 [%] 15 | m.allow_demagn = ${'%12.3f' % model.get('allow_demagn', 0)} -- Allow Demagnetisation:= 1:yes,= 0:no 16 | m.maenergy = ${'%12.3f' % model.get('maenergy', 0)} -- Force from magn energy 1 :yes,= 0:no 17 | m.el_order_ag = ${'%12.3f' % model.get('el_order_ag', 1)} -- El. order in air gap: lin=1: quadr=2 18 | m.export_scrpt = ${'%12.3f' % model.get('export_scrpt', 0)} -- Export parameters in script: yes > 0 19 | 20 | pre_models("FE-contr-data") 21 | -------------------------------------------------------------------------------- /src/femagtools/templates/fieldcalc.mako: -------------------------------------------------------------------------------- 1 | 2 | -- no load single calculation 3 | 4 | maxit=300 5 | du_u0=1e-3 6 | 7 | get_wdg_keys("wkeys") 8 | 9 | -- set cur to zero 10 | for i = 1, #wkeys do 11 | def_curr_wdg(wkeys[i],0, 0) 12 | end 13 | % if model.get('noload_ex_cur', 0): 14 | def_curr_wdg(wkeys[#wkeys], ${model['noload_ex_cur']}, 0) 15 | % endif 16 | 17 | calc_field_single(maxit, reset, du_u0) 18 | 19 | post_models("induct(x)","b_airgap") -- Calculate field distribution 20 | 21 | data=io.open("bag.dat","w") -- Output in data file 22 | N = table.getn(b_airgap) -- Number of elements in array 23 | i = 1 24 | repeat 25 | data:write(string.format("%g %g %g\n",b_airgap[i],b_airgap[i+1],b_airgap[i+2])) 26 | i = i+3 27 | until i>=N 28 | io.close(data) 29 | 30 | -- experimental (new femag-classic needed) 31 | export_calc_results('fieldcalc.vtu') -------------------------------------------------------------------------------- /src/femagtools/templates/inductances.mako: -------------------------------------------------------------------------------- 1 | % if model.get('calc_inductances',0): 2 | 3 | L={} 4 | curr = 1/a 5 | ksym = m.num_poles/m.npols_gen 6 | curr = { 7 | {1/a, 0, 0}, 8 | {0, 1/a, 0}, 9 | {0, 0, 1/a} } 10 | 11 | data=io.open("inductances.dat","w+") 12 | for i=1,m.num_phases do 13 | for k=1,m.num_phases do 14 | def_curr_wdg(k,curr[i][k],0) 15 | end 16 | calc_field_single({ 17 | maxit=1,permode='actual',freq=m.frequency}) 18 | 19 | for k=1,m.num_phases do 20 | psi_Re,psi_Im=flux_winding_wk(k) 21 | data:write(string.format("%g ", 22 | math.sqrt(psi_Re^2+psi_Im^2)*m.arm_length/a*ksym)) 23 | end 24 | data:write('\n') 25 | end 26 | io.close(data) 27 | % endif 28 | -------------------------------------------------------------------------------- /src/femagtools/templates/ld_lq_fast.mako: -------------------------------------------------------------------------------- 1 | -- 2 | -- Ld-Lq- Identification 3 | -- 4 | 5 | m.move_action = 0.0 -- rotate 6 | % if isinstance(model, dict) and 'lfe' in model: 7 | m.arm_length = ${model.get('lfe')*1e3} 8 | % endif 9 | m.speed = ${model.get('speed')*60} 10 | m.skew_angle = ${model.get('skew_angle',0)} 11 | m.nu_skew_steps = ${model.get('num_skew_steps',0)} 12 | m.magn_temp = ${model.get('magn_temp', 'nil')} 13 | m.fc_mult_move_type = 1.0 -- Type of move path in air gap 14 | m.phi_start = ${model.get('phi_start', 0)} 15 | m.range_phi = ${model.get('range_phi', 0)} 16 | m.nu_move_steps = ${model.get('num_move_steps', 49)} 17 | m.num_par_wdgs = ${model.get('num_par_wdgs',1)} 18 | 19 | m.current = ${model['i1_max']}*math.sqrt(2.0)/m.num_par_wdgs 20 | m.num_cur_steps = ${model['num_cur_steps']} 21 | m.nu_beta_steps = ${model['num_beta_steps']} 22 | m.beta_max = ${model['beta_max']} 23 | m.beta_min = ${model['beta_min']} 24 | % if model.get('calc_fe_loss', 0): 25 | m.calc_fe_loss = ${model['calc_fe_loss']} 26 | % endif 27 | % if model.get('loss_funct',0): 28 | m.loss_funct = ${model.get('loss_funct')} 29 | % endif 30 | 31 | m.pm_eff_aktiv = 0.0 32 | m.calc_noload = ${model.get('calc_noload', 1)} 33 | m.period_frac = ${model.get('period_frac', 1)} 34 | 35 | m.pocfilename = '${model.get('pocfilename', 'sin.poc')}' 36 | % if model.get('load_ex_cur',0): 37 | m.load_ex_cur = ${model.get('load_ex_cur',0)} 38 | run_models("ld_lq_f_cur") 39 | %else: 40 | run_models("ld_lq_fast") 41 | %endif -------------------------------------------------------------------------------- /src/femagtools/templates/leak_dist_wind.mako: -------------------------------------------------------------------------------- 1 | -- End-Winding Leakage 2 | m.nseg = m.tot_num_slot/m.num_slots -- Number of segments 3 | m.npolsim = m.npols_gen -- Number of poles simulated 4 | % if 'perimrad' not in model: 5 | m.perimrad = (da1+dy1)/4 -- Radius of perimeter [mm] 6 | % else: 7 | m.perimrad = ${model['perimrad']*1e3} -- Radius of perimeter [mm] 8 | % endif 9 | m.vbendrad = ${model['vbendrad']*1e3} -- Bending radius vertical [mm] 10 | m.endheight = ${model['endheight']*1e3} -- End winding height [mm] 11 | m.wiredia = ${model['wiredia']*1e3} -- Wire diameter [mm] 12 | pre_models("leak_dist_wind") 13 | -------------------------------------------------------------------------------- /src/femagtools/templates/leak_evol_wind.mako: -------------------------------------------------------------------------------- 1 | -- End-Winding Leakage 2 | m.nseg = m.tot_num_slot/m.num_slots -- Number of segments 3 | m.npolsim = m.npols_gen -- Number of poles simulated 4 | 5 | m.evol1rad = ${model['evol1rad']*1e3} -- Top radius of first evolvent [mm] 6 | m.evol2rad = ${model['evol2rad']*1e3} -- Top radius of second evolvent [mm] 7 | m.botlevel = ${model['botlevel']*1e3} -- Level at bottom of evolvents [mm] 8 | m.toplevel = ${model['toplevel']*1e3} -- Level at top of evolvents [mm] 9 | m.endheight = ${model['endheight']*1e3} -- End winding height [mm] 10 | m.evolbend = ${model['evolbend']*1e3} -- Bending radius [mm] 11 | m.wiredia = ${model['wiredia']*1e3} -- Wire diameter [mm] 12 | 13 | pre_models("leak_evol_wind") 14 | -------------------------------------------------------------------------------- /src/femagtools/templates/leak_tooth_wind.mako: -------------------------------------------------------------------------------- 1 | -- End-Winding Leakage 2 | m.nseg = m.tot_num_slot/m.num_slots -- Number of segments 3 | m.npolsim = m.npols_gen -- Number of poles simulated 4 | 5 | m.endheight = ${model['endheight']*1e3} -- End winding height [mm] 6 | m.bendrad = ${model['bendrad']*1e3} -- Bending radius [mm] 7 | m.wiredia = ${model['wiredia']*1e3} -- Wire diameter [mm] 8 | 9 | pre_models("leak_tooth_wind") 10 | -------------------------------------------------------------------------------- /src/femagtools/templates/magnet-data.mako: -------------------------------------------------------------------------------- 1 | -- Magnet-data 2 | %if model.get('remanenc',0): 3 | m.remanenc = ${model.get('remanenc')} 4 | %endif 5 | %if model.get('relperm',0): 6 | m.relperm = ${model.get('relperm')} 7 | %endif 8 | %if model.get('spmaweigth',0): 9 | m.spmaweight = ${model.get('spmaweight')*1e-3} 10 | %endif 11 | %if model.get('temcoefbr',0): 12 | m.temcoefbr = ${model.get('temcoefbr')*100} 13 | %endif 14 | %if model.get('temcoefhc',0): 15 | m.temcoefhc = ${model.get('temcoefhc')*100} 16 | %endif 17 | %if model.get('magntemp',0): 18 | m.magntemp = ${model.get('magntemp')} 19 | %endif 20 | %if model.get('magncond',0): 21 | m.magncond = ${model.get('magncond')} 22 | %endif 23 | %if model.get('rlen',0): 24 | m.rlen = ${model.get('rlen')*100} 25 | %endif 26 | %if model.get('mcvkey',0): 27 | m.mcvkey_magnet = '${model.get('mcvkey')}' 28 | %if model.get('orient', 0): 29 | m.orient = ${model.get('orient', 'm.cartiso')} 30 | %endif 31 | %else: 32 | %if model.get('magnwidth',0): 33 | m.magsegwid = ${model.get('magnwidth')*1e3} 34 | %elif model.get('magnsegwidth',0): 35 | m.magsegwid = ${model.get('magnsegwidth')*1e3} 36 | %endif 37 | %if model.get('magnlength',0): 38 | m.magseglen = ${model.get('magnlength')*1e3} 39 | %endif 40 | %if model.get('magnseglength',0): 41 | m.magseglen = ${model.get('magnseglength')*1e3} 42 | %endif 43 | %endif 44 | 45 | pre_models("Magnet-data") 46 | -------------------------------------------------------------------------------- /src/femagtools/templates/magnetFC2.mako: -------------------------------------------------------------------------------- 1 | m.yoke_rad = dy2/2 2 | m.rotor_rad = da2/2 3 | 4 | m.yoke_height = ${model['yoke_height']*1e3} 5 | 6 | m.iron_h1 = ${model['iron_h1']*1e3} 7 | m.iron_h2 = ${model['iron_h2']*1e3} 8 | m.iron_b = ${model['iron_b']*1e3} 9 | m.magn_width = ${model['magn_width']*1e3} 10 | m.magn_height = ${model['magn_height']*1e3} 11 | m.iron_bfe = ${model['iron_bfe']*1e3} 12 | m.iron_bfo = ${model['iron_bfo']*1e3} 13 | m.iron_shape = ${model['iron_shape']*1e3} 14 | m.iron_hp = ${model['iron_hp']*1e3} 15 | m.magn_num = ${model['magn_num']} 16 | 17 | m.nodedist = ${model.get('nodedist',0.0)} 18 | m.zeroangl = ${model.get('zeroangle',0)} 19 | 20 | m.mcvkey_yoke = mcvkey_yoke 21 | 22 | pre_models("Rotor_FC2") 23 | -------------------------------------------------------------------------------- /src/femagtools/templates/magnetSectorLinear.mako: -------------------------------------------------------------------------------- 1 | 2 | -- M-Sector-Lin 3 | 4 | m.l_corner_x0 = 0.0 5 | m.l_corner_y0 = 0.0 6 | m.magn_height = ${model['magn_height']*1e3} 7 | % if model.get('magn_width_pct'): 8 | m.magn_width = ${model['magn_width_pct']*1e2} 9 | % else: 10 | m.magn_width = -${model['magn_width']*1e3} 11 | % endif 12 | m.pole_width = ${model['pole_width']*1e3} 13 | m.yoke_heigth = ${model['yoke_height']*1e3} 14 | m.magn_len = ${model['magn_len']*100} 15 | m.magn_rem = m.remanenc 16 | m.gap_ma_yoke = ${model['gap_ma_yoke']*1e3} 17 | m.magn_ori = ${model['magn_ori']} 18 | m.airgap_shape = ${model['airgap_shape']*1e3} 19 | m.magn_type = ${model['magn_type']} 20 | 21 | m.zeroangl = ${model.get('zeroangle',0)} 22 | 23 | m.mcvkey_yoke = mcvkey_yoke 24 | 25 | pre_models("M-Sector-Lin"); 26 | -------------------------------------------------------------------------------- /src/femagtools/templates/magnetShell.mako: -------------------------------------------------------------------------------- 1 | 2 | 3 | m.magn_r1 = da1/2 -- Inner Radius Magnet R1 [mm] 4 | m.magn_r2 = dy1/2 - ${model.get('yoke_height')*1e3} -- Outer Radius Magnet R2 [mm] 5 | m.magn_r4 = ${model.get('magn_r4')*1e3} -- Eccentr. Radius Magnet R4 [mm] 6 | m.eccentr = ${model.get('eccentr')*1e3} -- Eccentricity E1 [mm] 7 | m.magn_r3 = ${model.get('eccentr')*1e3} -- Radius Magnet-end R3 [mm] 8 | m.magn_len = ${model.get('magn_len')*1e2} -- Magnet Length [%] 9 | m.magn_b1 = ${model.get('magn_b1')*1e3} -- Width Magnet outside B1 [mm] 10 | m.magn_h1 = ${model.get('magn_h1')*1e3} -- Height Magnet H1 [mm] 11 | m.magn_h2 = ${model.get('magn_h2')*1e3} -- Height Magnet H2 [mm] 12 | m.magn_rp = ${model.get('magn_rp')*1e3} -- Radius Housing Rp [mm] 13 | m.magn_a4 = ${model.get('magn_a4')} -- Angle of R4 A4 [Grad] 14 | m.magn_rem = 0.0 -- (ignored) Remanence Br [T] 15 | m.yoke_height = ${model.get('yoke_height')*1e3} -- Stator Housing height D [mm] 16 | m.magn_ori = ${model.get('magn_ori')} -- Orientation: par:1; Pol:2; cos:3 17 | --m.airgap = -1.0 -- Mesh height (2/3 airgap) [mm] 18 | 19 | m.mcvkey_yoke = mcvkey_yoke 20 | m.tot_num_sl = m.num_poles 21 | m.num_sl_gen = m.npols_gen 22 | 23 | m.zeroangl = ${model.get('zeroangl', 0)} 24 | 25 | pre_models("MAGNET_SHELL") 26 | -------------------------------------------------------------------------------- /src/femagtools/templates/modified_steinmetz.mako: -------------------------------------------------------------------------------- 1 | 2 | function pfe(Bx,By,kh,fnu,km,z,d) 3 | 4 | -- Bx flux density x component 5 | -- By flux density y component 6 | -- kh Hysterese Factor 7 | -- fnu frequency 8 | -- km material factor 9 | -- ph return for hysterese losses 10 | -- pw return for eddy current losses 11 | -- iret status 12 | 13 | -- Parameter 14 | 15 | basfrq=${model['base_frequency']} -- Base Frequency for ch and cw [Hz] 16 | basind=${model['base_induction']} -- Base Induction (Peak) [T] 17 | ch=${model['ch']} -- Fe Hysteresis Coefficient ch [W/kg] 18 | cw=${model['cw']} -- Fe Eddy Current Coefficient cw [W/kg] 19 | alpha=${model['alpha']} -- Hysteresis Frequency Coefficient Alpha 20 | beta=${model['beta']} -- Hysteresis Frequency Coefficient Beta 21 | spweight= ${model['special_weight']} -- Specific Weight Iron [gr/m3] 22 | fillfact=${model['fillfac']} -- Fillfactor Iron <= 1 23 | 24 | -- Modified Steinmetz Iron Loss Model 25 | -- pvfe = ch*hi*(b**(alpha + beta*b)) + cw*(hi**2)*(b**2) 26 | hxx = Bx/fillfact -- Bx 27 | hyy = By/fillfact -- By 28 | b21 = math.sqrt(hxx*hxx+hyy*hyy) 29 | 30 | b = b21/basind 31 | hi = fnu/basfrq 32 | coeff = alpha+beta*b 33 | ph = kh*spweight*km*ch*hi*(b^coeff) -- [W/m3] 34 | pw = spweight*km*cw*(b^2)*(hi^2) -- [W/m3] 35 | pe = 0.0 36 | 37 | iret=1 38 | return ph, pw, pe, iret 39 | end -------------------------------------------------------------------------------- /src/femagtools/templates/mult_cal_fast.mako: -------------------------------------------------------------------------------- 1 | -- 2 | -- Multi Calculation I/x 3 | -- 4 | m.move_action = 0 -- rotate 5 | % if 'lfe' in model: 6 | m.arm_length = ${model.get('lfe')*1e3} 7 | % endif 8 | m.skew_angle = ${model.get('skew_angle',0)} 9 | m.nu_skew_steps = ${model.get('num_skew_steps',0)} 10 | m.nu_force_pat = 0.0 11 | m.num_par_wdgs = ${model.get('num_par_wdgs',1)} 12 | m.current = ${model.get('current')}*math.sqrt(2.0)/m.num_par_wdgs 13 | m.angl_i_up = ${model.get('angl_i_up')} 14 | m.cur_control = 0 -- 0: range, 1: poc, 6 15 | m.max_current = 100.0 -- % 16 | m.num_cur_steps = ${model['num_cur_steps']} 17 | m.phi_start = ${model.get('phi_start', 0)} 18 | m.range_phi = ${model.get('range_phi', 0)} 19 | m.nu_move_steps = ${model.get('num_move_steps', 49)} 20 | m.speed = ${model.get('speed')*60} 21 | m.fc_mult_move_type = 1.0 -- Type of move path in air gap 22 | m.fc_force_points = 0.0 -- number move points in air gap 23 | m.loss_funct = ${model.get('loss_funct', 0)} -- loss functon 0: own 1: ext 24 | m.loss_fact = ${model.get('loss_fact', 1)} -- loss multiplication factor 25 | % if model.get('calc_fe_loss', 0): 26 | m.calc_fe_loss = ${model['calc_fe_loss']} 27 | % endif 28 | 29 | % if model.get('vtu_movie', 0): 30 | m.movie_type = 'vtu' 31 | % else: 32 | m.movie_type = nil 33 | % endif 34 | 35 | m.pocfilename = '${model.get('pocfilename', 'sin.poc')}' 36 | 37 | run_models("mult_cal_fast") 38 | -------------------------------------------------------------------------------- /src/femagtools/templates/new_model.mako: -------------------------------------------------------------------------------- 1 | 2 | exit_on_error=${model.get('exit_on_error', 'false')} 3 | exit_on_end=${model.get('exit_on_end', 'false')} 4 | verbosity=${model.get('verbosity', 1)} 5 | 6 | model = '${model.get('name')}' 7 | description = '${model.get('description','')}' 8 | % if model.get('scratch_mode', 0): 9 | new_model(model, '', 'scratch') 10 | % else: 11 | new_model_force(model, description) 12 | %endif 13 | -------------------------------------------------------------------------------- /src/femagtools/templates/open.mako: -------------------------------------------------------------------------------- 1 | exit_on_error=${model.get('exit_on_error', 'false')} 2 | exit_on_end=${model.get('exit_on_end')} 3 | verbosity=${model.get('verbosity', 1)} 4 | 5 | model = '${model.get(['name'])}' 6 | load_model(model) 7 | 8 | m.num_poles = get_dev_data("num_poles") 9 | m.num_pol_pair = m.num_poles/2 10 | m.npols_gen = get_mod_data("num_poles") 11 | m.arm_length = get_dev_data("arm_length") 12 | -------------------------------------------------------------------------------- /src/femagtools/templates/plots.mako: -------------------------------------------------------------------------------- 1 | % for p in model.get('plots', []): 2 | % if not isinstance(p, str): 3 | % if p[0] == 'field_lines': 4 | % if len(p) < 2: 5 | field_lines('field.svg', 20) 6 | % else: 7 | field_lines('field.svg', ${p[1]}) 8 | % endif 9 | % else: 10 | % if len(p) < 3: 11 | color_gradation( 0,0, 'tot', '${p[0]}', 0, 0, '${p[0]}'..'.svg') 12 | % elif len(p) < 4: 13 | color_gradation( 0,0, 'tot', '${p[0]}', ${p[1]}, ${p[2]}, '${p[0]}'..'.svg') 14 | % else: 15 | color_gradation( 0,0, 'tot', '${p[0]}', ${p[1]}, ${p[2]}, '${p[3]}') 16 | % endif 17 | % endif 18 | % else: 19 | % if p == 'field_lines': 20 | field_lines('field.svg', 20) 21 | % else: 22 | color_gradation( 0,0, 'tot', '${p}', 0, 0, '${p}'..'.svg') 23 | % endif 24 | % endif 25 | % endfor 26 | -------------------------------------------------------------------------------- /src/femagtools/templates/pm_sym_f_cur.mako: -------------------------------------------------------------------------------- 1 | -- 2 | -- SM Simulation with excitation current 3 | -- 4 | m.wdcon = ${model.get('wdgcon', 0)} -- Connection: 0=open, 1=star, 2=delta 5 | m.move_action = ${model.get('move_action', 0)} 6 | m.speed = ${model.get('speed')*60} 7 | m.skew_angle = ${model.get('skew_angle',0)} 8 | m.nu_skew_steps = ${model.get('num_skew_steps',0)} 9 | m.eval_force = ${model.get('eval_force', 0)} 10 | m.num_par_wdgs = ${model.get('num_par_wdgs',1)} 11 | m.current = ${model.get('current')}*math.sqrt(2.0)/m.num_par_wdgs 12 | m.angl_i_up = ${model.get('angl_i_up', 0)} 13 | 14 | m.optim_i_up = ${model.get('optim_i_up', 0)} 15 | m.nu_move_steps = ${model.get('num_move_steps', 49)} 16 | m.range_phi = ${model.get('range_phi', 0)} 17 | m.phi_start = ${model.get('phi_start', 0)} 18 | m.pm_eff_aktiv = 0 -- Generate additional output (>=1) 19 | m.fc_mult_move_type = 1 -- Type of move path in air gap (1=circ) 20 | m.calc_noload = ${model.get('calc_noload', 1)} 21 | m.period_frac = ${model.get('period_frac', 1)} 22 | m.pocfilename = '${model.get('pocfilename', 'sin.poc')}' 23 | % if model.get('vtu_movie', 0): 24 | m.movie_type = 'vtu' 25 | %endif 26 | % if model.get('calc_fe_loss'): 27 | m.calc_fe_loss = ${'%d' % model['calc_fe_loss']} 28 | % endif 29 | % if model.get('loss_funct',0): 30 | m.loss_funct = ${model.get('loss_funct')} 31 | % endif 32 | -- Excitation current 33 | m.nloa_ex_cur = ${model.get('noload_ex_cur', 0)} -- No Load Exciting current 34 | m.load_ex_cur = ${model.get('load_ex_cur', 0)} -- Load Exciting current 35 | m.wdgkeyex = 0 -- automatic winding selection 36 | 37 | run_models("pm_sym_f_cur") 38 | -------------------------------------------------------------------------------- /src/femagtools/templates/pm_sym_loss.mako: -------------------------------------------------------------------------------- 1 | -- 2 | -- PM/Rel Losses 3 | -- 4 | m.move_action = 0.0 -- rotate 5 | % if 'lfe' in model: 6 | m.arm_length = ${model.get('lfe')*1e3} 7 | % endif 8 | m.speed = 1000. 9 | m.skew_angle = ${model.get('skew_angle',0)} 10 | m.nu_skew_steps = ${model.get('num_skew_steps',0)} 11 | m.magn_temp = ${model.get('magn_temp')} 12 | m.fc_mult_move_type = 1.0 -- Type of move path in air gap 13 | m.fc_force_points = 0.0 -- number move points in air gap 14 | m.phi_start = ${model.get('phi_start', 0)} 15 | m.range_phi = ${model.get('range_phi', 0)} 16 | m.nu_move_steps = ${model.get('num_move_steps', 49)} 17 | m.num_par_wdgs = ${model.get('num_par_wdgs',1)} 18 | 19 | m.winding_temp = ${model.get('wind_temp')} 20 | m.current = 1.0 21 | m.ntibfilename = model..'.ntib' 22 | m.period_frac = ${model.get('period_frac', 1)} 23 | % if model.get('calc_fe_loss', 0): 24 | m.calc_fe_loss = ${model['calc_fe_loss']} 25 | % endif 26 | % if model.get('loss_funct',0): 27 | m.loss_funct = ${model.get('loss_funct')} 28 | % endif 29 | 30 | m.pocfilename = '${model.get('pocfilename', 'sin.poc')}' 31 | 32 | run_models("pm_sym_loss") 33 | -------------------------------------------------------------------------------- /src/femagtools/templates/psd_psq_fast.mako: -------------------------------------------------------------------------------- 1 | -- 2 | -- Psid-Psiq- Identification 3 | -- 4 | % if model.get('magn_temp',0): 5 | set_dev_data("magn_temp", ${model.get('magn_temp')}) 6 | %endif 7 | 8 | m.move_action = 0.0 -- rotate 9 | m.speed = ${model.get('speed')*60} 10 | m.skew_angle = ${model.get('skew_angle',0)} 11 | m.nu_skew_steps = ${model.get('num_skew_steps',0)} 12 | m.fc_mult_move_type = 1.0 -- Type of move path in air gap 13 | m.phi_start = ${model.get('phi_start', 0)} 14 | m.range_phi = ${model.get('range_phi', 0)} 15 | m.nu_move_steps = ${model.get('num_move_steps', 49)} 16 | m.num_par_wdgs = ${model.get('num_par_wdgs',1)} 17 | 18 | m.maxid = ${model['maxid']}/m.num_par_wdgs 19 | m.minid = ${model['minid']}/m.num_par_wdgs 20 | m.maxiq = ${model['maxiq']}/m.num_par_wdgs 21 | m.miniq = ${model['miniq']}/m.num_par_wdgs 22 | m.delta_id = ${model['delta_id']}/m.num_par_wdgs 23 | m.delta_iq = ${model['delta_iq']}/m.num_par_wdgs 24 | % if model.get('load_ex_cur',0): 25 | m.load_ex_cur = ${model['load_ex_cur']} 26 | %endif 27 | % if model.get('calc_fe_loss', 0): 28 | m.calc_fe_loss = ${model['calc_fe_loss']} 29 | % endif 30 | % if model.get('loss_funct',0): 31 | m.loss_funct = ${model.get('loss_funct')} 32 | % endif 33 | m.pm_eff_aktiv = 0.0 34 | m.calc_noload = ${model.get('calc_noload', 1)} 35 | m.period_frac = ${model.get('period_frac', 1)} 36 | m.pocfilename = '${model.get('pocfilename', 'sin.poc')}' 37 | run_models("psd_psq_fast") 38 | -------------------------------------------------------------------------------- /src/femagtools/templates/ring.mako: -------------------------------------------------------------------------------- 1 | --[[ 2 | Ring rotor (either laminated or pure air) 3 | --]] 4 | 5 | x1, y1 = pd2c(da2/2, m.zeroangl) 6 | x2, y2 = pd2c(dy2/2, m.zeroangl) 7 | x3, y3 = pd2c(dy2/2, m.zeroangl + 360/m.num_poles) 8 | x4, y4 = pd2c(da2/2, m.zeroangl + 360/m.num_poles) 9 | ndt(2*agndst) 10 | nc_circle(x1, y1, x4, y4, 0) 11 | ndt(8*agndst) 12 | nc_line(x1, y1, x2, y2, 0) 13 | nc_circle(x2, y2, x3, y3, 0) 14 | nc_line(x3, y3, x4, y4,0) 15 | xm, ym = pd2c((dy2+da2)/4, 90/m.num_poles) 16 | create_mesh_se(xm, ym) 17 | if mcvkey_yoke ~= 'dummy' then 18 | def_mat_fm_nlin(xm, ym, 'blue', m.mcvkey_yoke, 100) 19 | else 20 | def_mat_air(xm, ym) 21 | end 22 | if(m.npols_gen>1) then 23 | rotate_copy_nodechains(x2, y2, x1, y1, x4, y4, x3, y3, m.npols_gen-1) 24 | end 25 | -------------------------------------------------------------------------------- /src/femagtools/templates/rot_hsm.mako: -------------------------------------------------------------------------------- 1 | m.inside_diam = dy2 2 | m.rotor_diam = da2+2*ag 3 | 4 | m.gap_pol_shaft = ${model['gap_pol_shaft']*1e3} 5 | m.core_height = ${model['core_height']*1e3} 6 | m.pole_height = ${model['pole_height']*1e3} 7 | m.pole_rad = ${model['pole_rad']*1e3} 8 | m.core_width2 = ${model['core_width2']*1e3} 9 | m.core_width1 = ${model['core_width1']*1e3} 10 | m.pole_width_r = ${model['pole_width_r']*1e3} 11 | m.pole_width = ${model['pole_width']*1e3} 12 | m.slot_width = ${model['slot_width']*1e3} 13 | m.slot_height = ${model['slot_height']*1e3} 14 | m.damper_diam = ${model['damper_diam']*1e3} 15 | m.damper_div = ${model['damper_div']*1e3} 16 | m.mcvkey_yoke = mcvkey_yoke 17 | 18 | m.zeroangl = ${model.get('zeroangle', 0)} 19 | m.tot_num_sl = m.num_poles 20 | m.num_sl_gen = m.npols_gen 21 | m.airgap = ag 22 | 23 | pre_models("ROT_HSM") 24 | 25 | -- Yoke material 26 | if mcvkey_yoke ~= 'dummy' then 27 | x, y = pd2c( m.inside_diam/2+1, 360/m.num_poles/2) 28 | rellen = 100 -- relative length in % 29 | def_mat_fm_nlin(x, y, "blue", mcvkey_yoke, rellen) 30 | end 31 | -------------------------------------------------------------------------------- /src/femagtools/templates/rotorKs2.mako: -------------------------------------------------------------------------------- 1 | 2 | Q1 = m.tot_num_sl 3 | Q2 = ${model['num_slots']} 4 | m.tot_num_sl = Q2 5 | % if model.get('num_slots_gen', 0): 6 | m.num_sl_gen = ${model['num_slots_gen']} 7 | % else: 8 | m.num_sl_gen = Q2 * m.npols_gen/m.num_poles 9 | % endif 10 | 11 | m.rotor_diam = da2 12 | m.inside_diam = dy2 13 | m.slot_angle = ${model.get('slot_angle')} -- Angle ALPHA [degr] 14 | m.slot_height = ${model.get('slot_height')*1e3} -- Total height H [mm] 15 | m.slot_topwidth = ${model.get('slot_topwidth')*1e3} -- Slot width top B [mm] 16 | m.slot_width = ${model.get('slot_width')*1e3} -- Slot width SW [mm] 17 | m.slot_h1 = ${model.get('slot_h1')*1e3} -- Distance H1 [mm] 18 | m.slot_h2 = ${model.get('slot_h2')*1e3} -- Distance H2 [mm] 19 | m.slot_r1 = ${model.get('slot_r1')*1e3} -- Radius R1 [mm] 20 | m.slot_r2 = ${model.get('slot_r2')*1e3} -- Radius R2 [mm] 21 | m.middle_line = ${model.get('middle_line')} -- Centerline: no: 0; vertic: 1; horiz:2 22 | 23 | m.zeroangl = ${model.get('zeroangl',0)} 24 | m.nodedist = ${model.get('nodedist',1)} 25 | 26 | m.mcvkey_yoke = mcvkey_yoke 27 | pre_models("ROTOR_KS2") 28 | 29 | dphi=1e-2 30 | if mcvkey_yoke ~= 'dummy' then 31 | m.rlength = ${model.get('rlength', 1)*100} 32 | x, y = pd2c(m.rotor_diam/2-m.slot_height/2,m.zeroangl+dphi) 33 | def_mat_fm_nlin(x, y, "blue", mcvkey_yoke, m.rlength) 34 | 35 | x, y = pd2c(m.inside_diam/2+(m.rotor_diam/2-m.inside_diam/2-m.slot_height)/2,m.zeroangl+dphi) 36 | def_mat_fm_nlin(x, y, "blue", mcvkey_yoke, m.rlength) 37 | end 38 | -- for winding gen 39 | if m.middle_line == 2 then 40 | taus = 2*math.pi/m.tot_num_slot 41 | r = da2/2 - m.slot_height/4 42 | m.xcoil_1, m.ycoil_1 = pr2c(r, taus/2) 43 | m.xcoil_2, m.ycoil_2 = pr2c(r-m.slot_height/2, taus/2) 44 | end 45 | 46 | -- set subregions 'Bar' 47 | r=da2/2 - m.slot_height/2 48 | phi=180/Q2+m.zeroangl 49 | x,y=pd2c(r,phi) 50 | delete_sreg(x, y) 51 | x,y=pd2c(r,phi-dphi) 52 | def_new_subreg( x,y, 'Bar', violet ) 53 | 54 | for i=2, m.num_sl_gen do 55 | phi=(2*i-1)*180/Q2 + m.zeroangl 56 | x,y = pd2c(r,phi) 57 | add_to_subreg( x, y ) 58 | end 59 | -------------------------------------------------------------------------------- /src/femagtools/templates/rotor_winding.mako: -------------------------------------------------------------------------------- 1 | -- Winding (ROT_HSM or dxf) 2 | m.num_wires = ${model['num_wires']} 3 | 4 | phi = math.pi/m.num_poles 5 | if m.xcoil_r == nil then -- ROT_HSM 6 | a = m.rotor_diam/2 - ag - m.pole_height - m.core_height/2 7 | b = ((m.core_width1 + m.core_width2)/4 + m.pole_width/2)/2 8 | r = math.sqrt(a^2 + b^2) 9 | alpha = math.atan2(b, a) 10 | else 11 | r,beta = c2pr(m.xcoil_r, m.ycoil_r) 12 | alpha = phi - beta 13 | end 14 | dir = {'wi', 'wo'} 15 | xcoil, ycoil = pr2c(r, phi - alpha) 16 | def_new_wdg(xcoil, ycoil, yellow, "Exc", m.num_wires, 10.0, dir[1]) 17 | xcoil, ycoil = pr2c(r, phi + alpha) 18 | add_to_wdg(xcoil, ycoil, wsamekey, dir[2], 'wser') 19 | for i = 2, m.npols_gen do 20 | n = (i+1) % 2 + 1 21 | phi = phi + 2*math.pi/m.num_poles 22 | xcoil, ycoil = pr2c(r, phi - alpha) 23 | add_to_wdg(xcoil, ycoil, wsamekey, dir[n], 'wser') 24 | xcoil, ycoil = pr2c(r, phi + alpha) 25 | n = i % 2 + 1 26 | add_to_wdg(xcoil, ycoil, wsamekey, dir[n], 'wser') 27 | end 28 | -------------------------------------------------------------------------------- /src/femagtools/templates/shortcircuit.mako: -------------------------------------------------------------------------------- 1 | -- Short Circuit 2 | m.re_winding = ${model.get('r1',0)} -- Resistance stator winding Ra [Ohm] 3 | m.l_daxis = ${model.get('ld',0)} -- Inductance Ld [H/mm] 4 | m.l_qaxis = ${model.get('lq',0)} -- Inductance Lq [H/mm] 5 | m.l_endwindg = ${model.get('l_endwinding',0)} -- Stator ewdg inductance Le [H] 6 | m.l_external = ${model.get('l_external',0)} -- Stator external inductance Lex [H] 7 | m.magn_flux = ${model.get('psim',0)} -- Magn. flux (RMS) = Up/omega [Vs/mm] 8 | m.arm_length = ${model.get('lfe',0)*1e3} -- Effect. armature length lm [mm] 9 | m.current = ${model.get('current',0)} -- Current (operat. limit) (RMS) [A] 10 | m.angl_i_up = ${model.get('angl_i_up',0)} -- Angle current vs. voltage Vp [Deg] 11 | m.speed = ${model.get('speed',0)*60} -- Speed [1/min] 12 | m.num_pol_pair = ${model.get('num_pol_pair',0)} -- Number of Pole pairs p (>= 1) 13 | m.typ = ${model.get('sc_type',3)} -- Type of sc : 3ph = 3 14 | m.initial = ${model.get('initial',2)} -- Initial conditions: noload:1; load:2 15 | m.simultime = ${model.get('simultime',0.1)} -- Simulation time [s] 16 | m.fc_radius = ${model.get('fc_radius',0)*1e3} -- Radius air-gap center (torq.) [mm] 17 | m.num_par_wdgs = ${model.get('num_par_wdgs',0)} -- Number of parallel Windings(>= 1) a 18 | m.allow_demagn = ${model.get('allow_demagn',0)} -- Allow Demagnetisation:= 1:yes;= 0:no 19 | m.sim_demagn = ${model.get('sim_demagn',0)} -- Simulate Demagnetisation:1:yes; 0:no 20 | 21 | m.pocfilename = '${model.get('pocfilename','sin.poc')}' 22 | 23 | run_models("shortcircuit") 24 | -------------------------------------------------------------------------------- /src/femagtools/templates/stator1.mako: -------------------------------------------------------------------------------- 1 | m.yoke_rad = dy1/2 2 | m.inside_rad = da1/2 3 | 4 | m.tip_rh2 = ${model['tip_rh2']*1e3} 5 | m.tip_rh1 = ${model['tip_rh1']*1e3} 6 | m.slot_rf1 = ${model['slot_rf1']*1e3} 7 | m.slot_rf2 = m.slot_rf1 8 | m.yoke_rad2 = m.yoke_rad 9 | m.slot_width = ${model['slot_width']*1e3} 10 | m.tooth_width = ${model['tooth_width']*1e3} 11 | m.zeroangl = ${model['zeroangle']} 12 | m.rlength = ${model['rlength']*100} 13 | 14 | m.mcvkey_yoke = mcvkey_yoke 15 | m.wdg_location = -1.0 -- stator (internal values) 16 | 17 | pre_models( "STATOR_1") 18 | 19 | if mcvkey_teeth ~= nil then 20 | x0, y0 = pr2c( (m.tip_rh1 + m.slot_rf1)/2, 2*math.pi/m.tot_num_slot + m.zeroangl/180*math.pi) 21 | def_mat_fm_nlin(x0, y0, "blue", mcvkey_teeth, m.rlength) 22 | end 23 | -------------------------------------------------------------------------------- /src/femagtools/templates/stator2.mako: -------------------------------------------------------------------------------- 1 | m.yoke_rad = dy1/2 2 | m.inside_rad = da1/2 3 | 4 | m.slot_t1 = ${model['slot_t1']*1e3} 5 | m.slot_t2 = ${model['slot_t2']*1e3} 6 | m.slot_t3 = ${model['slot_t3']*1e3} 7 | m.slot_depth = ${model['slot_depth']*1e3} 8 | m.slot_width = ${model['slot_width']*1e3} 9 | m.corner_width = ${model['corner_width']*1e3} 10 | m.num_layer = ${model['num_layers']} 11 | m.zeroangl = ${model['zeroangle']} 12 | m.rlength = ${model['rlength']*100} 13 | 14 | m.mcvkey_yoke = mcvkey_yoke 15 | m.wdg_location = -1.0 -- stator (internal values) 16 | 17 | pre_models( "STATOR_2") 18 | 19 | -------------------------------------------------------------------------------- /src/femagtools/templates/stator3Linear.mako: -------------------------------------------------------------------------------- 1 | 2 | 3 | m.cood_system = ${model.get('coord_system', 1)} -- 1: x/y or 2: r/z 4 | 5 | m.l_corner_x0 = 0.0 6 | m.l_corner_y0 = 0.0 7 | m.slot_height = ${model['slot_height']*1e3} 8 | m.slot_h1 = ${model['slot_h1']*1e3} 9 | m.slot_h2 = ${model['slot_h2']*1e3} 10 | m.tip_slot = ${model['tip_slot']*1e3} 11 | m.yoke_height = ${model['yoke_height']*1e3} 12 | m.slot_r1 = ${model['slot_r1']*1e3} 13 | m.slot_r2 = ${model['slot_r2']*1e3} 14 | m.width_bz = ${model['width_bz']*1e3} 15 | m.tooth_width = ${model['tooth_width']*1e3} 16 | m.slot_width = m.width_bz - m.tooth_width 17 | 18 | m.middle_line = ${model['middle_line']} 19 | m.zeroangl = 0.000 -- Reference angle to x-axis [grad] 20 | 21 | m.mcvkey_yoke = mcvkey_yoke 22 | 23 | pre_models("STATOR3_Linear"); 24 | -------------------------------------------------------------------------------- /src/femagtools/templates/stator4.mako: -------------------------------------------------------------------------------- 1 | m.yoke_diam = dy1 2 | m.inside_diam = da1 3 | if( m.el_order_ag == nil ) then 4 | m.el_order_ag = 1 -- El. order in air gap: lin=1: quadr=2 5 | end 6 | m.slot_height = ${model['slot_height']*1e3} 7 | m.slot_h1 = ${model['slot_h1']*1e3} 8 | m.slot_h2 = ${model['slot_h2']*1e3} 9 | m.slot_h3 = ${model['slot_h3']*1e3} 10 | m.slot_h4 = ${model['slot_h4']*1e3} 11 | m.slot_r1 = ${model['slot_r1']*1e3} 12 | m.slot_width = ${model['slot_width']*1e3} 13 | m.wedge_width1 = ${model['wedge_width1']*1e3} 14 | m.wedge_width2 = ${model['wedge_width2']*1e3} 15 | m.wedge_width3 = ${model['wedge_width3']*1e3} 16 | 17 | m.num_layer = ${model['num_layers']} 18 | m.zeroangl = ${model['zeroangle']} 19 | 20 | m.mcvkey_yoke = mcvkey_yoke 21 | m.wdg_location = -1.0 -- stator (internal values) 22 | 23 | pre_models( "STATOR_4") 24 | 25 | if mcvkey_teeth ~= nil then 26 | m.rlength = ${model.get('rlength', 1)*100} 27 | if da1 > da2 then 28 | r = (da1 + m.slot_height)/2 29 | else 30 | r = (da1 - m.slot_height)/2 31 | end 32 | x0, y0 = pr2c(r, 2*math.pi/m.tot_num_slot + m.zeroangl/180*math.pi) 33 | def_mat_fm_nlin(x0, y0, "blue", mcvkey_teeth, m.rlength) 34 | end 35 | -------------------------------------------------------------------------------- /src/femagtools/templates/statorBG.mako: -------------------------------------------------------------------------------- 1 | 2 | m.yoke_diam = dy1 3 | m.inside_diam = da1 4 | m.yoke_diam_ins = ${model['yoke_diam_ins']*1e3} 5 | m.slot_h1 = ${model['slot_h1']*1e3} 6 | m.slot_h3 = ${model['slot_h3']*1e3} 7 | m.slot_width = ${model['slot_width']*1e3} 8 | m.slot_r1 = ${model['slot_r1']*1e3} 9 | m.slot_r2 = ${model['slot_r2']*1e3} 10 | m.tooth_width = ${model['tooth_width']*1e3} 11 | m.middle_line = ${model['middle_line']} 12 | 13 | m.tip_rad = ${model['tip_rad']*1e3} 14 | m.slottooth = ${model['slottooth']*1e3} 15 | m.wdg_location = -1.0 -- stator (internal values) 16 | 17 | m.zeroangl = ${model['zeroangle']} 18 | 19 | m.rlength = ${model['rlength']*100} 20 | m.mcvkey_yoke = mcvkey_yoke 21 | 22 | pre_models("STATOR_BG") 23 | 24 | if mcvkey_teeth ~= nil then 25 | r = (da1 + m.yoke_diam_ins)/4 26 | x0, y0 = pr2c(r, 2*math.pi/m.tot_num_slot + m.zeroangl/180*math.pi) 27 | def_mat_fm_nlin(x0, y0, "blue", mcvkey_teeth, m.rlength) 28 | end 29 | -------------------------------------------------------------------------------- /src/femagtools/templates/stator_msh.mako: -------------------------------------------------------------------------------- 1 | 2 | 3 | read_msh("${model['name']}") 4 | x1, y1 = pd2c(dy1/2, 360/m.tot_num_slot/2) 5 | x2, y2 = pd2c(da1/2, 360/m.tot_num_slot/2) 6 | mirror_nodechains(x1, y1, x2, y2) 7 | 8 | x1, y1 = pd2c(da1/2, 0) 9 | x2, y2 = pd2c(dy1/2, 0) 10 | x3, y3 = pd2c(dy1/2, 360/m.tot_num_slot) 11 | x4, y4 = pd2c(da1/2, 360/m.tot_num_slot) 12 | rotate_copy_nodechains(x1, y1, x2, y2, x3, y3, x4, y4, m.num_sl_gen-1) 13 | 14 | -- airgap meshing 15 | 16 | x1, y1 = pd2c(da1/2, 0) 17 | x2, y2 = pd2c(da1/2 - ag/3, 0) 18 | x3, y3 = pd2c(da1/2 - ag/3, 360/m.tot_num_slot*m.num_sl_gen) 19 | x4, y4 = pd2c(da1/2, 360/m.tot_num_slot*m.num_sl_gen) 20 | 21 | nc_line(x1, y1, x2, y2, 2) 22 | nc_line(x3, y3, x4, y4, 2) 23 | nc_circle_m(x2, y2, x3, y3, 0, 0, num_agnodes+1) 24 | x1, y1 = pd2c(da1/2 - ag/6, 360/m.tot_num_slot*m.num_sl_gen/2) 25 | create_mesh_se(x1, y1) 26 | 27 | % for y in model['yoke']: 28 | x, y = ${model[y][0]*1e3}, ${model[y][1]*1e3} 29 | if( mcvkey_yoke ~= 'dummy' ) then 30 | def_mat_fm_nlin(x, y, "blue", mcvkey_yoke, 100) -- ${y} 31 | else 32 | def_mat_fm(x, y, "blue", 1000, 100) -- ${y} 33 | end 34 | % endfor 35 | % for t in model['teeth']: 36 | x, y = ${model[t][0]*1e3}, ${model[t][1]*1e3} 37 | if( mcvkey_yoke ~= 'dummy' ) then 38 | def_mat_fm_nlin(x, y, "blue", mcvkey_teeth, 100) -- ${t} 39 | else 40 | def_mat_fm_nlin(x, y, "blue", 1000, 100) -- ${t} 41 | end 42 | % endfor 43 | % for a in model['air']: 44 | x, y = ${model[a][0]*1e3}, ${model[a][1]*1e3} 45 | def_mat_air(x, y) -- ${a} 46 | % endfor 47 | % if 'wdg' in model: 48 | m.xcoil_1, m.ycoil_1 = ${model['wdg'][0]*1e3}, ${model['wdg'][1]*1e3} 49 | delete_sreg(m.xcoil_1, m.ycoil_1) 50 | 51 | r, phi = c2pd(m.xcoil_1, m.ycoil_1) 52 | for n = 1, m.num_sl_gen do 53 | s = tostring(n) 54 | x, y = pd2c( r, (n-1)*360/m.tot_num_slot + phi) 55 | def_new_sreg(x, y, s, 'white') 56 | x, y = pd2c(r, n*360/m.tot_num_slot - phi) 57 | add_to_sreg(x, y, s) 58 | end 59 | % else: 60 | m.xcoil_1, m.ycoil_1 = pd2c(da1/2 + (dy1-da1)/8, 360/m.tot_num_slot/2-0.1) 61 | create_mesh() 62 | % endif 63 | -------------------------------------------------------------------------------- /src/femagtools/templates/therm_static.mako: -------------------------------------------------------------------------------- 1 | -- EXPERIMENTAL 2 | -- Caution: this will likely be modified 3 | -- 4 | slots_gen = get_mod_data("num_slots") 5 | num_slots = get_dev_data("num_slots") 6 | state_of_problem("therm_static") 7 | 8 | beta = 360*slots_gen/num_slots 9 | m.zeroangl = 0 10 | 11 | heat_transfer_coefficient = ${model['heat_transfer_coefficient']} 12 | area_factor = 5 13 | 14 | % if 'inner_diam' in model and len(model['heat_transfer_coefficient'])>1: 15 | -- heat transfer inside 16 | dy2 = ${model['inner_diam']*1e3} 17 | x,y = pd2c(dy2/2-0.05, beta/2+m.zeroangl) 18 | % else: 19 | -- heat transfer outside 20 | dy1 = ${model['outer_diam']*1e3} 21 | x,y = pd2c(dy1/2+0.05, beta/2+m.zeroangl) 22 | def_heat_transfer(x,y,yellow,heat_transfer_coefficient, area_factor) 23 | %endif 24 | --------------------------------------------- 25 | -- import losses 26 | import_losses_from_femag_dc() 27 | -- overwrite magnet losses (IALH) 28 | %if not isinstance(model.get('magnet_loss_th', 0), list): 29 | printf('magnet losses from B2 Method') 30 | %else: 31 | printf('magnet losses from IAlH Method') 32 | %for i in model['magnet_loss_th']: 33 | elkeys = get_spel_data("elkeys", ${i[0]}) 34 | x, y = get_elem_data("xycp", elkeys[1]) 35 | def_losses ( x,y,'red', ${i[1]}) 36 | %endfor 37 | %endif 38 | 39 | color_gradation_th(0,0,tot,Losses,0,0, "losses.svg") 40 | 41 | --------------------------------------------- 42 | calc_therm_field() 43 | color_gradation_th(0,0,tot,Temp,0.0,0, "temp.svg") 44 | 45 | state_of_problem("mag_static") 46 | -------------------------------------------------------------------------------- /src/femagtools/utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def fft(pos, y, pmod=0): 4 | """calculate fft spectrum of y and return samples, 5 | values, amplitude and phase of base harmonic 6 | 7 | Arguments: 8 | pos: (list of floats) sample positions 9 | y: (list of floats) y values 10 | pmod: number of poles in model (ignored if 0) 11 | """ 12 | model_angle = pos[-1] - pos[0] 13 | if 360/model_angle < 1: 14 | ntiles=1 15 | else: 16 | ntiles = int(round(360/model_angle)) 17 | 18 | if pmod: 19 | negative_periodic = pmod % 2 20 | else: 21 | #negative_periodic = np.abs(y[0] - y[-1])/np.max(y) > 1 22 | # count zero crossings 23 | ypos = np.asarray(y)-np.mean(y) > 0 24 | nypos = ~ypos 25 | nzc = len(((ypos[:-1] & nypos[1:]) 26 | | (nypos[:-1] & ypos[1:])).nonzero()[0]) 27 | negative_periodic = nzc == 0 or nzc % 2 == 1 28 | 29 | if negative_periodic: 30 | yx = np.concatenate( 31 | [n*y[:-1] 32 | for n in [m % 2 or -1 33 | for m in range(1, ntiles+1)]]) 34 | else: 35 | yx = np.tile(y[:-1], ntiles) 36 | 37 | N = len(yx) 38 | # compute DFT from induction (eliminate DC offset) 39 | a0 = np.mean(yx) 40 | Y = np.fft.fft(yx-a0) 41 | 42 | # find the peak (amplitude of base harmonic) 43 | i = np.argmax(np.abs(Y[:N//2])) 44 | 45 | a = 2*np.abs(Y[i])/N 46 | freq = np.fft.fftfreq(N, d=360/N) 47 | nmax = min(18*ntiles, N//2) 48 | T0 = 0 49 | if abs(freq[i]) > 0: 50 | T0 = np.abs(1/freq[i]) 51 | npoles = 2*int(360/T0) 52 | nmax = min(9*npoles, N//2) 53 | 54 | alfa0 = np.angle(Y[i]) 55 | alfa = np.angle(Y[:nmax]) 56 | 57 | 58 | return {'a': a, 'a0': a0, 'T0': T0, 'alfa0': alfa0, 59 | 'alfa': alfa, 60 | 'nue': (2*np.abs(Y[:nmax])/N).tolist(), 61 | 'yi': yx.tolist()} 62 | -------------------------------------------------------------------------------- /src/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/__init__.py -------------------------------------------------------------------------------- /src/tests/data/AMELA: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "succeed" -------------------------------------------------------------------------------- /src/tests/data/AMELA.bat: -------------------------------------------------------------------------------- 1 | @echo succeed -------------------------------------------------------------------------------- /src/tests/data/FERRIT_20gC.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/FERRIT_20gC.MCV -------------------------------------------------------------------------------- /src/tests/data/M270-50A_1000Hz_L.jhb: -------------------------------------------------------------------------------- 1 | ./M270-50A_1000Hz_L.jhb 2 | 2 0.000 3 | 0.000 0.000 4 | 0.194 70.000 5 | 0.291 93.000 6 | 0.388 117.000 7 | 0.485 145.000 8 | 0.582 176.000 9 | 0.679 210.000 10 | 0.776 248.000 11 | 0.873 291.000 12 | 0.970 339.000 13 | 1.020 37124.230 14 | 1.070 75249.062 15 | 1.120 114310.867 16 | 1.170 153831.047 17 | -------------------------------------------------------------------------------- /src/tests/data/TKM270-50A-LOSS.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/TKM270-50A-LOSS.MCV -------------------------------------------------------------------------------- /src/tests/data/TKS-M400-65A.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/TKS-M400-65A.txt -------------------------------------------------------------------------------- /src/tests/data/TKS_NO_20.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/TKS_NO_20.MCV -------------------------------------------------------------------------------- /src/tests/data/V800-50A_aniso.MCV: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/V800-50A_aniso.MCV -------------------------------------------------------------------------------- /src/tests/data/aniso.jhb: -------------------------------------------------------------------------------- 1 | aniso.jhb 2 | 3 0.000 90.000 3 | 0.100 33.960 16.980 4 | 0.200 47.000 23.500 5 | 0.300 56.300 28.150 6 | 0.400 64.600 32.300 7 | 0.500 72.790 36.395 8 | 0.600 80.390 40.185 9 | 0.700 89.820 44.910 10 | 0.800 100.610 50.305 11 | 0.900 114.390 57.195 12 | 1.000 134.070 67.035 13 | 1.050 147.920 73.960 14 | 1.100 166.190 83.085 15 | 1.150 191.010 95.505 16 | 1.200 228.320 114.160 17 | 1.250 288.840 144.420 18 | 1.301 397.660 198.830 19 | 1.351 617.220 308.610 20 | 1.401 1043.110 521.555 21 | 1.452 1738.700 896.350 22 | 1.504 2768.920 1384.460 23 | 1.555 4098.940 2046.470 24 | 1.607 5683.790 2841.895 25 | 1.712 9891.200 4945.600 26 | 1.793 14187.790 7093.895 27 | 1.854 20000.000 10000.000 28 | 1.913 30000.000 15000.000 29 | 1.977 50000.000 25000.000 30 | 2.028 75000.000 37500.000 31 | 2.069 100000.000 50000.000 32 | 2.211 200000.000 100000.000 33 | 2.341 300000.000 150000.000 34 | 2.470 400000.000 200000.000 35 | 2.597 500000.000 250000.000 36 | 2.724 600000.000 300000.000 37 | 2.850 700000.000 350000.000 38 | 2.976 800000.000 400000.000 39 | 3.102 900000.000 450000.000 40 | 3.228 1000000.000 500000.000 41 | 4.485 2000000.000 1000000.000 42 | -------------------------------------------------------------------------------- /src/tests/data/cogging.BATCH: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/cogging.BATCH -------------------------------------------------------------------------------- /src/tests/data/convert/Designer.jplot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/convert/Designer.jplot -------------------------------------------------------------------------------- /src/tests/data/convert/quads.ISA7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/convert/quads.ISA7 -------------------------------------------------------------------------------- /src/tests/data/convert/quads.nas: -------------------------------------------------------------------------------- 1 | $ 2 | $ this is a comment 3 | $ 4 | BEGIN BULK 5 | GRID 1 0. 0. 0. 6 | GRID 2 1. 0. 0. 7 | $ also a comment 8 | GRID 3 1. .5 0. 9 | GRID 4 1. 1. 0. 10 | GRID 5 0. 1. 0. 11 | GRID 6 0. .5 0. 12 | CQUAD4 1 1 1 2 3 6 13 | CQUAD4 2 1 6 3 4 5 14 | ENDDATA 15 | $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 16 | $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 17 | -------------------------------------------------------------------------------- /src/tests/data/convert/superelements.nas: -------------------------------------------------------------------------------- 1 | $ 2 | $ this is a comment 3 | $ 4 | BEGIN BULK 5 | GRID 1 0. 0. 0. 6 | GRID 2 1. 0. 0. 7 | $ also a comment 8 | GRID 3 1. .5 0. 9 | GRID 4 1. 1. 0. 10 | GRID 5 0. 1. 0. 11 | GRID 6 0. .5 0. 12 | CTRIA3 1 2 3 4 6 13 | CTRIA3 1 1 4 5 6 14 | CQUAD4 2 2 1 2 3 6 15 | ENDDATA 16 | $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 17 | $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 18 | -------------------------------------------------------------------------------- /src/tests/data/convert/triangles.ISA7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/convert/triangles.ISA7 -------------------------------------------------------------------------------- /src/tests/data/convert/triangles.nas: -------------------------------------------------------------------------------- 1 | $ 2 | $ this is a comment 3 | $ 4 | BEGIN BULK 5 | GRID 1 0. 0. 0. 6 | GRID 2 1. 0. 0. 7 | $ also a comment 8 | GRID 3 1. 1. 0. 9 | GRID 4 0. 1. 0. 10 | CTRIA3 1 1 1 2 3 11 | CTRIA3 2 1 1 3 4 12 | ENDDATA 13 | $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 14 | $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ 15 | -------------------------------------------------------------------------------- /src/tests/data/dq.BATCH: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/dq.BATCH -------------------------------------------------------------------------------- /src/tests/data/ldlq.erg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/ldlq.erg -------------------------------------------------------------------------------- /src/tests/data/m270_35.vbf: -------------------------------------------------------------------------------- 1 | M235_35 2 | 50 1.5 3 | 7 19 4 | 50 100 200 400 500 1000 2000 5 | 0.10103 0.01859 0.04461 0.10782 0.2838 0.39409 1.16244 3.57408 6 | 0.20105 0.07684 0.17722 0.43127 1.13022 1.56273 4.45273 13.07317 7 | 0.30106 0.16358 0.37426 0.91707 2.4104 3.32623 9.37392 27.14519 8 | 0.40008 0.26768 0.62212 1.53547 4.04873 5.59287 15.76365 46.63288 9 | 0.50109 0.39037 0.91211 2.2716 6.00803 8.36762 23.62688 70.58197 10 | 0.60109 0.52917 1.24424 3.11803 8.32548 11.54513 33.63035 100.6593 11 | 0.70111 0.68284 1.61478 4.07599 10.9825 15.27785 45.09369 0 12 | 0.80013 0.85386 2.02498 5.14797 14.00635 19.56824 58.67124 0 13 | 0.90115 1.04347 2.48104 6.34264 17.45898 24.86492 74.72488 0 14 | 1.00118 1.25539 2.98914 7.70708 21.67625 30.61766 93.57929 0 15 | 1.10022 1.49457 3.56541 9.20166 26.22441 37.20815 115.6707 0 16 | 1.2013 1.77713 4.23834 10.96019 31.44426 44.76528 141.527 0 17 | 1.30049 2.12289 5.06866 13.09795 37.6766 53.71784 0 0 18 | 1.40116 2.50335 6.18773 16.00159 0 0 0 0 19 | 1.50311 2.89992 7.22253 18.82715 0 0 0 0 20 | 1.61841 3.35349 8.12348 0 0 0 0 0 21 | 1.71087 3.65588 0 0 0 0 0 0 22 | 1.81709 3.97809 0 0 0 0 0 0 23 | 1.92619 4.28171 0 0 0 0 0 0 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/tests/data/magnsec.AUX7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/magnsec.AUX7 -------------------------------------------------------------------------------- /src/tests/data/magnsec.ISA7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/magnsec.ISA7 -------------------------------------------------------------------------------- /src/tests/data/minimal.AUX7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/minimal.AUX7 -------------------------------------------------------------------------------- /src/tests/data/minimal.ISA7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/minimal.ISA7 -------------------------------------------------------------------------------- /src/tests/data/minimal.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/minimal.nc -------------------------------------------------------------------------------- /src/tests/data/parident/bar.dat: -------------------------------------------------------------------------------- 1 | 2 0.00011541 3.57991e-07 3.57872e-07 3.5619e-07 3.49832e-07 2 | 10 0.00011581 3.5777e-07 3.57651e-07 3.55972e-07 3.49623e-07 3 | 18 0.000116736 3.57258e-07 3.5714e-07 3.55466e-07 3.49142e-07 4 | 26 0.000118173 3.56464e-07 3.56347e-07 3.54683e-07 3.48396e-07 5 | 34 0.000120097 3.55403e-07 3.55289e-07 3.53636e-07 3.47398e-07 6 | 42 0.000122477 3.54095e-07 3.53982e-07 3.52345e-07 3.46165e-07 7 | 50 0.000125276 3.5256e-07 3.5245e-07 3.50831e-07 3.44719e-07 8 | 58 0.000128454 3.50824e-07 3.50718e-07 3.49117e-07 3.43081e-07 9 | 66 0.000131968 3.48914e-07 3.48811e-07 3.47231e-07 3.41276e-07 10 | 74 0.000135773 3.46856e-07 3.46756e-07 3.45198e-07 3.39329e-07 11 | 82 0.000139824 3.44677e-07 3.44582e-07 3.43045e-07 3.37264e-07 12 | 90 0.000144079 3.42403e-07 3.42313e-07 3.408e-07 3.35108e-07 13 | 98 0.000148497 3.4006e-07 3.39973e-07 3.38483e-07 3.32882e-07 14 | 106 0.00015304 3.37671e-07 3.37586e-07 3.36121e-07 3.30609e-07 15 | 114 0.000157674 3.35254e-07 3.35173e-07 3.33731e-07 3.28306e-07 16 | -------------------------------------------------------------------------------- /src/tests/data/pm_data.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/pm_data.nc -------------------------------------------------------------------------------- /src/tests/data/test.poc: -------------------------------------------------------------------------------- 1 | 3 2 | 1 3 | 2 4 | 3 5 | 0 6 | 120 7 | 240 8 | 360.00000 9 | sin 10 | 30.000000 11 | 3 12 | 13 | -------------------------------------------------------------------------------- /src/tests/data/test_disp_stat.ISA7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/test_disp_stat.ISA7 -------------------------------------------------------------------------------- /src/tests/data/test_disp_stat.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/test_disp_stat.nc -------------------------------------------------------------------------------- /src/tests/data/zzz_pm_model_ts.nc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/data/zzz_pm_model_ts.nc -------------------------------------------------------------------------------- /src/tests/engines/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/engines/__init__.py -------------------------------------------------------------------------------- /src/tests/engines/config.ini: -------------------------------------------------------------------------------- 1 | [amazon] 2 | iam_instance_profile = ecsInstanceRole 3 | key_name = test-key-pair-eucentral-1 4 | security_group_ids = sg-123456, 5 | server_location = eu-central-1 6 | instance_type = t2.small 7 | 8 | -------------------------------------------------------------------------------- /src/tests/engines/data/cloud_init.txt: -------------------------------------------------------------------------------- 1 | Test Cloud init 2 | {{ENV}} 3 | -------------------------------------------------------------------------------- /src/tests/engines/test_config.py: -------------------------------------------------------------------------------- 1 | import femagtools.config 2 | import os.path 3 | import platform 4 | 5 | 6 | def test_femag(): 7 | if platform.system() == "Windows": 8 | expected = "wfemagw64" 9 | else: 10 | expected = "xfemag64" 11 | 12 | try: 13 | msg = femagtools.config.get_executable() 14 | except Exception as e: 15 | msg = str(e) 16 | assert msg.find(expected) > -1 17 | 18 | 19 | def test_engine_config(): 20 | default_config = { 21 | 'ENGINE': 'amazon', 22 | 'INSTANCE_TYPE': 't2.micro'} 23 | config = femagtools.config.Config(default_config) 24 | ini_file = os.path.join(os.path.dirname(__file__), 'config.ini') 25 | config.from_ini_file(ini_file) 26 | assert config['KEY_NAME'] == 'test-key-pair-eucentral-1' 27 | -------------------------------------------------------------------------------- /src/tests/geom/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/geom/__init__.py -------------------------------------------------------------------------------- /src/tests/geom/test_functions.py: -------------------------------------------------------------------------------- 1 | import femagtools.dxfsl.geom as g 2 | import numpy as np 3 | import logging 4 | import pytest 5 | 6 | 7 | def test_alpha_points(): 8 | p1 = (3.0, 1.0) 9 | p2 = (4.0, 5.0) 10 | p3 = (1.0, 3.0) 11 | 12 | alfa1 = g.alpha_points(p1, p2, p3) 13 | alfa2 = g.alpha_points(p2, p3, p1) 14 | alfa3 = g.alpha_points(p3, p1, p2) 15 | 16 | alfa = alfa1 + alfa2 + alfa3 17 | assert(np.isclose(alfa, 2*np.pi)) 18 | 19 | 20 | def test_points_are_close(): 21 | rtol = 1e-05 22 | atol = 1e-08 23 | p1 = (3.14, 2.7666) 24 | p2 = (3.141592, 2.77) 25 | 26 | A = g.points_are_close(p1, p2, rtol, atol) 27 | B = g.points_are_close(p1, p2, rtol, 0.001) 28 | assert(A == B) 29 | 30 | A = g.points_are_close(p1, p2, 1e-01, atol) 31 | B = g.points_are_close(p1, p2, 1e-02, atol) 32 | assert(A == B) 33 | 34 | 35 | def test_same_angle(): 36 | assert(g.is_same_angle(3.14159266, np.pi)) 37 | assert(g.is_same_angle(3.14159266, -np.pi)) 38 | 39 | 40 | def test_misc(): 41 | assert(g.gcd(4, 5) == 1) 42 | assert(g.gcd(24, 6) == 6) 43 | assert(g.gcd(47, 23) == 1) 44 | assert(g.gcd(18, 3) == 3) 45 | assert(g.gcd(39, 13) == 13) 46 | 47 | 48 | if __name__ == "__main__": 49 | 50 | logging.basicConfig(level=logging.INFO, 51 | format='%(asctime)s %(message)s') 52 | 53 | test_alpha_points() 54 | test_points_are_close() 55 | test_same_angle() 56 | test_misc() 57 | -------------------------------------------------------------------------------- /src/tests/mcvwriter: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # dummy mcvwriter 4 | # 5 | cat > dummy.mc 6 | 7 | -------------------------------------------------------------------------------- /src/tests/moo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SEMAFORInformatik/femagtools/7023116e47c0718b9966c897481648830dfb5121/src/tests/moo/__init__.py -------------------------------------------------------------------------------- /src/tests/moo/test_problem.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | import unittest 4 | from femagtools import moo 5 | 6 | 7 | class ProblemTest(unittest.TestCase): 8 | def test_compare_fc(self): 9 | prob = moo.Problem(0, 0, 2) 10 | f1 = (0, 0) 11 | f2 = (1, 1) 12 | c1 = [] 13 | c2 = [] 14 | self.assertTrue(prob.compare_fc(f1, c1, f2, c2)) 15 | self.assertFalse(prob.compare_fc(f2, c2, f1, c1)) 16 | self.assertFalse(prob.compare_fc(f2, c2, f2, c2)) 17 | 18 | if __name__ == '__main__': 19 | unittest.main() 20 | -------------------------------------------------------------------------------- /src/tests/test_airgap_induction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | import femagtools.airgap as ag 4 | import numpy as np 5 | import os 6 | 7 | 8 | def test_airgap_induction(): 9 | testPath = os.path.join(os.path.split(__file__)[0], 'data') 10 | if len(testPath) == 0: 11 | testPath = os.path.join(os.path.abspath('.'), 'data') 12 | r = ag.read(os.path.join(testPath, 'bag.dat')) 13 | np.testing.assert_almost_equal(r['Bamp'], 1.26914, 3) 14 | assert r['npoles'] == 8 15 | harms = [nue for nue, amp in zip(r['nue'], 16 | r['B_nue']) if amp > 1e-2] 17 | 18 | assert harms == [4, 12, 20, 28, 36, 44, 52, 60, 68] 19 | 20 | def test_airgap_induction2(): 21 | testPath = os.path.join(os.path.split(__file__)[0], 'data') 22 | if len(testPath) == 0: 23 | testPath = os.path.join(os.path.abspath('.'), 'data') 24 | r = ag.read(os.path.join(testPath, 'bag2.dat')) 25 | np.testing.assert_almost_equal(r['Bamp'], 0.9272, 3) 26 | assert r['npoles'] == 32 27 | harms = [nue for nue, amp in zip(r['nue'], 28 | r['B_nue']) if amp > 1e-2] 29 | 30 | assert harms == [16, 48, 80, 112, 144, 176, 208, 272] 31 | -------------------------------------------------------------------------------- /src/tests/test_amela.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import json 3 | from femagtools import amela 4 | from pathlib import Path 5 | 6 | def read_output(): 7 | return (Path(__file__).parent/ "data/amela.out").read_text().split('\n')[0] 8 | 9 | def read_json(): 10 | return json.loads( 11 | (Path(__file__).parent/"data/pm_data/pm_data_se38.json").read_text()) 12 | 13 | def test_amela(): 14 | al = amela.Amela(workdir='src/tests/data', 15 | magnet_data=dict(name='pm_data')) 16 | loss = al() 17 | r = read_json() 18 | assert r['name'] == 'pm_data_se38' 19 | assert len(r['phi']) == 73 20 | assert read_output() == 'succeed' 21 | assert round(loss['pm_data_se38']['total_loss'], 3) == 0.881 22 | -------------------------------------------------------------------------------- /src/tests/test_asm.py: -------------------------------------------------------------------------------- 1 | import femagtools.asm 2 | import pathlib 3 | import pytest 4 | 5 | expected = {'version': '9.2.x-202-geff049a1', 6 | 'project': './LS4p.nc', 'filename': 'TEST_001', 'date': '2021-05-27T13:23', 7 | 'wdgconn': 'star', 8 | 'f1': [50.0, 50.0, 50.0], 'r1': 1.2, 'lfe': 160.0, 9 | 'rbarlen': 246.0, 'num_phases': 3, 'p': 2, 'p_gen': 1, 10 | 'num_par_wdgs': 1, 'mcfile': 'M330-50A', 11 | 'felosscoeff': 1.44, 'maxiters': 300, 12 | 'permchg': 0.0, 's': [0.0, 0.025, 0.05], 'T': [0.0, 48.8, 92.4], 13 | 'u1': [380.0, 380.0, 380.0], 14 | 'Tp2': [0.0, 45.5, 84.7], 'p2': [0.0, 179.0, 665.0], 'pfe1': [], 15 | 'i1': [8.52, 14.9, 25.3], 'p1': [0.0, 7230.0, 13600.0], 16 | 'cosphi': [0.0, 0.738, 0.818], 17 | 'pcu': [261.32544, 799.236, 2304.324], 18 | 'pltotal': [261.32544, 978.236, 2969.324], 19 | 'lh': 0.079515, 'ls1': 0.00245, 20 | 'ls2': 0.00925, 'r2': 0.406538, 'sk': 0.1135} 21 | 22 | 23 | def test_read_asm(): 24 | datadir = pathlib.Path(__file__).resolve().parent.joinpath('data') 25 | 26 | content = (datadir / 'test.ASM').read_text() 27 | r = femagtools.asm.read(content.split('\n')) 28 | assert r.keys() == expected.keys() 29 | for k in r.keys(): 30 | if isinstance(r[k], float) or isinstance(r[k], list): 31 | assert pytest.approx(r[k], rel=0.01) == expected[k] 32 | else: 33 | assert r[k] == expected[k] 34 | -------------------------------------------------------------------------------- /src/tests/test_conductor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | import femagtools.conductor 5 | 6 | condMat = [dict( 7 | name="Cu", 8 | spmaweight=8.96, 9 | elconduct=56e6, 10 | tempcoef=3.9e-3) 11 | ] 12 | 13 | 14 | def test_findById(): 15 | cond = femagtools.conductor.Conductor(condMat) 16 | result = cond.find('Cu') 17 | expected = condMat[0] 18 | assert result == expected 19 | -------------------------------------------------------------------------------- /src/tests/test_dxfsl.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | from femagtools.dxfsl.converter import convert 3 | 4 | def test_convert(): 5 | p = pathlib.Path(__file__).parent / 'data' / 'IPM-130-4.dxf' 6 | r = convert(str(p)) 7 | 8 | assert r['num_poles'] == 4 9 | assert r['tot_num_slot'] == 12 10 | totnumsl = [l for l in r['fsl'] if l.startswith('m.tot_num_slot')] 11 | assert len(totnumsl) == 1 12 | assert totnumsl[0].split()[-1] == '12' 13 | -------------------------------------------------------------------------------- /src/tests/test_effloss.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | import pytest 4 | import femagtools.machine.effloss 5 | 6 | 7 | @pytest.fixture 8 | def impars(): 9 | return {'p': 2, 'm': 3, 'f1ref': 50, 'u1ref': 230.94, 'rotor_mass': 12.19, 'kfric_b': 1, 10 | 'r1': 0.2, 'r2': 0.54459629551, 11 | 'lsigma1': 0.0009996977709180593, 'lsigma2': 0.006836872295316844, 12 | 'psiref': 0.728735006166921, 'wref': 314.1592653589793, 13 | 'fec': 64.10000000000001, 'fee': 0, 'fexp': 7.0, 14 | 'im': [2.043764851047857, 4.087529702095714, 6.1312945531435705, 15 | 8.175059404191428, 10.218824255239285], 16 | 'psi': [0.27117452078113785, 0.5286659550273167, 0.7135568973434478, 17 | 0.8133415467307101, 0.8671946085010127]} 18 | 19 | 20 | def test_imeffloss(impars): 21 | nmax = 8000/60 22 | T = 32.9 23 | u1 = 230 24 | temp = (120, 120) 25 | 26 | r = femagtools.machine.effloss.efficiency_losses_map( 27 | impars, u1, T, temp, nmax, npoints=(5, 4)) 28 | assert r['T'] == pytest.approx( 29 | [-32.9, -0.5, 0.4, 32.9, 30 | -16.7, -0.5, 0.4, 15.8, 31 | -10.8, -0.5, 0.4, 10.1, 32 | -8.0, -0.5, 0.4, 7.4, 33 | -6.4, -0.5, 0.4, 6.0], abs=1e-1) 34 | -------------------------------------------------------------------------------- /src/tests/test_erg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | import os 4 | import femagtools.erg 5 | import numpy as np 6 | 7 | 8 | def read_erg(filename): 9 | testPath = os.path.join(os.path.split(__file__)[0], 'data') 10 | if len(testPath) == 0: 11 | testPath = os.path.join(os.path.abspath('.'), 'data') 12 | r = femagtools.erg.read(os.path.join(testPath, filename)) 13 | return r 14 | 15 | 16 | def test_read_erg(): 17 | r = read_erg('ldlq.erg') 18 | assert len(r.keys()) == 14 19 | assert min(r['beta']) == -90.0 20 | assert max(r['beta']) == 0.0 21 | np.array(r['M_FE']).shape == (10, 10) 22 | 23 | -------------------------------------------------------------------------------- /src/tests/test_forcedens.py: -------------------------------------------------------------------------------- 1 | 2 | from femagtools import forcedens 3 | 4 | 5 | def test_plt_read(): 6 | filename = 'src/tests/data/PLT.0' 7 | fdens = forcedens.ForceDensity() 8 | fdens.read(filename) 9 | 10 | assert fdens.title == 'Load PM-Syn_motor airgap 1, No Skewing' 11 | assert len(fdens.positions) == 31 12 | assert sorted(fdens.positions[0].keys()) == ['B_N', 'B_T', 'FN', 'FT', 13 | 'Radius', 'X', 14 | 'column_units', 'position', 15 | 'unit'] 16 | -------------------------------------------------------------------------------- /src/tests/test_heat_source_network.py: -------------------------------------------------------------------------------- 1 | import femagtools.heat_source_network as hsn 2 | import pathlib 3 | import pytest 4 | 5 | 6 | @pytest.fixture 7 | def data_dir(): 8 | return pathlib.Path(__file__).with_name('data') 9 | 10 | 11 | def test_heat_source_network(data_dir): 12 | model = hsn.read(str(data_dir / 'temp_model.hsn')) 13 | assert [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13] == model.nodes 14 | names = model.get_node_names() 15 | assert ['StZa', 'outs', 'StJo', 'Slot', 16 | 'Shaf', 'Iron', 'PMag', 'PMag', 17 | 'W1 ', 'W2 ', 'W3 '] == names 18 | T = model.solve() 19 | # [130.22552926, 56.75737966, 116.12788806, 150.18881253, 20 | # 175.77455152, 175.77455152, 175.77526274, 175.77455152, 21 | # 126.04691063, 122.49609205, 125.27401647]) 22 | -------------------------------------------------------------------------------- /src/tests/test_hxy.py: -------------------------------------------------------------------------------- 1 | import femagtools.hxy 2 | import pathlib 3 | import pytest 4 | 5 | 6 | @pytest.fixture 7 | def data_dir(): 8 | return pathlib.Path(__file__).with_name('data') / 'hxy' 9 | 10 | 11 | def test_read(data_dir): 12 | num_magnets = 2 13 | magnets = femagtools.hxy.read(data_dir / 'PM270L8_011.hxy', 14 | num_magnets) 15 | assert len(magnets) == num_magnets 16 | assert set([len(m['e'][0]) for m in magnets]) == {169, 189} 17 | assert [m['pos'][0] for m in magnets] == [0.0, 0.0] 18 | assert sorted([m['havg'][0] for m in magnets]) == pytest.approx([156.3, 156.5], 0.1) 19 | assert sorted([m['hmax'][0] for m in magnets]) == pytest.approx([195.6, 304.4], 0.1) 20 | -------------------------------------------------------------------------------- /src/tests/test_im.py: -------------------------------------------------------------------------------- 1 | import femagtools.machine.im 2 | import pathlib 3 | import pytest 4 | import numpy as np 5 | 6 | 7 | @pytest.fixture 8 | def im(): 9 | impars = { 10 | "p": 2, "m": 3, "f1type": 50, "u1type": 230, "rotor_mass": 6, "kfric_b": 1, 11 | "r1": 0.2, "r2": 0.5389, "lsigma1": 2e-3, 12 | "lsigma2": 4.4e-3, "kh": 10, "zeta2": 1, 13 | "fec": 120, "fee": 0, "fexp": 7.0, 14 | "iml": 5.317456519935536, "ims": 3.425169199057511, "mexp": 8.75033417091787} 15 | return femagtools.machine.im.InductionMachine(impars) 16 | 17 | 18 | def test_im(im): 19 | u1 = 230 20 | f1 = 50 21 | s = 0.01 22 | torque = im.torqueu(2*np.pi*f1, u1, 2*np.pi*(1-s)*f1/im.p) 23 | assert pytest.approx(torque, rel=0.01) == 17.77 24 | -------------------------------------------------------------------------------- /src/tests/test_jhb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | import os 4 | import femagtools.jhb 5 | 6 | 7 | def test_read_jhb(): 8 | testPath = os.path.split(__file__)[0] 9 | if not testPath: 10 | testPath = '.' 11 | filename = "data/M270-50A_1000Hz_L.jhb" 12 | jhb = femagtools.jhb.Reader('{0}/{1}'.format(testPath, filename)) 13 | assert jhb['name'] == 'M270-50A_1000Hz_L' 14 | assert len(jhb['curve']) == 1 15 | assert len(jhb['curve'][0]['hi']) == 13 16 | assert jhb['curve'][0]['bi'][-1] == 1.17 17 | 18 | 19 | def test_read_jhb_aniso(): 20 | testPath = os.path.split(__file__)[0] 21 | if not testPath: 22 | testPath = '.' 23 | filename = "data/aniso.jhb" 24 | jhb = femagtools.jhb.Reader('{0}/{1}'.format(testPath, filename)) 25 | assert jhb['name'] == 'aniso' 26 | assert len(jhb['curve']) == 2 27 | assert len(jhb['curve'][0]['hi']) == 39 28 | assert jhb['curve'][0]['bi'][-1] == 4.485 29 | 30 | -------------------------------------------------------------------------------- /src/tests/test_job.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | import femagtools.job 4 | import tempfile 5 | import os 6 | 7 | 8 | def test_condor(): 9 | workdir = tempfile.mkdtemp() 10 | job = femagtools.job.CondorJob(workdir) 11 | task = job.add_task() 12 | task.add_file('femag.fsl', ['exit_on_end=True']) 13 | try: 14 | job.prepareDescription() 15 | 16 | with open(os.path.join(workdir, 'femag.submit')) as f: 17 | x = [l.strip().split('=') for l in f] 18 | 19 | len(x) == 12 20 | x[-1][0].split() == '1' 21 | 22 | d = {l[0].strip(): l[1].strip() for l in x if len(l) > 1} 23 | d['Universe'] == 'vanilla' 24 | except Exception as e: 25 | pass # no femag installed on ci server. 26 | 27 | 28 | def test_job(): 29 | workdir = tempfile.mkdtemp() 30 | job = femagtools.job.Job(workdir) 31 | task = job.add_task() 32 | task.add_file('femag.fsl', ['exit_on_end=True']) 33 | 34 | with open(os.path.join(workdir, '0/femag.fsl')) as f: 35 | x = [l.strip().split('=') for l in f] 36 | d = {k: v for k, v in x} 37 | d['exit_on_end'] == 'True' 38 | -------------------------------------------------------------------------------- /src/tests/test_magnet.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | import femagtools.magnet 5 | 6 | magMat = [dict( 7 | name="M395", 8 | remanenc=1) 9 | ] 10 | 11 | 12 | def test_findById(): 13 | mag = femagtools.magnet.Magnet(magMat) 14 | result = mag.find('M395') 15 | expected = magMat[0] 16 | assert result == expected 17 | -------------------------------------------------------------------------------- /src/tests/test_me.py: -------------------------------------------------------------------------------- 1 | from femagtools import me 2 | 3 | def test_me(): 4 | r = me.get_eigenvectors(['src/tests/data/Mode_001.txt'], []) 5 | assert r[2]['0']['eigenvecs'].shape[0] == 5796 6 | assert round(r[1][0], 2) == 52.07 7 | -------------------------------------------------------------------------------- /src/tests/test_parident.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import femagtools.machine 3 | from femagtools.job import Task 4 | import pathlib 5 | import pytest 6 | 7 | 8 | @pytest.fixture 9 | def data_dir(): 10 | return pathlib.Path(__file__).with_name('data') 11 | 12 | 13 | def test_ecsim_eval(data_dir): 14 | task = Task(id=1, directory=data_dir / 'parident') 15 | eval = femagtools.machine.im._eval_ecsim() 16 | r = eval(task) 17 | expected = {'r2': 0.00011541, 18 | 'ls2': 3.57991e-07, 19 | 'zeta2': 0.9891, 20 | 'pl2v': 0.913} 21 | assert expected['r2'] == r['r2'] 22 | assert expected['ls2'] == r['ls2'] 23 | assert expected['zeta2'] == round(r['zeta2'], 4) 24 | assert expected['pl2v'] == round(r['pl2v'], 3) 25 | 26 | 27 | def test_noloadrot_eval(data_dir): 28 | task = Task(id=1, directory=data_dir / 'parident') 29 | i1tab = [2.0384197650236815, 4.076839530047363, 30 | 6.115259295071045, 8.153679060094726, 10.192098825118407] 31 | u1ph = 400/np.sqrt(3) 32 | pmod = 0 33 | eval = femagtools.machine.im._eval_noloadrot(pmod) 34 | r = eval(task) 35 | i0 = [2.0384, 4.0768, 6.1153, 8.1537, 10.1921] 36 | psi1_0 = [0.2725, 0.5301, 0.7106, 0.8091, 0.8641] 37 | #Bamp = [0.3091, 0.6013, 0.8058, 0.9159, 0.9768] 38 | Bamp = [0.3001, 0.5836, 0.7809, 0.8866, 0.9453] 39 | assert i0 == [round(x, 4) for x in r['i1_0']] 40 | assert psi1_0 == [round(x, 4) for x in np.mean(r['psi1_0'], axis=1)] 41 | assert Bamp == [round(x, 4) for x in np.mean(r['Bamp'], axis=1)] 42 | -------------------------------------------------------------------------------- /src/tests/test_sizing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | import pytest 4 | import femagtools.machine.sizing 5 | 6 | 7 | def test_im(): 8 | P = 1.5e3 9 | fs = 12e3 10 | lda = 0.9 11 | p = 4 12 | f1 = 100 13 | n = f1/p 14 | udc = 550 15 | r = femagtools.machine.sizing.im(P, n, p, udc=udc, 16 | sigmas=fs, Ba=0.77, 17 | cos_phi=0.8, eta=0.8, 18 | lda=0.9, rtype='statorRotor3') 19 | assert round(r['outer_diam'], 3) == 0.182 20 | assert r['stator']['num_slots'] == 36 21 | 22 | 23 | def test_spm(): 24 | P = 1.5e3 25 | fs = 12e3 26 | lda = 0.9 27 | p = 4 28 | f1 = 100 29 | n = f1/p 30 | udc = 550 31 | 32 | r = femagtools.machine.sizing.spm(P, n, p, udc=udc, 33 | Hc=700, sigmas=fs, brem=1.1, Ba=0.77, 34 | cos_phi=0.7, eta=0.8, demag=6.8, 35 | lda=0.9) 36 | assert round(r['outer_diam'], 3) == 0.181 37 | assert r['stator']['num_slots'] == 24 38 | 39 | 40 | def test_eesm(): 41 | P = 10e3 42 | speed = 4440/60 43 | p = 4 44 | udc = 600 45 | r = femagtools.machine.sizing.eesm(P, speed, p, udc=udc, Q1=36) 46 | assert r['rotor']['rot_hsm'] 47 | -------------------------------------------------------------------------------- /src/tests/test_tksreader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | import os 4 | import femagtools.tks 5 | 6 | 7 | def test_read_tks(): 8 | testPath = os.path.split(__file__)[0] 9 | if not testPath: 10 | testPath = '.' 11 | filename = "data/TKS-M400-65A.txt" 12 | tks = femagtools.tks.Reader('{0}/{1}'.format(testPath, filename)) 13 | assert tks['name'] == 'TKS-M400-65A' 14 | assert len(tks['losses']['f']) == 4 15 | assert len(tks['losses']['B']) == 13 16 | assert len(tks['losses']['pfe']) == 4 17 | assert len(tks['losses']['pfe'][0]) == 13 18 | assert tks['losses']['f'] == [50.0, 100.0, 200.0, 400.0] 19 | assert round(tks['losses']['B'][-1], 1) == 1.8 20 | # 13.1279112, 17.92205587, 23.79869172, 30.84129721, 39.3434623, 48.97389844, 60.25629981, 72.88007909 21 | assert len([x for x in tks['losses']['pfe'][3] if x]) == 8 22 | -------------------------------------------------------------------------------- /src/tests/test_ts.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | from femagtools import ts 3 | 4 | 5 | @pytest.fixture 6 | def losses(): 7 | dirname = 'src/tests/data/zzz_pm_model_ts_results_1' 8 | modelname = 'src/tests/data/zzz_pm_model_ts' 9 | return ts.Losses(modelname, dirname) 10 | 11 | 12 | def test_read(losses): 13 | e = losses.ohm_lossenergy(0.0, 0.0) 14 | assert len(e) == 6 15 | assert {'key': 1, 'name': 'stfe', 'losses': 0.0} == e[0] 16 | assert {'key': 2, 'name': 'rofe', 'losses': 0.0} == e[1] 17 | assert {'key': 3, 'name': 'wefe', 'losses': 0.0} == e[2] 18 | assert pytest.approx( 19 | {'key': 4, 'name': '', 'losses': 0.001913}, abs=1e-5) == e[3] 20 | assert pytest.approx( 21 | {'key': 5, 'name': '', 'losses': 0.001967}, abs=1e-5) == e[4] 22 | assert pytest.approx( 23 | {'key': 6, 'name': '', 'losses': 0.001886}, abs=1e-5) == e[5] 24 | p = losses.ohm_powerlosses() 25 | assert len(p) == 6 26 | assert {'key': 1, 'name': 'stfe', 'losses': 0.0} == p[0] 27 | assert {'key': 2, 'name': 'rofe', 'losses': 0.0} == p[1] 28 | assert {'key': 3, 'name': 'wefe', 'losses': 0.0} == p[2] 29 | assert pytest.approx( 30 | {'key': 4, 'name': '', 'losses': 0.09809}, abs=1e-5) == p[3] 31 | assert pytest.approx( 32 | {'key': 5, 'name': '', 'losses': 0.10102}, abs=1e-5) == p[4] 33 | assert pytest.approx( 34 | {'key': 6, 'name': '', 'losses': 0.09673}, abs=1e-5) == p[5] 35 | p = losses.ohm_powerlosses_fft() 36 | assert len(p) == 6 37 | assert {'key': 1, 'name': 'stfe', 'losses': 0.0} == p[0] 38 | assert {'key': 2, 'name': 'rofe', 'losses': 0.0} == p[1] 39 | assert {'key': 3, 'name': 'wefe', 'losses': 0.0} == p[2] 40 | assert pytest.approx( 41 | {'key': 4, 'name': '', 'losses': 0.101086}, abs=1e-5) == p[3] 42 | assert pytest.approx( 43 | {'key': 5, 'name': '', 'losses': 0.101086}, abs=1e-5) == p[4] 44 | assert pytest.approx( 45 | {'key': 6, 'name': '', 'losses': 0.101086}, abs=1e-5) == p[5] 46 | -------------------------------------------------------------------------------- /src/tests/test_vbfreader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | import unittest 4 | import os 5 | import femagtools.vbf 6 | 7 | 8 | class VbfReaderTest(unittest.TestCase): 9 | def test_read_vbf(self): 10 | testPath = os.path.split(__file__)[0] 11 | if not testPath: 12 | testPath = '.' 13 | 14 | filename = "data/m270_35.vbf" 15 | vbf = femagtools.vbf.Reader('{0}/{1}'.format(testPath, filename)) 16 | r = vbf.getLossValues() 17 | self.assertEqual(r['name'], 'M235_35') 18 | self.assertEqual(len(r['f']), 7) 19 | self.assertEqual(len(r['B']), 19) 20 | self.assertEqual(len(r['pfe']), 19) 21 | self.assertEqual(len(r['pfe'][0]), 7) 22 | self.assertAlmostEqual(r['f'][-1], 2000.0, 1) 23 | self.assertAlmostEqual(r['B'][-1], 1.926, 3) 24 | self.assertAlmostEqual(r['pfe'][3][-1], 46.633, 3) 25 | 26 | if __name__ == '__main__': 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /src/tests/test_vtu.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import pathlib 3 | from femagtools import vtu 4 | 5 | 6 | @pytest.fixture 7 | def ts_data_dir(): 8 | return pathlib.Path(__file__).with_name('data') / 'zzz_pm_model_ts_results_1/' 9 | 10 | @pytest.fixture 11 | def demag_data_dir(): 12 | return pathlib.Path(__file__).with_name('data') / 'demag-vtu/' 13 | 14 | 15 | def test_read(ts_data_dir): 16 | vtu_data = vtu.read(ts_data_dir / 'zzz_pm_model_ts_0000.vtu') 17 | assert vtu_data.field_data_names == [ 18 | 'time [s]', 'angle [rad]', 19 | 'speed [rad/s]', 'torque [Nm]', 20 | 'winding 1 current [A]', 'winding 1 voltage [V]', 21 | 'winding 2 current [A]', 'winding 2 voltage [V]', 22 | 'winding 3 current [A]', 'winding 3 voltage [V]', 'branch names'] 23 | assert vtu_data.point_data_names == ['vector potential'] 24 | assert vtu_data.cell_data_names == [ 25 | 'b', 'curd', 'demagnetization', 'current [A]', 'voltage [V]'] 26 | 27 | b = vtu_data.get_data_vector('b', 1) 28 | assert b[0] == pytest.approx([-0.003114], abs=1e-5) 29 | assert b[1] == pytest.approx([-0.00313], abs=1e-5) 30 | assert b[2] == [0.0] 31 | 32 | def test_demag(demag_data_dir): 33 | vtu_data = vtu.read(demag_data_dir / 'PM_130_L10_0000.vtu') 34 | keys = [7412, 7413, 7414, 7415, 7416] 35 | class Element: 36 | def __init__(self, key): 37 | self.key = key 38 | elements = [Element(k) for k in keys] 39 | expected = [241.5, 250.2, 262.3, 276.5, 390.5] 40 | actual = vtu_data.demag(elements) 41 | assert len(actual) == 1 42 | assert actual[0] == pytest.approx(expected, abs=0.1) 43 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (http://tox.testrun.org/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py27,py34,py35,py36 8 | 9 | [testenv] 10 | commands = py.test tests {posargs} 11 | deps = 12 | pytest 13 | femagtools 14 | matplotlib 15 | py27: mock 16 | 17 | [travis] 18 | python = 19 | 2.7: py27 20 | 3.4: py34 21 | 3.5: py35 22 | 3.6: py36 --------------------------------------------------------------------------------