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.
- femagtools/__init__.py +1 -1
- femagtools/bch.py +21 -12
- femagtools/ecloss.py +12 -4
- femagtools/femag.py +1 -2
- femagtools/fsl.py +28 -4
- femagtools/job.py +6 -3
- femagtools/machine/__init__.py +35 -3
- femagtools/machine/effloss.py +37 -13
- femagtools/machine/im.py +9 -6
- femagtools/machine/sizing.py +4 -3
- femagtools/machine/sm.py +64 -69
- femagtools/parstudy.py +28 -16
- femagtools/plot/bch.py +27 -11
- femagtools/shortcircuit.py +53 -49
- femagtools/templates/ec-rotorbar.mako +2 -1
- femagtools/templates/gen_hairpin_winding.mako +8 -6
- femagtools/templates/ld_lq_fast.mako +1 -1
- femagtools/templates/mesh-airgap.mako +1 -0
- femagtools/templates/noloadflux-rot.mako +32 -4
- femagtools/templates/psi-torq-rem.mako +112 -0
- femagtools/templates/psi-torq-rot.mako +7 -0
- femagtools/templates/rotor_winding_ks2.mako +44 -0
- femagtools/templates/rotor_winding_ks2_ecSimulation.mako +44 -0
- femagtools/templates/statorRing.mako +1 -1
- femagtools/ts.py +38 -7
- femagtools/zmq.py +4 -1
- {femagtools-1.8.11.dist-info → femagtools-1.8.13.dist-info}/METADATA +3 -31
- {femagtools-1.8.11.dist-info → femagtools-1.8.13.dist-info}/RECORD +34 -32
- {femagtools-1.8.11.dist-info → femagtools-1.8.13.dist-info}/WHEEL +1 -1
- tests/test_bchreader.py +5 -5
- tests/test_femag.py +1 -1
- tests/test_fsl.py +3 -3
- femagtools-1.8.11.dist-info/LICENSE +0 -26
- {femagtools-1.8.11.dist-info → femagtools-1.8.13.dist-info}/entry_points.txt +0 -0
- {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
|
46
|
-
num_exc_steps: number of excitation current (default
|
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
|
-
|
513
|
+
self.uqd(w1, *iqde)) <= u1max*np.sqrt(2):
|
517
514
|
if log:
|
518
515
|
log(iqde)
|
519
516
|
return (*iqde, torque)
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
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
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
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
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
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
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
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
|
-
|
587
|
-
|
588
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
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
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
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
|
|
femagtools/shortcircuit.py
CHANGED
@@ -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
|
-
|
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
|
-
|
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,
|
118
|
-
|
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'] =
|
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
|
-
'
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
342
|
-
|
343
|
-
|
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 = [[
|
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
|
-
|
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
|
361
|
+
'calculationMode': 'psi-torq-rem',
|
362
|
+
'phi': phirot,
|
363
|
+
'magntemp': simulation['Tmag'],
|
351
364
|
'curvec': curvec})
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
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
|
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")
|
@@ -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
|
123
|
-
|
124
|
-
|
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
|