femagtools 1.8.6__py3-none-any.whl → 1.8.8__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/mcv.py CHANGED
@@ -99,7 +99,8 @@ def norm_pfe(B, pfe):
99
99
  b = list(b)
100
100
  b[-1] = Bv[n]
101
101
  n += 1
102
- pfunc = make_interp_spline(b, pfe[i])
102
+ k = 3 if len(pfe[i]) > 3 else 2
103
+ pfunc = make_interp_spline(b, pfe[i], k=k)
103
104
  m.append([float(pfunc(x))
104
105
  for x in Bv[:n]] + [None]*(len(Bv)-n))
105
106
  return Bv.tolist(), m
@@ -298,6 +299,8 @@ class Mcv(object):
298
299
  # {'ch': 0, 'cw': 0, 'ch_freq':0, 'cw_freq':0}
299
300
  self.bertotti = {}
300
301
  # {'ch': 0, 'cw': 0, 'ce':0, 'ch_freq':0, 'cw_freq':0}
302
+ self.steinmetz_modified = {}
303
+ # {'ch': 0, 'cw': 0, 'ch_freq': 1, 'b_beta_coeff': 0, 'cw_freq': 2, 'b_coeff': 2}
301
304
  self.MC1_FE_SPEZ_WEIGTH = 7.65
302
305
  self.MC1_FE_SAT_MAGNETIZATION = 2.15
303
306
 
@@ -359,7 +362,7 @@ class Mcv(object):
359
362
  for k in wtrans:
360
363
  if wtrans[k] in data.keys():
361
364
  self.__setattr__(k, data[wtrans[k]])
362
- for k in ('bertotti', 'jordan', 'steinmetz'):
365
+ for k in ('bertotti', 'jordan', 'steinmetz', 'steinmetz_modified'):
363
366
  if k in data:
364
367
  self.__setattr__(k, data[k])
365
368
  self.curve = data['curve']
@@ -374,6 +377,13 @@ class Mcv(object):
374
377
  # assume jordan iron loss parameters
375
378
  for k in self.jordan:
376
379
  self.jordan[k] = getattr(self, transl[k])
380
+ # set loss coeffs when existing
381
+ try:
382
+ for k in ('bertotti', 'jordan', 'steinmetz', 'steinmetz_modified'):
383
+ if k in data:
384
+ self.__setattr__(k, data[k])
385
+ except:
386
+ pass
377
387
  return
378
388
 
379
389
  def rtrimValueList(self, vlist):
@@ -489,14 +499,24 @@ class Writer(Mcv):
489
499
  feloss: (str) iron loss method (bertotti, jordan)
490
500
  """
491
501
  curve = self._prepare(fillfac, recsin)
502
+ write_losses = True
492
503
  try:
493
504
  if feloss.lower() == 'bertotti':
494
505
  for k in self.bertotti:
495
506
  setattr(self, transl[k], self.bertotti[k])
496
- del self.losses
497
- else:
507
+ write_losses = False
508
+ elif feloss.lower() == 'jordan':
498
509
  for k in self.jordan:
499
510
  setattr(self, transl[k], self.jordan[k])
511
+ write_losses = False
512
+ elif feloss.lower() == 'steinmetz':
513
+ for k in self.steinmetz:
514
+ setattr(self, transl[k], self.steinmetz[k])
515
+ write_losses = False
516
+ elif feloss.lower() == 'modified steinmetz':
517
+ for k in self.steinmetz_modified:
518
+ setattr(self, transl[k], self.steinmetz_modified[k])
519
+ write_losses = False
500
520
  except AttributeError as e:
501
521
  logger.warning("%s", e)
502
522
  pass
@@ -578,7 +598,8 @@ class Writer(Mcv):
578
598
  self.writeBlock([self.mc1_angle[K], self.mc1_db2[K]])
579
599
 
580
600
  try:
581
- if not (self.mc1_ch_factor or self.mc1_cw_factor) and self.losses:
601
+ if (not (self.mc1_ch_factor or self.mc1_cw_factor)
602
+ and self.losses and write_losses):
582
603
  # fit loss parameters
583
604
  pfe = self.losses['pfe']
584
605
  f = self.losses['f']
@@ -611,12 +632,25 @@ class Writer(Mcv):
611
632
  float(self.mc1_fe_spez_weigth),
612
633
  float(self.mc1_fe_sat_magnetization)])
613
634
 
635
+ logger.info("MCV coeffs %s",
636
+ {"fo": float(self.mc1_base_frequency),
637
+ "Bo": float(self.mc1_base_induction),
638
+ "ch": float(self.mc1_ch_factor),
639
+ "cw": float(self.mc1_cw_factor),
640
+ "ch_freq": float(self.mc1_ch_freq_factor),
641
+ "cw_freq": float(self.mc1_cw_freq_factor),
642
+ "b_coeff": float(self.mc1_induction_factor),
643
+ "fr_spez_weight": float(self.mc1_fe_spez_weigth),
644
+ "fe_sat_magnetization": float(self.mc1_fe_sat_magnetization)})
645
+
614
646
  if not hasattr(self, 'losses') or not self.losses:
615
647
  # new variables: ce factor for bertotti losses
616
648
  # b_beta_coeff for modified steinmetz
617
649
  try:
618
650
  self.writeBlock([float(self.mc1_ce_factor),
619
651
  float(self.mc1_induction_beta_factor)])
652
+ #logger.info(f"ce = {float(self.mc1_ce_factor)}")
653
+ #logger.info(f"b_beta_coeff = {float(self.mc1_induction_beta_factor)}")
620
654
  except:
621
655
  pass
622
656
  return
@@ -677,13 +711,24 @@ class Writer(Mcv):
677
711
  [0.0]*(M_LOSS_INDUCT - len(pl)))
678
712
  self.writeBlock(float(f))
679
713
  nrec += 1
680
- for m in range(M_LOSS_FREQ - nrec):
681
- self.writeBlock([0.0]*M_LOSS_INDUCT)
682
- self.writeBlock(0.0)
714
+
715
+ if write_losses:
716
+ logger.info("Append empty blocks %d x %d",
717
+ M_LOSS_FREQ - nrec, M_LOSS_INDUCT)
718
+ for m in range(M_LOSS_FREQ - nrec):
719
+ self.writeBlock([0.0]*M_LOSS_INDUCT)
720
+ self.writeBlock(0.0)
683
721
 
684
722
  self.writeBlock([self.losses['cw'], self.losses['cw_freq'],
685
723
  self.losses['b_coeff'], self.losses['fo'],
686
724
  self.losses['Bo']])
725
+ logger.info("loss coeff %s",
726
+ {"cw": float(self.losses['cw']),
727
+ "cw_freq": float(self.losses['cw_freq']),
728
+ "b_coeff": float(self.losses['b_coeff']),
729
+ "fo": float(self.losses['fo']),
730
+ "Bo": float(self.losses['Bo'])})
731
+
687
732
  self.writeBlock([1])
688
733
  logger.info('Losses n freq %d n ind %d', nfreq, nind)
689
734
  except Exception as e:
@@ -1113,7 +1158,7 @@ class MagnetizingCurve(object):
1113
1158
  repls.items(), name)
1114
1159
 
1115
1160
  def writefile(self, name, directory='.',
1116
- fillfac=None, recsin='', feloss='jordan'):
1161
+ fillfac=None, recsin='', feloss=''):
1117
1162
  """find magnetic curve by name or id and write binary file
1118
1163
  Arguments:
1119
1164
  name: key of mcv dict (name or id)
@@ -1175,6 +1220,125 @@ class MagnetizingCurve(object):
1175
1220
  losses['fo'] = self.mcv[m]['fo']
1176
1221
 
1177
1222
 
1223
+ class MCVconvert:
1224
+ def __init__(self, bhdata):
1225
+ self.steinmetz = dict(cw=0, cw_freq=0, b_coeff=0)
1226
+ self.jordan = dict(ch=0, ch_freq=0, cw=0, cw_freq=0, b_coeff=0)
1227
+ self.bertotti = dict(ch=0, cw=0, ce=0)
1228
+ self.steinmetz_modified = dict(ch=0, cw=0, ch_freq=1, b_beta_coeff=0, cw_freq=2, b_coeff=2)
1229
+ self.losscalc = None
1230
+
1231
+ B = []
1232
+ f = [50.0, 100.0, 200.0, 400.0, 1000.0, 2000.0]
1233
+ pfe = []
1234
+ jordan = False
1235
+ bertotti = False
1236
+ modified_steinmetz = False
1237
+ flag = False
1238
+
1239
+ if "losses" in bhdata:
1240
+ # test if any nan in data
1241
+ for i in ("B", "f"):
1242
+ if np.any(np.isnan(bhdata["losses"][i])) or \
1243
+ np.any(np.isnan(bhdata["losses"][i])):
1244
+ flag = True
1245
+ for i in bhdata["losses"]['pfe']:
1246
+ if np.any(np.isnan(i)):
1247
+ flag = True
1248
+
1249
+ if 'losses' not in bhdata or flag:
1250
+ # check steinmetz or jordan
1251
+ bhdata.update({"losses": {"pfe": [], "f":[], "B": []}})
1252
+ B = bhdata["curve"][-1]["bi"]
1253
+ if "ch" in bhdata:
1254
+
1255
+ if "ce" in bhdata:
1256
+ if bhdata['ce'] > 1e-15:
1257
+ bertotti = True
1258
+
1259
+ if bhdata["ch"] > 1e-15 and bhdata['ce'] < 1e-15:
1260
+ jordan = True
1261
+
1262
+ else:
1263
+ jordan = True
1264
+
1265
+ #if (conditions for modified steinmetz):
1266
+ # modified_steinmetz = True
1267
+
1268
+ if jordan:
1269
+ self.losscalc = 'jordan'
1270
+ logger.info("calculating based on jordan...")
1271
+ for i in f:
1272
+ pfe.append(lc.pfe_jordan(i, np.array(B), bhdata['ch'], bhdata['ch_freq'], bhdata['cw'],
1273
+ bhdata['cw_freq'], bhdata['b_coeff'], 50, 1.5))
1274
+
1275
+ elif bertotti:
1276
+ self.losscalc = 'bertotti'
1277
+ logger.info("calculating based on bertotti")
1278
+ for i in f:
1279
+ pfe.append(lc.wbert(i, np.array(B), bhdata['ch'], bhdata['cw'], bhdata['ce']))
1280
+
1281
+ elif modified_steinmetz:
1282
+ self.losscalc = 'modified steinmetz'
1283
+ logger.info("calculating based on modified steinmetz...")
1284
+ for i in f:
1285
+ pfe.append(lc.pfe_modified_steinmetz(i, np.array(B), bhdata['ch'], bhdata['cw'], bhdata['b_coeff'], bhdata['b_beta_coeff'], 1, 1))
1286
+
1287
+ else: # steinmetz
1288
+ self.losscalc = 'steinmetz'
1289
+ logger.info("calculating based on steinmetz...")
1290
+ for i in f:
1291
+ pfe.append(lc.pfe_steinmetz(i, np.array(B), bhdata['cw'],
1292
+ bhdata['cw_freq'], bhdata['b_coeff'], 50, 1.5))
1293
+ bhdata['losses']['pfe'] = pfe
1294
+ bhdata['losses']['B'] = B
1295
+ bhdata['losses']['f'] = f
1296
+
1297
+ idx = 0
1298
+ for i, j in enumerate(bhdata['losses']['f']):
1299
+ if j == 0:
1300
+ idx = i
1301
+ break
1302
+ idx = idx - 1
1303
+ z = lc.fitsteinmetz(bhdata['losses']['f'][0:idx],
1304
+ bhdata['losses']['B'],
1305
+ bhdata['losses']['pfe'][0:idx],
1306
+ 1.5,
1307
+ 50)
1308
+
1309
+ for i, j in enumerate(self.steinmetz):
1310
+ self.steinmetz[j] = z[i]
1311
+ self.steinmetz.update({"Bo": 1.5, "fo": 50})
1312
+
1313
+ z = lc.fitjordan(bhdata['losses']['f'][0:idx],
1314
+ bhdata['losses']['B'],
1315
+ bhdata['losses']['pfe'][0:idx],
1316
+ 1.5,
1317
+ 50)
1318
+
1319
+ for i, j in enumerate(self.jordan):
1320
+ self.jordan[j] = z[i]
1321
+ self.jordan.update({"Bo": 1.5, "fo": 50})
1322
+
1323
+ z = lc.fit_bertotti(bhdata['losses']['f'][0:idx],
1324
+ bhdata['losses']['B'],
1325
+ bhdata['losses']['pfe'][0:idx])
1326
+
1327
+ for i, j in enumerate(self.bertotti):
1328
+ self.bertotti[j] = z[i]
1329
+ self.bertotti.update({"Bo": 1, "fo": 1, "alpha": 2.0, "ch_freq": 1.0, "cw_freq": 2.0, "b_coeff": 2.0})
1330
+
1331
+ z = lc.fit_modified_steinmetz(bhdata['losses']['f'][0:idx],
1332
+ bhdata['losses']['B'],
1333
+ bhdata['losses']['pfe'][0:idx], 1, 1)
1334
+
1335
+ for i,j in enumerate(self.steinmetz_modified):
1336
+ self.steinmetz_modified[j] = z[i]
1337
+ self.steinmetz_modified.update({"Bo": 1, "fo": 1})
1338
+
1339
+ bhdata['losses']['pfe'] = np.transpose(bhdata['losses']['pfe']).tolist() #len(B) rows and len(f) columns
1340
+
1341
+
1178
1342
  def read(filename):
1179
1343
  """read MC/MCV file and return mc dict"""
1180
1344
  mcv = Reader()
femagtools/nc.py CHANGED
@@ -192,21 +192,23 @@ class Reader(object):
192
192
  for k in ('sr_key', 'nxt_sr_pntr')]
193
193
  except:
194
194
  pass
195
- try:
196
- grp = ds.groups['machine']
195
+
196
+ grp = ds.groups['machine']
197
+ if 'speed' in grp.variables:
197
198
  self.speed = float(grp.variables['speed'].getValue().data)
199
+ if 'fc_radius' in grp.variables:
198
200
  self.FC_RADIUS = float(grp.variables['fc_radius'].getValue().data)
199
- self.pole_pairs = int(grp.variables['pole_pairs'].getValue().data)
201
+ self.delta_node_angle = float( # rad
202
+ grp.variables['delta_node_angle'].getValue().data)
203
+ self.arm_length = float(grp.variables['arm_length'].getValue().data)
204
+ for attr in ('pole_pairs', 'poles_sim', 'coil_span',
205
+ 'state_of_problem', 'move_action'):
206
+ if attr in grp.variables:
207
+ setattr(self, attr, int(grp.variables[attr].getValue().data))
208
+ if 'num_layers' in grp.variables:
200
209
  self.layers = int(grp.variables['num_layers'].getValue().data)
201
- self.coil_span = int(grp.variables['coil_span'].getValue().data)
202
- self.delta_node_angle = float( # rad
203
- grp.variables['delta_node_angle'].getValue().data)
204
- self.poles_sim = int(grp.variables['poles_sim'].getValue().data)
210
+ if 'num_slots' in grp.variables:
205
211
  self.slots = int(grp.variables['num_slots'].getValue().data)
206
- self.arm_length = float(grp.variables['arm_length'].getValue().data)
207
- self.state_of_problem = int(grp.variables['state_of_problem'].getValue().data)
208
- except:
209
- pass
210
212
 
211
213
  if hasattr(self, 'state_of_problem'):
212
214
  if self.state_of_problem == 5:
@@ -236,18 +238,18 @@ class Reader(object):
236
238
  except KeyError:
237
239
  pass
238
240
 
239
- try:
241
+ if 'el_induction' in ds.groups:
240
242
  grp = ds.groups['el_induction']
241
243
  (self.pos_el_fe_induction,
242
244
  self.el_fe_induction_1,
243
245
  self.el_fe_induction_2,
244
- self.eddy_cu_vpot) = [grp.variables[k][:]
246
+ self.eddy_cu_vpot) = [grp.variables[k][:] if k in grp.variables else []
245
247
  for k in ('position',
246
248
  'fe_induction_1',
247
249
  'fe_induction_2',
248
250
  'eddy_cu_vpot')]
249
251
  logger.debug('el_fe_induction %d', len(self.pos_el_fe_induction))
250
- except KeyError:
252
+ else:
251
253
  self.pos_el_fe_induction = []
252
254
  self.el_fe_induction_1 = []
253
255
  self.el_fe_induction_2 = []
femagtools/parstudy.py CHANGED
@@ -6,6 +6,7 @@ import scipy as sc
6
6
  import logging
7
7
  import glob
8
8
  import os
9
+ import re
9
10
  import time
10
11
  import shutil
11
12
  import functools
@@ -172,7 +173,8 @@ class ParameterStudy(object):
172
173
  else:
173
174
  workdir = pathlib.Path(self.femag.workdir)
174
175
  for d in workdir.glob('[0-9]*'):
175
- shutil.rmtree(d)
176
+ if re.search(r'^\d+$', d.name):
177
+ shutil.rmtree(d)
176
178
 
177
179
  extra_result_files = []
178
180
  if simulation.get('airgap_induc', False):
femagtools/plot/bch.py CHANGED
@@ -515,80 +515,151 @@ def cogging(bch, title=''):
515
515
  fig.subplots_adjust(top=0.92)
516
516
 
517
517
 
518
- def transientsc(bch, title=''):
519
- """creates a transient short circuit plot"""
520
- cols = 1
521
- rows = 2
522
- htitle = 1.5 if title else 0
523
- fig, ax = plt.subplots(nrows=rows, ncols=cols,
524
- figsize=(10, 3*rows + htitle))
525
- if title:
526
- fig.suptitle(title, fontsize=16)
527
-
528
- row = 1
529
- plt.subplot(rows, cols, row)
530
- ax = plt.gca()
518
+ def demagnetization(demag, ax=0):
519
+ """plot rel. remanence vs. current"""
520
+ if ax == 0:
521
+ ax = plt.gca()
522
+ scale = 1
523
+ unit = 'A'
524
+ if np.max(demag['i1']) > 25e3:
525
+ scale = 1e-3
526
+ unit = 'kA'
527
+ i1 = [scale*x for x in demag['i1']]
528
+ ax.plot(i1, demag['rr'], 'o', color='C0')
529
+ ax.plot(i1, demag['rr'], color='C0')
530
+ rrmin = 0.6
531
+ if demag.get('i1c', 0):
532
+ 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',
542
+ bbox={'facecolor': 'white',
543
+ 'edgecolor': 'white'})
544
+ ax.set_ylim([rrmin, 1.01])
545
+ ax.set_ylabel('Rel. Remanence')
546
+ ax.set_xlabel(f'Phase Current / {unit}')
547
+ ax.grid()
548
+
549
+
550
+ def transientsc_currents(scData, ax=0, title='', set_xlabel=True):
551
+ """plot transient shortcircuit currents vs time"""
552
+ if ax == 0:
553
+ ax = plt.gca()
531
554
  ax.grid(True)
532
- istat = np.array([bch.scData[i]
555
+ if title:
556
+ ax.set_title(title)
557
+ istat = np.array([scData[i]
533
558
  for i in ('ia', 'ib', 'ic')])
534
559
  pv = [find_peaks_and_valleys(
535
- np.array(bch.scData['time']), i1)
560
+ np.array(scData['time']), i1)
536
561
  for i1 in istat]
537
562
  try:
538
563
  ipvmax = np.argmax(
539
564
  [y['yp'] if np.abs(y['yp']) > np.abs(y['yv']) else y['yv']
540
- for y in pv])
565
+ for y in pv if y['yp']])
541
566
  imax = pv[ipvmax]['yp'] if np.abs(pv[ipvmax]['yp']) > np.abs(pv[ipvmax]['yv']) else pv[ipvmax]['yv']
567
+ iac = [pv[ipvmax]['tpeaks'][-1], pv[ipvmax]['peaks'][-1]]
542
568
  except KeyError:
543
569
  pass
544
570
  if np.max(istat) > 4000:
545
571
  istat *= 1e-3
546
- imax *= 1e-3
547
- ax.set_title('Currents / kA')
572
+ try:
573
+ imax *= 1e-3
574
+ iac[1] *= 1e-3
575
+ except NameError:
576
+ pass
577
+ ax.set_ylabel('Currents / kA')
548
578
  else:
549
- ax.set_title('Currents / A')
579
+ ax.set_ylabel('Currents / A')
550
580
 
551
581
  for i, iph in zip(('ia', 'ib', 'ic'), istat):
552
- ax.plot(bch.scData['time'], iph, label=i)
582
+ ax.plot(scData['time'], iph, label=i)
553
583
  try:
554
584
  ax.plot([pv[ipvmax]['tp']], [imax], '.')
585
+ ax.plot([iac[0]], [iac[1]], '.')
586
+ dtx = (scData['time'][-1]-scData['time'][0])/75
587
+ dy = imax/25
555
588
  ax.annotate(f'Imax = {imax:.1f}',
556
589
  xy=(pv[ipvmax]['tp'], imax),
557
- xytext=(pv[ipvmax]['tp']+0.01, imax))
590
+ xytext=(pv[ipvmax]['tp']+dtx, imax-dy))
591
+ dy = iac[1]/25
592
+ ax.annotate(f'I = {iac[1]:.1f}',
593
+ xy=iac,
594
+ xytext=(iac[0]+dtx, iac[1]-dy))
558
595
  except NameError:
559
596
  pass
560
- ax.set_xlabel('Time / s')
597
+ if set_xlabel:
598
+ ax.set_xlabel('Time / s')
561
599
  ax.legend()
562
600
 
563
- row = 2
564
- plt.subplot(rows, cols, row)
565
- ax = plt.gca()
601
+
602
+ def transientsc_torque(scData, ax=0, title='', set_xlabel=True):
603
+ """plot transient shortcircuit torque vs time"""
604
+ if ax == 0:
605
+ ax = plt.gca()
606
+ if title:
607
+ ax.set_title(title)
566
608
  pv = find_peaks_and_valleys(
567
- np.array(bch.scData['time']), np.array(bch.scData['torque']))
609
+ np.array(scData['time']), np.array(scData['torque']))
568
610
  try:
569
611
  tqmax = pv['yp'] if np.abs(pv['yp']) > np.abs(pv['yv']) else pv['yv']
570
612
  tp = pv['tp'] if np.abs(pv['yp']) > np.abs(pv['yv']) else pv['tv']
571
- except KeyError:
613
+ tc = [pv['tpeaks'][-1], pv['peaks'][-1]]
614
+ except (KeyError, ValueError):
572
615
  pass
573
- torque = np.array(bch.scData['torque'])
616
+ torque = np.array(scData['torque'])
574
617
  if np.max(torque) > 4000:
575
618
  torque *= 1e-3
576
- tqmax *= 1e-3
577
- ax.set_title('Torque / kNm')
619
+ try:
620
+ tqmax *= 1e-3
621
+ tc[1] *= 1e-3
622
+ except NameError:
623
+ pass
624
+ ax.set_ylabel('Torque / kNm')
578
625
  else:
579
- ax.set_title('Torque / Nm')
626
+ ax.set_ylabel('Torque / Nm')
580
627
 
581
628
  ax.grid(True)
582
- ax.plot(bch.scData['time'], torque)
629
+ ax.plot(scData['time'], torque)
583
630
  try:
584
631
  ax.plot([tp], [tqmax], '.')
632
+ ax.plot([tc[0]], [tc[1]], '.')
633
+ dtx = (scData['time'][-1]-scData['time'][0])/75
634
+ dy = tqmax/25
585
635
  ax.annotate(f'Tmax = {tqmax:.1f}',
586
636
  xy=(tp, tqmax),
587
- xytext=(tp+0.01, tqmax))
637
+ xytext=(tp+dtx, tqmax-dy))
638
+ dy = tc[1]/25
639
+ ax.annotate(f'T = {tc[1]:.1f}',
640
+ xy=tc,
641
+ xytext=(tc[0]+dtx, tc[1]))
588
642
  except NameError:
589
643
  pass
590
- ax.set_xlabel('Time / s')
644
+ if set_xlabel:
645
+ ax.set_xlabel('Time / s')
646
+
647
+ def transientsc(bch, title=''):
648
+ """creates a transient short circuit plot"""
649
+ try:
650
+ scData = bch.scData
651
+ except AttributeError:
652
+ scData = bch
653
+ cols = 1
654
+ rows = 2
655
+ htitle = 1.5 if title else 0
656
+ fig, axs = plt.subplots(nrows=rows, ncols=cols, sharex=True,
657
+ figsize=(10, 3*rows + htitle))
658
+ if title:
659
+ fig.suptitle(title, fontsize=16)
591
660
 
661
+ transientsc_currents(scData, axs[0], set_xlabel=False)
662
+ transientsc_torque(scData, axs[1])
592
663
  fig.tight_layout(h_pad=2)
593
664
  if title:
594
665
  fig.subplots_adjust(top=0.92)
@@ -602,24 +673,35 @@ def transientsc_demag(demag, magnet=0, title='', ax=0):
602
673
  """
603
674
  if ax == 0:
604
675
  ax = plt.gca()
605
- pos = [d['displ'] for d in demag if 'displ' in d]
606
- hmax = [-d['H_max'] for d in demag if 'H_max' in d]
607
- havg = [-d['H_av'] for d in demag if 'H_av' in d]
608
- hclim = [-d['lim_hc'] for d in demag if 'lim_hc' in d]*2
609
-
676
+ if type(d) == list:
677
+ pos = [d['displ'] for d in demag if 'displ' in d]
678
+ hmax = [-d['H_max'] for d in demag if 'H_max' in d]
679
+ havg = [-d['H_av'] for d in demag if 'H_av' in d]
680
+ hclim = [-d['lim_hc'] for d in demag if 'lim_hc' in d][0]
681
+ else:
682
+ pos = demag['displ']
683
+ hmax = demag['H_max']
684
+ havg = demag['H_av']
685
+ hclim = demag['Hk']
610
686
  ax.set_title('Transient Short Circuit Demagnetization [kA/m]')
611
687
  ax.plot(pos, hmax,
612
688
  label='H Max {:4.2f} kA/m'.format(max(hmax)))
613
689
  ax.plot(pos, havg,
614
690
  label='H Avg {:4.2f} kA/m'.format(max(havg)))
615
691
  if len(hclim) > 1:
616
- ax.plot([pos[0], pos[-1]], hclim, color='C3', linestyle='dashed',
617
- label='Hc {:4.2f} kA/m'.format(hclim[0]))
618
-
692
+ ax.plot([pos[0], pos[-1]], [hclim,hclim], color='C3',
693
+ linestyle='dashed',
694
+ label='Hc {:4.2f} kA/m'.format(hclim))
695
+ if 'Tmag' in demag:
696
+ Tmag = demag['Tmag']
697
+ elif magnet:
698
+ Tmag = magnet['Tmag']
699
+ else:
700
+ Tmag = ''
619
701
  ax.set_xlabel('Rotor Position / °')
620
702
  ax.grid(True)
621
- if magnet:
622
- ax.legend(title=f"Magnet Temperature {magnet['Tmag']}°C")
703
+ if Tmag:
704
+ ax.legend(title=f"Magnet Temperature {Tmag}°C")
623
705
  else:
624
706
  ax.legend()
625
707
 
femagtools/plot/nc.py CHANGED
@@ -130,6 +130,19 @@ def demag(isa, cmap=DEFAULT_CMAP, ax=0):
130
130
  logger.info("Max demagnetization %f", np.max(demag))
131
131
 
132
132
 
133
+ def remanence(isa, cmap=DEFAULT_CMAP, ax=0):
134
+ """plot remanence of NC/I7/ISA7 model
135
+ Args:
136
+ isa: Isa7/NC object
137
+ """
138
+ emag = [e for e in isa.elements if e.is_magnet()]
139
+ rem = np.linalg.norm([e.remanence(isa.MAGN_TEMPERATURE)
140
+ for e in emag], axis=1)
141
+ _contour(ax, f'Remanence at {isa.MAGN_TEMPERATURE} °C (min {np.min(rem):.1f} T)',
142
+ emag, rem, 'T', cmap, isa)
143
+ logger.info("Min remanence %f", np.min(rem))
144
+
145
+
133
146
  def demag_pos(isa, pos=-1, icur=-1, ibeta=-1, cmap=DEFAULT_CMAP, ax=0):
134
147
  """plot demag of NC/I7/ISA7 model at rotor position
135
148
  Args: