femagtools 1.8.1__py3-none-any.whl → 1.8.2__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/dxfsl/area.py +45 -1
- femagtools/dxfsl/areabuilder.py +93 -45
- femagtools/dxfsl/converter.py +51 -26
- femagtools/dxfsl/fslrenderer.py +5 -4
- femagtools/dxfsl/geom.py +123 -137
- femagtools/dxfsl/machine.py +161 -9
- femagtools/dxfsl/shape.py +46 -1
- femagtools/dxfsl/svgparser.py +1 -1
- femagtools/dxfsl/symmetry.py +115 -30
- femagtools/fsl.py +10 -10
- femagtools/machine/__init__.py +5 -4
- femagtools/machine/afpm.py +41 -15
- femagtools/machine/sizing.py +189 -11
- femagtools/machine/utils.py +2 -2
- femagtools/mcv.py +2 -3
- femagtools/model.py +4 -3
- femagtools/parstudy.py +1 -1
- femagtools/plot/nc.py +2 -2
- {femagtools-1.8.1.dist-info → femagtools-1.8.2.dist-info}/METADATA +1 -1
- {femagtools-1.8.1.dist-info → femagtools-1.8.2.dist-info}/RECORD +26 -26
- tests/test_mcv.py +1 -1
- {femagtools-1.8.1.dist-info → femagtools-1.8.2.dist-info}/LICENSE +0 -0
- {femagtools-1.8.1.dist-info → femagtools-1.8.2.dist-info}/WHEEL +0 -0
- {femagtools-1.8.1.dist-info → femagtools-1.8.2.dist-info}/entry_points.txt +0 -0
- {femagtools-1.8.1.dist-info → femagtools-1.8.2.dist-info}/top_level.txt +0 -0
femagtools/dxfsl/shape.py
CHANGED
@@ -11,7 +11,7 @@ from __future__ import print_function
|
|
11
11
|
import numpy as np
|
12
12
|
import logging
|
13
13
|
from .functions import less_equal, greater_equal
|
14
|
-
from .functions import distance, line_m, line_n
|
14
|
+
from .functions import distance, line_m, line_n, mirror_point
|
15
15
|
from .functions import point, points_are_close, points_on_arc
|
16
16
|
from .functions import alpha_line, alpha_angle, alpha_triangle
|
17
17
|
from .functions import normalise_angle, min_angle, max_angle, get_angle_of_arc
|
@@ -54,6 +54,9 @@ class Shape(object):
|
|
54
54
|
def classname(self):
|
55
55
|
return "Shape"
|
56
56
|
|
57
|
+
def clone(self):
|
58
|
+
return None
|
59
|
+
|
57
60
|
def set_my_color(self, color):
|
58
61
|
self.my_color = color
|
59
62
|
|
@@ -314,6 +317,32 @@ class Shape(object):
|
|
314
317
|
def is_near(self, n):
|
315
318
|
return False
|
316
319
|
|
320
|
+
def mirror_shape(self, geom_center, axis_m, axis_n):
|
321
|
+
n2 = mirror_point(self.start(), geom_center, axis_m, axis_n)
|
322
|
+
n1 = mirror_point(self.end(), geom_center, axis_m, axis_n)
|
323
|
+
|
324
|
+
el = None
|
325
|
+
if isinstance(self, Line):
|
326
|
+
el = Line(Element(start=n1, end=n2))
|
327
|
+
|
328
|
+
elif isinstance(self, Arc):
|
329
|
+
c = mirror_point(self.center, geom_center, axis_m, axis_n)
|
330
|
+
alpha1 = alpha_line(c, n1)
|
331
|
+
alpha2 = alpha_line(c, n2)
|
332
|
+
el = Arc(Element(center=c,
|
333
|
+
radius=self.radius,
|
334
|
+
start_angle=alpha1*180/np.pi,
|
335
|
+
end_angle=alpha2*180/np.pi))
|
336
|
+
|
337
|
+
elif isinstance(self, Circle):
|
338
|
+
c = mirror_point(self.center, geom_center, axis_m, axis_n)
|
339
|
+
el = Circle(Element(center=c,
|
340
|
+
radius=self.radius))
|
341
|
+
|
342
|
+
if el:
|
343
|
+
el.copy_attributes(self)
|
344
|
+
return el
|
345
|
+
|
317
346
|
def print_nodes(self):
|
318
347
|
return " n1={}/n2={}".format(self.n1, self.n2)
|
319
348
|
|
@@ -354,6 +383,10 @@ class Circle(Shape):
|
|
354
383
|
def classname(self):
|
355
384
|
return "Circle"
|
356
385
|
|
386
|
+
def clone(self):
|
387
|
+
return Circle(Element(center=self.center,
|
388
|
+
radius=self.radius))
|
389
|
+
|
357
390
|
def render(self, renderer, color='blue', with_nodes=False):
|
358
391
|
tmp_color = self.get_my_color()
|
359
392
|
if not tmp_color:
|
@@ -742,6 +775,14 @@ class Arc(Circle):
|
|
742
775
|
def classname(self):
|
743
776
|
return "Arc"
|
744
777
|
|
778
|
+
def clone(self):
|
779
|
+
alpha_start = alpha_line(self.center, self.p1)
|
780
|
+
alpha_end = alpha_line(self.center, self.p2)
|
781
|
+
return Arc(Element(center=self.center,
|
782
|
+
radius=self.radius,
|
783
|
+
start_angle=alpha_start*180/np.pi,
|
784
|
+
end_angle=alpha_end*180/np.pi))
|
785
|
+
|
745
786
|
def render(self, renderer, color='blue', with_nodes=False):
|
746
787
|
tmp_color = self.get_my_color()
|
747
788
|
if not tmp_color:
|
@@ -1285,6 +1326,10 @@ class Line(Shape):
|
|
1285
1326
|
def classname(self):
|
1286
1327
|
return "Line"
|
1287
1328
|
|
1329
|
+
def clone(self):
|
1330
|
+
return Line(Element(start=self.p1,
|
1331
|
+
end=self.p2))
|
1332
|
+
|
1288
1333
|
def render(self, renderer, color='blue', with_nodes=False):
|
1289
1334
|
tmp_color = self.get_my_color()
|
1290
1335
|
if not tmp_color:
|
femagtools/dxfsl/svgparser.py
CHANGED
@@ -106,7 +106,7 @@ def svgshapes(svgfile):
|
|
106
106
|
for p in svg.findall(".//{http://www.w3.org/2000/svg}path"):
|
107
107
|
m = bcolor.search(p.get('style'))
|
108
108
|
if m:
|
109
|
-
logger.
|
109
|
+
logger.debug("subregion %d: %s", sr, m.groups()[0])
|
110
110
|
yield from get_shapes(p.get('d'))
|
111
111
|
sr += 1
|
112
112
|
for p in svg.findall(".//{http://www.w3.org/2000/svg}line"):
|
femagtools/dxfsl/symmetry.py
CHANGED
@@ -12,6 +12,7 @@ import logging
|
|
12
12
|
import sys
|
13
13
|
from femagtools.dxfsl.shape import Element, Line
|
14
14
|
from femagtools.dxfsl.area import Area
|
15
|
+
import femagtools.dxfsl.area as AREA
|
15
16
|
from femagtools.dxfsl.functions import alpha_angle, positive_angle, is_same_angle
|
16
17
|
from femagtools.dxfsl.functions import min_angle, max_angle, gcd, point
|
17
18
|
from femagtools.dxfsl.functions import less_equal, less, points_are_close
|
@@ -100,24 +101,25 @@ class Symmetry(object):
|
|
100
101
|
return positive_angle(alpha_angle(self.startangle,
|
101
102
|
a.get_mid_angle(self.geom.center)))
|
102
103
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
104
|
+
def area_list_entry(self, a):
|
105
|
+
return (round(a.get_alpha(self.geom.center), 3),
|
106
|
+
round(a.min_dist, 1),
|
107
|
+
round(a.height, 1),
|
108
|
+
self.calc_mid_angle(a),
|
109
|
+
a)
|
109
110
|
|
110
|
-
|
111
|
+
def build_area_list(self, types=()):
|
112
|
+
arealist = self.geom.list_of_areas()
|
113
|
+
if types:
|
114
|
+
arealist = [a for a in arealist if a.type in types]
|
111
115
|
|
112
116
|
areas = []
|
113
117
|
for a in arealist:
|
114
|
-
areas.append((
|
115
|
-
round(a.min_dist, 1),
|
116
|
-
round(a.height, 1),
|
117
|
-
self.calc_mid_angle(a),
|
118
|
-
a))
|
118
|
+
areas.append(self.area_list_entry(a))
|
119
119
|
areas.sort(reverse=True)
|
120
|
+
return areas
|
120
121
|
|
122
|
+
def build_results(self, areas):
|
121
123
|
a0_alpha, a0_min_dist, a0_height, a0_mid_angle, a0 = areas[0]
|
122
124
|
equal_areas = [(a0_mid_angle, a0)]
|
123
125
|
check_rslt = []
|
@@ -146,6 +148,86 @@ class Symmetry(object):
|
|
146
148
|
rslt['area'] = a0
|
147
149
|
rslt['areasize'] = areasize
|
148
150
|
check_rslt.append((areasize, rslt))
|
151
|
+
return check_rslt
|
152
|
+
|
153
|
+
def get_winding_symmetry(self, inside=False):
|
154
|
+
if inside:
|
155
|
+
areas = [self.area_list_entry(a) for a in self.geom.list_of_areas()
|
156
|
+
if not a.close_to_ag]
|
157
|
+
else:
|
158
|
+
areas = self.build_area_list((AREA.TYPE_WINDINGS,))
|
159
|
+
|
160
|
+
logger.debug("begin of Symmetry::get_winding_symmetry: %s areas available", len(areas))
|
161
|
+
if not areas:
|
162
|
+
logger.debug("end of Symmetry::get_winding_symmetry: no areas")
|
163
|
+
return 0
|
164
|
+
|
165
|
+
check_rslt = self.build_results(areas)
|
166
|
+
logger.debug("%s results available", len(check_rslt))
|
167
|
+
[logger.debug("Result: %s", rslt) for rslt in check_rslt]
|
168
|
+
|
169
|
+
parts, start_delta = self.get_symmetry_parts(check_rslt)
|
170
|
+
if parts <= 1:
|
171
|
+
return 0
|
172
|
+
self.create_cut_lines(parts, start_delta)
|
173
|
+
|
174
|
+
sym = self.geom_part * parts
|
175
|
+
delta = 2*np.pi/sym
|
176
|
+
self.set_symmetry_parameters(self.startangle, parts, delta)
|
177
|
+
|
178
|
+
logger.debug("end of Symmetry::get_winding_symmetry: parts=%s", parts)
|
179
|
+
return parts
|
180
|
+
|
181
|
+
def get_magnet_symmetry(self):
|
182
|
+
areas = self.build_area_list((AREA.TYPE_MAGNET_AIRGAP, AREA.TYPE_MAGNET_RECT,))
|
183
|
+
air = self.build_area_list((AREA.TYPE_AIR,))
|
184
|
+
mag_list = [a for a in self.geom.list_of_areas() if a.is_magnet()]
|
185
|
+
air_list = [a for a in self.geom.list_of_areas() if a.is_air()]
|
186
|
+
sz_list = [a.area_size() for a in self.geom.list_of_areas()]
|
187
|
+
max_sz = max(sz_list)
|
188
|
+
for a in air_list:
|
189
|
+
if a.area_size() < max_sz * 0.005:
|
190
|
+
continue
|
191
|
+
for m in mag_list:
|
192
|
+
if a.is_touching(m):
|
193
|
+
areas.append(self.area_list_entry(a))
|
194
|
+
break
|
195
|
+
|
196
|
+
logger.debug("begin of Symmetry::get_magnet_symmetry: %s areas available", len(areas))
|
197
|
+
if not areas:
|
198
|
+
logger.debug("end of Symmetry::get_magnet_symmetry: no areas")
|
199
|
+
return 0
|
200
|
+
|
201
|
+
check_rslt = self.build_results(areas)
|
202
|
+
logger.debug("%s results available", len(check_rslt))
|
203
|
+
[logger.debug("Result: %s", rslt) for rslt in check_rslt]
|
204
|
+
for sz, rslt in check_rslt:
|
205
|
+
if not rslt.get('startdelta', 0.0) == 0.0:
|
206
|
+
return 0 # not proper
|
207
|
+
if rslt.get('halfslice', None):
|
208
|
+
return 0 # not proper
|
209
|
+
|
210
|
+
parts, start_delta = self.get_symmetry_parts(check_rslt)
|
211
|
+
if parts <= 1:
|
212
|
+
return 0
|
213
|
+
self.create_cut_lines(parts, start_delta)
|
214
|
+
|
215
|
+
sym = self.geom_part * parts
|
216
|
+
delta = 2*np.pi/sym
|
217
|
+
self.set_symmetry_parameters(self.startangle, parts, delta)
|
218
|
+
|
219
|
+
logger.debug("end of Symmetry::get_magnet_symmetry: parts=%s", parts)
|
220
|
+
return parts
|
221
|
+
|
222
|
+
def find_symmetry(self):
|
223
|
+
areas = self.build_area_list()
|
224
|
+
|
225
|
+
logger.debug("begin of Symmetry::find_symmetry: %s areas available", len(areas))
|
226
|
+
if not areas:
|
227
|
+
logger.debug("end of Symmetry::find_symmetry: no areas")
|
228
|
+
return 0
|
229
|
+
|
230
|
+
check_rslt = self.build_results(areas)
|
149
231
|
|
150
232
|
parts, start_delta = self.get_symmetry_parts(check_rslt)
|
151
233
|
if parts < 2:
|
@@ -156,18 +238,7 @@ class Symmetry(object):
|
|
156
238
|
self.startangle = self.startangle - self.delta_angle_corr
|
157
239
|
self.endangle = self.endangle - self.delta_angle_corr
|
158
240
|
|
159
|
-
self.
|
160
|
-
for alpha in self.symmetry_lines(parts,
|
161
|
-
self.startangle,
|
162
|
-
start_delta,
|
163
|
-
self.endangle):
|
164
|
-
plus = self.geom.max_radius / 10
|
165
|
-
min_radius = max(10, self.geom.min_radius - plus)
|
166
|
-
p1 = point(self.geom.center, min_radius, alpha)
|
167
|
-
p2 = point(self.geom.center, self.geom.max_radius + plus, alpha)
|
168
|
-
line = Line(Element(start=p1, end=p2))
|
169
|
-
line.init_attributes(color='green')
|
170
|
-
self.geom.add_cut_line(line)
|
241
|
+
self.create_cut_lines(parts, start_delta)
|
171
242
|
|
172
243
|
logger.debug("end of Symmetry::find_symmetry: -> %s", parts)
|
173
244
|
return parts
|
@@ -375,9 +446,6 @@ class Symmetry(object):
|
|
375
446
|
|
376
447
|
dlist = []
|
377
448
|
x = 0
|
378
|
-
# logger.info("inx: %s", inx)
|
379
|
-
# [logger.info("%s deltas: %s", n, d) for n, d in deltas]
|
380
|
-
# [logger.info("area: %s", m) for m, a in area_list]
|
381
449
|
|
382
450
|
for i in inx:
|
383
451
|
for n in range(x, i):
|
@@ -833,6 +901,20 @@ class Symmetry(object):
|
|
833
901
|
logger.debug("return %s parts", parts)
|
834
902
|
return parts
|
835
903
|
|
904
|
+
def create_cut_lines(self, parts, start_delta):
|
905
|
+
self.geom.clear_cut_lines()
|
906
|
+
for alpha in self.symmetry_lines(parts,
|
907
|
+
self.startangle,
|
908
|
+
start_delta,
|
909
|
+
self.endangle):
|
910
|
+
plus = self.geom.max_radius / 10
|
911
|
+
min_radius = max(10, self.geom.min_radius - plus)
|
912
|
+
p1 = point(self.geom.center, min_radius, alpha)
|
913
|
+
p2 = point(self.geom.center, self.geom.max_radius + plus, alpha)
|
914
|
+
line = Line(Element(start=p1, end=p2))
|
915
|
+
line.init_attributes(color='green')
|
916
|
+
self.geom.add_cut_line(line)
|
917
|
+
|
836
918
|
def symmetry_lines(self, parts, startangle, start_delta, endangle):
|
837
919
|
logger.debug("begin symmetry_lines from %s to %s with start %s",
|
838
920
|
startangle,
|
@@ -858,14 +940,17 @@ class Symmetry(object):
|
|
858
940
|
yield start
|
859
941
|
|
860
942
|
# Damit man anschliessend ohne Umstände schneiden kann.
|
861
|
-
self.
|
862
|
-
|
943
|
+
self.set_symmetry_parameters(sym_startangle, parts, delta)
|
944
|
+
logger.debug("end symmetry_lines")
|
945
|
+
|
946
|
+
def set_symmetry_parameters(self, startangle, parts, delta):
|
947
|
+
self.geom.sym_startangle = startangle
|
948
|
+
self.geom.sym_endangle = startangle + delta
|
863
949
|
self.geom.sym_slices = parts
|
864
950
|
self.geom.sym_slice_angle = delta
|
865
951
|
self.geom.sym_area = Area([], (0,0), 0.0)
|
866
952
|
self.geom.sym_area.sym_startangle = self.geom.sym_startangle
|
867
953
|
self.geom.sym_area.sym_endangle = self.geom.sym_endangle
|
868
|
-
logger.debug("end symmetry_lines")
|
869
954
|
|
870
955
|
def check_symmetry_of_mirror(self, mirror_geom, mirrorangle):
|
871
956
|
logger.debug("begin of Symmetry::check_symmetry_of_mirror")
|
femagtools/fsl.py
CHANGED
@@ -158,13 +158,13 @@ class Builder:
|
|
158
158
|
if templ == 'statorFsl':
|
159
159
|
# obsolete
|
160
160
|
th_props = [' ']
|
161
|
-
try:
|
161
|
+
try:
|
162
162
|
th_props = [f'stator_density = {model.stator["density"]}',
|
163
163
|
f'stator_thcond = {model.stator["thcond"]}',
|
164
164
|
f'stator_thcap = {model.stator["thcap"]}',
|
165
165
|
]
|
166
|
-
except:
|
167
|
-
pass
|
166
|
+
except:
|
167
|
+
pass
|
168
168
|
if 'parameter' in model.stator['statorFsl']:
|
169
169
|
return self.render_template(
|
170
170
|
model.stator['statorFsl']['content_template'],
|
@@ -226,20 +226,20 @@ class Builder:
|
|
226
226
|
self.fsl_rotor = True
|
227
227
|
# obsolete
|
228
228
|
th_props = [' ']
|
229
|
-
try:
|
229
|
+
try:
|
230
230
|
logger.info(model.magnet)
|
231
231
|
th_props = [f'rotor_density = {model["magnet"]["density"]}',
|
232
232
|
f'rotor_thcond = {model["magnet"]["thcond"]}',
|
233
233
|
f'rotor_thcap = {model["magnet"]["thcap"]}'
|
234
234
|
]
|
235
|
-
except:
|
236
|
-
pass
|
235
|
+
except:
|
236
|
+
pass
|
237
237
|
if 'parameter' in model.magnet['magnetFsl']:
|
238
238
|
return mcv + self.render_template(
|
239
239
|
model.magnet['magnetFsl']['content_template'],
|
240
240
|
model.magnet['magnetFsl']['parameter']) + th_props
|
241
241
|
elif model.magnet['magnetFsl'].get('content'):
|
242
|
-
return mcv + model.magnet['magnetFsl']['content'].split('\n')
|
242
|
+
return mcv + model.magnet['magnetFsl']['content'].split('\n')
|
243
243
|
if isinstance(model.magnet['magnetFsl']
|
244
244
|
['content_template'], str):
|
245
245
|
with open(model.magnet['magnetFsl']
|
@@ -248,7 +248,7 @@ class Builder:
|
|
248
248
|
else:
|
249
249
|
templ = model.magnet['magnetFsl']['content_template']
|
250
250
|
return mcv + self.render_template(
|
251
|
-
'\n'.join(templ),
|
251
|
+
'\n'.join(templ),
|
252
252
|
model.magnet['magnetFsl'])
|
253
253
|
|
254
254
|
templ = model.magnettype()
|
@@ -364,8 +364,8 @@ class Builder:
|
|
364
364
|
"""return connect_model if rotating machine and incomplete model
|
365
365
|
(Note: femag bug with connect model)"
|
366
366
|
"""
|
367
|
-
if (model.
|
368
|
-
model.
|
367
|
+
if (model.connect_full or (
|
368
|
+
model.get('move_action', 0) == 0 and
|
369
369
|
model.stator['num_slots'] > model.stator['num_slots_gen'])):
|
370
370
|
fslcmds = ['pre_models("connect_models")\n']
|
371
371
|
if 'thcond' in model.stator:
|
femagtools/machine/__init__.py
CHANGED
@@ -68,8 +68,9 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
|
|
68
68
|
psid = rwdg*rlfe*dqp['psid']
|
69
69
|
psiq = rwdg*rlfe*dqp['psiq']
|
70
70
|
losses = __scale_losses(dqp['losses'], rlfe)
|
71
|
-
losses['ef'] = dqpars[-1]['losses']
|
72
|
-
losses['
|
71
|
+
losses['ef'] = dqpars[-1]['losses'].get('ef', [2.0, 2.0])
|
72
|
+
losses['hf'] = dqpars[-1]['losses'].get('hf', [1.0, 1.0])
|
73
|
+
# TODO handle bertotti excess loss factor
|
73
74
|
|
74
75
|
if 'psidq' in eecpars:
|
75
76
|
machine = PmRelMachinePsidq(
|
@@ -140,7 +141,7 @@ def create(bch, r1, ls, lfe=1, wdg=1):
|
|
140
141
|
try:
|
141
142
|
losses = __scale_losses(bch.psidq['losses'], rlfe)
|
142
143
|
losses['ef'] = bch.lossPar.get('ef', [2.0, 2.0])
|
143
|
-
losses['
|
144
|
+
losses['hf'] = bch.lossPar.get('hf', [1.0, 1.0])
|
144
145
|
except KeyError:
|
145
146
|
losses = {}
|
146
147
|
if 'ex_current' in bch.machine:
|
@@ -162,7 +163,7 @@ def create(bch, r1, ls, lfe=1, wdg=1):
|
|
162
163
|
try:
|
163
164
|
losses = __scale_losses(bch.ldq['losses'], rlfe)
|
164
165
|
losses['ef'] = bch.lossPar.get('ef', [2.0, 2.0])
|
165
|
-
losses['
|
166
|
+
losses['hf'] = bch.lossPar.get('hf', [1.0, 1.0])
|
166
167
|
except KeyError:
|
167
168
|
losses = {}
|
168
169
|
if 'ex_current' in bch.machine:
|
femagtools/machine/afpm.py
CHANGED
@@ -25,6 +25,25 @@ AFM_TYPES = (
|
|
25
25
|
"S2R1_all" # 2 stator, 1 rotor, all simulated
|
26
26
|
)
|
27
27
|
|
28
|
+
def num_agnodes(Q, p, pw, ag):
|
29
|
+
"""return total number of nodes in airgap per pole
|
30
|
+
Args:
|
31
|
+
Q: (int) number of slots
|
32
|
+
p: (int) number of pole pairs
|
33
|
+
pw: (float) pole width
|
34
|
+
ag: (float) airgap height
|
35
|
+
"""
|
36
|
+
num_nodes = np.arange(12, 120, 6)
|
37
|
+
i = np.argmin(np.abs(pw/num_nodes - ag/2))
|
38
|
+
if p*num_nodes[i-1] % Q:
|
39
|
+
lcm = np.lcm(Q, 2*p)//p
|
40
|
+
nmin, nmax = num_nodes[0]//lcm, num_nodes[-1]//lcm
|
41
|
+
num_nodes = np.array(
|
42
|
+
[i*lcm for i in range(nmin, nmax) if i*lcm % 6 == 0])
|
43
|
+
i = np.argmin(np.abs(pw/num_nodes - ag/2))
|
44
|
+
# nodedist 0.5, 2, 4, 6
|
45
|
+
return num_nodes[i-1]
|
46
|
+
|
28
47
|
def _integrate(radius, pos, val):
|
29
48
|
interp = RegularGridInterpolator((radius, pos), val)
|
30
49
|
def func(x, y):
|
@@ -141,10 +160,8 @@ def parident(workdir, engine, temp, machine,
|
|
141
160
|
|
142
161
|
if "num_agnodes" not in machine:
|
143
162
|
for pw in pole_width:
|
144
|
-
machine['num_agnodes'] =
|
145
|
-
|
146
|
-
#if machine['num_agnodes'] < nper:
|
147
|
-
# machine['num_agnodes'] = 8*round(pw/machine['airgap']/4)
|
163
|
+
machine['num_agnodes'] = num_agnodes(Q1, p//2, pw,
|
164
|
+
machine['airgap'])
|
148
165
|
|
149
166
|
nlparvardef = {
|
150
167
|
"decision_vars": [
|
@@ -189,7 +206,8 @@ def parident(workdir, engine, temp, machine,
|
|
189
206
|
|
190
207
|
nlresults = pstudy(nlparvardef, machine, nlcalc, engine)
|
191
208
|
if nlresults['status'].count('C') != len(nlresults['status']):
|
192
|
-
raise ValueError(
|
209
|
+
raise ValueError(
|
210
|
+
f"Noload simulation failed {nlresults['status']}")
|
193
211
|
else:
|
194
212
|
nlresults = {"x": [], "f": []}
|
195
213
|
i = 0
|
@@ -210,7 +228,7 @@ def parident(workdir, engine, temp, machine,
|
|
210
228
|
nlresults['f'].append({k: v for k, v in r.items()})
|
211
229
|
i = i + 1
|
212
230
|
nlresults.update(process(lfe, pole_width, machine, nlresults['f']))
|
213
|
-
|
231
|
+
weights = nlresults['weights']
|
214
232
|
current_angles = nlresults['f'][0]['current_angles']
|
215
233
|
results = []
|
216
234
|
i = 0
|
@@ -325,7 +343,7 @@ def parident(workdir, engine, temp, machine,
|
|
325
343
|
(-1, num_beta_steps)),
|
326
344
|
axis=1).T.tolist()})
|
327
345
|
ldq.append({'temperature': magtemp,
|
328
|
-
'i1':i1, 'beta':beta,
|
346
|
+
'i1': i1, 'beta': beta,
|
329
347
|
'psid': psid.tolist(), 'psiq': psiq.tolist(),
|
330
348
|
'ld': ld, 'lq': lq,
|
331
349
|
'torque': torque.tolist(),
|
@@ -334,7 +352,8 @@ def parident(workdir, engine, temp, machine,
|
|
334
352
|
#iq, id = femagtools.machine.utils.iqd(*np.meshgrid(beta, i1))
|
335
353
|
|
336
354
|
return {'m': machine[wdgk]['num_phases'],
|
337
|
-
'p': machine['poles']//2,
|
355
|
+
'p': machine['poles']//2, 'weights': weights,
|
356
|
+
'rotor_mass': sum(weights[1]), "kfric_b": 1,
|
338
357
|
'ls1': 0, 'r1': r1, 'ldq': ldq}
|
339
358
|
|
340
359
|
|
@@ -442,8 +461,17 @@ def process(lfe, pole_width, machine, bch):
|
|
442
461
|
mmod.outer_diam, mmod.inner_diam)
|
443
462
|
i1 = np.mean([np.max(c) for c in currents])/np.sqrt(2)
|
444
463
|
plcu = mmod.winding['num_phases']*i1**2*r1
|
464
|
+
weights = np.array([[0, 0, 0], [0, 0, 0]])
|
465
|
+
try:
|
466
|
+
for b in bch:
|
467
|
+
weights = weights + b['weights']
|
468
|
+
weights *= scale_factor
|
469
|
+
except KeyError as exc:
|
470
|
+
#logger.warning("missing key %s", exc)
|
471
|
+
pass
|
445
472
|
|
446
473
|
return {
|
474
|
+
'weights': weights.tolist(),
|
447
475
|
'pos': pos.tolist(), 'r1': r1,
|
448
476
|
'torque': torque,
|
449
477
|
'emf': emf,
|
@@ -603,14 +631,12 @@ class AFPM:
|
|
603
631
|
for pw in pole_width]
|
604
632
|
|
605
633
|
if "num_agnodes" not in machine:
|
634
|
+
Q1 = machine['stator']['num_slots']
|
635
|
+
p = machine['poles']
|
606
636
|
for pw in pole_width:
|
607
|
-
machine['num_agnodes'] =
|
608
|
-
|
609
|
-
|
610
|
-
#nper = np.lcm(Q, p)
|
611
|
-
#if machine['num_agnodes'] < nper:
|
612
|
-
# machine['num_agnodes'] = 8*round(pw/machine['airgap']/4)
|
613
|
-
|
637
|
+
machine['num_agnodes'] = num_agnodes(Q1, p//2, pw,
|
638
|
+
machine['airgap'])
|
639
|
+
logger.info("Num agnodes/pole %d", machine['num_agnodes'])
|
614
640
|
parvardef = {
|
615
641
|
"decision_vars": [
|
616
642
|
{"values": pole_width,
|