femagtools 1.7.3__py3-none-any.whl → 1.7.5__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/airgap.py +11 -0
- femagtools/bch.py +32 -21
- femagtools/dxfsl/area.py +1 -0
- femagtools/dxfsl/fslrenderer.py +3 -2
- femagtools/dxfsl/geom.py +39 -1
- femagtools/fsl.py +8 -17
- femagtools/heat_source_network.py +403 -0
- femagtools/machine/pm.py +79 -4
- femagtools/machine/utils.py +109 -51
- femagtools/model.py +12 -1
- femagtools/parstudy.py +4 -5
- femagtools/plot/char.py +5 -2
- femagtools/templates/basic_modpar.mako +2 -0
- femagtools/templates/{therm-static.mako → therm_static.mako} +15 -13
- femagtools/windings.py +5 -2
- {femagtools-1.7.3.dist-info → femagtools-1.7.5.dist-info}/METADATA +2 -2
- {femagtools-1.7.3.dist-info → femagtools-1.7.5.dist-info}/RECORD +24 -22
- {femagtools-1.7.3.dist-info → femagtools-1.7.5.dist-info}/WHEEL +1 -1
- tests/test_heat_source_network.py +21 -0
- tests/test_machine.py +4 -4
- {femagtools-1.7.3.dist-info → femagtools-1.7.5.dist-info}/LICENSE +0 -0
- {femagtools-1.7.3.dist-info → femagtools-1.7.5.dist-info}/entry_points.txt +0 -0
- {femagtools-1.7.3.dist-info → femagtools-1.7.5.dist-info}/top_level.txt +0 -0
femagtools/__init__.py
CHANGED
femagtools/airgap.py
CHANGED
@@ -52,3 +52,14 @@ def read(filename, pmod=0):
|
|
52
52
|
return(dict())
|
53
53
|
|
54
54
|
return fft(bag[0], bag[1], pmod)
|
55
|
+
|
56
|
+
if __name__ == '__main__':
|
57
|
+
import sys
|
58
|
+
import matplotlib.pyplot as plt
|
59
|
+
import femagtools.plot.fluxdens
|
60
|
+
ag = read(sys.argv[1])
|
61
|
+
fig, axs = plt.subplots(nrows=2)
|
62
|
+
femagtools.plot.fluxdens.airgap(ag, ax=axs[0])
|
63
|
+
femagtools.plot.fluxdens.airgap_fft(ag, ax=axs[1])
|
64
|
+
fig.tight_layout()
|
65
|
+
plt.show()
|
femagtools/bch.py
CHANGED
@@ -70,7 +70,7 @@ def sttylosses(losses):
|
|
70
70
|
except KeyError:
|
71
71
|
pass
|
72
72
|
return d
|
73
|
-
|
73
|
+
|
74
74
|
if sregs == {'StYoke', 'StTeeth'}:
|
75
75
|
return hysteddy('StYoke', 'StTeeth', losses)
|
76
76
|
if sregs == {'StJo', 'StZa'}:
|
@@ -95,9 +95,9 @@ def sttylosses(losses):
|
|
95
95
|
return l
|
96
96
|
return {}
|
97
97
|
|
98
|
-
def losses_mapping_external_rotor(losses):
|
98
|
+
def losses_mapping_external_rotor(losses):
|
99
99
|
styoke = 'rotor'
|
100
|
-
rotor = 'Iron'
|
100
|
+
rotor = 'Iron'
|
101
101
|
d = {}
|
102
102
|
try:
|
103
103
|
d['styoke'] = losses[styoke]
|
@@ -613,6 +613,7 @@ class Reader:
|
|
613
613
|
|
614
614
|
def __read_general_machine_data(self, content):
|
615
615
|
mcfiles = []
|
616
|
+
slotsides = 1
|
616
617
|
for l in content:
|
617
618
|
try:
|
618
619
|
if l.find('Armature Length') > -1:
|
@@ -631,8 +632,10 @@ class Reader:
|
|
631
632
|
self.machine['p_sim'] = int(l.split()[-1])
|
632
633
|
elif l.find('Total Number of Slots') > -1:
|
633
634
|
self.machine['Q'] = int(l.split()[-1])
|
635
|
+
elif l.find('Total Number of Slot-Sides') > -1:
|
636
|
+
slotsides = int(l.split()[-1])
|
634
637
|
elif l.find('Number of Slot-Sides sim.') > -1:
|
635
|
-
self.machine['qs_sim'] = int(l.split()[-1])
|
638
|
+
self.machine['qs_sim'] = int(l.split()[-1])*self.machine['Q']//slotsides
|
636
639
|
elif l.find('POC-File used in calculation') > -1:
|
637
640
|
self.machine['pocfile'] = l.split(
|
638
641
|
':')[-1].strip().replace('\\', '\\\\')
|
@@ -1046,7 +1049,7 @@ class Reader:
|
|
1046
1049
|
'''
|
1047
1050
|
diff = np.floor(np.abs(np.diff(idList)))
|
1048
1051
|
if idList[-1] == 0 and len(idList) > 2 and \
|
1049
|
-
|
1052
|
+
diff[-1] == 0:
|
1050
1053
|
idList = idList[:-1]
|
1051
1054
|
return idList
|
1052
1055
|
|
@@ -1062,7 +1065,8 @@ class Reader:
|
|
1062
1065
|
m.append([floatnan(x) for x in rec])
|
1063
1066
|
|
1064
1067
|
m = np.array(m).T
|
1065
|
-
|
1068
|
+
d = np.diff(m[1])
|
1069
|
+
ncols = (len(d)+1)//(len(d[d < 0])+1)
|
1066
1070
|
if ncols == 1 and len(m[1]) > 1 and m[1][0] != m[1][1]: # simple correction
|
1067
1071
|
ncols = 2
|
1068
1072
|
iq = np.reshape(m[1], (-1, ncols))[0]
|
@@ -1071,7 +1075,8 @@ class Reader:
|
|
1071
1075
|
ncols = ncols-1
|
1072
1076
|
|
1073
1077
|
id = np.reshape(m[0], (-1, ncols)).T[0]
|
1074
|
-
id
|
1078
|
+
if id[0] >= 0:
|
1079
|
+
id = self.__removeTrailingZero(id)
|
1075
1080
|
nrows = len(id)
|
1076
1081
|
if nrows > 1 and id[nrows-1] < id[nrows-2]:
|
1077
1082
|
nrows = nrows-1
|
@@ -1096,7 +1101,8 @@ class Reader:
|
|
1096
1101
|
m.append([floatnan(x) for x in rec])
|
1097
1102
|
|
1098
1103
|
m = np.array(m).T
|
1099
|
-
|
1104
|
+
d = np.diff(m[1])
|
1105
|
+
ncols = (len(d)+1)//(len(d[d < 0])+1)
|
1100
1106
|
if ncols == 1 and len(m[1]) > 1 and m[1][0] != m[1][1]: # simple correction
|
1101
1107
|
ncols = 2
|
1102
1108
|
iq = np.linspace(np.min(m[1]), np.max(m[1]), ncols)
|
@@ -1105,7 +1111,8 @@ class Reader:
|
|
1105
1111
|
ncols = ncols-1
|
1106
1112
|
|
1107
1113
|
id = np.reshape(m[0], (-1, ncols)).T[0]
|
1108
|
-
id
|
1114
|
+
if id[0] >= 0:
|
1115
|
+
id = self.__removeTrailingZero(id)
|
1109
1116
|
nrows = len(id)
|
1110
1117
|
if nrows > 1 and id[nrows-1] < id[nrows-2]:
|
1111
1118
|
nrows = nrows-1
|
@@ -1168,7 +1175,7 @@ class Reader:
|
|
1168
1175
|
for name in content[2].split('\t') if name][2:]
|
1169
1176
|
# outer rotor motor
|
1170
1177
|
if 'Iron' in subregs and \
|
1171
|
-
'Rotor' in subregs:
|
1178
|
+
'Rotor' in subregs:
|
1172
1179
|
self.external_rotor = True
|
1173
1180
|
logger.info("Stator Subregions: %s", subregs)
|
1174
1181
|
speed = float(content[0].split()[-1])/60.
|
@@ -1184,7 +1191,11 @@ class Reader:
|
|
1184
1191
|
if not m:
|
1185
1192
|
return
|
1186
1193
|
m = np.array(m).T
|
1187
|
-
|
1194
|
+
d = np.diff(m[1])
|
1195
|
+
if self.ldq:
|
1196
|
+
ncols = (len(d)+1)//(len(d[d > 0])+1)
|
1197
|
+
else:
|
1198
|
+
ncols = (len(d)+1)//(len(d[d < 0])+1)
|
1188
1199
|
if ncols == 1 and len(m[1]) > 1 and m[1][0] != m[1][1]:
|
1189
1200
|
ncols = 2
|
1190
1201
|
id = np.reshape(m[0], (-1, ncols)).T[0]
|
@@ -1229,9 +1240,9 @@ class Reader:
|
|
1229
1240
|
(nrows, ncols)).T.tolist()
|
1230
1241
|
for k, v in zip(cols, m[2:])})
|
1231
1242
|
ls['speed'] = speed
|
1232
|
-
if self.external_rotor:
|
1243
|
+
if self.external_rotor:
|
1233
1244
|
ls.update(losses_mapping_external_rotor(ls))
|
1234
|
-
else:
|
1245
|
+
else:
|
1235
1246
|
ls.update(sttylosses(ls))
|
1236
1247
|
if self.ldq:
|
1237
1248
|
self.ldq['losses'] = ls
|
@@ -1487,9 +1498,9 @@ class Reader:
|
|
1487
1498
|
def __read_losses(self, content):
|
1488
1499
|
losses = {}
|
1489
1500
|
i = 0
|
1490
|
-
# check if external rotor
|
1501
|
+
# check if external rotor
|
1491
1502
|
if self.weights[0][1] == 0.0 and \
|
1492
|
-
self.weights[0][-1] > 0:
|
1503
|
+
self.weights[0][-1] > 0:
|
1493
1504
|
self.external_rotor = True
|
1494
1505
|
# find results for angle:
|
1495
1506
|
while True:
|
@@ -1548,8 +1559,8 @@ class Reader:
|
|
1548
1559
|
losses['total'] += losses['staza']+losses['stajo']
|
1549
1560
|
elif len(rec) == 1:
|
1550
1561
|
t = l.split(':')[-1].strip()
|
1551
|
-
if t == 'Iron':
|
1552
|
-
if self.external_rotor:
|
1562
|
+
if t == 'Iron':
|
1563
|
+
if self.external_rotor:
|
1553
1564
|
losses['rotfe'] = floatnan(rec[0])
|
1554
1565
|
losses['total'] += losses['rotfe']
|
1555
1566
|
else:
|
@@ -1561,14 +1572,14 @@ class Reader:
|
|
1561
1572
|
continue
|
1562
1573
|
|
1563
1574
|
if _rotloss.search(l):
|
1564
|
-
if l.find('StZa') > -1:
|
1575
|
+
if l.find('StZa') > -1:
|
1565
1576
|
self.external_rotor = True
|
1566
1577
|
rec = self.__findNums(content[i+2])
|
1567
1578
|
if len(rec) == 1:
|
1568
|
-
if self.external_rotor:
|
1579
|
+
if self.external_rotor:
|
1569
1580
|
losses['staza'] = floatnan(rec[0])
|
1570
1581
|
losses['total'] += losses['staza']
|
1571
|
-
else:
|
1582
|
+
else:
|
1572
1583
|
rotfe = floatnan(rec[0])
|
1573
1584
|
losses['rotfe'] += rotfe
|
1574
1585
|
losses['total'] += rotfe
|
@@ -1602,7 +1613,7 @@ class Reader:
|
|
1602
1613
|
if content[i+1].split() == ['rotf', '----']:
|
1603
1614
|
losses['rotfe'] = sum([floatnan(x) for x in rec])
|
1604
1615
|
losses['total'] += losses['rotfe']
|
1605
|
-
|
1616
|
+
|
1606
1617
|
if content[i+1].split() == ['Iron', '----']: # external rotor
|
1607
1618
|
losses['rotfe'] = sum([floatnan(x) for x in rec])
|
1608
1619
|
losses['total'] += losses['rotfe']
|
femagtools/dxfsl/area.py
CHANGED
femagtools/dxfsl/fslrenderer.py
CHANGED
@@ -189,7 +189,7 @@ class FslRenderer(object):
|
|
189
189
|
'-- min_corner = {}, {}'.format(
|
190
190
|
geom.start_min_corner(0),
|
191
191
|
geom.start_min_corner(1)),
|
192
|
-
'-- max_corner = {}, {}'.format(
|
192
|
+
'-- max_corner start = {}, {}'.format(
|
193
193
|
geom.start_max_corner(0),
|
194
194
|
geom.start_max_corner(1)),
|
195
195
|
'\n']
|
@@ -211,11 +211,12 @@ class FslRenderer(object):
|
|
211
211
|
'r, phi = c2pr(x0, y0)',
|
212
212
|
'x1, y1 = pr2c(r1, phi)',
|
213
213
|
'x2, y2 = pr2c(r1, {}*math.pi/parts)'.format(slice),
|
214
|
+
f'r = {geom.dist_end_max_corner()}',
|
214
215
|
'x3, y3 = pr2c(r, {}*math.pi/parts)'.format(slice),
|
215
216
|
'nc_line(x0, y0, x1, y1, 0)',
|
216
217
|
'nc_circle_m(x1, y1, x2, y2, 0.0, 0.0, 0)',
|
217
218
|
'nc_line(x2, y2, x3, y3, 0)',
|
218
|
-
'x0, y0 = pr2c(r1 - hair/2, math.pi/parts)',
|
219
|
+
'x0, y0 = pr2c(r1 - hair/2, math.pi/parts/2)',
|
219
220
|
'create_mesh_se(x0, y0)',
|
220
221
|
'\n',
|
221
222
|
'outer_da_start = {}'.format(
|
femagtools/dxfsl/geom.py
CHANGED
@@ -2478,7 +2478,8 @@ class Geometry(object):
|
|
2478
2478
|
groups_inside = {g.id: g for g in grouplist}
|
2479
2479
|
area.areas_inside = groups_inside
|
2480
2480
|
areas_outside.append(area)
|
2481
|
-
for g in
|
2481
|
+
for g in grouplist:
|
2482
|
+
g.group_is_inside = True
|
2482
2483
|
alist = groups.get(g.id, [])
|
2483
2484
|
alist.append(area)
|
2484
2485
|
groups[g.id] = alist
|
@@ -2532,6 +2533,11 @@ class Geometry(object):
|
|
2532
2533
|
for area in area_list:
|
2533
2534
|
if self.create_aux_lines(area, rightangle, leftangle):
|
2534
2535
|
done = True
|
2536
|
+
main_groups = [g for g in self.areagroup_list
|
2537
|
+
if not g.group_is_inside]
|
2538
|
+
if len(main_groups) > 1:
|
2539
|
+
if self.create_outside_aux_lines(main_groups):
|
2540
|
+
done = True
|
2535
2541
|
else:
|
2536
2542
|
logger.debug("-> start create_auxiliary_lines")
|
2537
2543
|
self.set_areas_inside_for_all_areas()
|
@@ -2856,6 +2862,38 @@ class Geometry(object):
|
|
2856
2862
|
area.get_id())
|
2857
2863
|
return done
|
2858
2864
|
|
2865
|
+
def create_outside_aux_lines(self, grouplist):
|
2866
|
+
done = False
|
2867
|
+
aux_color = 'blue'
|
2868
|
+
aux_linestyle = 'dotted'
|
2869
|
+
|
2870
|
+
i = 0
|
2871
|
+
gaps = []
|
2872
|
+
for group in grouplist:
|
2873
|
+
i += 1
|
2874
|
+
for g in grouplist[i:]:
|
2875
|
+
gaps += group.get_lowest_gap_list(g,
|
2876
|
+
self.center, self.max_radius,
|
2877
|
+
None, None)
|
2878
|
+
gaps.sort()
|
2879
|
+
|
2880
|
+
l = len(grouplist) -1
|
2881
|
+
for d, points, token, id in gaps[:l]:
|
2882
|
+
logger.info("Token %s", token)
|
2883
|
+
line = Line(Element(start=points[0],
|
2884
|
+
end=points[1]),
|
2885
|
+
color=aux_color,
|
2886
|
+
linestyle=aux_linestyle,
|
2887
|
+
attr='outside_auxline')
|
2888
|
+
n1 = self.find_the_node(line.node1(ndec))
|
2889
|
+
n2 = self.find_the_node(line.node2(ndec))
|
2890
|
+
if n1 and n2:
|
2891
|
+
self.add_element(line,
|
2892
|
+
rtol=self.rtol,
|
2893
|
+
atol=self.atol)
|
2894
|
+
done = True
|
2895
|
+
return done
|
2896
|
+
|
2859
2897
|
def set_rotor(self):
|
2860
2898
|
self.sym_counterpart = 1
|
2861
2899
|
self.sym_part = 0
|
femagtools/fsl.py
CHANGED
@@ -106,6 +106,7 @@ class Builder:
|
|
106
106
|
params['show_plots'] = model.stator[templ].get('plot', False)
|
107
107
|
params['write_fsl'] = True
|
108
108
|
params['airgap'] = -1.0
|
109
|
+
params['nodedist'] = model.stator.get('nodedist', 1)
|
109
110
|
pos = 'in' if model.external_rotor else 'out'
|
110
111
|
params['part'] = ('stator', pos)
|
111
112
|
conv = convert(model.stator['dxffile']['name'], **params)
|
@@ -491,6 +492,11 @@ class Builder:
|
|
491
492
|
if not hasattr(model, 'stator'):
|
492
493
|
setattr(model, 'stator', {})
|
493
494
|
model.stator['num_slots'] = conv.get('tot_num_slot')
|
495
|
+
if model.get('num_agnodes', 0) == 0:
|
496
|
+
model.set_value('agndst', conv['agndst']*1e-3)
|
497
|
+
logger.info("num poles %d num slots %d outer diameter %.4f m agndst %.4f mm",
|
498
|
+
model.poles, model.stator['num_slots'],
|
499
|
+
model.outer_diam, model.agndst*1e3)
|
494
500
|
if params['full_model']:
|
495
501
|
model.stator['num_slots_gen'] = model.stator['num_slots']
|
496
502
|
else:
|
@@ -531,21 +537,6 @@ class Builder:
|
|
531
537
|
logger.info("create new model '%s'", model.name)
|
532
538
|
if model.is_dxffile():
|
533
539
|
self.prepare_model_with_dxf(model)
|
534
|
-
if model.get('num_agnodes', 0) == 0:
|
535
|
-
from femagtools.dxfsl.fslrenderer import agndst
|
536
|
-
ag = model.get('airgap')
|
537
|
-
model.set_value(
|
538
|
-
'agndst',
|
539
|
-
agndst(model.get('bore_diam'),
|
540
|
-
model.get('bore_diam') - 2*ag,
|
541
|
-
model.stator.get('num_slots'),
|
542
|
-
model.get('poles'),
|
543
|
-
model.dxffile.get('nodedist')))
|
544
|
-
|
545
|
-
logger.info(" num poles %d num slots %d outer diameter %.4f m",
|
546
|
-
model.poles, model.stator['num_slots'],
|
547
|
-
model.outer_diam)
|
548
|
-
|
549
540
|
else:
|
550
541
|
self.prepare_stator(model)
|
551
542
|
if hasattr(model, 'magnet'):
|
@@ -553,9 +544,9 @@ class Builder:
|
|
553
544
|
self.prepare_diameter(model)
|
554
545
|
if self.fsl_stator and model.get('num_agnodes', 0) == 0:
|
555
546
|
from femagtools.dxfsl.fslrenderer import agndst
|
556
|
-
if model.get('agndst'):
|
547
|
+
if model.get('agndst',0):
|
557
548
|
pass
|
558
|
-
else:
|
549
|
+
else:
|
559
550
|
ag = model.get('airgap')
|
560
551
|
model.set_value(
|
561
552
|
'agndst',
|