femagtools 1.5.7__py3-none-any.whl → 1.6.0__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 +14 -1
- femagtools/dxfsl/area.py +2 -3
- femagtools/dxfsl/converter.py +10 -2
- femagtools/dxfsl/fslrenderer.py +1 -2
- femagtools/dxfsl/functions.py +24 -27
- femagtools/dxfsl/geom.py +116 -80
- femagtools/dxfsl/machine.py +16 -7
- femagtools/dxfsl/plotrenderer.py +2 -2
- femagtools/dxfsl/shape.py +68 -17
- femagtools/femag.py +21 -3
- femagtools/fsl.py +14 -2
- femagtools/machine/__init__.py +13 -33
- femagtools/machine/afpm.py +22 -21
- femagtools/machine/pm.py +22 -21
- femagtools/machine/utils.py +112 -58
- femagtools/mcv.py +27 -1
- femagtools/model.py +4 -2
- femagtools/nc.py +7 -0
- femagtools/opt.py +1 -1
- femagtools/parstudy.py +5 -2
- femagtools/plot/__init__.py +1 -0
- femagtools/plot/bch.py +2 -0
- femagtools/plot/fieldlines.py +37 -0
- femagtools/templates/basic_modpar.mako +8 -0
- femagtools/templates/bertotti.mako +40 -0
- femagtools/templates/modified_steinmetz.mako +39 -0
- femagtools/ts.py +1 -1
- femagtools/utils.py +7 -1
- {femagtools-1.5.7.dist-info → femagtools-1.6.0.dist-info}/METADATA +1 -1
- {femagtools-1.5.7.dist-info → femagtools-1.6.0.dist-info}/RECORD +38 -35
- tests/test_bchreader.py +12 -1
- tests/test_femag.py +1 -1
- tests/test_fsl.py +1 -1
- {femagtools-1.5.7.dist-info → femagtools-1.6.0.dist-info}/LICENSE +0 -0
- {femagtools-1.5.7.dist-info → femagtools-1.6.0.dist-info}/WHEEL +0 -0
- {femagtools-1.5.7.dist-info → femagtools-1.6.0.dist-info}/entry_points.txt +0 -0
- {femagtools-1.5.7.dist-info → femagtools-1.6.0.dist-info}/top_level.txt +0 -0
femagtools/dxfsl/shape.py
CHANGED
@@ -9,7 +9,6 @@
|
|
9
9
|
"""
|
10
10
|
from __future__ import print_function
|
11
11
|
import numpy as np
|
12
|
-
import sys
|
13
12
|
import logging
|
14
13
|
from .functions import less_equal, greater_equal
|
15
14
|
from .functions import distance, line_m, line_n
|
@@ -18,7 +17,7 @@ from .functions import alpha_line, alpha_angle, alpha_triangle
|
|
18
17
|
from .functions import normalise_angle, min_angle, max_angle, get_angle_of_arc
|
19
18
|
from .functions import lines_intersect_point, nodes_are_equal
|
20
19
|
from .functions import is_angle_inside, intersect_point
|
21
|
-
from .functions import middle_angle
|
20
|
+
from .functions import middle_angle, middle_point_of_line
|
22
21
|
|
23
22
|
logger = logging.getLogger('femagtools.geom')
|
24
23
|
|
@@ -50,7 +49,10 @@ class Shape(object):
|
|
50
49
|
if hasattr(s, 'my_attrs'):
|
51
50
|
self.my_attrs = []
|
52
51
|
for a in s.my_attrs:
|
53
|
-
|
52
|
+
self.my_attrs.append(a)
|
53
|
+
|
54
|
+
def classname(self):
|
55
|
+
return "Shape"
|
54
56
|
|
55
57
|
def get_my_color(self):
|
56
58
|
if hasattr(self, 'my_color'):
|
@@ -209,8 +211,8 @@ class Shape(object):
|
|
209
211
|
d1 = distance(n, self.n1)
|
210
212
|
d2 = distance(n, self.n2)
|
211
213
|
if d1 == d2:
|
212
|
-
logger.
|
213
|
-
|
214
|
+
logger.warning("distances of %s and %s are equal (%s / %s)",
|
215
|
+
self.n1, self.n2, d1, d2)
|
214
216
|
raise ValueError('both nodes are equal in element')
|
215
217
|
|
216
218
|
if d1 < d2:
|
@@ -307,6 +309,9 @@ class Circle(Shape):
|
|
307
309
|
self.n1 = None
|
308
310
|
self.n2 = None
|
309
311
|
|
312
|
+
def classname(self):
|
313
|
+
return "Circle"
|
314
|
+
|
310
315
|
def render(self, renderer, color='blue', with_nodes=False):
|
311
316
|
tmp_color = self.get_my_color()
|
312
317
|
if not tmp_color:
|
@@ -544,6 +549,19 @@ class Circle(Shape):
|
|
544
549
|
assert(len(points) == 0)
|
545
550
|
return []
|
546
551
|
|
552
|
+
def cut_into_halves(self):
|
553
|
+
""" return two arcs
|
554
|
+
"""
|
555
|
+
a1 = Arc(Element(center=self.center,
|
556
|
+
radius=self.radius,
|
557
|
+
start_angle=0.0,
|
558
|
+
end_angle=180.0))
|
559
|
+
a2 = Arc(Element(center=self.center,
|
560
|
+
radius=self.radius,
|
561
|
+
start_angle=180.0,
|
562
|
+
end_angle=0.0))
|
563
|
+
return a1, a2
|
564
|
+
|
547
565
|
def get_angle_of_arc(self):
|
548
566
|
return np.pi*2.0
|
549
567
|
|
@@ -608,6 +626,9 @@ class Arc(Circle):
|
|
608
626
|
else:
|
609
627
|
self.rtheta = None
|
610
628
|
|
629
|
+
def classname(self):
|
630
|
+
return "Arc"
|
631
|
+
|
611
632
|
def render(self, renderer, color='blue', with_nodes=False):
|
612
633
|
tmp_color = self.get_my_color()
|
613
634
|
if not tmp_color:
|
@@ -715,8 +736,9 @@ class Arc(Circle):
|
|
715
736
|
points.append(e.p2)
|
716
737
|
|
717
738
|
elif e.is_point_inside(self.p2, rtol, atol):
|
718
|
-
if not points_are_close(self.p1, e.p1):
|
739
|
+
if not points_are_close(self.p1, e.p1, rtol=rtol, atol=atol):
|
719
740
|
logger.error("FATAL ERROR in overlapping_shape() of Arc")
|
741
|
+
|
720
742
|
raise ValueError('FATAL ERROR in overlapping_shape() of Arc')
|
721
743
|
points.append(e.p1)
|
722
744
|
points.append(self.p2)
|
@@ -808,6 +830,20 @@ class Arc(Circle):
|
|
808
830
|
assert(len(points_inside) == 0)
|
809
831
|
return []
|
810
832
|
|
833
|
+
def cut_into_halves(self):
|
834
|
+
""" return two arcs
|
835
|
+
"""
|
836
|
+
midangle = middle_angle(self.startangle, self.endangle)
|
837
|
+
a1 = Arc(Element(center=self.center,
|
838
|
+
radius=self.radius,
|
839
|
+
start_angle=self.startangle*180/np.pi,
|
840
|
+
end_angle=midangle*180/np.pi))
|
841
|
+
a2 = Arc(Element(center=self.center,
|
842
|
+
radius=self.radius,
|
843
|
+
start_angle=midangle*180/np.pi,
|
844
|
+
end_angle=self.endangle*180/np.pi))
|
845
|
+
return a1, a2
|
846
|
+
|
811
847
|
def concatenate_arc(self, n1, n2, el):
|
812
848
|
if not points_are_close(self.center, el.center):
|
813
849
|
return None
|
@@ -833,30 +869,30 @@ class Arc(Circle):
|
|
833
869
|
def is_point_inside(self, p, rtol=1e-03, atol=1e-03, include_end=False):
|
834
870
|
""" returns true if p is on arc
|
835
871
|
"""
|
836
|
-
logger.debug("is_point_inside: p=%s", p)
|
872
|
+
# logger.debug("is_point_inside: p=%s", p)
|
837
873
|
d = distance(p, self.center)
|
838
874
|
if not np.isclose(d, self.radius, rtol=rtol, atol=atol):
|
839
|
-
logger.debug(" <== RADIUS %s, DISTANCE %s",
|
840
|
-
|
875
|
+
# logger.debug(" <== RADIUS %s, DISTANCE %s",
|
876
|
+
# self.radius, d)
|
841
877
|
return False
|
842
878
|
if points_are_close(p, self.p1, rtol=rtol, atol=atol):
|
843
|
-
logger.debug(" <== CLOSE TO P1 %s: rtol=%s, atol=%s",
|
844
|
-
|
879
|
+
# logger.debug(" <== CLOSE TO P1 %s: rtol=%s, atol=%s",
|
880
|
+
# self.p1, rtol, atol)
|
845
881
|
return include_end
|
846
882
|
elif points_are_close(p, self.p2, rtol=rtol, atol=atol):
|
847
|
-
logger.debug(" <== CLOSE TO P2 %s: rtol=%s, atol=%s",
|
848
|
-
|
883
|
+
# logger.debug(" <== CLOSE TO P2 %s: rtol=%s, atol=%s",
|
884
|
+
# self.p2, rtol, atol)
|
849
885
|
return include_end
|
850
886
|
elif points_are_close(self.p1, self.p2, rtol=rtol, atol=atol):
|
851
|
-
logger.debug(" <== P1 AND P2 CLOSE TOGETHER")
|
887
|
+
# logger.debug(" <== P1 AND P2 CLOSE TOGETHER")
|
852
888
|
return False
|
853
889
|
|
854
890
|
alpha_p1 = alpha_line(self.center, self.p1)
|
855
891
|
alpha_p2 = alpha_line(self.center, self.p2)
|
856
892
|
alpha_p = alpha_line(self.center, p)
|
857
893
|
alpha_inside = is_angle_inside(alpha_p1, alpha_p2, alpha_p)
|
858
|
-
logger.debug("is_point_inside: %s (%s, %s ,%s)",
|
859
|
-
|
894
|
+
# logger.debug("is_point_inside: %s (%s, %s ,%s)",
|
895
|
+
# alpha_inside, alpha_p1, alpha_p2, alpha_p)
|
860
896
|
return alpha_inside
|
861
897
|
|
862
898
|
def is_angle_inside(self, alpha, rtol=1e-03, atol=1e-03,
|
@@ -889,7 +925,7 @@ class Arc(Circle):
|
|
889
925
|
self.startangle = np.arctan2(p1[1], p1[0])
|
890
926
|
self.endangle = np.arctan2(p2[1], p2[0])
|
891
927
|
if self.rtheta is not None:
|
892
|
-
self.rtheta = self.rtheta +
|
928
|
+
self.rtheta = self.rtheta + dest_alpha
|
893
929
|
return self
|
894
930
|
|
895
931
|
def minmax(self):
|
@@ -1054,6 +1090,9 @@ class Line(Shape):
|
|
1054
1090
|
self.n1 = None
|
1055
1091
|
self.n2 = None
|
1056
1092
|
|
1093
|
+
def classname(self):
|
1094
|
+
return "Line"
|
1095
|
+
|
1057
1096
|
def render(self, renderer, color='blue', with_nodes=False):
|
1058
1097
|
tmp_color = self.get_my_color()
|
1059
1098
|
if not tmp_color:
|
@@ -1186,6 +1225,14 @@ class Line(Shape):
|
|
1186
1225
|
return split_lines
|
1187
1226
|
return []
|
1188
1227
|
|
1228
|
+
def cut_into_halves(self):
|
1229
|
+
""" return two lines
|
1230
|
+
"""
|
1231
|
+
pm = middle_point_of_line(self.p1, self.p2)
|
1232
|
+
l1 = Line(Element(start=self.p1, end=pm))
|
1233
|
+
l2 = Line(Element(start=pm, end=self.p2))
|
1234
|
+
return l1, l2
|
1235
|
+
|
1189
1236
|
def concatenate_line(self, n1, n2, el):
|
1190
1237
|
if np.isclose(self.m(999999.0), el.m(999999.0)):
|
1191
1238
|
return Line(Element(start=n1, end=n2))
|
@@ -1293,6 +1340,9 @@ class Point(Shape):
|
|
1293
1340
|
def __init__(self, p):
|
1294
1341
|
self.p1 = p
|
1295
1342
|
|
1343
|
+
def classname(self):
|
1344
|
+
return "Point"
|
1345
|
+
|
1296
1346
|
def render(self, renderer):
|
1297
1347
|
renderer.point(self.p1)
|
1298
1348
|
|
@@ -1301,6 +1351,7 @@ class Point(Shape):
|
|
1301
1351
|
self.p1 = (n[0], n[1])
|
1302
1352
|
return self
|
1303
1353
|
|
1354
|
+
|
1304
1355
|
def is_Circle(e):
|
1305
1356
|
return isinstance(e, Circle) and not isinstance(e, Arc)
|
1306
1357
|
|
femagtools/femag.py
CHANGED
@@ -90,7 +90,7 @@ def get_shortCircuit_parameters(bch, nload):
|
|
90
90
|
fc_radius=bch.machine['fc_radius'],
|
91
91
|
lfe=bch.armatureLength/1e3,
|
92
92
|
pocfilename=bch.machine['pocfile'],
|
93
|
-
num_par_wdgs=bch.machine
|
93
|
+
num_par_wdgs=bch.machine.get('num_par_wdgs', 0),
|
94
94
|
calculationMode='shortcircuit')
|
95
95
|
except (KeyError, AttributeError, IndexError):
|
96
96
|
raise FemagError("missing pm/Rel-Sim results")
|
@@ -222,6 +222,12 @@ class BaseFemag(object):
|
|
222
222
|
pass
|
223
223
|
builder = femagtools.fsl.Builder(self.templatedirs)
|
224
224
|
if simulation:
|
225
|
+
if 'num_par_wdgs' not in simulation:
|
226
|
+
try:
|
227
|
+
num_par_wdgs = self.model.winding['num_par_wdgs']
|
228
|
+
simulation['num_par_wdgs'] = num_par_wdgs
|
229
|
+
except:
|
230
|
+
pass
|
225
231
|
set_magnet_properties(self.model, simulation, self.magnets)
|
226
232
|
return builder.create(self.model, simulation,
|
227
233
|
self.magnets, self.condMat)
|
@@ -351,6 +357,16 @@ class BaseFemag(object):
|
|
351
357
|
|
352
358
|
def readResult(self, simulation, bch=None):
|
353
359
|
if simulation:
|
360
|
+
if simulation['calculationMode'] == "fieldcalc":
|
361
|
+
nc = self.read_nc()
|
362
|
+
pmod = nc.poles_sim
|
363
|
+
r = {'airgap': ag.read(
|
364
|
+
os.path.join(self.workdir, 'bag.dat'), pmod=pmod)}
|
365
|
+
if 'plots' in simulation:
|
366
|
+
if 'field_lines' in simulation['plots']:
|
367
|
+
r['field_lines'] = os.path.join(
|
368
|
+
self.workdir, 'field.svg')
|
369
|
+
return r
|
354
370
|
if simulation['calculationMode'] == "pm_sym_loss":
|
355
371
|
return self.read_los(self.modelname)
|
356
372
|
|
@@ -365,7 +381,8 @@ class BaseFemag(object):
|
|
365
381
|
|
366
382
|
if simulation['calculationMode'] == 'therm-dynamic':
|
367
383
|
temp = [[float(n) for n in l.split()]
|
368
|
-
for l in (pathlib.Path(self.workdir) /
|
384
|
+
for l in (pathlib.Path(self.workdir) /
|
385
|
+
'temperature.dat').read_text().split('\n') if l]
|
369
386
|
ttemp = list(zip(*temp))
|
370
387
|
return {'t': ttemp[0], 'temperature': ttemp[1]}
|
371
388
|
|
@@ -383,9 +400,10 @@ class BaseFemag(object):
|
|
383
400
|
set_magnet_properties(self.model, simulation, self.magnets)
|
384
401
|
fslcmds = (builder.open_model(self.model) +
|
385
402
|
builder.create_shortcircuit(simulation))
|
403
|
+
fslfile = 'shortcicuit.fsl'
|
386
404
|
with open(os.path.join(self.workdir, fslfile), 'w') as f:
|
387
405
|
f.write('\n'.join(fslcmds))
|
388
|
-
self.run(fslfile
|
406
|
+
self.run(fslfile) #, options?
|
389
407
|
bchfile = self.get_bch_file(self.modelname)
|
390
408
|
if bchfile:
|
391
409
|
bchsc = femagtools.bch.Reader()
|
femagtools/fsl.py
CHANGED
@@ -484,7 +484,11 @@ class Builder:
|
|
484
484
|
if not hasattr(model, 'stator'):
|
485
485
|
setattr(model, 'stator', {})
|
486
486
|
model.stator['num_slots'] = conv.get('tot_num_slot')
|
487
|
-
model.stator
|
487
|
+
if model.stator.get('num_slots_gen', 0):
|
488
|
+
if model.stator['num_slots'] % model.stator['num_slots_gen'] > 0:
|
489
|
+
model.stator['num_slots_gen'] = conv.get('num_sl_gen')
|
490
|
+
else:
|
491
|
+
model.stator['num_slots_gen'] = conv.get('num_sl_gen')
|
488
492
|
if 'fsl_stator' in conv:
|
489
493
|
self.fsl_stator = True
|
490
494
|
model.stator['dxf'] = dict(fsl=conv['fsl_stator'])
|
@@ -633,15 +637,23 @@ class Builder:
|
|
633
637
|
|
634
638
|
def create_analysis(self, sim):
|
635
639
|
pfefunc = sim.get('loss_funct', '')
|
640
|
+
custom_fefunc = ['']
|
636
641
|
if pfefunc:
|
637
642
|
sim['loss_funct'] = 1 # 3?
|
643
|
+
if pfefunc == 'bertotti' or 'modified_steinmetz':
|
644
|
+
custom_fefunc = self.__render(sim['PVFE_FSL'], pfefunc)
|
645
|
+
else:
|
646
|
+
custom_fefunc = pfefunc.split('\n')
|
647
|
+
|
638
648
|
airgap_induc = (self.create_airgap_induc()
|
639
649
|
if sim.get('airgap_induc', 0) else [])
|
640
|
-
felosses =
|
650
|
+
felosses = custom_fefunc + self.create_fe_losses(sim)
|
641
651
|
fslcalc = (self.__render(sim, sim.get('calculationMode')) +
|
642
652
|
airgap_induc)
|
653
|
+
'''
|
643
654
|
if pfefunc:
|
644
655
|
sim['loss_funct'] = pfefunc
|
656
|
+
'''
|
645
657
|
|
646
658
|
if sim.get('calculationMode') in ('cogg_calc',
|
647
659
|
'ld_lq_fast',
|
femagtools/machine/__init__.py
CHANGED
@@ -14,13 +14,14 @@ import logging
|
|
14
14
|
logger = logging.getLogger(__name__)
|
15
15
|
|
16
16
|
|
17
|
-
def __scale_losses(losses,
|
17
|
+
def __scale_losses(losses, rlfe):
|
18
18
|
if losses:
|
19
|
-
l = {k:
|
19
|
+
l = {k: rlfe*np.array(losses[k]) for k in (
|
20
20
|
'styoke_hyst', 'styoke_eddy',
|
21
21
|
'stteeth_hyst', 'stteeth_eddy',
|
22
|
+
'styoke_excess', 'stteeth_excess', 'rotor_excess',
|
22
23
|
'rotor_hyst', 'rotor_eddy',
|
23
|
-
'magnet')}
|
24
|
+
'magnet') if k in losses}
|
24
25
|
l['speed'] = losses['speed']
|
25
26
|
return l
|
26
27
|
return {}
|
@@ -66,18 +67,15 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
|
|
66
67
|
|
67
68
|
psid = rwdg*rlfe*dqp['psid']
|
68
69
|
psiq = rwdg*rlfe*dqp['psiq']
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
except KeyError as e:
|
74
|
-
logger.warning(e)
|
75
|
-
losses = {}
|
70
|
+
losses = __scale_losses(dqp['losses'], rlfe)
|
71
|
+
losses['ef'] = dqpars[-1]['losses']['ef']
|
72
|
+
losses['eh'] = dqpars[-1]['losses']['ef']
|
73
|
+
|
76
74
|
if 'psidq' in eecpars:
|
77
75
|
machine = PmRelMachinePsidq(
|
78
76
|
eecpars['m'], eecpars['p'],
|
79
|
-
r1=eecpars
|
80
|
-
ls=eecpars
|
77
|
+
r1=eecpars.get('r1', 0)*rlfe*rwdg**2,
|
78
|
+
ls=eecpars.get('ls1', 0)*rwdg**2,
|
81
79
|
psid=psid,
|
82
80
|
psiq=psiq,
|
83
81
|
losses=losses,
|
@@ -90,8 +88,8 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
|
|
90
88
|
i1 = np.array(dqp['i1'])/rwdg
|
91
89
|
machine = PmRelMachineLdq(
|
92
90
|
eecpars['m'], eecpars['p'],
|
93
|
-
r1=eecpars
|
94
|
-
ls=eecpars
|
91
|
+
r1=eecpars.get('r1', 0)*rlfe*rwdg**2,
|
92
|
+
ls=eecpars.get('ls1', 0)*rwdg**2,
|
95
93
|
psid=psid,
|
96
94
|
psiq=psiq,
|
97
95
|
losses=losses,
|
@@ -103,7 +101,7 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
|
|
103
101
|
|
104
102
|
# must be an induction machine (TODO: check scaling)
|
105
103
|
pars = copy.deepcopy(eecpars)
|
106
|
-
pars['r1'] = rlfe*rwdg**2*pars
|
104
|
+
pars['r1'] = rlfe*rwdg**2*pars.get('r1', 0)
|
107
105
|
pars['lsigma1'] = rlfe*pars['lsigma1']
|
108
106
|
pars['lsigma2'] = rlfe*pars['lsigma2']
|
109
107
|
pars['psiref'] = rwdg*rlfe*pars['psiref']
|
@@ -119,24 +117,6 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
|
|
119
117
|
return InductionMachine(pars)
|
120
118
|
|
121
119
|
|
122
|
-
def __scale_losses(losses, rlfe):
|
123
|
-
if losses:
|
124
|
-
l = {k: rlfe*np.array(losses[k]) for k in (
|
125
|
-
'styoke_hyst', 'styoke_eddy',
|
126
|
-
'stteeth_hyst', 'stteeth_eddy',
|
127
|
-
'rotor_hyst', 'rotor_eddy',
|
128
|
-
'magnet')}
|
129
|
-
if 'styoke_exc' in losses:
|
130
|
-
l.update({k: rlfe*np.array(losses[k])
|
131
|
-
for k in (
|
132
|
-
'styoke_exc',
|
133
|
-
'stteeth_exc',
|
134
|
-
'rotor_exc')})
|
135
|
-
l['speed'] = losses['speed']
|
136
|
-
return l
|
137
|
-
return {}
|
138
|
-
|
139
|
-
|
140
120
|
def create(bch, r1, ls, lfe=1, wdg=1):
|
141
121
|
"""create PmRelMachine from BCH
|
142
122
|
|
femagtools/machine/afpm.py
CHANGED
@@ -45,7 +45,7 @@ def ld_interpol(i1, beta, v):
|
|
45
45
|
cur = copy.deepcopy(i1)
|
46
46
|
betad = copy.deepcopy(beta)
|
47
47
|
if np.amin(beta) < -90 and \
|
48
|
-
np.amax(beta) > -90:
|
48
|
+
np.amax(beta) > -90:
|
49
49
|
# motor and generator
|
50
50
|
v[0] = v[1]
|
51
51
|
v[-1] = v[-2]
|
@@ -53,18 +53,18 @@ def ld_interpol(i1, beta, v):
|
|
53
53
|
dbeta = np.abs(beta[0][0] - beta[1][0])
|
54
54
|
bp = [[beta[0][0]-dbeta for i in range(len(np.unique(i1)))]] + beta[1:-1] + \
|
55
55
|
[[dbeta for i in range(len(np.unique(i1)))]]
|
56
|
-
else:
|
56
|
+
else:
|
57
57
|
v[-1] = v[-2]
|
58
58
|
dbeta = np.abs(beta[0][0] - beta[1][0])
|
59
59
|
bp = beta[0:-1] + \
|
60
60
|
[[dbeta for i in range(len(np.unique(i1)))]]
|
61
|
-
|
61
|
+
|
62
62
|
return RectBivariateSpline(np.unique(bp), np.unique(cur), \
|
63
63
|
np.array(v)).ev(*[betad, i1]).tolist()
|
64
64
|
|
65
65
|
def lq_interpol(i1, beta, v):
|
66
66
|
'''interpolate Lq at beta -90°'''
|
67
|
-
if -90 not in np.unique(beta):
|
67
|
+
if -90 not in np.unique(beta):
|
68
68
|
return v
|
69
69
|
# lq
|
70
70
|
betad = copy.deepcopy(beta)
|
@@ -75,7 +75,7 @@ def lq_interpol(i1, beta, v):
|
|
75
75
|
v.pop(inx[0, 0])
|
76
76
|
bp = beta[0:inx[0, 0]] + beta[inx[0, 0]+1:]
|
77
77
|
cp = i1[0:inx[0, 0]] + i1[inx[0, 0]+1:]
|
78
|
-
else:
|
78
|
+
else:
|
79
79
|
v[0] = v[1]
|
80
80
|
dbeta = np.abs(beta[0][0] - beta[1][0])
|
81
81
|
bp = [[-90-dbeta for i in i1[0]]] + beta[1::]
|
@@ -181,7 +181,7 @@ def parident(workdir, engine, temp, machine,
|
|
181
181
|
poc=poc.Poc(999),
|
182
182
|
speed=0)
|
183
183
|
logging.info("Noload simulation")
|
184
|
-
if kwargs.get('use_multiprocessing', True):
|
184
|
+
if kwargs.get('use_multiprocessing', True):
|
185
185
|
pstudy = parstudy.List(
|
186
186
|
workdir, condMat=condMat, magnets=magnetMat,
|
187
187
|
magnetizingCurves=magnetizingCurves,
|
@@ -190,17 +190,17 @@ def parident(workdir, engine, temp, machine,
|
|
190
190
|
nlresults = pstudy(nlparvardef, machine, nlcalc, engine)
|
191
191
|
if nlresults['status'].count('C') != len(nlresults['status']):
|
192
192
|
raise ValueError('Noload simulation failed %s', nlresults['status'])
|
193
|
-
else:
|
193
|
+
else:
|
194
194
|
nlresults = {"x": [], "f": []}
|
195
195
|
i = 0
|
196
|
-
for pw, le, sp in zip(pole_width, lfe, linspeed):
|
196
|
+
for pw, le, sp in zip(pole_width, lfe, linspeed):
|
197
197
|
nlmachine = {k: machine[k] for k in machine}
|
198
198
|
nlmachine['pole_width'] = pw
|
199
199
|
nlmachine['lfe'] = le
|
200
200
|
nlcalc.update({"speed": sp})
|
201
201
|
nlsubdir = f'{workdir}/{i}'
|
202
202
|
nlworkdir = Path(nlsubdir)
|
203
|
-
if nlworkdir.exists():
|
203
|
+
if nlworkdir.exists():
|
204
204
|
shutil.rmtree(nlworkdir)
|
205
205
|
nlworkdir.mkdir(exist_ok=True)
|
206
206
|
noloadsim = femag.Femag(nlworkdir, condMat=condMat, magnets=magnetMat,
|
@@ -235,8 +235,8 @@ def parident(workdir, engine, temp, machine,
|
|
235
235
|
num_move_steps=60,
|
236
236
|
speed=linspeed[i],
|
237
237
|
num_par_wdgs=machine[wdgk].get('num_par_wdgs', 1))
|
238
|
-
|
239
|
-
if kwargs.get('use_multiprocessing', True):
|
238
|
+
|
239
|
+
if kwargs.get('use_multiprocessing', True):
|
240
240
|
gpstudy = parstudy.Grid(
|
241
241
|
subdir, condMat=condMat, magnets=magnetMat,
|
242
242
|
magnetizingCurves=magnetizingCurves,
|
@@ -248,7 +248,7 @@ def parident(workdir, engine, temp, machine,
|
|
248
248
|
domain_beta = np.linspace(beta_min, 0, num_beta_steps).tolist()
|
249
249
|
domain_cur = np.linspace(i1_max/num_cur_steps, i1_max, num_cur_steps).tolist()
|
250
250
|
dir_index = 0
|
251
|
-
for cur in domain_cur:
|
251
|
+
for cur in domain_cur:
|
252
252
|
for be in domain_beta:
|
253
253
|
simulation['angl_i_up'] = be
|
254
254
|
simulation['current'] = cur
|
@@ -256,7 +256,7 @@ def parident(workdir, engine, temp, machine,
|
|
256
256
|
subsubdir = subdir + f'/{dir_index}'
|
257
257
|
dir_index = dir_index + 1
|
258
258
|
lworkdir = Path(subsubdir)
|
259
|
-
if lworkdir.exists():
|
259
|
+
if lworkdir.exists():
|
260
260
|
shutil.rmtree(lworkdir)
|
261
261
|
lworkdir.mkdir(exist_ok=True)
|
262
262
|
loadsim = femag.Femag(lworkdir, condMat=condMat, magnets=magnetMat,
|
@@ -264,7 +264,7 @@ def parident(workdir, engine, temp, machine,
|
|
264
264
|
cmd=kwargs.get('cmd', None))
|
265
265
|
r = loadsim(mpart, simulation)
|
266
266
|
lresults['f'].append({k: v for k, v in r.items()})
|
267
|
-
|
267
|
+
|
268
268
|
f = [{k: bch[k]
|
269
269
|
for k in ('linearForce', 'flux', 'losses', 'lossPar')}
|
270
270
|
for bch in lresults['f']]
|
@@ -288,18 +288,18 @@ def parident(workdir, engine, temp, machine,
|
|
288
288
|
(-1, num_beta_steps)).T/np.sqrt(2)
|
289
289
|
psiq = np.reshape([r['psiq'] for r in postp],
|
290
290
|
(-1, num_beta_steps)).T/np.sqrt(2)
|
291
|
-
|
291
|
+
|
292
292
|
ld = np.reshape([r['Ld'] for r in postp],
|
293
293
|
(-1, num_beta_steps)).T.tolist()
|
294
294
|
lq = np.reshape([r['Lq'] for r in postp],
|
295
295
|
(-1, num_beta_steps)).T.tolist()
|
296
296
|
# interpolation ld, lq
|
297
|
-
curr, angl = [], []
|
298
|
-
for cr in range(len(beta)):
|
297
|
+
curr, angl = [], []
|
298
|
+
for cr in range(len(beta)):
|
299
299
|
curr.append(i1)
|
300
|
-
for al in beta:
|
300
|
+
for al in beta:
|
301
301
|
tmp = []
|
302
|
-
for cr in range(len(i1)):
|
302
|
+
for cr in range(len(i1)):
|
303
303
|
tmp.append(al)
|
304
304
|
angl.append(tmp)
|
305
305
|
try:
|
@@ -307,10 +307,10 @@ def parident(workdir, engine, temp, machine,
|
|
307
307
|
ld = ld_interpol(xx, yy, ld)
|
308
308
|
xx, yy = copy.deepcopy(curr), copy.deepcopy(angl)
|
309
309
|
lq = lq_interpol(xx, yy, lq)
|
310
|
-
except:
|
310
|
+
except:
|
311
311
|
ld = np.zeros_like(psid).tolist()
|
312
312
|
lq = np.zeros_like(psid).tolist()
|
313
|
-
|
313
|
+
|
314
314
|
torque = np.reshape([r['torque'] for r in postp],
|
315
315
|
(-1, num_beta_steps)).T
|
316
316
|
losses = {k: np.flip(np.reshape([r['plfe'][k] for r in postp],
|
@@ -547,6 +547,7 @@ def wdg_resistance(wdg, n, g, aw, outer_diam, inner_diam,
|
|
547
547
|
def _get_copper_losses(scale_factor, bch):
|
548
548
|
"""return copper losses from bch files"""
|
549
549
|
try:
|
550
|
+
wdgk = 'winding'
|
550
551
|
cu_losses = sum([b['losses'][0][wdgk] for b in bch])
|
551
552
|
return scale_factor*cu_losses
|
552
553
|
except KeyError:
|
femagtools/machine/pm.py
CHANGED
@@ -638,10 +638,10 @@ class PmRelMachine(object):
|
|
638
638
|
'rotor_hyst': hf[1],
|
639
639
|
'rotor_eddy': ef[1]}
|
640
640
|
# 'magnet'):
|
641
|
-
if '
|
642
|
-
self.plexp.update({'
|
643
|
-
'
|
644
|
-
'
|
641
|
+
if 'styoke_excess' in pfe:
|
642
|
+
self.plexp.update({'styoke_excess': cf[0],
|
643
|
+
'stteeth_excess':cf[0],
|
644
|
+
'rotor_excess': cf[1]})
|
645
645
|
|
646
646
|
def betai1_plcu(self, i1, w1=0):
|
647
647
|
return self.m*self.rstat(w1)*i1**2
|
@@ -1143,15 +1143,16 @@ class PmRelMachineLdq(PmRelMachine):
|
|
1143
1143
|
kx = len(beta)-1
|
1144
1144
|
try:
|
1145
1145
|
pfe = kwargs['losses']
|
1146
|
-
if '
|
1146
|
+
if 'styoke_excess' in pfe and np.any(pfe['styoke_excess']):
|
1147
1147
|
self.bertotti = True
|
1148
|
-
self.losskeys += ['
|
1149
|
-
'
|
1150
|
-
'
|
1148
|
+
self.losskeys += ['styoke_excess',
|
1149
|
+
'stteeth_excess',
|
1150
|
+
'rotor_excess']
|
1151
1151
|
self._set_losspar(pfe)
|
1152
1152
|
self._losses = {k: ip.RectBivariateSpline(
|
1153
1153
|
beta, i1, np.array(pfe[k]),
|
1154
|
-
kx=kx, ky=ky).ev for k in
|
1154
|
+
kx=kx, ky=ky).ev for k in self.losskeys
|
1155
|
+
if k in pfe}
|
1155
1156
|
except KeyError as e:
|
1156
1157
|
logger.warning("loss map missing: %s", e)
|
1157
1158
|
pass
|
@@ -1238,12 +1239,12 @@ class PmRelMachineLdq(PmRelMachine):
|
|
1238
1239
|
|
1239
1240
|
def betai1_plfe1(self, beta, i1, f1):
|
1240
1241
|
stator_losskeys = ['styoke_eddy', 'styoke_hyst',
|
1241
|
-
|
1242
|
+
'stteeth_eddy', 'stteeth_hyst']
|
1242
1243
|
if self.bertotti:
|
1243
|
-
stator_losskeys += ['
|
1244
|
+
stator_losskeys += ['styoke_excess', 'stteeth_excess']
|
1244
1245
|
return np.sum([
|
1245
|
-
self._losses[k](beta, i1)*(f1/self.fo)**self.plexp[k]
|
1246
|
-
k in
|
1246
|
+
self._losses[k](beta, i1)*(f1/self.fo)**self.plexp[k]
|
1247
|
+
for k in stator_losskeys if k in self._losses], axis=0)
|
1247
1248
|
|
1248
1249
|
def iqd_plfe1(self, iq, id, f1):
|
1249
1250
|
return self.betai1_plfe1(*betai1(iq, id), f1)
|
@@ -1251,7 +1252,7 @@ class PmRelMachineLdq(PmRelMachine):
|
|
1251
1252
|
def betai1_plfe2(self, beta, i1, f1):
|
1252
1253
|
rotor_losskeys = ['rotor_eddy', 'rotor_hyst']
|
1253
1254
|
if self.bertotti:
|
1254
|
-
rotor_losskeys += ['
|
1255
|
+
rotor_losskeys += ['rotor_excess']
|
1255
1256
|
return np.sum([
|
1256
1257
|
self._losses[k](beta, i1)*(f1/self.fo)**self.plexp[k] for
|
1257
1258
|
k in tuple(rotor_losskeys)], axis=0)
|
@@ -1295,7 +1296,7 @@ class PmRelMachinePsidq(PmRelMachine):
|
|
1295
1296
|
self.iqrange = (min(iq), max(iq))
|
1296
1297
|
self.betarange = (-np.pi if min(iq) < 0 else -np.pi/2,
|
1297
1298
|
0 if max(iq) > 0 else -np.pi/2)
|
1298
|
-
self.i1range = (0,
|
1299
|
+
self.i1range = (0, betai1(np.max(iq), 0)[1])
|
1299
1300
|
self.io = np.max(iq)/2, np.min(id)/2
|
1300
1301
|
|
1301
1302
|
if np.any(psid.shape < (4, 4)):
|
@@ -1322,11 +1323,11 @@ class PmRelMachinePsidq(PmRelMachine):
|
|
1322
1323
|
self._psiq = ip.RectBivariateSpline(iq, id, psiq).ev
|
1323
1324
|
try:
|
1324
1325
|
pfe = kwargs['losses']
|
1325
|
-
if '
|
1326
|
+
if 'styoke_excess' in pfe and np.any(pfe['styoke_excess']):
|
1326
1327
|
self.bertotti = True
|
1327
|
-
self.losskeys += ['
|
1328
|
-
'
|
1329
|
-
'
|
1328
|
+
self.losskeys += ['styoke_excess',
|
1329
|
+
'stteeth_excess',
|
1330
|
+
'rotor_excess']
|
1330
1331
|
self._set_losspar(pfe)
|
1331
1332
|
self._losses = {k: ip.RectBivariateSpline(
|
1332
1333
|
iq, id, np.array(pfe[k])).ev for k in (
|
@@ -1385,7 +1386,7 @@ class PmRelMachinePsidq(PmRelMachine):
|
|
1385
1386
|
stator_losskeys = ['styoke_eddy', 'styoke_hyst',
|
1386
1387
|
'stteeth_eddy', 'stteeth_hyst']
|
1387
1388
|
if self.bertotti:
|
1388
|
-
stator_losskeys += ['
|
1389
|
+
stator_losskeys += ['styoke_excess', 'stteeth_excess']
|
1389
1390
|
return np.sum([
|
1390
1391
|
self._losses[k](iq, id)*(f1/self.fo)**self.plexp[k] for
|
1391
1392
|
k in tuple(stator_losskeys)], axis=0)
|
@@ -1396,7 +1397,7 @@ class PmRelMachinePsidq(PmRelMachine):
|
|
1396
1397
|
def iqd_plfe2(self, iq, id, f1):
|
1397
1398
|
rotor_losskeys = ['rotor_eddy', 'rotor_hyst']
|
1398
1399
|
if self.bertotti:
|
1399
|
-
rotor_losskeys += ['
|
1400
|
+
rotor_losskeys += ['rotor_excess']
|
1400
1401
|
return np.sum([
|
1401
1402
|
self._losses[k](iq, id)*(f1/self.fo)**self.plexp[k] for
|
1402
1403
|
k in tuple(rotor_losskeys)], axis=0)
|