femagtools 1.8.13__py3-none-any.whl → 1.8.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. femagtools/__init__.py +1 -1
  2. femagtools/bch.py +36 -9
  3. femagtools/femag.py +8 -1
  4. femagtools/fsl.py +31 -37
  5. femagtools/isa7.py +16 -0
  6. femagtools/job.py +9 -0
  7. femagtools/machine/__init__.py +7 -38
  8. femagtools/machine/afpm.py +12 -2
  9. femagtools/machine/effloss.py +7 -8
  10. femagtools/machine/im.py +57 -26
  11. femagtools/machine/pm.py +2 -1
  12. femagtools/machine/sizing.py +92 -7
  13. femagtools/machine/sm.py +5 -1
  14. femagtools/machine/utils.py +37 -14
  15. femagtools/multiproc.py +6 -0
  16. femagtools/parstudy.py +1 -1
  17. femagtools/plot/wdg.py +26 -5
  18. femagtools/templates/FE-losses.mako +0 -3
  19. femagtools/templates/ec-rotorbar.mako +1 -2
  20. femagtools/templates/ld_lq_fast.mako +1 -1
  21. femagtools/templates/mesh-airgap.mako +0 -1
  22. femagtools/templates/noloadflux-rot.mako +5 -32
  23. femagtools/templates/statorRing.mako +1 -1
  24. femagtools/utils.py +5 -1
  25. femagtools/windings.py +32 -14
  26. {femagtools-1.8.13.dist-info → femagtools-1.8.15.dist-info}/METADATA +31 -2
  27. {femagtools-1.8.13.dist-info → femagtools-1.8.15.dist-info}/RECORD +34 -35
  28. {femagtools-1.8.13.dist-info → femagtools-1.8.15.dist-info}/WHEEL +1 -1
  29. femagtools-1.8.15.dist-info/licenses/LICENSE +26 -0
  30. tests/test_femag.py +1 -1
  31. tests/test_fsl.py +5 -5
  32. tests/test_windings.py +11 -0
  33. femagtools/templates/rotor_winding_ks2.mako +0 -44
  34. femagtools/templates/rotor_winding_ks2_ecSimulation.mako +0 -44
  35. {femagtools-1.8.13.dist-info → femagtools-1.8.15.dist-info}/entry_points.txt +0 -0
  36. {femagtools-1.8.13.dist-info → femagtools-1.8.15.dist-info}/top_level.txt +0 -0
femagtools/machine/im.py CHANGED
@@ -119,7 +119,6 @@ class InductionMachine(Component):
119
119
  if 'u1type' in parameters:
120
120
  self.u1ref = self.u1type
121
121
  if hasattr(self, 'f1ref'):
122
- #self.wref = 2*np.pi*self.f1ref[0]
123
122
  self.wref = 2*np.pi*self.f1ref
124
123
  if hasattr(self, 'u1ref'):
125
124
  self.psiref = self.u1ref/self.wref
@@ -522,9 +521,10 @@ class InductionMachine(Component):
522
521
  wmrange = sorted([0, wmType, wmPullout, wmMax])
523
522
  elif wmMax < wmType:
524
523
  wmrange = sorted([0, wmMax])
524
+ elif wmType<0 or wmPullout<0 or wmMax<0:
525
+ wmrange = sorted([1, abs(min(wmMax,wmType, wmPullout)), abs(max(wmMax,wmType, wmPullout))])
525
526
  else:
526
527
  wmrange = sorted([0, wmType, wmMax])
527
-
528
528
  logger.info("Speed range %s", wmrange)
529
529
  wmlin = []
530
530
  dw = 0
@@ -604,6 +604,7 @@ class InductionMachine(Component):
604
604
  r['eta'] += (pmech[i:]/(p1[i:])).tolist()
605
605
  else:
606
606
  r['eta'] += (p1[i:]/pmech[i:]).tolist()
607
+
607
608
  return r
608
609
 
609
610
 
@@ -660,7 +661,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
660
661
  num_steps)]
661
662
  else:
662
663
  i1tab = np.linspace(i1min, i1max, num_steps).tolist()
663
-
664
+
664
665
  m = copy.deepcopy(machine)
665
666
  Q2 = m['rotor']['num_slots']
666
667
  noloadsim = dict(
@@ -668,7 +669,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
668
669
  curvec=i1tab,
669
670
  num_par_wdgs=machine[wdgk].get('num_par_wdgs', 1),
670
671
  Q2=Q2)
671
-
672
+
672
673
  da1 = m['bore_diam']
673
674
  ag = m['airgap']
674
675
  # do not create airgap nodechains automatically
@@ -679,11 +680,11 @@ def parident(workdir, engine, f1, u1, wdgcon,
679
680
  m[wdgk].pop('resistance')
680
681
  except KeyError:
681
682
  pass
682
-
683
+
683
684
  parstudy = femagtools.parstudy.ParameterStudy(
684
685
  workdir, condMat=condMat,
685
686
  magnetizingCurves=magnetizingCurves, cmd=cmd)
686
-
687
+
687
688
  builder = femagtools.fsl.Builder(kwargs.get('templatedirs', []))
688
689
  model = femagtools.model.MachineModel(m)
689
690
  # modelfiles = parstudy.setup_model(builder, model)
@@ -722,7 +723,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
722
723
  rotorbar['rotor'][k]['num_slots_gen'] = 1
723
724
  rotorbar['rotor'][k]['zeroangle'] = 90-180/Q2
724
725
  break
725
-
726
+
726
727
  loadsim = dict( # not used
727
728
  calculationMode="asyn_motor",
728
729
  bar_len=bar_len,
@@ -740,7 +741,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
740
741
  task = job.add_task(_eval_noloadrot(pmod), extra_result_files)
741
742
  logger.debug("Task %s noload workdir %s result files %s",
742
743
  task.id, task.directory, task.extra_result_files)
743
- # create model
744
+ # create model
744
745
  for mc in parstudy.femag.copy_magnetizing_curves(
745
746
  model,
746
747
  dir=task.directory):
@@ -754,11 +755,10 @@ def parident(workdir, engine, f1, u1, wdgcon,
754
755
 
755
756
  # ec simulation
756
757
  barmodel = femagtools.model.MachineModel(rotorbar)
757
- barmodel_new = barmodel
758
- barmodel_new['stator']['ecSimulation']=1
759
758
  extra_result_files = ['bar.dat']
760
759
  r = (da1-ag)/2
761
- task = job.add_task(_eval_ecsim())
760
+ #task = job.add_task(_eval_ecsim())
761
+ task = job.add_task(_eval_ecsim(), extra_result_files)
762
762
  logger.debug("Task %s rotobar workdir %s result files %s",
763
763
  task.id, task.directory, task.extra_result_files)
764
764
  task.set_stateofproblem('mag_dynamic')
@@ -769,7 +769,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
769
769
  task.add_file(mc)
770
770
  task.add_file(
771
771
  'femag.fsl',
772
- builder.create_model(barmodel_new,
772
+ builder.create_model(barmodel,
773
773
  condMat=parstudy.femag.condMat) +
774
774
  builder.create_analysis(ecsim) +
775
775
  ['save_model("close")'])
@@ -795,10 +795,9 @@ def parident(workdir, engine, f1, u1, wdgcon,
795
795
  logger.info('Started %s', status)
796
796
  status = engine.join()
797
797
  tend = time.time()
798
- logger.info("Elapsed time %d s Status %s",
798
+ logger.info("Elapssed time %d s Status %s",
799
799
  (tend-tstart), status)
800
800
  if any([x != 'C' for x in status]):
801
- logger.error("AC simulation failed with statuses: %s", status)
802
801
  raise ValueError("AC simulation failed")
803
802
  # collect results
804
803
  results = [t.get_results() for t in job.tasks]
@@ -821,16 +820,17 @@ def parident(workdir, engine, f1, u1, wdgcon,
821
820
  u1ref = u1ph
822
821
  psiref = u1ref/w1
823
822
 
824
- # def inoload(x, iml, ims, mexp):
825
- # """return noload current"""
826
- # return iml*x/psiref + ims*(x/psiref)**mexp
827
- # fitp, cov = so.curve_fit(inoload, psihtab, i10tab, (1, 1, 1))
828
- # iml, ims, mexp = fitp
829
- # logger.info("iml, ims, mexp %g, %g, %g",
830
- # iml, ims, mexp)
831
- # i1tab.insert(0, 0)
832
- # psi1_0.insert(0, 0)
833
- # i1_0.insert(0, 0)
823
+ # def inoload(x, iml, ims, mexp):
824
+ # """return noload current"""
825
+ # return iml*x/psiref + ims*(x/psiref)**mexp
826
+ # fitp, cov = so.curve_fit(inoload, psihtab, i10tab, (1, 1, 1))
827
+ # iml, ims, mexp = fitp
828
+ # logger.info("iml, ims, mexp %g, %g, %g",
829
+ # iml, ims, mexp)
830
+ # i1tab.insert(0, 0)
831
+ # psi1_0.insert(0, 0)
832
+ # i1_0.insert(0, 0)
833
+
834
834
  logger.info("psi1_0 %s", np.mean(psi1_0, axis=1))
835
835
  logger.info("psih %s", psih)
836
836
  logger.debug("psi1_0-psih %s", np.mean(psi1_0, axis=1)-psih)
@@ -851,7 +851,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
851
851
  hs = machine['stator'][slotmodel].get('slot_height',
852
852
  0.33*(machine['outer_diam']-da1))
853
853
  n = machine[wdgk]['num_wires']
854
- if 'dia_wire' in machine[wdgk]:
854
+ if 'dia_wire' in machine[wdgk] and machine[wdgk].get('dia_wire', 1e-3) !=0:
855
855
  aw = np.pi*machine[wdgk].get('dia_wire', 1e-3)**2/4
856
856
  else: # wire diameter from slot area
857
857
  aw = 0.75 * \
@@ -878,6 +878,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
878
878
  # kind='quadratic')(imref))
879
879
  psihref = float(log_interp1d(i1tab, psih)(imref))
880
880
  psi1ref = float(psi1(imref))
881
+
881
882
 
882
883
  lh = psihref/imref
883
884
  L1 = psi1ref/imref
@@ -908,8 +909,37 @@ def parident(workdir, engine, f1, u1, wdgcon,
908
909
  # r2 = results[1]['r2']
909
910
  # ls2 = results[1]['ls2']
910
911
  pfe = results[2]['pfe1'][0]
912
+
913
+ end_ring_section = machine['rotor']['Aring']
914
+ bore_diam = machine['bore_diam']
915
+ for key, value in machine['rotor'].items():
916
+ if isinstance(value, dict) and 'slot_height' in value:
917
+ slot_height_rotor = value['slot_height']
918
+ break
919
+ if slot_height_rotor is not None:
920
+ rayon = (bore_diam / 2) - slot_height_rotor/2
921
+ end_ring_length = 2 * np.pi * rayon
922
+ else:
923
+ end_ring_length = 0
924
+
925
+ end_ring_volume = end_ring_section*end_ring_length
926
+
927
+ for material_info in condMat:
928
+ if material_info.get('name') == machine.get('rotor', {}).get('material'):
929
+ spmaweight_rotor = material_info.get('spmaweight')
930
+ break
931
+ else:
932
+ spmaweight_rotor = 0
933
+ end_ring_mass = end_ring_volume * spmaweight_rotor*1e3
934
+
911
935
  rotor_mass = sum([results[2].get('conweight', 0),
912
936
  results[2].get('lamweight', 0)])
937
+ logger.info('Conductor mass in rotor = %s',results[2].get('conweight', 0))
938
+ logger.info('Lamination mass in rotor = %s',results[2].get('lamweight', 0))
939
+ logger.info('Rotor mass without end-ring = %s',rotor_mass)
940
+ rotor_mass += 2*end_ring_mass
941
+ logger.info('One end-ring mass = %s',end_ring_mass)
942
+ logger.info('Total rotor mass = %s',rotor_mass)
913
943
 
914
944
  n = machine[wdgk]['num_wires']
915
945
  g = loadsim['num_par_wdgs']
@@ -977,12 +1007,13 @@ class _eval_noloadrot():
977
1007
  i0 = np.linalg.norm(
978
1008
  femagtools.machine.T(0).dot(ire.T),
979
1009
  axis=0)/np.sqrt(2)
1010
+
980
1011
 
981
1012
  psi0 = np.array([np.linalg.norm(
982
1013
  femagtools.machine.T(0).dot(psire[:, k, :].T),
983
1014
  axis=0)/np.sqrt(2)
984
1015
  for k in range(ncurs)])
985
-
1016
+
986
1017
  # matrix (i x j x k) of curr, rotor pos, angle
987
1018
  Bamp = [[femagtools.airgap.fft(bags[:, 0], b, self.pmod)['Bamp']
988
1019
  for b in bags.T[1:]]
femagtools/machine/pm.py CHANGED
@@ -92,7 +92,8 @@ class PmRelMachine(object):
92
92
  self.io = (1, -1)
93
93
  self.fo = 50.0
94
94
  self.tcu1 = 20
95
- self.tmag = 20
95
+ # for information purpose only
96
+ self.tmag = kwargs.get('tmag', 20)
96
97
  self.zeta1 = 0.2
97
98
  self.gam = 0.7
98
99
  self.kh = 2
@@ -381,7 +381,7 @@ def get_stator_dimensions(par, slots=[]):
381
381
  Da2 = Da1-2*airgap
382
382
  r = dict(
383
383
  lfe=round(lfe, 3),
384
- Dy1=round(Dy1, 3),
384
+ Dy1=round(Dy1, 3),
385
385
  Da1=round(Da1, 4),
386
386
  Da2=round(Da2, 4),
387
387
  ans=round(ans, 6),
@@ -546,9 +546,10 @@ def get_interior_magnet_dimensions(I1, N, kw, psi1, lfe, Da2, par):
546
546
  iron_shape=Da2/2))
547
547
 
548
548
 
549
- def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='rotorKs2'):
549
+ def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='statorRotor3'):
550
550
  r = dict()
551
551
  r['Da2'] = Da2
552
+ r['rotorfilfact']=0.95
552
553
  if 'Q2' not in par:
553
554
  r['num_slots'] = _rotor_slots(par['Q1'], par['p'])[0]
554
555
  else:
@@ -568,15 +569,42 @@ def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='rotorKs2'):
568
569
  taup = np.pi * Da2/(2*par['p'])
569
570
  hyr = psi1/2/lfe*par['By']
570
571
  r['Dy2'] = round(Da2 - 2*hr - 2*hyr, 4)
571
- logger.info("Dy2 %f Da2 %f hys %f hr %f",
572
- r['Dy2']*1e3, Da2*1e3, hyr*1e3, hr*1e3)
573
572
  slotwidth = 1e-3
574
573
  Q2 = r['num_slots']
575
574
  r1 = wr/2-slotwidth
576
575
  r2 = (Da2/2-hr-hs1)*np.tan(alfar)
576
+
577
577
  logger.info("Dy2 %f Da2 %f hys %f hr %f",
578
578
  r['Dy2']*1e3, Da2*1e3, hyr*1e3, hr*1e3)
579
- if rtype == 'statorRotor3':
579
+
580
+ # End-ring calculation
581
+ Ir_total_estimated = A * np.pi * Da2 / (2 * par['p'])
582
+ Ibar_eff = Ir_total_estimated / r['num_slots']
583
+
584
+ if r['num_slots'] > 0:
585
+ sin_term = np.sin(np.pi / r['num_slots'])
586
+ if sin_term != 0:
587
+ Iring_max_eff = Ibar_eff / (2 * sin_term)
588
+ else:
589
+ Iring_max_eff = 0
590
+ else:
591
+ Iring_max_eff = 0
592
+ if 'Jring' not in par:
593
+ par['Jring'] = par.get('J', 4e6)
594
+
595
+ Jring = par['Jring']
596
+
597
+ if 'kfilling_ring' not in par:
598
+ par['kfilling_ring'] = 1.0
599
+
600
+ kfilling_ring = par['kfilling_ring']
601
+
602
+ if Jring * kfilling_ring > 0:
603
+ Aring = Iring_max_eff / (Jring * kfilling_ring)
604
+ else:
605
+ Aring = 0
606
+
607
+ """if rtype == 'statorRotor3':
580
608
  r['statorRotor3'] = dict(
581
609
  slot_width=slotwidth,
582
610
  tooth_width=round(wt, 4),
@@ -589,6 +617,18 @@ def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='rotorKs2'):
589
617
  wedge_width1=0,
590
618
  wedge_width2=0,
591
619
  middle_line=0)
620
+ r['statorRotor3'] = dict(
621
+ slot_width=1e-3,
622
+ tooth_width=0,
623
+ slot_height=0.0157,
624
+ slot_top_sh=0,
625
+ slot_h1=0.5e-3,
626
+ slot_h2=2.2e-3,
627
+ slot_r1=2.2e-3,
628
+ slot_r2=1e-3,
629
+ wedge_width1=1e-3,
630
+ wedge_width2=0,
631
+ middle_line=0)
592
632
  elif rtype == 'rotorAsyn':
593
633
  r['rotorAsyn'] = dict(
594
634
  slot_bs2=0.1e-3,
@@ -612,8 +652,52 @@ def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='rotorKs2'):
612
652
  slot_h2=0,
613
653
  slot_r1=1e-3, # r1,
614
654
  slot_r2=1e-3, # r2,
655
+ middle_line=0)"""
656
+
657
+ all_rotor_types = {}
658
+
659
+ all_rotor_types['statorRotor3'] = dict(
660
+ slot_width=slotwidth,
661
+ tooth_width=round(wt, 4),
662
+ slot_height=round(hr+r2, 4),
663
+ slot_top_sh=1.0,
664
+ slot_h1=round(hs1, 4),
665
+ slot_h2=round(hs1+r1, 4),
666
+ slot_r1=round(r1, 4),
667
+ slot_r2=round(r2),
668
+ wedge_width1=0,
669
+ wedge_width2=0,
615
670
  middle_line=0)
616
671
 
672
+ all_rotor_types['rotorAsyn'] = dict(
673
+ slot_bs2=0.1e-3,
674
+ slot_hs2=0.5e-3,
675
+ slot_b32=0.0,
676
+ slot_h32=0.0,
677
+ slot_b42=0.0,
678
+ slot_h42=0.0,
679
+ slot_b52=round(wr, 4),
680
+ slot_b62=3e-3,
681
+ slot_h52=2.5e-3,
682
+ slot_h62=round(hr, 4),
683
+ slot_h72=2e-3
684
+ )
685
+
686
+ all_rotor_types['rotorKs2'] = dict(
687
+ slot_angle=round(2 * alfar * 180 / np.pi, 2),
688
+ slot_height=round(hr + r1 + r2, 4),
689
+ slot_topwidth=round(wr, 4),
690
+ slot_width=slotwidth,
691
+ slot_h1=hs1,
692
+ slot_h2=0,
693
+ slot_r1=1e-3, # r1,
694
+ slot_r2=1e-3, # r2,
695
+ middle_line=0
696
+ )
697
+
698
+
699
+ r.update(all_rotor_types)
700
+ r['Aring'] = Aring
617
701
  return r
618
702
 
619
703
 
@@ -949,7 +1033,7 @@ def im(pnom: float, speed: float, p: int, **kwargs) -> dict:
949
1033
  slots = []
950
1034
  r = get_stator_dimensions(par, slots=slots)
951
1035
  # rotor parameters
952
- rtype = kwargs.get('rtype', 'rotorKs2')
1036
+ rtype = kwargs.get('rtype', 'statorRotor3')
953
1037
  r['rotor'] = get_im_rotor_dimensions(
954
1038
  par['cos_phi']*r['A'], r['Da2'], r['psi1'], r['lfe'],
955
1039
  par, rtype=rtype)
@@ -987,12 +1071,13 @@ def eesm(pnom: float, speed: float, p: int, **kwargs) -> dict:
987
1071
  r['name'] = f"EESM-{r['poles']}"
988
1072
  return r
989
1073
 
1074
+
990
1075
  if __name__ == "__main__":
991
1076
  # sizing example with SPM
992
1077
  pnom = 10e3 # shaft power in W
993
1078
  speed = 4400/60 # speed in 1/s
994
1079
  p = 4 # number of pole pairs
995
- udc = 600 # DC voltage in V
1080
+ udc = 600 # DC voltage in V
996
1081
 
997
1082
  r = spm(pnom, speed, p, udc=udc)
998
1083
 
femagtools/machine/sm.py CHANGED
@@ -7,7 +7,7 @@ import pathlib
7
7
  import numpy as np
8
8
  import scipy.optimize as so
9
9
  import scipy.interpolate as ip
10
- from .utils import skin_resistance, wdg_resistance, betai1, iqd, KTH, create_wdg
10
+ from .utils import skin_resistance, wdg_resistance, betai1, iqd, KTH, create_wdg, loss_models
11
11
  from .. import parstudy, windings
12
12
  import femagtools.bch
13
13
 
@@ -50,6 +50,7 @@ def parident(workdir, engine, machine,
50
50
  beta_max: maximal current angle (default 0°)
51
51
  num_move_steps: number of move steps
52
52
  cmd: femag command (default None, platform executable)
53
+ feloss: jordan, steinmetz, modified steinmetz, bertotti
53
54
  """
54
55
  cmd = kwargs.get('cmd', None)
55
56
 
@@ -125,6 +126,9 @@ def parident(workdir, engine, machine,
125
126
  period_frac=kwargs.get('period_frac', 6),
126
127
  speed=kwargs.get('speed', 50))
127
128
 
129
+ if kwargs.get("feloss", 0):
130
+ simulation["feloss"] = kwargs["feloss"]
131
+ machine["calc_fe_loss"] = loss_models[kwargs["feloss"].lower()]
128
132
  ###self.cleanup() # remove previously created files in workdir
129
133
  results = parvar(parvardef, machine, simulation, engine)
130
134
  b = results['f'][-1]
@@ -8,9 +8,16 @@ import numpy.linalg as la
8
8
  import scipy.interpolate as ip
9
9
  import logging
10
10
  from .. import parstudy, windings
11
+ from ..model import MachineModel
11
12
 
12
13
  logger = logging.getLogger(__name__)
13
14
 
15
+ loss_models = {
16
+ "modified steinmetz": 10,
17
+ "bertotti": 11,
18
+ "jordan": 1,
19
+ "steinmetz": 1
20
+ }
14
21
 
15
22
  def K(d):
16
23
  """space phasor transformation matrix
@@ -369,6 +376,7 @@ def dqparident(workdir, engine, temp, machine,
369
376
  period_frac: (int) fraction of rotating angle (default 6)
370
377
  dqtype: (str) type of identification: 'ldq' (default), 'psidq'
371
378
  cmd: femag executable
379
+ feloss: jordan, steinmetz, modified steinmetz, bertotti
372
380
  """
373
381
  import pathlib
374
382
 
@@ -390,21 +398,25 @@ def dqparident(workdir, engine, temp, machine,
390
398
  else:
391
399
  fcu = 0.42
392
400
 
393
- try: # calc basic dimensions if not fsl or dxf model
394
- from ..model import MachineModel
401
+ try:
395
402
  wdg = create_wdg(machine)
396
- Q1 = wdg.Q
397
- model = MachineModel(machine)
398
- Jmax = 30e6 # max current density in A/m2
399
- Acu = fcu*model.slot_area() # approx. copper area of one slot
400
- i1_max = round(g*Acu/wdg.l/N*Jmax/10)*10
401
403
  except KeyError:
402
- if kwargs.get('i1_max', 0) == 0:
403
- raise ValueError('i1_max missing')
404
+ pass
405
+ model = MachineModel(machine)
406
+ if kwargs.get('i1_max', 0):
404
407
  i1_max = kwargs['i1_max']
408
+ else:
409
+ try: # calc basic dimensions if not fsl or dxf model
410
+ Jmax = 30e6 # max current density in A/m2
411
+ Acu = fcu*model.slot_area() # approx. copper area of one slot
412
+ i1_max = round(g*Acu/wdg.l/N*Jmax/10)*10
413
+ except KeyError:
414
+ raise ValueError('i1_max missing')
405
415
 
406
416
  # winding resistance
407
417
  try:
418
+ da1 = machine['bore_diam']
419
+ hs = model.slot_height()
408
420
  if 'wire_gauge' in machine[wdgk]:
409
421
  aw = machine[wdgk]['wire_gauge']
410
422
  elif 'dia_wire' in machine[wdgk]:
@@ -412,10 +424,10 @@ def dqparident(workdir, engine, temp, machine,
412
424
  elif ('wire_width' in machine[wdgk]) and ('wire_height' in machine[wdgk]):
413
425
  aw = machine[wdgk]['wire_width']*machine[wdgk]['wire_height']
414
426
  else: # wire diameter from slot area
415
- da1 = machine['bore_diam']
427
+ Q1 = wdg.Q
416
428
  aw = 0.75 * fcu * np.pi*da1*hs/Q1/wdg.l/N
417
- r1 = wdg_resistance(wdg, N, g, aw, da1, hs, lfe)
418
- except (NameError, KeyError):
429
+ r1 = float(wdg_resistance(wdg, N, g, aw, da1, hs, lfe))
430
+ except (NameError, KeyError) as ex:
419
431
  r1 = 0 # cannot calc winding resistance
420
432
 
421
433
  n = len(temp)
@@ -483,6 +495,10 @@ def dqparident(workdir, engine, temp, machine,
483
495
  speed=kwargs.get('speed', defspeed),
484
496
  period_frac=period_frac)
485
497
 
498
+ if kwargs.get("feloss", 0):
499
+ simulation["feloss"] = kwargs["feloss"]
500
+ machine["calc_fe_loss"] = loss_models[kwargs["feloss"].lower()]
501
+
486
502
  # TODO: cleanup() # remove previously created files in workdir
487
503
  # start calculation
488
504
  results = parvar(parvardef, machine, simulation, engine)
@@ -490,7 +506,6 @@ def dqparident(workdir, engine, temp, machine,
490
506
  if 'poles' not in machine: # dxf model?
491
507
  machine['poles'] = 2*results['f'][0]['machine']['p']
492
508
  da1 = 2*results['f'][0]['machine']['fc_radius']
493
- wdg = create_wdg(machine)
494
509
  if 'bore_diam' in machine:
495
510
  da1 = machine['bore_diam']
496
511
  ls1 = 0
@@ -506,6 +521,14 @@ def dqparident(workdir, engine, temp, machine,
506
521
  except KeyError:
507
522
  rotor_mass = 0 # need femag classic > rel-9.3.x-48-gca42bbd0
508
523
 
524
+ if rotor_mass == 0:
525
+ try:
526
+ nc = parvar.femag.read_nc()
527
+ rotor_mass = float(sum(nc.get_mass()[1].values()))
528
+ logger.info("rotor mass from nc-file: %.1f kg", rotor_mass)
529
+ except StopIteration:
530
+ logger.warning("Could not read nc-file. Setting rotor_mass = 0!")
531
+
509
532
  dq = []
510
533
  if dqtype == 'ldq':
511
534
  for i in range(0, len(results['f']), 2):
@@ -585,7 +608,7 @@ def dqparident(workdir, engine, temp, machine,
585
608
  # diameter of wires
586
609
  aw = fcu*asl/Q1/nlayers/N
587
610
  hs = asl/(np.pi*da1/3)
588
- dqpars['r1'] = wdg_resistance(wdg, N, g, aw, da1, hs, lfe)
611
+ dqpars['r1'] = float(wdg_resistance(wdg, N, g, aw, da1, hs, lfe))
589
612
 
590
613
  if 'current_angles' in results['f'][0]:
591
614
  dqpars['current_angles'] = results['f'][0]['current_angles']
femagtools/multiproc.py CHANGED
@@ -235,6 +235,12 @@ class Engine:
235
235
  self.pool = None # garbage collector deletes threads
236
236
  return status
237
237
 
238
+ def read_nc(self):
239
+ """return a generator object of nc list"""
240
+ for t in self.job.tasks:
241
+ yield t.read_nc()
242
+ return None
243
+
238
244
  def stopThreads(self):
239
245
  """ stop all running treads
240
246
  """
femagtools/parstudy.py CHANGED
@@ -310,7 +310,7 @@ class ParameterStudy(object):
310
310
  set_magnet_properties(model, fea, self.femag.magnets)
311
311
  task.add_file(
312
312
  'femag.fsl',
313
- builder.create_model(model, self.femag.magnets) if not data_model_created else [] +
313
+ (builder.create_model(model, self.femag.magnets) if not data_model_created else []) +
314
314
  builder.create_analysis(fea) +
315
315
  ['save_model("close")'],
316
316
  append=data_model_created # model already created, append fsl
femagtools/plot/wdg.py CHANGED
@@ -7,6 +7,7 @@
7
7
  """
8
8
  import numpy as np
9
9
  import matplotlib.pyplot as plt
10
+ import logging
10
11
 
11
12
 
12
13
  def currdist(wdg, title='', k='all', phi=0, ax=0):
@@ -81,13 +82,13 @@ def mmf_fft(f, title='', mmfmin=1e-2, ax=0):
81
82
  pass
82
83
 
83
84
 
84
- def zoneplan(wdg, write_title=True, max_slots=0, ax=0):
85
+ def zoneplan(wdg, write_title=True, ax=0, max_slots=0):
85
86
  """plot zone plan of winding wdg"""
86
87
  from matplotlib.patches import Rectangle
87
88
  upper, lower = wdg.zoneplan()
88
89
  Qb = len([n for l in upper for n in l])
89
90
  if max_slots:
90
- Qb = max_slots
91
+ Qb = min(max_slots, Qb)
91
92
  from femagtools.windings import coil_color
92
93
  h = 0.5
93
94
  w = 1
@@ -171,7 +172,7 @@ def winding_factors(wdg, n=8, ax=0):
171
172
  pass
172
173
 
173
174
 
174
- def winding(wdg, ax=0):
175
+ def winding(wdg, ax=0, max_slots=0):
175
176
  """plot coils of windings wdg"""
176
177
  from matplotlib.patches import Rectangle
177
178
  from matplotlib.lines import Line2D
@@ -186,12 +187,16 @@ def winding(wdg, ax=0):
186
187
  if ax == 0:
187
188
  ax = plt.gca()
188
189
  z = wdg.zoneplan()
190
+ z0 = z[0] if len(z[0]) >= len(z[1]) else z[1]
191
+ Qb = sum([len(l) for l in z0])
192
+ if max_slots:
193
+ Qb = min(max_slots, Qb)
189
194
  xoff = 0
190
195
  if z[-1]:
191
196
  xoff = 0.75
192
197
  yd = dslot*wdg.yd
193
198
  mh = 2*coil_height/yd
194
- slots = sorted([abs(n) for m in z[0] for n in m])
199
+ slots = sorted([abs(n) for m in z[0] for n in m])[:Qb]
195
200
  smax = slots[-1]*dslot
196
201
  for n in slots: # draw slots and lamination
197
202
  x = n*dslot
@@ -204,6 +209,15 @@ def winding(wdg, ax=0):
204
209
  backgroundcolor="white",
205
210
  bbox=dict(boxstyle='circle,pad=0', fc="white", lw=0))
206
211
 
212
+ # colors in slots
213
+ csl = [['']*(Qb+1), ['']*(Qb+1)]
214
+ for i, layer in enumerate(z):
215
+ for m, mslots in enumerate(layer):
216
+ for k in mslots:
217
+ if abs(k) > Qb:
218
+ continue
219
+ csl[i][abs(k)-1] = coil_color[m]
220
+
207
221
  nl = 2 if z[1] else 1
208
222
  line_thickness = [0.6, 1.2]
209
223
  for i, layer in enumerate(z):
@@ -213,8 +227,9 @@ def winding(wdg, ax=0):
213
227
  d = 1
214
228
  for m, mslots in enumerate(layer):
215
229
  for k in mslots:
230
+ if abs(k) > Qb:
231
+ continue
216
232
  x = abs(k) * dslot + b
217
- kcoil = (abs(k)-1)//wdg.yd
218
233
  xpoints = []
219
234
  ypoints = []
220
235
  if nl == 2:
@@ -224,6 +239,12 @@ def winding(wdg, ax=0):
224
239
  d = 1 if i == 1 else 0
225
240
  else:
226
241
  d = 0 if k > 0 else 1
242
+ if abs(k) > 1:
243
+ if csl[0][abs(k)-2] == coil_color[m]:
244
+ d = 1
245
+ csl[0][abs(k)-1] = ''
246
+ else:
247
+ d = 0
227
248
 
228
249
  if direction[d] == 'right':
229
250
  # first layer, positive dir or neg. dir and 2-layers:
@@ -15,6 +15,3 @@ m.poison = ${model.get('poison', 0.3)}
15
15
  m.dampfact = ${model.get('dampfact', 0.0)}
16
16
  m.thcond = ${model.get('thcond', 30.0)}
17
17
  m.thcap = ${model.get('thcap', 480.0)}
18
-
19
- pre_models("FE-Losses-1")
20
- pre_models("FE-Losses-2")
@@ -6,8 +6,7 @@ muer = 1
6
6
  rel = 100
7
7
  cur = {1, 0}
8
8
  sigma1, sigma2 = get_dev_data( "cond_conduct" )
9
- --rotorbar = def_new_bar(xb,yb, "green", "U", cur[1],cur[2], "wi",
10
- rotorbar = def_new_bar(xcoil,ycoil, "green", "U", cur[1],cur[2], "wi", -- xcoil and ycoil defined in rotor_winding_ks2.mako
9
+ rotorbar = def_new_bar(xb,yb, "green", "U", cur[1],cur[2], "wi",
11
10
  sigma2, muer, rel, "polar", 0, 0)
12
11
  Abar = get_sreg_data("area",rotorbar)
13
12
 
@@ -38,4 +38,4 @@ m.load_ex_cur = ${model.get('load_ex_cur',0)}
38
38
  run_models("ld_lq_f_cur")
39
39
  %else:
40
40
  run_models("ld_lq_fast")
41
- %endif
41
+ %endif
@@ -19,7 +19,6 @@ if not airgap_created then
19
19
  end
20
20
  x1, y1 = pr2c(r1, alfa)
21
21
  n = math.floor(m.fc_radius*alfa/agndst + 1.5)
22
- n = n/10 -- Otherwise stacking mesh error TODO find a better formula
23
22
  nc_circle_m(r1, 0, x1, y1, 0.0, 0.0, n)
24
23
  if(m.npols_gen == m.num_poles) then
25
24
  nc_circle_m(x1, y1, r1, 0, 0.0, 0.0, n)