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 +1 -1
- femagtools/bch.py +49 -15
- femagtools/ecloss.py +12 -4
- femagtools/femag.py +3 -2
- femagtools/fsl.py +28 -10
- femagtools/isa7.py +16 -0
- femagtools/job.py +15 -3
- femagtools/machine/__init__.py +8 -7
- femagtools/machine/effloss.py +37 -14
- femagtools/machine/im.py +51 -17
- femagtools/machine/pm.py +2 -1
- femagtools/machine/sizing.py +91 -5
- femagtools/machine/sm.py +69 -70
- femagtools/machine/utils.py +37 -14
- femagtools/multiproc.py +6 -0
- femagtools/parstudy.py +20 -14
- femagtools/plot/bch.py +1 -1
- femagtools/shortcircuit.py +15 -9
- femagtools/templates/FE-losses.mako +0 -3
- femagtools/templates/gen_hairpin_winding.mako +8 -6
- femagtools/templates/noloadflux-rot.mako +1 -0
- femagtools/ts.py +38 -7
- femagtools/utils.py +5 -1
- femagtools/zmq.py +4 -1
- {femagtools-1.8.12.dist-info → femagtools-1.8.14.dist-info}/METADATA +3 -2
- {femagtools-1.8.12.dist-info → femagtools-1.8.14.dist-info}/RECORD +32 -32
- {femagtools-1.8.12.dist-info → femagtools-1.8.14.dist-info}/WHEEL +1 -1
- tests/test_bchreader.py +5 -5
- tests/test_fsl.py +2 -2
- {femagtools-1.8.12.dist-info → femagtools-1.8.14.dist-info}/entry_points.txt +0 -0
- {femagtools-1.8.12.dist-info → femagtools-1.8.14.dist-info/licenses}/LICENSE +0 -0
- {femagtools-1.8.12.dist-info → femagtools-1.8.14.dist-info}/top_level.txt +0 -0
femagtools/__init__.py
CHANGED
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:
|
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
|
-
|
1064
|
-
|
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
|
-
|
1379
|
-
|
1380
|
-
|
1381
|
-
|
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'] =
|
1395
|
-
self.dqPar['psiq'] =
|
1396
|
-
|
1397
|
-
|
1398
|
-
|
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
|
-
|
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'])
|
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=
|
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
|
-
|
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
|
-
|
450
|
-
|
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
|
-
|
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
|
-
|
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:
|
femagtools/machine/__init__.py
CHANGED
@@ -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):
|
femagtools/machine/effloss.py
CHANGED
@@ -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
|
-
|
29
|
-
|
30
|
-
|
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,
|
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
|
-
|
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
|
-
|
263
|
-
|
264
|
-
|
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
|
-
|
357
|
-
|
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("
|
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
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
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:]]
|