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/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  """
4
4
  __title__ = 'femagtools'
5
- __version__ = '1.8.12'
5
+ __version__ = '1.8.14'
6
6
  __author__ = 'Ronald Tanner'
7
7
  __license__ = 'BSD'
8
8
  __copyright__ = 'Copyright 2023-2025 Gamma Technology'
femagtools/bch.py CHANGED
@@ -7,6 +7,7 @@ import numpy as np
7
7
  import re
8
8
  import logging
9
9
  import logging.config
10
+ from .utils import fft
10
11
 
11
12
  logger = logging.getLogger('femagtools.bch')
12
13
 
@@ -114,6 +115,22 @@ def losses_mapping_external_rotor(losses):
114
115
  pass
115
116
  return d
116
117
 
118
+ def _convert(obj):
119
+ """make dict jsonizable"""
120
+ if isinstance(obj, dict):
121
+ return {k: _convert(v) for k, v in obj.items()}
122
+ elif isinstance(obj, (np.float32, np.float64)):
123
+ return float(obj)
124
+ elif isinstance(obj, list):
125
+ return [_convert(k) for k in obj]
126
+ elif isinstance(obj, tuple):
127
+ return tuple(_convert(k) for k in obj)
128
+ elif isinstance(obj, np.ndarray):
129
+ return obj.tolist()
130
+ elif isinstance(obj, (np.int32, np.int64)):
131
+ return int(obj)
132
+ else:
133
+ return obj
117
134
 
118
135
  def _readSections(f):
119
136
  """return list of bch sections
@@ -1057,11 +1074,14 @@ class Reader:
1057
1074
  e.g. : idList[-450, -350, -250, -150, -50, 0]
1058
1075
  idList[-500, -400, -300, -200, -100, 0, 0]
1059
1076
  '''
1060
- if list(idList).count(0) > 1: # femag writes duplicate id==0 values
1077
+ if list(idList).count(0) > 1: # femag may write duplicate id==0 values
1061
1078
  idList = idList[:-1]
1062
1079
  diff = np.floor(np.abs(np.diff(idList)))
1063
- if n := np.trim_zeros(np.diff(diff)).size:
1064
- idList = idList[:-n]
1080
+ maxdiff = np.max(diff)
1081
+ # also remove samples that are close
1082
+ if n := np.trim_zeros(np.diff(
1083
+ np.round(diff/maxdiff, 2))).size:
1084
+ return idList[:-n]
1065
1085
  return idList
1066
1086
 
1067
1087
  def __read_psidq(self, content):
@@ -1375,10 +1395,14 @@ class Reader:
1375
1395
  try:
1376
1396
  w1 = np.pi*self.dqPar['speed']*self.dqPar['npoles']
1377
1397
  r1 = self.machine.get('r1', 0.0)
1378
- uq, ud = (r1*iq + self.dqPar['up'] + id*w1*self.dqPar['ld'][0],
1379
- r1*id - iq*w1*self.dqPar['lq'][0])
1380
- self.dqPar['u1'] = [np.sqrt(uq**2 + ud**2)]
1381
- self.dqPar['gamma'] = [-np.arctan2(ud, uq)*180/np.pi]
1398
+ pos = self.flux['1'][0]['displ']
1399
+ emfft = [fft(pos, f['voltage_dpsi']) for f in self.flux['1']]
1400
+ gamma = [emfft[0]['alfa0'] - e['alfa0'] for e in emfft[1:]]
1401
+ emf = np.array([e['a']/np.sqrt(2) for e in emfft[1:]])
1402
+ uq, ud = r1*iq + np.cos(gamma)*emf, r1*id + np.sin(gamma)*emf
1403
+ self.dqPar['u1'] = np.sqrt(uq**2 + ud**2).tolist()
1404
+ self.dqPar['gamma'] = (-np.arctan2(ud, uq)*180/np.pi).tolist()
1405
+
1382
1406
  self.dqPar['psim0'] = lfe*self.dqPar['psim0']
1383
1407
  self.dqPar['phi'] = [self.dqPar['beta'][0] +
1384
1408
  self.dqPar['gamma'][0]]
@@ -1386,16 +1410,22 @@ class Reader:
1386
1410
  for phi in self.dqPar['phi']]
1387
1411
  self.dqPar['i1'].insert(0, 0)
1388
1412
  self.dqPar['u1'].insert(0, self.dqPar.get('up0', 0))
1413
+
1389
1414
  except KeyError:
1390
1415
  pass
1391
1416
 
1392
- # if next section is absent
1393
1417
  try:
1394
- self.dqPar['psid'] = [self.dqPar['psim'][0]]
1395
- self.dqPar['psiq'] = [self.dqPar['lq'][0] *
1396
- self.dqPar['i1'][-1]]
1397
- except KeyError:
1398
- pass
1418
+ self.dqPar['psid'] = list(np.cos(gamma)*emf/w1)
1419
+ self.dqPar['psiq'] = list(-np.sin(gamma)*emf/w1)
1420
+ except UnboundLocalError:
1421
+ try:
1422
+ self.dqPar['psid'] = [self.dqPar['psim'][0]]
1423
+ self.dqPar['psiq'] = [self.dqPar['lq'][0] *
1424
+ self.dqPar['i1'][-1]]
1425
+ except KeyError:
1426
+ pass
1427
+
1428
+ self.dqPar = _convert(self.dqPar)
1399
1429
  return # end of first section
1400
1430
 
1401
1431
  # second DQ-Parameter section
@@ -1467,6 +1497,7 @@ class Reader:
1467
1497
  self.dqPar['u1'].insert(0, self.dqPar.get('up0', 0))
1468
1498
  except:
1469
1499
  pass
1500
+ self.dqPar = _convert(self.dqPar)
1470
1501
 
1471
1502
  def __read_weights(self, content):
1472
1503
  # Stator-Iron - Conductors - Magnets
@@ -1612,8 +1643,8 @@ class Reader:
1612
1643
 
1613
1644
  elif content[i+1].split() == ['Iron', '----']:
1614
1645
  losses['rotfe'] = sum([floatnan(x) for x in rec])
1615
- losses['total'] += losses['rotfe']
1616
-
1646
+ losses['total'] += losses['rotfe']
1647
+
1617
1648
  else:
1618
1649
  losses['rotfe'] = floatnan(rec[1])
1619
1650
  losses['total'] += losses['rotfe']
@@ -1836,6 +1867,9 @@ def read(filename):
1836
1867
 
1837
1868
  if __name__ == "__main__":
1838
1869
  import json
1870
+ logging.basicConfig(level=logging.INFO,
1871
+ format='%(asctime)s %(message)s')
1872
+
1839
1873
  if len(sys.argv) == 2:
1840
1874
  filename = sys.argv[1]
1841
1875
  else:
femagtools/ecloss.py CHANGED
@@ -263,10 +263,11 @@ class MagnLoss:
263
263
  for i in range((npos-1)//2 + 1) if i > 0])
264
264
  npos_nonzero = np.argwhere(tmp_period > 0.1*np.amax(bxy_amp)).squeeze()
265
265
  period = tmp_period[npos_nonzero]
266
-
267
266
  if np.sum(np.around([period[0]%i for i in period])) == 0:
268
- npos = min(int(np.ceil(np.amax(period))+1), bxy.shape[2])
269
-
267
+ try:
268
+ npos = min(int(np.ceil(np.amax(period))+1), bxy.shape[2])
269
+ except:
270
+ pass
270
271
  try:
271
272
  self.tgrid = 60/self.speed*(self.theta[npos-1] - self.theta[0])/360
272
273
  except AttributeError:
@@ -765,7 +766,12 @@ class MagnLoss:
765
766
  i["wm"]*1e3, i["hm"]*1e3, i["lm"]*1e3,
766
767
  (nsegx, nsegy, nsegz))
767
768
 
768
- (nt, bx_fft, by_fft) = self.periodicity_id(i['bl']) # finds the time periodic part of the simulation
769
+ (nt, bx_fft, by_fft) = self.periodicity_id(i['bl'])
770
+ if self.tgrid == 0:
771
+ logger.warning(f"Time series couldn't be identified. Cannot calculate losses \
772
+ for loadcase {i['loadcase']}, superelement {i['spel_key']}")
773
+ all_load_cases.append(0)
774
+ continue
769
775
  (nx, ny, nz, excpl_new, eycpl_new) = Segmentation(
770
776
  i['wm'], i['hm'], i['lm'], i['elcp'],
771
777
  nsegx, nsegy, nsegz)
@@ -778,6 +784,8 @@ class MagnLoss:
778
784
  nx, ny, nsegx, nsegy, nt, i['elcp'], i['bl'], excpl_new, eycpl_new)
779
785
  loss = self.loss_ialh2(sx_abs, sy_abs, sx_phase, sy_phase, freq_range,
780
786
  nx, ny, wm, hm, lm, nsegx, nsegy, nsegz, delta_eff) * self.numpoles
787
+ if np.isnan(loss):
788
+ loss = 0
781
789
  ialh_loss += loss
782
790
  logger.info('Loadcase %d, Superelement %s, Total losses = %.3f W',
783
791
  i["loadcase"], i["spel_key"], loss)
femagtools/femag.py CHANGED
@@ -475,9 +475,8 @@ class BaseFemag(object):
475
475
  if simulation.get('magnet_loss', False):
476
476
  logger.info('Evaluating magnet losses...')
477
477
  ops = range(len(bch.torque))
478
- ncf = pathlib.Path(self.workdir) / self.modelname
479
478
  m = femagtools.ecloss.MagnLoss(
480
- nc=femagtools.nc.read(ncf), ibeta=ops)
479
+ nc=self.read_nc(), ibeta=ops)
481
480
  try:
482
481
  # change from ialh to ialh2: since v1.8.1
483
482
  magn_losses = m.calc_losses_ialh2()
@@ -486,6 +485,8 @@ class BaseFemag(object):
486
485
 
487
486
  if len(ops) != len(bch.losses):
488
487
  magn_losses.insert(0, magn_losses[0])
488
+
489
+ magn_losses = [float(i) for i in magn_losses]
489
490
  try:
490
491
  for i in range(len(bch.losses)):
491
492
  bch.losses[i].update({"magnetH": magn_losses[i]})
femagtools/fsl.py CHANGED
@@ -436,25 +436,38 @@ class Builder:
436
436
  return self.__render(windings, 'cu_losses')
437
437
 
438
438
  def create_fe_losses(self, model):
439
- for part in ('stator', 'rotor', 'commutator', 'magnet'):
439
+ fe_losses = []
440
+ fe_losses_items = (
441
+ 'ffactor', 'cw', 'ch', 'hyscoef',
442
+ 'edycof', 'indcof', 'fillfact',
443
+ 'fillfac', 'basfreq', 'basind',
444
+ 'ffactor')
445
+
446
+ part = 'stator'
447
+ if model.get(part, 0):
448
+ submod = model.get(part)
449
+ if any([submod.get(k, 0) for k in fe_losses_items]):
450
+ if submod.get('fillfac', 0):
451
+ submod['fillfact'] = submod['fillfac']
452
+ fe_losses += self.__render(submod, 'FE-losses')
453
+ fe_losses.append('pre_models("FE-Losses-1")')
454
+
455
+ for part in ('rotor', 'commutator', 'magnet'):
440
456
  if model.get(part, 0):
441
457
  submod = model.get(part)
442
- if any(submod.get(k, 0) for k in (
443
- 'ffactor', 'cw', 'ch', 'hyscoef',
444
- 'edycof', 'indcof', 'fillfact',
445
- 'fillfac','basfreq', 'basind',
446
- 'ffactor')):
458
+ if any([submod.get(k, 0) for k in fe_losses_items]):
447
459
  if submod.get('fillfac', 0):
448
460
  submod['fillfact'] = submod['fillfac']
449
- return self.__render(submod, 'FE-losses')
450
- return []
461
+ fe_losses += self.__render(submod, 'FE-losses')
462
+ fe_losses.append('pre_models("FE-Losses-2")')
463
+ return fe_losses
451
464
 
452
465
  def create_gen_winding(self, model):
453
466
  try:
454
467
  model.winding['wire'].update(
455
468
  {"num_layers": model.winding["num_layers"]})
456
469
  genwdg = self.__render(model.winding,
457
- 'gen_' + model.winding['wire'].get('name'))
470
+ 'gen_' + model.winding['wire'].get('name'))
458
471
  except:
459
472
  genwdg = self.__render(model, 'gen_winding')
460
473
 
@@ -677,7 +690,6 @@ class Builder:
677
690
  self.create_connect_models(model) +
678
691
  self.create_rotor_winding(model)) + \
679
692
  self.create_thermal_properties(model)
680
-
681
693
  return (self.open_model(model) +
682
694
  self.create_fe_losses(model) +
683
695
  self.create_magnet(model, magnetMat))
@@ -738,6 +750,11 @@ class Builder:
738
750
  if sim.get('airgap_induc', 0) else [])
739
751
  displ_stator_rotor = self.create_displ_stator_rotor(
740
752
  sim.get('eccentricity', {}))
753
+ # sliding band
754
+ sliding_band = []
755
+ if sim.get("sliding", 0):
756
+ sliding_band = [f'save_model("cont")',
757
+ f'enable_sliding()']
741
758
  revert_displ = []
742
759
  if displ_stator_rotor:
743
760
  sim['eval_force'] = 1
@@ -757,6 +774,7 @@ class Builder:
757
774
  sim.noload_ex_cur = sim.get('nload_ex_cur')
758
775
  felosses = custom_fefunc + self.create_fe_losses(sim)
759
776
  fslcalc = (displ_stator_rotor
777
+ + sliding_band
760
778
  + self.__render(sim, sim.get('calculationMode'))
761
779
  + airgap_induc + revert_displ
762
780
  + ['save_model("cont")'])
femagtools/isa7.py CHANGED
@@ -1035,16 +1035,28 @@ class Isa7(object):
1035
1035
  def get_mass(self):
1036
1036
  """ return mass (in kg) of material conductors, iron, magnets
1037
1037
  """
1038
+ masse_rotor_yoke = 0
1039
+ section_rotor_yoke = 0
1038
1040
  try:
1039
1041
  return self.mass
1040
1042
  except AttributeError:
1041
1043
  self.mass = [{'iron': 0, 'conductors': 0, 'magnets': 0},
1042
1044
  {'iron': 0, 'conductors': 0, 'magnets': 0}]
1043
1045
  scf = self.scale_factor()
1046
+ for se in self.subregions:
1047
+ if se.name == 'Bar':
1048
+ r = 1 # as rotor bar is inside
1049
+ spw = self.CU_SPEZ_WEIGHT*1e3
1050
+ l = 1 #self.PS_LENGTH_CU[r]*1e-2
1051
+ slf = 1 #self.PS_FILFACTOR_CU[r]
1052
+ self.mass[r]['conductors'] += scf*se.area()*self.arm_length*spw*l*slf
1044
1053
  for se in self.superelements:
1054
+ winding_detected=0
1055
+ lamination_detected=0
1045
1056
  r = 0 if se.outside else 1
1046
1057
  if se.subregion:
1047
1058
  if se.subregion.winding:
1059
+ winding_detected=1
1048
1060
  spw = self.CU_SPEZ_WEIGHT*1e3
1049
1061
  l = self.PS_LENGTH_CU[r]*1e-2
1050
1062
  slf = self.PS_FILFACTOR_CU[r]
@@ -1052,6 +1064,7 @@ class Isa7(object):
1052
1064
  continue
1053
1065
 
1054
1066
  if se.mcvtype or se.elements[0].is_lamination():
1067
+ lamination_detected=1
1055
1068
  try:
1056
1069
  spw = self.iron_loss_coefficients[se.mcvtype-1][
1057
1070
  'spec_weight']*1e3 # kg/m³
@@ -1062,6 +1075,9 @@ class Isa7(object):
1062
1075
  fillfact = 1
1063
1076
  #logger.warning('missing iron losscoeffs using defaults')
1064
1077
  m = scf*self.arm_length*se.area()*spw*fillfact
1078
+ if r == 1:
1079
+ masse_rotor_yoke += m
1080
+ section_rotor_yoke += se.area()
1065
1081
  self.mass[r]['iron'] += m
1066
1082
  else:
1067
1083
  try:
femagtools/job.py CHANGED
@@ -76,12 +76,14 @@ class Task(object):
76
76
  def set_stateofproblem(self, stateofproblem):
77
77
  self.stateofproblem = stateofproblem
78
78
 
79
- def add_file(self, fname, content=None):
79
+ def add_file(self, fname, content=None, append=False):
80
80
  """adds a file required by this task
81
81
 
82
82
  Args:
83
83
  fname: file name
84
- content: list of str written to file if not None"""
84
+ content: list of str written to file if not None
85
+ append: append file mode if true
86
+ """
85
87
  base = os.path.basename(fname)
86
88
  self.transfer_files.append(fname)
87
89
  if os.path.splitext(base)[-1] == '.fsl':
@@ -94,7 +96,8 @@ class Task(object):
94
96
  return
95
97
 
96
98
  # this file has to be created
97
- with open(os.path.join(self.directory, base), 'w') as f:
99
+ fmode = 'a' if append else 'w'
100
+ with open(os.path.join(self.directory, base), fmode) as f:
98
101
  f.writelines('\n'.join(content))
99
102
 
100
103
  def get_results(self):
@@ -143,6 +146,15 @@ class Task(object):
143
146
  result = dict(error=msg)
144
147
  return result
145
148
 
149
+ def read_nc(self):
150
+ "read most recent NC file and return result"
151
+ basedir = pathlib.Path(self.directory)
152
+ ncfiles = sorted(basedir.glob('*.nc'))
153
+ if not ncfiles:
154
+ return None
155
+ import femagtools.nc
156
+ return femagtools.nc.read(ncfiles[-1])
157
+
146
158
  def readErrorMessage(self, html=True):
147
159
  errstr = ""
148
160
  if html:
@@ -65,8 +65,8 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
65
65
  logger.warning(
66
66
  "single temperature DQ parameters: unable to fit temperature %s", temp)
67
67
 
68
- psid = rwdg*rlfe*dqp['psid']
69
- psiq = rwdg*rlfe*dqp['psiq']
68
+ psid = rwdg*rlfe*np.array(dqp['psid'])
69
+ psiq = rwdg*rlfe*np.array(dqp['psiq'])
70
70
  losses = __scale_losses(dqp['losses'], rlfe)
71
71
  losses['ef'] = dqpars[-1]['losses'].get('ef', [2.0, 2.0])
72
72
  losses['hf'] = dqpars[-1]['losses'].get('hf', [1.0, 1.0])
@@ -82,7 +82,7 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
82
82
  losses=losses,
83
83
  id=np.array(dqp['id'])/rwdg,
84
84
  iq=np.array(dqp['iq'])/rwdg,
85
- tcu1=temp[0],
85
+ tcu1=temp[0], tmag=temp[1],
86
86
  **opts)
87
87
  else:
88
88
  beta = dqp['beta']
@@ -96,7 +96,7 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
96
96
  losses=losses,
97
97
  beta=beta,
98
98
  i1=i1,
99
- tcu1=temp[0],
99
+ tcu1=temp[0], tmag=temp[1],
100
100
  **opts)
101
101
  return machine
102
102
 
@@ -117,7 +117,6 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
117
117
  pars.update(opts)
118
118
  return InductionMachine(pars)
119
119
 
120
-
121
120
  def create(bch, r1, ls, lfe=1, wdg=1):
122
121
  """create PmRelMachine from BCH
123
122
 
@@ -147,7 +146,8 @@ def create(bch, r1, ls, lfe=1, wdg=1):
147
146
  if 'ex_current' in bch.machine:
148
147
  raise ValueError("not yet implemented for EESM")
149
148
  machine = PmRelMachinePsidq(m, p, psid, psiq, r1*rlfe*rwdg**2,
150
- id, iq, ls*rwdg**2, losses=losses)
149
+ id, iq, ls*rwdg**2, losses=losses,
150
+ tmag=bch.magnet.get('Tmag', 20))
151
151
  try:
152
152
  machine.rotor_mass = rlfe*np.sum(bch.weights[1])
153
153
  except (IndexError, AttributeError):
@@ -172,7 +172,8 @@ def create(bch, r1, ls, lfe=1, wdg=1):
172
172
  machine = PmRelMachineLdq(m, p, psid=psid, psiq=psiq,
173
173
  r1=r1*rlfe*rwdg**2,
174
174
  i1=i1, beta=beta, ls=ls*rwdg**2,
175
- losses=losses)
175
+ losses=losses,
176
+ tmag=bch.magnet.get('Tmag', 20))
176
177
  try:
177
178
  machine.rotor_mass = rlfe*np.sum(bch.weights[1])
178
179
  except (IndexError, AttributeError):
@@ -10,7 +10,7 @@ from . import create_from_eecpars
10
10
  logger = logging.getLogger("femagtools.effloss")
11
11
 
12
12
 
13
- def iqd_tmech_umax(m, u1, with_mtpa, progress, speed_torque, iq, id, iex):
13
+ def iqd_tmech_umax(m, u1, with_mtpa, with_tmech, progress, speed_torque, iq, id, iex):
14
14
  """calculate iq, id for each load (n, T) from speed_torque at voltage u1
15
15
 
16
16
  Args:
@@ -25,9 +25,14 @@ def iqd_tmech_umax(m, u1, with_mtpa, progress, speed_torque, iq, id, iex):
25
25
  num_iv = round(nsamples/7)
26
26
  try:
27
27
  for i, nT in enumerate(speed_torque):
28
- iqde = m.iqd_tmech_umax(
29
- nT[1], 2*np.pi*nT[0]*m.p,
30
- u1, with_mtpa=with_mtpa)[:-1]
28
+ if with_tmech:
29
+ iqde = m.iqd_tmech_umax(
30
+ nT[1], 2*np.pi*nT[0]*m.p,
31
+ u1, with_mtpa=with_mtpa)[:-1]
32
+ else:
33
+ iqde = m.iqd_torque_umax(
34
+ nT[1], 2*np.pi*nT[0]*m.p,
35
+ u1, with_mtpa=with_mtpa)[:-1]
31
36
  iq[i] = iqde[0]
32
37
  id[i] = iqde[1]
33
38
  if len(iqde) > 2:
@@ -39,7 +44,8 @@ def iqd_tmech_umax(m, u1, with_mtpa, progress, speed_torque, iq, id, iex):
39
44
  finally:
40
45
  progress.close()
41
46
 
42
- def iqd_tmech_umax_multi(num_proc, ntmesh, m, u1, with_mtpa, publish=0):
47
+ def iqd_tmech_umax_multi(num_proc, ntmesh, m, u1, with_mtpa, with_tmech,
48
+ publish=0):
43
49
  """calculate iqd for sm and pm using multiproc
44
50
  """
45
51
  progress_readers = []
@@ -59,7 +65,7 @@ def iqd_tmech_umax_multi(num_proc, ntmesh, m, u1, with_mtpa, publish=0):
59
65
  iex.append(multiprocessing.Array('d', chunksize))
60
66
  iexk = iex[k]
61
67
  p = multiprocessing.Process(target=iqd_tmech_umax,
62
- args=(m, u1, with_mtpa,
68
+ args=(m, u1, with_mtpa, with_tmech,
63
69
  prog_writer,
64
70
  ntmesh.T[i:i+chunksize],
65
71
  iq[k], id[k], iexk))
@@ -254,14 +260,26 @@ def efficiency_losses_map(eecpars, u1, T, temp, n, npoints=(60, 40),
254
260
  rb['n'], rb['T'], npoints)
255
261
  else:
256
262
  nt = []
257
- iq, id = m.iqd_torque(T[-1])
263
+ if isinstance(m, (SynchronousMachineLdq, SynchronousMachinePsidq)):
264
+ iq, id, iex = m.iqd_torque(T[-1])
265
+ i1max = betai1(iq, id)[1]
266
+ w1type, tmax = m.w1_imax_umax(i1max, u1)
267
+ pmax = tmax*w1type/m.p
268
+ else:
269
+ iq, id = m.iqd_torque(T[-1])
270
+
258
271
  i1max = betai1(iq, id)[1]
259
272
  logger.info("%s %s", n, T)
260
273
  for nx in n:
261
274
  w1 = 2*np.pi*nx*m.p
262
- iq, id, tq = m.iqd_imax_umax(i1max, w1, u1, T[-1],
263
- with_tmech=with_tmech,
264
- with_mtpa=with_mtpa)
275
+ if isinstance(m, (SynchronousMachineLdq, SynchronousMachinePsidq)):
276
+ tq = T[-1]
277
+ if tq*w1/m.p > pmax:
278
+ tq = pmax/w1*m.p
279
+ else:
280
+ iq, id, tq = m.iqd_imax_umax(i1max, w1, u1, T[-1],
281
+ with_tmech=with_tmech,
282
+ with_mtpa=with_mtpa)
265
283
  if np.isclose(tq, T[-1]):
266
284
  tq = T[-1]
267
285
  for Tx in T:
@@ -271,12 +289,12 @@ def efficiency_losses_map(eecpars, u1, T, temp, n, npoints=(60, 40),
271
289
  raise ValueError("Speed, Torque Mesh is empty")
272
290
  nsamples = len(n)
273
291
  ntmesh = np.array(nt).T
274
-
275
292
  logger.info("total speed,torque samples %s", ntmesh.shape)
276
293
  if isinstance(m, (PmRelMachine, SynchronousMachine)):
277
294
  if num_proc > 1:
278
295
  iqd = iqd_tmech_umax_multi(num_proc, ntmesh, m, u1, with_mtpa,
279
- publish=progress)
296
+ with_tmech, publish=progress)
297
+
280
298
  else:
281
299
  class ProgressLogger:
282
300
  def __init__(self, nsamples, publish):
@@ -353,8 +371,13 @@ def efficiency_losses_map(eecpars, u1, T, temp, n, npoints=(60, 40),
353
371
  plfe2 = m.kpfe*m.iqd_plfe2(*iqd, f1)
354
372
  plmag = np.zeros_like(plfe2)
355
373
  plcu1 = m.iqd_plcu1(iqd[0], iqd[1], 2*np.pi*f1)
356
- plcu1_dc = [] # reserved for winding (dc, ac) losses
357
- plcu1_ac = []
374
+ try:
375
+ plcu1_dc = m.iqd_plcu1(iqd[0], iqd[1],
376
+ np.array([0.0 for i in f1])).tolist()
377
+ plcu1_ac = [i-j for i, j in zip(plcu1.tolist(), plcu1_dc)]
378
+ except:
379
+ plcu1_dc, plcu1_ac = [], []
380
+
358
381
  plcu2 = m.iqd_plcu2(*iqd)
359
382
  tfric = m.tfric
360
383
  logger.info("Iex %f %f",
femagtools/machine/im.py CHANGED
@@ -521,9 +521,10 @@ class InductionMachine(Component):
521
521
  wmrange = sorted([0, wmType, wmPullout, wmMax])
522
522
  elif wmMax < wmType:
523
523
  wmrange = sorted([0, wmMax])
524
+ elif wmType<0 or wmPullout<0 or wmMax<0:
525
+ wmrange = sorted([1, abs(min(wmMax,wmType, wmPullout)), abs(max(wmMax,wmType, wmPullout))])
524
526
  else:
525
527
  wmrange = sorted([0, wmType, wmMax])
526
-
527
528
  logger.info("Speed range %s", wmrange)
528
529
  wmlin = []
529
530
  dw = 0
@@ -679,11 +680,11 @@ def parident(workdir, engine, f1, u1, wdgcon,
679
680
  m[wdgk].pop('resistance')
680
681
  except KeyError:
681
682
  pass
682
-
683
+
683
684
  parstudy = femagtools.parstudy.ParameterStudy(
684
685
  workdir, condMat=condMat,
685
686
  magnetizingCurves=magnetizingCurves, cmd=cmd)
686
-
687
+
687
688
  builder = femagtools.fsl.Builder(kwargs.get('templatedirs', []))
688
689
  model = femagtools.model.MachineModel(m)
689
690
  # modelfiles = parstudy.setup_model(builder, model)
@@ -756,7 +757,8 @@ def parident(workdir, engine, f1, u1, wdgcon,
756
757
  barmodel = femagtools.model.MachineModel(rotorbar)
757
758
  extra_result_files = ['bar.dat']
758
759
  r = (da1-ag)/2
759
- task = job.add_task(_eval_ecsim())
760
+ #task = job.add_task(_eval_ecsim())
761
+ task = job.add_task(_eval_ecsim(), extra_result_files)
760
762
  logger.debug("Task %s rotobar workdir %s result files %s",
761
763
  task.id, task.directory, task.extra_result_files)
762
764
  task.set_stateofproblem('mag_dynamic')
@@ -793,7 +795,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
793
795
  logger.info('Started %s', status)
794
796
  status = engine.join()
795
797
  tend = time.time()
796
- logger.info("Elapsed time %d s Status %s",
798
+ logger.info("Elapssed time %d s Status %s",
797
799
  (tend-tstart), status)
798
800
  if any([x != 'C' for x in status]):
799
801
  raise ValueError("AC simulation failed")
@@ -818,16 +820,17 @@ def parident(workdir, engine, f1, u1, wdgcon,
818
820
  u1ref = u1ph
819
821
  psiref = u1ref/w1
820
822
 
821
- # def inoload(x, iml, ims, mexp):
822
- # """return noload current"""
823
- # return iml*x/psiref + ims*(x/psiref)**mexp
824
- # fitp, cov = so.curve_fit(inoload, psihtab, i10tab, (1, 1, 1))
825
- # iml, ims, mexp = fitp
826
- # logger.info("iml, ims, mexp %g, %g, %g",
827
- # iml, ims, mexp)
828
- # i1tab.insert(0, 0)
829
- # psi1_0.insert(0, 0)
830
- # i1_0.insert(0, 0)
823
+ # def inoload(x, iml, ims, mexp):
824
+ # """return noload current"""
825
+ # return iml*x/psiref + ims*(x/psiref)**mexp
826
+ # fitp, cov = so.curve_fit(inoload, psihtab, i10tab, (1, 1, 1))
827
+ # iml, ims, mexp = fitp
828
+ # logger.info("iml, ims, mexp %g, %g, %g",
829
+ # iml, ims, mexp)
830
+ # i1tab.insert(0, 0)
831
+ # psi1_0.insert(0, 0)
832
+ # i1_0.insert(0, 0)
833
+
831
834
  logger.info("psi1_0 %s", np.mean(psi1_0, axis=1))
832
835
  logger.info("psih %s", psih)
833
836
  logger.debug("psi1_0-psih %s", np.mean(psi1_0, axis=1)-psih)
@@ -848,7 +851,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
848
851
  hs = machine['stator'][slotmodel].get('slot_height',
849
852
  0.33*(machine['outer_diam']-da1))
850
853
  n = machine[wdgk]['num_wires']
851
- if 'dia_wire' in machine[wdgk]:
854
+ if 'dia_wire' in machine[wdgk] and machine[wdgk].get('dia_wire', 1e-3) !=0:
852
855
  aw = np.pi*machine[wdgk].get('dia_wire', 1e-3)**2/4
853
856
  else: # wire diameter from slot area
854
857
  aw = 0.75 * \
@@ -875,6 +878,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
875
878
  # kind='quadratic')(imref))
876
879
  psihref = float(log_interp1d(i1tab, psih)(imref))
877
880
  psi1ref = float(psi1(imref))
881
+
878
882
 
879
883
  lh = psihref/imref
880
884
  L1 = psi1ref/imref
@@ -905,8 +909,37 @@ def parident(workdir, engine, f1, u1, wdgcon,
905
909
  # r2 = results[1]['r2']
906
910
  # ls2 = results[1]['ls2']
907
911
  pfe = results[2]['pfe1'][0]
912
+
913
+ end_ring_section = machine['rotor']['Aring']
914
+ bore_diam = machine['bore_diam']
915
+ for key, value in machine['rotor'].items():
916
+ if isinstance(value, dict) and 'slot_height' in value:
917
+ slot_height_rotor = value['slot_height']
918
+ break
919
+ if slot_height_rotor is not None:
920
+ rayon = (bore_diam / 2) - slot_height_rotor/2
921
+ end_ring_length = 2 * np.pi * rayon
922
+ else:
923
+ end_ring_length = 0
924
+
925
+ end_ring_volume = end_ring_section*end_ring_length
926
+
927
+ for material_info in condMat:
928
+ if material_info.get('name') == machine.get('rotor', {}).get('material'):
929
+ spmaweight_rotor = material_info.get('spmaweight')
930
+ break
931
+ else:
932
+ spmaweight_rotor = 0
933
+ end_ring_mass = end_ring_volume * spmaweight_rotor*1e3
934
+
908
935
  rotor_mass = sum([results[2].get('conweight', 0),
909
936
  results[2].get('lamweight', 0)])
937
+ logger.info('Conductor mass in rotor = %s',results[2].get('conweight', 0))
938
+ logger.info('Lamination mass in rotor = %s',results[2].get('lamweight', 0))
939
+ logger.info('Rotor mass without end-ring = %s',rotor_mass)
940
+ rotor_mass += 2*end_ring_mass
941
+ logger.info('One end-ring mass = %s',end_ring_mass)
942
+ logger.info('Total rotor mass = %s',rotor_mass)
910
943
 
911
944
  n = machine[wdgk]['num_wires']
912
945
  g = loadsim['num_par_wdgs']
@@ -974,12 +1007,13 @@ class _eval_noloadrot():
974
1007
  i0 = np.linalg.norm(
975
1008
  femagtools.machine.T(0).dot(ire.T),
976
1009
  axis=0)/np.sqrt(2)
1010
+
977
1011
 
978
1012
  psi0 = np.array([np.linalg.norm(
979
1013
  femagtools.machine.T(0).dot(psire[:, k, :].T),
980
1014
  axis=0)/np.sqrt(2)
981
1015
  for k in range(ncurs)])
982
-
1016
+
983
1017
  # matrix (i x j x k) of curr, rotor pos, angle
984
1018
  Bamp = [[femagtools.airgap.fft(bags[:, 0], b, self.pmod)['Bamp']
985
1019
  for b in bags.T[1:]]