femagtools 1.8.11__py3-none-any.whl → 1.8.13__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 (35) hide show
  1. femagtools/__init__.py +1 -1
  2. femagtools/bch.py +21 -12
  3. femagtools/ecloss.py +12 -4
  4. femagtools/femag.py +1 -2
  5. femagtools/fsl.py +28 -4
  6. femagtools/job.py +6 -3
  7. femagtools/machine/__init__.py +35 -3
  8. femagtools/machine/effloss.py +37 -13
  9. femagtools/machine/im.py +9 -6
  10. femagtools/machine/sizing.py +4 -3
  11. femagtools/machine/sm.py +64 -69
  12. femagtools/parstudy.py +28 -16
  13. femagtools/plot/bch.py +27 -11
  14. femagtools/shortcircuit.py +53 -49
  15. femagtools/templates/ec-rotorbar.mako +2 -1
  16. femagtools/templates/gen_hairpin_winding.mako +8 -6
  17. femagtools/templates/ld_lq_fast.mako +1 -1
  18. femagtools/templates/mesh-airgap.mako +1 -0
  19. femagtools/templates/noloadflux-rot.mako +32 -4
  20. femagtools/templates/psi-torq-rem.mako +112 -0
  21. femagtools/templates/psi-torq-rot.mako +7 -0
  22. femagtools/templates/rotor_winding_ks2.mako +44 -0
  23. femagtools/templates/rotor_winding_ks2_ecSimulation.mako +44 -0
  24. femagtools/templates/statorRing.mako +1 -1
  25. femagtools/ts.py +38 -7
  26. femagtools/zmq.py +4 -1
  27. {femagtools-1.8.11.dist-info → femagtools-1.8.13.dist-info}/METADATA +3 -31
  28. {femagtools-1.8.11.dist-info → femagtools-1.8.13.dist-info}/RECORD +34 -32
  29. {femagtools-1.8.11.dist-info → femagtools-1.8.13.dist-info}/WHEEL +1 -1
  30. tests/test_bchreader.py +5 -5
  31. tests/test_femag.py +1 -1
  32. tests/test_fsl.py +3 -3
  33. femagtools-1.8.11.dist-info/LICENSE +0 -26
  34. {femagtools-1.8.11.dist-info → femagtools-1.8.13.dist-info}/entry_points.txt +0 -0
  35. {femagtools-1.8.11.dist-info → femagtools-1.8.13.dist-info}/top_level.txt +0 -0
femagtools/machine/sm.py CHANGED
@@ -42,8 +42,8 @@ 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°)
@@ -79,9 +79,14 @@ def parident(workdir, engine, machine,
79
79
  exc_logspace = True
80
80
  ifmin, ifmax = ifnom/4, 1.4*ifnom
81
81
  if exc_logspace:
82
- excur = np.logspace(np.log(ifmin), np.log(ifmax),
82
+ """excur = np.logspace(np.log(ifmin), np.log(ifmax),
83
83
  kwargs.get("num_exc_steps", 6),
84
- base=np.exp(1)).tolist()
84
+ base=np.exp(1)).tolist()"""
85
+ # create a data grid always contains ifnom
86
+ excur = np.logspace(np.log(ifmin), np.log(ifnom),
87
+ kwargs.get("num_exc_steps", 6) - 2,
88
+ base=np.exp(1), endpoint=False).tolist()
89
+ excur.extend([ifnom, ifmax])
85
90
  else:
86
91
  excur = np.linspace(ifmin, ifmax,
87
92
  kwargs.get("num_exc_steps", 6))
@@ -440,10 +445,6 @@ class SynchronousMachine(object):
440
445
 
441
446
  with warnings.catch_warnings():
442
447
  warnings.simplefilter("ignore")
443
- def sqrtculoss(iqde):
444
- pcu = self.culoss(iqde)
445
- return pcu
446
-
447
448
  res = so.minimize(
448
449
  self.culoss, startvals, method='SLSQP', # trust-constr
449
450
  bounds=self.bounds,
@@ -469,10 +470,6 @@ class SynchronousMachine(object):
469
470
 
470
471
  with warnings.catch_warnings():
471
472
  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
473
  res = so.minimize(
477
474
  self.culoss, startvals, method='SLSQP', # trust-constr
478
475
  bounds=self.bounds,
@@ -513,42 +510,38 @@ class SynchronousMachine(object):
513
510
  with minimal losses at max voltage"""
514
511
  iqde = self.iqd_tmech(torque, w1/2/np.pi/self.p)
515
512
  if np.linalg.norm(
516
- self.uqd(w1, *iqde)) <= u1max*np.sqrt(2):
513
+ self.uqd(w1, *iqde)) <= u1max*np.sqrt(2):
517
514
  if log:
518
515
  log(iqde)
519
516
  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
517
+ beta, i1 = betai1(iqde[0], iqde[1])
518
+ iex = iqde[2]
519
+ def ubeta(b):
520
+ return np.sqrt(2)*u1max - np.linalg.norm(
521
+ self.uqd(w1, *iqd(b, i1), iex))
522
+ beta = -np.pi/4 if torque>0 else -3*np.pi/4
523
+ io = *iqd(beta, i1), iex
525
524
 
526
525
  # 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)
526
+ n = w1/2/np.pi/self.p
527
+ res = so.minimize(
528
+ self.culoss, io, method='SLSQP', # trust-constr
529
+ bounds=self.bounds,
530
+ constraints=[
531
+ {'type': 'eq',
532
+ 'fun': lambda iqd: self.tmech_iqd(*iqd, n) - torque},
533
+ {'type': 'eq',
534
+ 'fun': lambda iqd: np.linalg.norm(
535
+ self.uqd(w1, *iqd)) - u1max*np.sqrt(2)}])
536
+
537
+ if log:
538
+ log(res.x)
539
+ if res["success"]:
547
540
  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
541
+
542
+ logger.warning("%s: w1=%f torque=%f, u1max=%f, io=%s",
543
+ res['message'], w1, torque, u1max, io)
544
+ raise ValueError(res['message'])
552
545
 
553
546
  def iqd_torque_umax(self, torque, w1, u1max,
554
547
  disp=False, maxiter=500, log=0, **kwargs):
@@ -559,33 +552,31 @@ class SynchronousMachine(object):
559
552
  if log:
560
553
  log(iqde)
561
554
  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)
555
+ beta, i1 = betai1(iqde[0], iqde[1])
556
+ iex = iqde[2]
557
+ def ubeta(b):
558
+ return np.sqrt(2)*u1max - np.linalg.norm(
559
+ self.uqd(w1, *iqd(b, i1), iex))
560
+ beta = -np.pi/4 if torque>0 else -3*np.pi/4
561
+ io = *iqd(beta, i1), iex
562
+ res = so.minimize(
563
+ self.culoss, io, method='SLSQP', # trust-constr
564
+ bounds=self.bounds,
565
+ #options={'disp': disp, 'maxiter': maxiter},
566
+ # jac=gradient_respecting_bounds(self.bounds, self.culoss),
567
+ constraints=[
568
+ {'type': 'eq',
569
+ 'fun': lambda iqd: self.torque_iqd(*iqd) - torque},
570
+ {'type': 'eq',
571
+ 'fun': lambda iqd: u1max*np.sqrt(2) - np.linalg.norm(
572
+ self.uqd(w1, *iqd))}])
573
+ if log:
574
+ log(res.x)
575
+ if res['success']:
585
576
  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'])
577
+ logger.warning("%s: w1=%f torque=%f, u1max=%f, io=%s",
578
+ res['message'], w1, torque, u1max, io)
579
+ raise ValueError(res['message'])
589
580
 
590
581
  def w1_imax_umax(self, i1max, u1max):
591
582
  """return frequency w1 and shaft torque at voltage u1max and current i1max
@@ -669,10 +660,12 @@ class SynchronousMachine(object):
669
660
 
670
661
  wmtab = []
671
662
  dw = 0
663
+ wmMax = 2*np.pi*n
664
+ '''
672
665
  wmMax = 5*wmType
673
666
  if n > 0:
674
667
  wmMax = min(wmMax, 2*np.pi*n)
675
-
668
+ '''
676
669
  if wmType > wmMax:
677
670
  wmrange = sorted([0, wmMax])
678
671
  wmtab = np.linspace(0, wmMax, nsamples).tolist()
@@ -793,6 +786,7 @@ class SynchronousMachinePsidq(SynchronousMachine):
793
786
  self.psiqf = ip.RegularGridInterpolator(
794
787
  (exc, iqx, idx), psiq,
795
788
  method='cubic', bounds_error=False, fill_value=None)
789
+ # excitation currents bounds should respect ifnom
796
790
  self.bounds = [(min(iq), max(iq)),
797
791
  (min(id), 0),
798
792
  (iexc[0], iexc[-1])]
@@ -909,6 +903,7 @@ class SynchronousMachineLdq(SynchronousMachine):
909
903
  method='cubic'
910
904
  , bounds_error=False, fill_value=None)
911
905
  i1max = np.sqrt(2)*(max(i1))
906
+ # excitation currents bounds should respect ifnom
912
907
  self.bounds = [(np.cos(min(beta))*i1max, i1max),
913
908
  (-i1max, 0),
914
909
  (iexc[0], iexc[-1])]
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):
@@ -190,13 +194,15 @@ class ParameterStudy(object):
190
194
  simulation['range_phi'] = 720/model.get('poles')
191
195
  except AttributeError: # if dxf or pure fsl model
192
196
  simulation['range_phi'] = 0.0
193
- simulation.update(model.winding)
197
+ try:
198
+ simulation.update(model.winding)
199
+ except AttributeError:
200
+ pass
194
201
  fea = femagtools.model.FeaModel(simulation)
195
202
 
196
203
  prob = femagtools.moproblem.FemagMoProblem(decision_vars,
197
204
  objective_vars)
198
-
199
- if immutable_model:
205
+ if not data_model_created and immutable_model:
200
206
  modelfiles = self.setup_model(builder, model, recsin=fea.recsin,
201
207
  feloss=simulation.get('feloss', ''))
202
208
  logger.info("Files %s", modelfiles+extra_files)
@@ -229,7 +235,10 @@ class ParameterStudy(object):
229
235
  fea.poc.pole_pitch = 2*360/model.get('poles')
230
236
  fea.pocfilename = fea.poc.filename()
231
237
  if not hasattr(fea, 'pocfilename'):
232
- fea.pocfilename = f"{model.name}_{model.get('poles')}p.poc"
238
+ try:
239
+ fea.pocfilename = f"{model.name}_{model.get('poles')}p.poc"
240
+ except AttributeError:
241
+ logger.warning("Missing number of poles")
233
242
  elapsedTime = 0
234
243
  self.bchmapper_data = [] # clear bch data
235
244
  # split x value (par_range) array in handy chunks:
@@ -276,7 +285,7 @@ class ParameterStudy(object):
276
285
  task = job.add_task(self.result_func)
277
286
  for fn in extra_files:
278
287
  task.add_file(fn)
279
- if immutable_model:
288
+ if not data_model_created and immutable_model:
280
289
  prob.prepare(x, [fea, self.femag.magnets])
281
290
  for m in modelfiles:
282
291
  task.add_file(m)
@@ -291,18 +300,21 @@ class ParameterStudy(object):
291
300
  else:
292
301
  prob.prepare(x, [model, fea, self.femag.magnets])
293
302
  logger.info("prepare %s", x)
294
- for mc in self.femag.copy_magnetizing_curves(
295
- model,
296
- dir=task.directory,
297
- recsin=fea.recsin,
298
- feloss=feloss):
299
- task.add_file(mc)
300
- 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)
301
311
  task.add_file(
302
312
  'femag.fsl',
303
- builder.create_model(model, self.femag.magnets) +
313
+ builder.create_model(model, self.femag.magnets) if not data_model_created else [] +
304
314
  builder.create_analysis(fea) +
305
- ['save_model("close")'])
315
+ ['save_model("close")'],
316
+ append=data_model_created # model already created, append fsl
317
+ )
306
318
 
307
319
  if hasattr(fea, 'poc'):
308
320
  task.add_file(fea.pocfilename,
femagtools/plot/bch.py CHANGED
@@ -527,23 +527,39 @@ def demagnetization(demag, ax=0):
527
527
  i1 = [scale*x for x in demag['i1']]
528
528
  ax.plot(i1, demag['rr'], 'o', color='C0')
529
529
  ax.plot(i1, demag['rr'], color='C0')
530
- rrmin = 0.6
530
+ rrmin = min(0.6, np.min(demag['rr']))
531
+
532
+ Imax = scale*abs(demag['i1max'])
533
+ demaglabels = [f'Imax = {Imax:.1f} {unit}']
531
534
  if demag.get('i1c', 0):
532
535
  Icrit = scale*demag['i1c']
533
- Hk = demag['Hk']
534
- Tmag = demag['Tmag']
535
- di = 0.05*np.max(i1)
536
- rrmin = min(0.6, np.min(demag['rr']))
537
- ax.plot([Icrit, Icrit], [rrmin, 1], 'k--')
538
- ax.annotate(
539
- f'Icrit = {Icrit:.1f}{unit}\nHk = {Hk:.1f} kA/m\nTmag={Tmag:.1f} °C',
540
- xy=(Icrit, rrmin),
541
- xytext=(Icrit-di, rrmin+0.1*(1-rrmin)), ha='right',
536
+ ax.plot([Icrit, Icrit], [rrmin, 1], 'r:')
537
+ ax.text(Icrit, rrmin+0.15, 'Icrit', fontfamily='monospace',
538
+ rotation=90, size='large', ha='right', va='bottom')
539
+ demaglabels.append(f'Icrit = {Icrit:.1f} {unit}')
540
+
541
+ ax.plot([Imax, Imax], [rrmin, 1], 'g:')
542
+ ax.text(Imax, rrmin+0.05, 'Imax', fontfamily='monospace',
543
+ rotation=90, size='large', ha='right', va='bottom')
544
+
545
+ Hk = demag['Hk']
546
+ Tmag = demag['Tmag']
547
+ demaglabels += [f'Hk = {Hk:.1f} kA/m',
548
+ f'Tmag = {Tmag:.1f} °C']
549
+
550
+ ax.text(0, rrmin+0.05,
551
+ '\n'.join(demaglabels),
552
+ fontfamily='monospace',
553
+ ha='left', va='bottom', size='large',
542
554
  bbox={'facecolor': 'white',
543
555
  'edgecolor': 'white'})
556
+
557
+ #ax.annotate('Imax', xy=(Imax, demag['rr_i1max']), ha='center', va='bottom',
558
+ # xytext=(Imax, demag['rr_i1max']-0.1), rotation=90,
559
+ # arrowprops=dict(facecolor='green', edgecolor='green', shrink=0.05))
544
560
  ax.set_ylim([rrmin, 1.01])
545
561
  ax.set_ylabel('Rel. Remanence')
546
- ax.set_xlabel(f'Phase Current / {unit}')
562
+ ax.set_xlabel(f'Phase Current / {unit} (peak)')
547
563
  ax.grid()
548
564
 
549
565
 
@@ -106,16 +106,24 @@ def shortcircuit(femag, machine, bch, simulation, engine=0):
106
106
  encoding='latin1', errors='ignore'))
107
107
  bchsc.scData['demag'] = bchsc.demag
108
108
  if simulation.get('sim_demagn', 0):
109
- d = {'displ': [d['displ']
109
+ dd = {'displ': [d['displ']
110
110
  for d in bchsc.demag if 'displ' in d],
111
111
  'H_max': [d['H_max']
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
- simulation['i1max'] = bchsc.scData['iks']
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
116
123
  bchsc.scData['demag'] = demag(
117
- femag, machine, simulation, engine)
118
- bchsc.scData['demag'].update(d)
124
+ femag, machine, simulation,
125
+ i1max, phirot, phi, engine)
126
+ bchsc.scData['demag'].update(dd)
119
127
  scdata = bchsc.scData
120
128
  #for w in bch.flux:
121
129
  # try:
@@ -129,7 +137,7 @@ def shortcircuit(femag, machine, bch, simulation, engine=0):
129
137
  if simulation.get('sc_type', 3) == 2:
130
138
  if 'i1max' not in simulation:
131
139
  # just a wild guess
132
- simulation['i1max'] = 4.5*bch.machine['i1']
140
+ simulation['i1max'] = 5*bch.machine['i1']
133
141
  logger.info("2phase short circuit simulation i1max = %.0f",
134
142
  simulation['i1max'])
135
143
  scdata = shortcircuit_2phase(femag, machine, simulation, engine)
@@ -161,12 +169,13 @@ def shortcircuit_2phase(femag, machine, simulation, engine=0):
161
169
  num_cur_steps = 4
162
170
  i1 = np.linspace(0, i1max, num_cur_steps)
163
171
  i1vec = np.concat((-i1[::-1], i1[1:]))
164
- num_par_wdgs = machine['winding'].get('num_par_wdgs', 1)
165
172
  flux_sim = {
166
173
  'calculationMode': 'psi-torq-rot',
167
174
  'i1max': i1max,
168
175
  'curvec': [],
169
- 'num_par_wdgs': num_par_wdgs}
176
+ 'magntemp': simulation['magn_temp'],
177
+ 'fc_radius': simulation['fc_radius'],
178
+ 'num_par_wdgs': simulation['num_par_wdgs']}
170
179
 
171
180
  if engine:
172
181
  parstudy = _parstudy_list(femag, sc_result_func)
@@ -304,6 +313,11 @@ def shortcircuit_2phase(femag, machine, simulation, engine=0):
304
313
  logger.info("Torque %.1f %.1f %.1f (dphi %.4f)",
305
314
  tp[1], tv[1], tc[1], dphi)
306
315
 
316
+ # rotor position at maximum current:
317
+ trot = min(iav[0], iap[0])
318
+ phirot = wm*trot + phi0
319
+ logger.info("phi %.1f")
320
+
307
321
  scData = {
308
322
  'ia': ia.tolist(),
309
323
  'ib': (-ia).tolist(),
@@ -316,63 +330,53 @@ def shortcircuit_2phase(femag, machine, simulation, engine=0):
316
330
  'iks': iap[1] if iap[1] > abs(iav[1]) else iav[1],
317
331
  'tks': tp[1] if tp[1] > abs(tv[1]) else tv[1]
318
332
  }
319
- scData['peakWindingCurrents'] = [scData['iks'],
320
- -scData['iks'], 0]
333
+ scData['peakWindingCurrents'] = [float(scData['iks']),
334
+ -float(scData['iks']), 0]
321
335
  if simulation.get('sim_demagn', 0):
322
- scData['demag'] = demag(femag, machine, simulation, engine)
336
+ i1max = iap[1] if iap[1] > abs(iav[1]) else iav[1]
337
+ scData['demag'] = demag(femag, machine, simulation,
338
+ i1max, phirot, 0, engine)
323
339
  return scData
324
340
 
325
- def dm_result_func(task):
326
- basedir = pathlib.Path(task.directory)
327
- i1rr = []
328
- for f in sorted(basedir.glob('psi-torq-rem-rot-*.dat')):
329
- ptr = np.loadtxt(f)
330
- i1rr.append((np.max(ptr.T[1:4]), np.min(ptr.T[-1])))
331
- return i1rr
332
-
333
- def demag(femag, machine, simulation, engine=0):
341
+ def demag(femag, machine, simulation, i1max, phirot, phi, engine=0):
334
342
  """demag simulation using psi-torq-rem-rot"""
335
343
  logger.info("Demagnetization processing")
336
- i1max = simulation['i1max']
337
- i1min = simulation.get('i1min', i1max/4)
344
+ i1min = simulation.get('i1min', abs(i1max/3))
338
345
  num_steps = 7
339
- b = (i1min-i1max)/np.log(i1min/i1max)
340
- a = i1max/b
341
- i1tab = [b*(a+np.log(x))
342
- for x in np.linspace(i1min/i1max, 1,
343
- num_steps)]
346
+ b = (i1min-abs(i1max))/np.log(i1min/abs(i1max))
347
+ a = abs(i1max)/b
348
+ xtab = np.linspace(i1min/abs(i1max),
349
+ 1+2*(1-i1min/abs(i1max))/(num_steps-1), num_steps+2)
350
+ i1tab = b*(a+np.log(xtab))
344
351
 
345
352
  if simulation.get('sc_type', 3) == 3:
346
- 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]
347
355
  else:
348
- curvec = [[a, -a, 0] for a in i1tab]
356
+ if i1max > 0:
357
+ curvec = [[a, -a, 0] for a in i1tab]
358
+ else:
359
+ curvec = [[-a, a, 0] for a in i1tab]
349
360
  simulation.update({
350
- 'calculationMode': 'psi-torq-rem-rot',
361
+ 'calculationMode': 'psi-torq-rem',
362
+ 'phi': phirot,
363
+ 'magntemp': simulation['Tmag'],
351
364
  'curvec': curvec})
352
- if engine:
353
- parstudy = _parstudy_list(femag, dm_result_func)
354
- parvardef = {
355
- "decision_vars": [
356
- {"values": curvec, "name": "curvec"}]
357
- }
358
- results = parstudy(parvardef, machine, simulation, engine)
359
- i1rr = np.vstack(
360
- ((0, 1),
361
- np.array(results['f']).reshape((-1, 2))))
362
- else:
363
- class Task:
364
- def __init__(self, workdir):
365
- self.directory = workdir
366
- _ = femag(machine, simulation)
367
- i1rr = np.vstack(
368
- [(0, 1), dm_result_func(Task(femag.workdir))])
369
- i1, rr = np.array(i1rr).T
365
+ _ = femag(machine, simulation)
366
+
367
+ ptr = np.loadtxt(femag.workdir / "psi-torq-rem.dat")
368
+ i1 = np.concat(([0], np.max(ptr[:,1:4], axis=1)))
369
+ rr = np.concat(([1], ptr[:,-1]))
370
370
  dmag = {'Hk': simulation['Hk'],
371
371
  'Tmag': simulation['Tmag'],
372
372
  'i1': i1.tolist(),
373
+ 'i1max': float(np.abs(i1max)),
373
374
  'rr': rr.tolist()}
374
375
  # critical current
375
376
  if np.min(rr) < 0.99:
376
- k = np.where(rr < 0.99)[0][0]
377
- dmag['i1c'] = i1[k]
377
+ k = np.where(np.diff(dmag['rr'])<-1e-3)[0][0]+1
378
+ dmag['i1c'] = float(i1[k])
379
+ if abs(i1max) < i1[-1]:
380
+ rrf = make_interp_spline(i1, rr)
381
+ dmag['rr_i1max'] = float(rrf(abs(i1max)))
378
382
  return dmag
@@ -6,7 +6,8 @@ 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",
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
10
11
  sigma2, muer, rel, "polar", 0, 0)
11
12
  Abar = get_sreg_data("area",rotorbar)
12
13
 
@@ -2,11 +2,11 @@
2
2
 
3
3
  slot_div_angle = 360/m.tot_num_slot
4
4
 
5
- if m.xcoil_1 ~= nil and m.ycoil_1 ~= nil then
5
+ if m.xcoil_1 ~= nil and m.ycoil_1 ~= nil then
6
6
  rcoil, phi_coil = c2pd(m.xcoil_1, m.ycoil_1)
7
7
  else
8
8
  rcoil, phi_coil = da1/2 + m.slot_height/2, slot_div_angle/2
9
- end
9
+ end
10
10
 
11
11
  -- delete existing mesh in the slot
12
12
  for i = 1, m.num_sl_gen do
@@ -173,11 +173,11 @@ for i = 1, #winding do
173
173
  slot_nr = winding[i][2]
174
174
  layer = winding[i][3]
175
175
  direction = winding[i][4]
176
- if direction < 0 then
176
+ if direction < 0 then
177
177
  dir = 'wo'
178
178
  else
179
179
  dir = 'wi'
180
- end
180
+ end
181
181
  if i == 1 then
182
182
  if slot_nr <= m.num_sl_gen then
183
183
  wkey = def_new_wdg(wire_xy[slot_nr][layer].x, wire_xy[slot_nr][layer].y, cols[winding[i][1]], "Phase"..winding[i][1], 1, 0, 0, dir)
@@ -188,7 +188,7 @@ for i = 1, #winding do
188
188
  if slot_nr <= m.num_sl_gen then
189
189
  add_to_wdg (wire_xy[slot_nr][layer].x, wire_xy[slot_nr][layer].y, "wsamekey", dir, "wser")
190
190
  end
191
-
191
+
192
192
  else
193
193
  if slot_nr <= m.num_sl_gen then
194
194
  wkey = def_new_wdg(wire_xy[slot_nr][layer].x, wire_xy[slot_nr][layer].y, cols[winding[i][1]], "Phase"..winding[i][1], 1, 0, 0, dir)
@@ -197,4 +197,6 @@ for i = 1, #winding do
197
197
  end
198
198
  end
199
199
  end
200
- m.num_par_wdgs = ${model.get('num_par_wdgs', 1)}
200
+ m.num_par_wdgs = ${model.get('num_par_wdgs', 1)}
201
+
202
+ pre_models("gen_pocfile")
@@ -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,6 +19,7 @@ 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
22
23
  nc_circle_m(r1, 0, x1, y1, 0.0, 0.0, n)
23
24
  if(m.npols_gen == m.num_poles) then
24
25
  nc_circle_m(x1, y1, r1, 0, 0.0, 0.0, n)
@@ -106,9 +106,13 @@ rotate({
106
106
  })
107
107
 
108
108
  file_psi = io.open("psi-rot-mag.dat","w")
109
+ value={}
110
+ temp={}
109
111
  for n=1,nrot+1 do
110
112
 
111
113
  pos, bag = calc_field(phi, curvec, file_psi)
114
+ value[n]=#pos
115
+ temp[n]=pos
112
116
  bags[n] = bag
113
117
  phi = n*dphi
114
118
  rotate({angle=phi, mode="absolute"})
@@ -116,16 +120,40 @@ end
116
120
  rotate({mode = "reset"}) -- restore the initial state (discard any changes)
117
121
  file_psi:close()
118
122
 
123
+ -- add otherwise nil value in bags[n][i][k]
124
+ for i=1, #value-1 do
125
+ if value[i]<value[i+1] then
126
+ num_pos=value[i]
127
+ end
128
+ end
129
+ -- end
130
+
131
+ --for i=1, #curvec do
132
+ -- bagfile = string.format("noloadbag-%d.dat", i)
133
+ -- file_bag = io.open(bagfile,"w")
134
+ -- for k = 1, num_pos do --#pos do -- add otherwise nil value in bags[n][i][k]
135
+ -- file_bag:write(string.format("%g ", pos[k]))
136
+ -- for n=1, nrot+1 do
137
+ -- file_bag:write(string.format("%g ",
138
+ -- bags[n][i][k])) -- Br, rotpos, cur, pos
139
+ -- end
140
+ -- file_bag:write("\n")
141
+ -- end
142
+ -- file_bag:close()
143
+ --end
144
+
145
+ -- add otherwise nil value in bags[n][i][k]
119
146
  for i=1, #curvec do
120
147
  bagfile = string.format("noloadbag-%d.dat", i)
121
148
  file_bag = io.open(bagfile,"w")
122
- for k = 1, #pos do
123
- file_bag:write(string.format("%g ", pos[k]))
124
- for n=1, nrot+1 do
149
+ for n=1, nrot+1 do
150
+ for k = 1, value[n] do --#pos do
151
+ pos=temp[n]
152
+ file_bag:write(string.format("%g ", pos[k]))
125
153
  file_bag:write(string.format("%g ",
126
154
  bags[n][i][k])) -- Br, rotpos, cur, pos
127
155
  end
128
156
  file_bag:write("\n")
129
157
  end
130
158
  file_bag:close()
131
- end
159
+ end