femagtools 1.8.12__py3-none-any.whl → 1.8.14__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.
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
@@ -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,13 +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)
577
- if rtype == 'statorRotor3':
576
+
577
+ logger.info("Dy2 %f Da2 %f hys %f hr %f",
578
+ r['Dy2']*1e3, Da2*1e3, hyr*1e3, hr*1e3)
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':
578
608
  r['statorRotor3'] = dict(
579
609
  slot_width=slotwidth,
580
610
  tooth_width=round(wt, 4),
@@ -587,6 +617,18 @@ def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='rotorKs2'):
587
617
  wedge_width1=0,
588
618
  wedge_width2=0,
589
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)
590
632
  elif rtype == 'rotorAsyn':
591
633
  r['rotorAsyn'] = dict(
592
634
  slot_bs2=0.1e-3,
@@ -610,8 +652,52 @@ def get_im_rotor_dimensions(A, Da2, psi1, lfe, par, rtype='rotorKs2'):
610
652
  slot_h2=0,
611
653
  slot_r1=1e-3, # r1,
612
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,
613
670
  middle_line=0)
614
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
615
701
  return r
616
702
 
617
703
 
@@ -947,7 +1033,7 @@ def im(pnom: float, speed: float, p: int, **kwargs) -> dict:
947
1033
  slots = []
948
1034
  r = get_stator_dimensions(par, slots=slots)
949
1035
  # rotor parameters
950
- rtype = kwargs.get('rtype', 'rotorKs2')
1036
+ rtype = kwargs.get('rtype', 'statorRotor3')
951
1037
  r['rotor'] = get_im_rotor_dimensions(
952
1038
  par['cos_phi']*r['A'], r['Da2'], r['psi1'], r['lfe'],
953
1039
  par, rtype=rtype)
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
 
@@ -42,14 +42,15 @@ def parident(workdir, engine, machine,
42
42
 
43
43
  optional arguments:
44
44
  num_cur_steps: number of current steps (default 5)
45
- num_beta_steps: number of current steps (default 13)
46
- num_exc_steps: number of excitation current (default 7)
45
+ num_beta_steps: number of beta steps (default 13)
46
+ num_exc_steps: number of excitation current (default 6)
47
47
  speed: rotor speed in 1/s (default 160/p)
48
48
  i1_max: maximum current in A rms (default approx 3*i1nom)
49
49
  beta_min: minimal current angle (default -180°)
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
 
@@ -79,9 +80,14 @@ def parident(workdir, engine, machine,
79
80
  exc_logspace = True
80
81
  ifmin, ifmax = ifnom/4, 1.4*ifnom
81
82
  if exc_logspace:
82
- excur = np.logspace(np.log(ifmin), np.log(ifmax),
83
+ """excur = np.logspace(np.log(ifmin), np.log(ifmax),
83
84
  kwargs.get("num_exc_steps", 6),
84
- base=np.exp(1)).tolist()
85
+ base=np.exp(1)).tolist()"""
86
+ # create a data grid always contains ifnom
87
+ excur = np.logspace(np.log(ifmin), np.log(ifnom),
88
+ kwargs.get("num_exc_steps", 6) - 2,
89
+ base=np.exp(1), endpoint=False).tolist()
90
+ excur.extend([ifnom, ifmax])
85
91
  else:
86
92
  excur = np.linspace(ifmin, ifmax,
87
93
  kwargs.get("num_exc_steps", 6))
@@ -120,6 +126,9 @@ def parident(workdir, engine, machine,
120
126
  period_frac=kwargs.get('period_frac', 6),
121
127
  speed=kwargs.get('speed', 50))
122
128
 
129
+ if kwargs.get("feloss", 0):
130
+ simulation["feloss"] = kwargs["feloss"]
131
+ machine["calc_fe_loss"] = loss_models[kwargs["feloss"].lower()]
123
132
  ###self.cleanup() # remove previously created files in workdir
124
133
  results = parvar(parvardef, machine, simulation, engine)
125
134
  b = results['f'][-1]
@@ -440,10 +449,6 @@ class SynchronousMachine(object):
440
449
 
441
450
  with warnings.catch_warnings():
442
451
  warnings.simplefilter("ignore")
443
- def sqrtculoss(iqde):
444
- pcu = self.culoss(iqde)
445
- return pcu
446
-
447
452
  res = so.minimize(
448
453
  self.culoss, startvals, method='SLSQP', # trust-constr
449
454
  bounds=self.bounds,
@@ -469,10 +474,6 @@ class SynchronousMachine(object):
469
474
 
470
475
  with warnings.catch_warnings():
471
476
  warnings.simplefilter("ignore")
472
- def sqrtculoss(iqde):
473
- pcu = self.culoss(iqde)
474
- #logger.info("iqde %s --> pcu %f", iqde, pcu)
475
- return pcu
476
477
  res = so.minimize(
477
478
  self.culoss, startvals, method='SLSQP', # trust-constr
478
479
  bounds=self.bounds,
@@ -513,42 +514,38 @@ class SynchronousMachine(object):
513
514
  with minimal losses at max voltage"""
514
515
  iqde = self.iqd_tmech(torque, w1/2/np.pi/self.p)
515
516
  if np.linalg.norm(
516
- self.uqd(w1, *iqde)) <= u1max*np.sqrt(2):
517
+ self.uqd(w1, *iqde)) <= u1max*np.sqrt(2):
517
518
  if log:
518
519
  log(iqde)
519
520
  return (*iqde, torque)
520
- #beta, i1 = betai1(iqde[0], iqde[1])
521
- #iex = iqde[2]
522
-
523
- #beta = 0 if torque>0 else np.pi
524
- io = iqde[0], 0, iqde[2] #*iqd(beta, i1), iex
521
+ beta, i1 = betai1(iqde[0], iqde[1])
522
+ iex = iqde[2]
523
+ def ubeta(b):
524
+ return np.sqrt(2)*u1max - np.linalg.norm(
525
+ self.uqd(w1, *iqd(b, i1), iex))
526
+ beta = -np.pi/4 if torque>0 else -3*np.pi/4
527
+ io = *iqd(beta, i1), iex
525
528
 
526
529
  # logger.debug("--- torque %g io %s", torque, io)
527
- with warnings.catch_warnings():
528
- warnings.simplefilter("ignore")
529
- n = w1/2/np.pi/self.p
530
- def sqrtculoss(iqde):
531
- pcu = self.culoss(iqde)
532
- #logger.info("iqde %s pcu %g", iqde, pcu)
533
- return pcu
534
-
535
- res = so.minimize(
536
- self.culoss, io, method='SLSQP', # trust-constr
537
- bounds=self.bounds,
538
- constraints=[
539
- {'type': 'eq',
540
- 'fun': lambda iqd: torque - self.tmech_iqd(*iqd, n)},
541
- {'type': 'eq',
542
- 'fun': lambda iqd: u1max*np.sqrt(2)
543
- - np.linalg.norm(self.uqd(w1, *iqd))}])
544
- #if res['success']:
545
- if log:
546
- log(res.x)
530
+ n = w1/2/np.pi/self.p
531
+ res = so.minimize(
532
+ self.culoss, io, method='SLSQP', # trust-constr
533
+ bounds=self.bounds,
534
+ constraints=[
535
+ {'type': 'eq',
536
+ 'fun': lambda iqd: self.tmech_iqd(*iqd, n) - torque},
537
+ {'type': 'eq',
538
+ 'fun': lambda iqd: np.linalg.norm(
539
+ self.uqd(w1, *iqd)) - u1max*np.sqrt(2)}])
540
+
541
+ if log:
542
+ log(res.x)
543
+ if res["success"]:
547
544
  return *res.x, self.tmech_iqd(*res.x, n)
548
- #logger.warning("%s: w1=%f torque=%f, u1max=%f, io=%s",
549
- # res['message'], w1, torque, u1max, io)
550
- #raise ValueError(res['message'])
551
- #return [float('nan')]*4
545
+
546
+ logger.warning("%s: w1=%f torque=%f, u1max=%f, io=%s",
547
+ res['message'], w1, torque, u1max, io)
548
+ raise ValueError(res['message'])
552
549
 
553
550
  def iqd_torque_umax(self, torque, w1, u1max,
554
551
  disp=False, maxiter=500, log=0, **kwargs):
@@ -559,33 +556,31 @@ class SynchronousMachine(object):
559
556
  if log:
560
557
  log(iqde)
561
558
  return (*iqde, torque)
562
- io = iqde[0], 0, iqde[2]
563
- # logger.debug("--- torque %g io %s", torque, io)
564
- with warnings.catch_warnings():
565
- warnings.simplefilter("ignore")
566
- def sqrtculoss(iqde):
567
- pcu = self.culoss(iqde)
568
- #logger.info("iqde %s pcu %g", iqde, pcu)
569
- return pcu
570
-
571
- res = so.minimize(
572
- self.culoss, io, method='SLSQP', # trust-constr
573
- bounds=self.bounds,
574
- #options={'disp': disp, 'maxiter': maxiter},
575
- # jac=gradient_respecting_bounds(self.bounds, self.culoss),
576
- constraints=[
577
- {'type': 'eq',
578
- 'fun': lambda iqd: self.torque_iqd(*iqd) - torque},
579
- {'type': 'eq',
580
- 'fun': lambda iqd: u1max*np.sqrt(2) - np.linalg.norm(
581
- self.uqd(w1, *iqd))}])
582
- #if res['success']:
583
- if log:
584
- log(res.x)
559
+ beta, i1 = betai1(iqde[0], iqde[1])
560
+ iex = iqde[2]
561
+ def ubeta(b):
562
+ return np.sqrt(2)*u1max - np.linalg.norm(
563
+ self.uqd(w1, *iqd(b, i1), iex))
564
+ beta = -np.pi/4 if torque>0 else -3*np.pi/4
565
+ io = *iqd(beta, i1), iex
566
+ res = so.minimize(
567
+ self.culoss, io, method='SLSQP', # trust-constr
568
+ bounds=self.bounds,
569
+ #options={'disp': disp, 'maxiter': maxiter},
570
+ # jac=gradient_respecting_bounds(self.bounds, self.culoss),
571
+ constraints=[
572
+ {'type': 'eq',
573
+ 'fun': lambda iqd: self.torque_iqd(*iqd) - torque},
574
+ {'type': 'eq',
575
+ 'fun': lambda iqd: u1max*np.sqrt(2) - np.linalg.norm(
576
+ self.uqd(w1, *iqd))}])
577
+ if log:
578
+ log(res.x)
579
+ if res['success']:
585
580
  return *res.x, self.torque_iqd(*res.x)
586
- #logger.warning("%s: w1=%f torque=%f, u1max=%f, io=%s",
587
- # res['message'], w1, torque, u1max, io)
588
- #raise ValueError(res['message'])
581
+ logger.warning("%s: w1=%f torque=%f, u1max=%f, io=%s",
582
+ res['message'], w1, torque, u1max, io)
583
+ raise ValueError(res['message'])
589
584
 
590
585
  def w1_imax_umax(self, i1max, u1max):
591
586
  """return frequency w1 and shaft torque at voltage u1max and current i1max
@@ -669,10 +664,12 @@ class SynchronousMachine(object):
669
664
 
670
665
  wmtab = []
671
666
  dw = 0
667
+ wmMax = 2*np.pi*n
668
+ '''
672
669
  wmMax = 5*wmType
673
670
  if n > 0:
674
671
  wmMax = min(wmMax, 2*np.pi*n)
675
-
672
+ '''
676
673
  if wmType > wmMax:
677
674
  wmrange = sorted([0, wmMax])
678
675
  wmtab = np.linspace(0, wmMax, nsamples).tolist()
@@ -793,6 +790,7 @@ class SynchronousMachinePsidq(SynchronousMachine):
793
790
  self.psiqf = ip.RegularGridInterpolator(
794
791
  (exc, iqx, idx), psiq,
795
792
  method='cubic', bounds_error=False, fill_value=None)
793
+ # excitation currents bounds should respect ifnom
796
794
  self.bounds = [(min(iq), max(iq)),
797
795
  (min(id), 0),
798
796
  (iexc[0], iexc[-1])]
@@ -909,6 +907,7 @@ class SynchronousMachineLdq(SynchronousMachine):
909
907
  method='cubic'
910
908
  , bounds_error=False, fill_value=None)
911
909
  i1max = np.sqrt(2)*(max(i1))
910
+ # excitation currents bounds should respect ifnom
912
911
  self.bounds = [(np.cos(min(beta))*i1max, i1max),
913
912
  (-i1max, 0),
914
913
  (iexc[0], iexc[-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
@@ -140,7 +140,8 @@ class ParameterStudy(object):
140
140
 
141
141
  def __call__(self, opt, machine, simulation,
142
142
  engine, bchMapper=None,
143
- extra_files=[], num_samples=0):
143
+ extra_files=[], num_samples=0,
144
+ data_model_created=False):
144
145
  """calculate objective vars for all decision vars
145
146
  Args:
146
147
  opt: variation parameter dict (decision_vars, objective_vars)
@@ -150,6 +151,8 @@ class ParameterStudy(object):
150
151
  bchMapper: bch result transformation function
151
152
  extra_files: list of additional input file names to be copied
152
153
  num_samples: number of samples (ingored with Grid sampling)
154
+ data_model_created: model and complete data structur
155
+ was already created before calling this function
153
156
  """
154
157
 
155
158
  self.stop = False # make sure the calculation will start. thomas.maier/OSWALD
@@ -174,7 +177,8 @@ class ParameterStudy(object):
174
177
  workdir = pathlib.Path(self.femag.workdir)
175
178
  for d in workdir.glob('[0-9]*'):
176
179
  if re.search(r'^\d+$', d.name):
177
- shutil.rmtree(d)
180
+ if not data_model_created:
181
+ shutil.rmtree(d)
178
182
 
179
183
  extra_result_files = []
180
184
  if simulation.get('airgap_induc', False):
@@ -198,8 +202,7 @@ class ParameterStudy(object):
198
202
 
199
203
  prob = femagtools.moproblem.FemagMoProblem(decision_vars,
200
204
  objective_vars)
201
-
202
- if immutable_model:
205
+ if not data_model_created and immutable_model:
203
206
  modelfiles = self.setup_model(builder, model, recsin=fea.recsin,
204
207
  feloss=simulation.get('feloss', ''))
205
208
  logger.info("Files %s", modelfiles+extra_files)
@@ -282,7 +285,7 @@ class ParameterStudy(object):
282
285
  task = job.add_task(self.result_func)
283
286
  for fn in extra_files:
284
287
  task.add_file(fn)
285
- if immutable_model:
288
+ if not data_model_created and immutable_model:
286
289
  prob.prepare(x, [fea, self.femag.magnets])
287
290
  for m in modelfiles:
288
291
  task.add_file(m)
@@ -297,18 +300,21 @@ class ParameterStudy(object):
297
300
  else:
298
301
  prob.prepare(x, [model, fea, self.femag.magnets])
299
302
  logger.info("prepare %s", x)
300
- for mc in self.femag.copy_magnetizing_curves(
301
- model,
302
- dir=task.directory,
303
- recsin=fea.recsin,
304
- feloss=feloss):
305
- task.add_file(mc)
306
- set_magnet_properties(model, fea, self.femag.magnets)
303
+ if not data_model_created:
304
+ for mc in self.femag.copy_magnetizing_curves(
305
+ model,
306
+ dir=task.directory,
307
+ recsin=fea.recsin,
308
+ feloss=feloss):
309
+ task.add_file(mc)
310
+ set_magnet_properties(model, fea, self.femag.magnets)
307
311
  task.add_file(
308
312
  'femag.fsl',
309
- builder.create_model(model, self.femag.magnets) +
313
+ (builder.create_model(model, self.femag.magnets) if not data_model_created else []) +
310
314
  builder.create_analysis(fea) +
311
- ['save_model("close")'])
315
+ ['save_model("close")'],
316
+ append=data_model_created # model already created, append fsl
317
+ )
312
318
 
313
319
  if hasattr(fea, 'poc'):
314
320
  task.add_file(fea.pocfilename,
femagtools/plot/bch.py CHANGED
@@ -559,7 +559,7 @@ def demagnetization(demag, ax=0):
559
559
  # arrowprops=dict(facecolor='green', edgecolor='green', shrink=0.05))
560
560
  ax.set_ylim([rrmin, 1.01])
561
561
  ax.set_ylabel('Rel. Remanence')
562
- ax.set_xlabel(f'Phase Current / {unit}')
562
+ ax.set_xlabel(f'Phase Current / {unit} (peak)')
563
563
  ax.grid()
564
564
 
565
565
 
@@ -112,12 +112,17 @@ def shortcircuit(femag, machine, bch, simulation, engine=0):
112
112
  for d in bchsc.demag if 'H_max' in d],
113
113
  'H_av': [d['H_av']
114
114
  for d in bchsc.demag if 'H_av' in d]}
115
- i1max = bchsc.scData['iks']
116
- if dd['displ']:
117
- phi = dd['displ'][0]/180*np.pi
115
+ x1 = bchsc.demag[0]['current_1']
116
+ x2 = bchsc.demag[0]['current_2']
117
+ def func(phi):
118
+ return x2*np.cos(phi) - x1*np.cos(phi-2*np.pi/3)
119
+ phi=so.fsolve(func, 0)[0]
120
+ i1max = x1/np.cos(phi)
121
+
122
+ phirot = dd['displ'][0]/180*np.pi
118
123
  bchsc.scData['demag'] = demag(
119
124
  femag, machine, simulation,
120
- i1max, phi, engine)
125
+ i1max, phirot, phi, engine)
121
126
  bchsc.scData['demag'].update(dd)
122
127
  scdata = bchsc.scData
123
128
  #for w in bch.flux:
@@ -310,7 +315,7 @@ def shortcircuit_2phase(femag, machine, simulation, engine=0):
310
315
 
311
316
  # rotor position at maximum current:
312
317
  trot = min(iav[0], iap[0])
313
- phi = wm*trot + phi0
318
+ phirot = wm*trot + phi0
314
319
  logger.info("phi %.1f")
315
320
 
316
321
  scData = {
@@ -330,10 +335,10 @@ def shortcircuit_2phase(femag, machine, simulation, engine=0):
330
335
  if simulation.get('sim_demagn', 0):
331
336
  i1max = iap[1] if iap[1] > abs(iav[1]) else iav[1]
332
337
  scData['demag'] = demag(femag, machine, simulation,
333
- i1max, phi, engine)
338
+ i1max, phirot, 0, engine)
334
339
  return scData
335
340
 
336
- def demag(femag, machine, simulation, i1max, phi, engine=0):
341
+ def demag(femag, machine, simulation, i1max, phirot, phi, engine=0):
337
342
  """demag simulation using psi-torq-rem-rot"""
338
343
  logger.info("Demagnetization processing")
339
344
  i1min = simulation.get('i1min', abs(i1max/3))
@@ -345,7 +350,8 @@ def demag(femag, machine, simulation, i1max, phi, engine=0):
345
350
  i1tab = b*(a+np.log(xtab))
346
351
 
347
352
  if simulation.get('sc_type', 3) == 3:
348
- curvec = [[-a/2, a, -a/2] for a in i1tab]
353
+ curvec = [[a*np.cos(phi), a*np.cos(phi-2*np.pi/3),
354
+ a*np.cos(phi+2*np.pi/3)] for a in i1tab]
349
355
  else:
350
356
  if i1max > 0:
351
357
  curvec = [[a, -a, 0] for a in i1tab]
@@ -353,7 +359,7 @@ def demag(femag, machine, simulation, i1max, phi, engine=0):
353
359
  curvec = [[-a, a, 0] for a in i1tab]
354
360
  simulation.update({
355
361
  'calculationMode': 'psi-torq-rem',
356
- 'phi': phi,
362
+ 'phi': phirot,
357
363
  'magntemp': simulation['Tmag'],
358
364
  'curvec': curvec})
359
365
  _ = femag(machine, simulation)
@@ -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")