femagtools 1.7.8__py3-none-any.whl → 1.8.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/amela.py +2 -2
- femagtools/dxfsl/area.py +142 -9
- femagtools/dxfsl/conv.py +2 -9
- femagtools/dxfsl/converter.py +33 -9
- femagtools/dxfsl/fslrenderer.py +13 -12
- femagtools/dxfsl/geom.py +39 -6
- femagtools/dxfsl/journal.py +2 -2
- femagtools/dxfsl/machine.py +14 -13
- femagtools/dxfsl/shape.py +3 -0
- femagtools/dxfsl/svgparser.py +31 -4
- femagtools/ecloss.py +381 -2
- femagtools/femag.py +55 -0
- femagtools/fsl.py +74 -47
- femagtools/isa7.py +41 -0
- femagtools/job.py +2 -2
- femagtools/machine/afpm.py +5 -1
- femagtools/machine/pm.py +1 -1
- femagtools/machine/sm.py +14 -0
- femagtools/machine/utils.py +4 -3
- femagtools/mcv.py +128 -124
- femagtools/me.py +13 -13
- femagtools/model.py +14 -1
- femagtools/moo/population.py +9 -7
- femagtools/nc.py +12 -0
- femagtools/plot/__init__.py +1 -1
- femagtools/plot/fieldlines.py +1 -1
- femagtools/plot/mcv.py +18 -0
- femagtools/plot/nc.py +22 -5
- femagtools/plot/wdg.py +40 -7
- femagtools/svgfsl/converter.py +6 -0
- femagtools/templates/gen_hairpin_winding.mako +36 -45
- femagtools/templates/gen_winding.mako +7 -0
- femagtools/templates/magnetIron.mako +30 -46
- femagtools/templates/magnetIron2.mako +39 -0
- femagtools/templates/magnetIron3.mako +39 -0
- femagtools/templates/magnetIron4.mako +39 -0
- femagtools/templates/magnetIron5.mako +39 -0
- femagtools/templates/magnetIronV.mako +34 -54
- femagtools/templates/magnetSector.mako +32 -47
- femagtools/templates/mesh-airgap.mako +12 -6
- femagtools/templates/prepare_thermal.mako +354 -0
- femagtools/templates/statorRotor3.mako +3 -22
- femagtools/windings.py +92 -59
- {femagtools-1.7.8.dist-info → femagtools-1.8.0.dist-info}/METADATA +20 -18
- {femagtools-1.7.8.dist-info → femagtools-1.8.0.dist-info}/RECORD +53 -53
- {femagtools-1.7.8.dist-info → femagtools-1.8.0.dist-info}/WHEEL +1 -1
- tests/test_fsl.py +1 -1
- tests/test_mcv.py +106 -1
- tests/test_windings.py +18 -2
- tests/test_mcvwriter.py +0 -96
- {femagtools-1.7.8.dist-info → femagtools-1.8.0.dist-info}/LICENSE +0 -0
- {femagtools-1.7.8.dist-info → femagtools-1.8.0.dist-info}/entry_points.txt +0 -0
- {femagtools-1.7.8.dist-info → femagtools-1.8.0.dist-info}/top_level.txt +0 -0
femagtools/__init__.py
CHANGED
femagtools/amela.py
CHANGED
@@ -200,10 +200,10 @@ class Amela():
|
|
200
200
|
for k, i in enumerate(mag_spels):
|
201
201
|
|
202
202
|
cond = i.conduc
|
203
|
-
if cond == 0:
|
203
|
+
if cond == 0:
|
204
204
|
cond = 625000
|
205
205
|
logger.info('Magnet conductivity equals 0, using 625000 S/m')
|
206
|
-
|
206
|
+
|
207
207
|
mur = np.abs(1/i.elements[0].reluc[0])
|
208
208
|
logger.debug('Magnet: mur=%s, conductivity=%s', mur, cond)
|
209
209
|
|
femagtools/dxfsl/area.py
CHANGED
@@ -171,6 +171,142 @@ class Area(object):
|
|
171
171
|
if e1.n1 == e2.n1 and e1.n2 == e2.n2:
|
172
172
|
yield e1
|
173
173
|
|
174
|
+
def reduce_line_nodes(self, geom, mindist=0.01):
|
175
|
+
"""reduces number of nodes (lines only)
|
176
|
+
https://rdp.readthedocs.io/en/latest
|
177
|
+
Note: this feature is deactivated silently
|
178
|
+
if the rdp package is not installed.
|
179
|
+
"""
|
180
|
+
try:
|
181
|
+
import rdp
|
182
|
+
except ModuleNotFoundError:
|
183
|
+
return 0
|
184
|
+
|
185
|
+
def is_valid_line_(n1, e):
|
186
|
+
if not isinstance(e, Line):
|
187
|
+
return False
|
188
|
+
if e.has_attribute('del'):
|
189
|
+
return False
|
190
|
+
return True
|
191
|
+
|
192
|
+
def reduce_nodes_(lines, mindist):
|
193
|
+
if not len(lines) > 1:
|
194
|
+
return 0
|
195
|
+
|
196
|
+
nodes = [n1 for n1, n2, e in lines]
|
197
|
+
n1, n2, e = lines[-1]
|
198
|
+
nodes.append(n2)
|
199
|
+
|
200
|
+
remaining_nodes = rdp.rdp(nodes,
|
201
|
+
epsilon=mindist)
|
202
|
+
nodes_deleted = len(nodes) - len(remaining_nodes)
|
203
|
+
if not nodes_deleted:
|
204
|
+
return 0
|
205
|
+
|
206
|
+
for n1, n2, e in lines:
|
207
|
+
e.set_attribute('del')
|
208
|
+
e.set_my_color('yellow')
|
209
|
+
geom.remove_edge(e)
|
210
|
+
|
211
|
+
n1 = remaining_nodes[0]
|
212
|
+
for n2 in remaining_nodes[1:]:
|
213
|
+
geom.add_line(n1, n2)
|
214
|
+
n1 = n2
|
215
|
+
|
216
|
+
self.area = []
|
217
|
+
return nodes_deleted
|
218
|
+
|
219
|
+
# -----
|
220
|
+
nodes_deleted = 0
|
221
|
+
lines = []
|
222
|
+
for n1, n2, e in self.list_of_elements():
|
223
|
+
if not is_valid_line_(n1, e):
|
224
|
+
nodes_deleted += reduce_nodes_(lines, mindist)
|
225
|
+
lines = []
|
226
|
+
elif not geom.num_of_neighbors(n1) == 2:
|
227
|
+
nodes_deleted += reduce_nodes_(lines, mindist)
|
228
|
+
lines = [(n1, n2, e)]
|
229
|
+
else:
|
230
|
+
lines.append((n1, n2, e))
|
231
|
+
|
232
|
+
nodes_deleted += reduce_nodes_(lines, mindist)
|
233
|
+
return nodes_deleted
|
234
|
+
|
235
|
+
def reduce_element_nodes(self, geom, mindist=0.01):
|
236
|
+
"""reduces number of nodes (lines only)
|
237
|
+
https://rdp.readthedocs.io/en/latest
|
238
|
+
Note: this feature is deactivated silently
|
239
|
+
if the rdp package is not installed.
|
240
|
+
"""
|
241
|
+
corners = geom.start_corners + geom.end_corners
|
242
|
+
|
243
|
+
try:
|
244
|
+
import rdp
|
245
|
+
except ModuleNotFoundError:
|
246
|
+
return 0
|
247
|
+
|
248
|
+
def is_valid_element_(n1, e):
|
249
|
+
return not e.has_attribute('del')
|
250
|
+
|
251
|
+
def reduce_nodes_(elements, mindist):
|
252
|
+
if not len(elements) > 1:
|
253
|
+
return 0
|
254
|
+
|
255
|
+
old_nodes = []
|
256
|
+
for n1, n2, e in elements:
|
257
|
+
old_nodes.append(n1)
|
258
|
+
nodes = [n for n in e.get_nodes(parts=24)]
|
259
|
+
if len(nodes) > 2:
|
260
|
+
if points_are_close(n1, nodes[0]):
|
261
|
+
old_nodes += nodes[1:-1]
|
262
|
+
elif points_are_close(n2, nodes[0]):
|
263
|
+
nodes.reverse()
|
264
|
+
old_nodes += nodes[1:-1]
|
265
|
+
n1, n2, e = elmts[-1]
|
266
|
+
old_nodes.append(n2)
|
267
|
+
|
268
|
+
new_nodes = rdp.rdp(old_nodes,
|
269
|
+
epsilon=mindist)
|
270
|
+
nodes_deleted = len(old_nodes) - len(new_nodes)
|
271
|
+
if not nodes_deleted:
|
272
|
+
return 0
|
273
|
+
|
274
|
+
for n1, n2, e in elements:
|
275
|
+
e.set_attribute('del')
|
276
|
+
e.set_my_color('yellow')
|
277
|
+
geom.remove_edge(e)
|
278
|
+
|
279
|
+
n1 = new_nodes[0]
|
280
|
+
for n2 in new_nodes[1:]:
|
281
|
+
geom.add_line(n1, n2)
|
282
|
+
n1 = n2
|
283
|
+
|
284
|
+
self.area = []
|
285
|
+
return nodes_deleted
|
286
|
+
|
287
|
+
# -----
|
288
|
+
nodes_deleted = 0
|
289
|
+
tiny_mindist = 0.05
|
290
|
+
elmts = []
|
291
|
+
has_tiny = False
|
292
|
+
for n1, n2, e in self.list_of_elements():
|
293
|
+
if not is_valid_element_(n1, e):
|
294
|
+
if has_tiny:
|
295
|
+
nodes_deleted += reduce_nodes_(elmts, mindist)
|
296
|
+
elmts = []
|
297
|
+
elif not geom.num_of_neighbors(n1) == 2 or n1 in corners:
|
298
|
+
if has_tiny:
|
299
|
+
nodes_deleted += reduce_nodes_(elmts, mindist)
|
300
|
+
has_tiny = e.is_tiny(tiny_mindist)
|
301
|
+
elmts = [(n1, n2, e)]
|
302
|
+
else:
|
303
|
+
if e.is_tiny(tiny_mindist):
|
304
|
+
has_tiny = True
|
305
|
+
elmts.append((n1, n2, e))
|
306
|
+
if has_tiny:
|
307
|
+
nodes_deleted += reduce_nodes_(elmts, mindist)
|
308
|
+
return nodes_deleted
|
309
|
+
|
174
310
|
def virtual_nodes(self, render=False, parts=64):
|
175
311
|
if len(self.area) < 2:
|
176
312
|
return
|
@@ -337,15 +473,9 @@ class Area(object):
|
|
337
473
|
return False
|
338
474
|
|
339
475
|
def minmax_dist_from_center(self, center):
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
r = np.linalg.norm(np.array(n)-center)
|
344
|
-
if r < rmin:
|
345
|
-
rmin = r
|
346
|
-
if r > rmax:
|
347
|
-
rmax = r
|
348
|
-
return rmin, rmax
|
476
|
+
nodes = np.array([n for e in self.area for n in e.get_nodes()])
|
477
|
+
return (np.min(np.linalg.norm(nodes-center, axis=1)),
|
478
|
+
np.max(np.linalg.norm(nodes-center, axis=1)))
|
349
479
|
|
350
480
|
def minmax_angle_dist_from_center(self, center, dist):
|
351
481
|
circ = Circle(Element(center=center, radius=dist))
|
@@ -959,11 +1089,14 @@ class Area(object):
|
|
959
1089
|
self.legend())
|
960
1090
|
|
961
1091
|
def remove_edges(self, g, ndec):
|
1092
|
+
r = 0
|
962
1093
|
for e in self.area:
|
963
1094
|
try:
|
964
1095
|
g.remove_edge(e.node1(ndec), e.node2(ndec))
|
1096
|
+
r+=1
|
965
1097
|
except Exception:
|
966
1098
|
continue
|
1099
|
+
return r
|
967
1100
|
|
968
1101
|
def is_circle(self):
|
969
1102
|
e = self.area[0]
|
femagtools/dxfsl/conv.py
CHANGED
@@ -9,18 +9,13 @@ import os
|
|
9
9
|
import io
|
10
10
|
import femagtools
|
11
11
|
from femagtools.dxfsl.converter import convert
|
12
|
-
from femagtools.dxfsl.journal import Journal, getJournal
|
13
12
|
import argparse
|
14
13
|
import logging
|
15
14
|
import logging.config
|
16
15
|
|
17
16
|
logger = logging.getLogger(__name__)
|
18
|
-
journal = None
|
19
|
-
|
20
17
|
|
21
18
|
def main():
|
22
|
-
global journal
|
23
|
-
|
24
19
|
argparser = argparse.ArgumentParser(
|
25
20
|
description='Process DXF file and create a plot or FSL file.')
|
26
21
|
argparser.add_argument('dxfile',
|
@@ -187,8 +182,6 @@ def main():
|
|
187
182
|
logger.info("Python: %s", sys.version)
|
188
183
|
sys.exit(0)
|
189
184
|
|
190
|
-
journal = getJournal(name='converter_journal', aktiv=args.journal)
|
191
|
-
|
192
185
|
if args.airgap > 0.0:
|
193
186
|
if args.airgap2 > 0.0:
|
194
187
|
logger.info("Airgap is set from {} to {}"
|
@@ -252,7 +245,8 @@ def main():
|
|
252
245
|
write_png=args.write_png,
|
253
246
|
write_id=args.write_id,
|
254
247
|
debug_mode=args.debugger,
|
255
|
-
full_model=args.full_model
|
248
|
+
full_model=args.full_model,
|
249
|
+
write_journal=args.journal)
|
256
250
|
keys = ('tot_num_slot', 'num_sl_gen', 'num_poles', 'nodedist',
|
257
251
|
'dy1', 'da1', 'da2', 'dy2', 'agndst', 'name')
|
258
252
|
logger.info("%s", {k: res[k] for k in keys if k in res})
|
@@ -261,7 +255,6 @@ def main():
|
|
261
255
|
basename = os.path.basename(args.dxfile).split('.')[0]
|
262
256
|
with io.open(basename + '.fsl', 'w', encoding='utf-8') as f:
|
263
257
|
f.write('\n'.join(res['fsl']))
|
264
|
-
journal.write_journal()
|
265
258
|
|
266
259
|
if __name__ == "__main__":
|
267
260
|
loglevel = logging.INFO
|
femagtools/dxfsl/converter.py
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
"""
|
4
4
|
import os
|
5
5
|
from pathlib import Path
|
6
|
+
from femagtools import __version__
|
6
7
|
from femagtools.dxfsl.geom import Geometry
|
7
8
|
from femagtools.dxfsl.shape import Shape
|
8
9
|
from femagtools.dxfsl.fslrenderer import FslRenderer, agndst
|
@@ -220,16 +221,33 @@ def build_machine_stator(machine, inner, mindist, plt, EESM=False, single=False)
|
|
220
221
|
if not machine.geom.is_stator():
|
221
222
|
logger.debug("Rotor with windings")
|
222
223
|
|
223
|
-
if machine.
|
224
|
+
if machine.is_mirrored():
|
225
|
+
plot_geom(False, # for developer
|
226
|
+
plt, machine.previous_machine.geom,
|
227
|
+
title="Mirrored Stator",
|
228
|
+
areas=True)
|
229
|
+
|
224
230
|
logger.debug("undo mirrored windings")
|
225
231
|
machine_temp = machine.undo_mirror()
|
226
232
|
machine_temp.delete_tiny_elements(mindist)
|
227
233
|
machine_temp.geom.set_stator()
|
228
234
|
machine_temp.search_stator_subregions(single=single)
|
229
|
-
machine_temp.
|
235
|
+
if not machine_temp.has_windings_in_the_middle():
|
236
|
+
logger.debug("Back to the mirrored machine")
|
237
|
+
machine_temp = machine # undo
|
238
|
+
else:
|
239
|
+
machine_temp.create_mirror_lines_outside_windings()
|
230
240
|
else:
|
231
241
|
machine_temp = machine
|
232
|
-
|
242
|
+
|
243
|
+
rebuild = machine_temp.create_auxiliary_lines()
|
244
|
+
if machine_temp.geom.reduce_element_nodes(mindist):
|
245
|
+
plot_geom(False, # for developer
|
246
|
+
plt, machine_temp.geom,
|
247
|
+
title="Nodes reduced",
|
248
|
+
areas=False)
|
249
|
+
rebuild = True
|
250
|
+
if rebuild:
|
233
251
|
machine_temp.rebuild_subregions(EESM, single=single)
|
234
252
|
|
235
253
|
if inner:
|
@@ -270,7 +288,8 @@ def convert(dxfile,
|
|
270
288
|
write_png=False,
|
271
289
|
write_id=False,
|
272
290
|
full_model=False,
|
273
|
-
debug_mode=False
|
291
|
+
debug_mode=False,
|
292
|
+
write_journal=False):
|
274
293
|
layers = ()
|
275
294
|
conv = {}
|
276
295
|
|
@@ -281,14 +300,19 @@ def convert(dxfile,
|
|
281
300
|
|
282
301
|
basename = input_file.stem
|
283
302
|
if part:
|
284
|
-
logger.info("***** start processing %s (%s) *****",
|
303
|
+
logger.info("***** start processing %s (%s) [%s] *****",
|
304
|
+
basename,
|
305
|
+
part,
|
306
|
+
__version__)
|
285
307
|
else:
|
286
|
-
logger.info("***** start processing %s *****",
|
308
|
+
logger.info("***** start processing %s [%s] *****",
|
309
|
+
basename,
|
310
|
+
__version__)
|
287
311
|
timer = Timer(start_it=True)
|
288
312
|
|
289
|
-
journal = getJournal(name='
|
313
|
+
journal = getJournal(name='converter_journal', aktiv=write_journal)
|
290
314
|
journal.get_journal(input_file.name)
|
291
|
-
journal.
|
315
|
+
journal.set_filename(str(input_file.resolve()))
|
292
316
|
journal.set('success', False)
|
293
317
|
journal.write_journal()
|
294
318
|
|
@@ -718,7 +742,6 @@ def convert(dxfile,
|
|
718
742
|
p,
|
719
743
|
EESM=EESM,
|
720
744
|
single=True)
|
721
|
-
|
722
745
|
params = create_femag_parameters_stator(machine,
|
723
746
|
part[1])
|
724
747
|
else:
|
@@ -801,6 +824,7 @@ def convert(dxfile,
|
|
801
824
|
t = timer.stop("-- all done in %0.4f seconds --", info=True)
|
802
825
|
journal.put('time_total', t)
|
803
826
|
journal.set('success', True)
|
827
|
+
journal.write_journal()
|
804
828
|
return conv
|
805
829
|
|
806
830
|
|
femagtools/dxfsl/fslrenderer.py
CHANGED
@@ -162,17 +162,16 @@ class FslRenderer(object):
|
|
162
162
|
geom.split_all_lines_longer_than(split_len)
|
163
163
|
self.content = []
|
164
164
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
(
|
174
|
-
|
175
|
-
(1.10, 5.5)]
|
165
|
+
MAXDST=4.0
|
166
|
+
NUMLEVELS=10
|
167
|
+
NDT0=1.1
|
168
|
+
# ndt list format [ (rdistx, ndtx) ...]
|
169
|
+
# where
|
170
|
+
# - rdistx is rel dist from airgap (range 0 .. NUMLEVELS-1/NUMLEVELS)
|
171
|
+
# - ndtx nodedist (range NDT0 .. (NUMLEVELS-1/NUMLEVELS))*(MAXDST-1.1) + NDT0)
|
172
|
+
ndt_list = [(1.1*nl/NUMLEVELS, nl/NUMLEVELS*(MAXDST-1.1)+NDT0)
|
173
|
+
for nl in range(NUMLEVELS+1)]
|
174
|
+
|
176
175
|
dist = geom.max_radius - geom.min_radius
|
177
176
|
el_sorted = self.sorted_elements(geom, inner)
|
178
177
|
|
@@ -182,7 +181,7 @@ class FslRenderer(object):
|
|
182
181
|
if ndt_list[n][0] < d_percent:
|
183
182
|
self.agndst = ndt_list[n][1] * self.agndst
|
184
183
|
self.content.append('\nndt({}*agndst)\n'.
|
185
|
-
format(ndt_list[n][1]))
|
184
|
+
format(round(ndt_list[n][1], 1)))
|
186
185
|
while ndt_list[n][0] < d_percent:
|
187
186
|
n += 1
|
188
187
|
e.render(self)
|
@@ -233,6 +232,8 @@ class FslRenderer(object):
|
|
233
232
|
'r, phi = c2pr(x0, y0)',
|
234
233
|
'x1, y1 = pr2c(r1, phi)',
|
235
234
|
'x2, y2 = pr2c(r1, {}*math.pi/parts)'.format(slice),
|
235
|
+
f'-- end max corner {geom.end_corners[-1]}',
|
236
|
+
f'-- center {geom.center}',
|
236
237
|
f'r = {geom.dist_end_max_corner()}',
|
237
238
|
'x3, y3 = pr2c(r, {}*math.pi/parts)'.format(slice),
|
238
239
|
'nc_line(x0, y0, x1, y1, 0)',
|
femagtools/dxfsl/geom.py
CHANGED
@@ -91,11 +91,12 @@ def create_geometry(new_elements, split=False):
|
|
91
91
|
|
92
92
|
|
93
93
|
def intersect_and_split(inp_elements, rtol, atol):
|
94
|
-
logger.info("Load input elements ... ")
|
94
|
+
logger.info("Load input elements ... %s", len(inp_elements))
|
95
95
|
out_elements = []
|
96
96
|
for e in inp_elements:
|
97
97
|
out_size = len(out_elements)
|
98
98
|
intersect_and_split_element(e, out_elements, 0, out_size, rtol, atol)
|
99
|
+
logger.debug(" done", e)
|
99
100
|
return out_elements
|
100
101
|
|
101
102
|
|
@@ -650,9 +651,9 @@ class Geometry(object):
|
|
650
651
|
return True
|
651
652
|
return False
|
652
653
|
|
653
|
-
def get_edge(self,
|
654
|
+
def get_edge(self, obj):
|
654
655
|
return [[e[0], e[1], e[2]['object']] for e in self.g.edges(data=True)
|
655
|
-
if e[2]['object'] is
|
656
|
+
if e[2]['object'] is obj]
|
656
657
|
|
657
658
|
def get_edge_element(self, n1, n2):
|
658
659
|
e_dict = self.g.get_edge_data(n1, n2)
|
@@ -679,9 +680,9 @@ class Geometry(object):
|
|
679
680
|
assert(len(e) == 1)
|
680
681
|
self._remove_edge(e[0][0], e[0][1])
|
681
682
|
|
682
|
-
def remove_edges(self,
|
683
|
-
for
|
684
|
-
self.remove_edge(
|
683
|
+
def remove_edges(self, objs):
|
684
|
+
for o in objs:
|
685
|
+
self.remove_edge(o)
|
685
686
|
|
686
687
|
def _remove_node(self, n):
|
687
688
|
for nbr in self.g.neighbors(n):
|
@@ -810,6 +811,10 @@ class Geometry(object):
|
|
810
811
|
def get_neighbors(self, n):
|
811
812
|
return [nbr for nbr in self.g.neighbors(n)]
|
812
813
|
|
814
|
+
def num_of_neighbors(self, n):
|
815
|
+
nbrs = [nbr for nbr in self.g.neighbors(n)]
|
816
|
+
return len(nbrs)
|
817
|
+
|
813
818
|
def angle_nodes(self, center, angle, rtol, atol):
|
814
819
|
if np.isclose(abs(angle), np.pi, rtol, atol):
|
815
820
|
angle_func = positive_angle
|
@@ -1843,6 +1848,24 @@ class Geometry(object):
|
|
1843
1848
|
return [h for (k, h) in legend.items()]
|
1844
1849
|
return []
|
1845
1850
|
|
1851
|
+
def reduce_winding_nodes(self, mindist=0.01):
|
1852
|
+
return self.reduce_element_nodes(mindist=mindist,
|
1853
|
+
area_types=(AREA.TYPE_WINDINGS,))
|
1854
|
+
|
1855
|
+
def reduce_element_nodes(self, mindist=0.01, area_types=()):
|
1856
|
+
timer = Timer(start_it=True)
|
1857
|
+
nodes_deleted = 0
|
1858
|
+
for area in self.list_of_areas():
|
1859
|
+
if not area_types or area.type in area_types:
|
1860
|
+
nodes_deleted += area.reduce_element_nodes(self, mindist)
|
1861
|
+
|
1862
|
+
t = timer.stop("-- {} nodes deleted in %0.4f seconds --".format(nodes_deleted))
|
1863
|
+
self.journal.put('time_deleting_nodes', t)
|
1864
|
+
if nodes_deleted:
|
1865
|
+
self.journal.put('nodes_deleted', nodes_deleted)
|
1866
|
+
self.area_list = []
|
1867
|
+
return nodes_deleted > 0
|
1868
|
+
|
1846
1869
|
def render_areagroups(self, renderer):
|
1847
1870
|
if not self.areagroup_list:
|
1848
1871
|
return
|
@@ -3587,6 +3610,16 @@ class Geometry(object):
|
|
3587
3610
|
return True
|
3588
3611
|
return False
|
3589
3612
|
|
3613
|
+
def windings_in_the_middle(self, midangle):
|
3614
|
+
wdg_areas = [a for a in self.list_of_areas()
|
3615
|
+
if a.is_winding()]
|
3616
|
+
logger.info("%s windings in geom", len(wdg_areas))
|
3617
|
+
for a in wdg_areas:
|
3618
|
+
if greater(a.max_angle, midangle) and \
|
3619
|
+
less(a.min_angle, midangle):
|
3620
|
+
return True
|
3621
|
+
return False
|
3622
|
+
|
3590
3623
|
def looking_for_corners(self):
|
3591
3624
|
if self.is_inner:
|
3592
3625
|
logger.debug("looking_for_corners: inner")
|
femagtools/dxfsl/journal.py
CHANGED
@@ -121,8 +121,8 @@ class Journal(object):
|
|
121
121
|
data_list.append(val)
|
122
122
|
self.data[name] = data_list
|
123
123
|
|
124
|
-
def
|
125
|
-
self.
|
124
|
+
def set_filename(self, val):
|
125
|
+
self.set('filename', val)
|
126
126
|
|
127
127
|
def put_areas(self, val):
|
128
128
|
self.put('areas', val)
|
femagtools/dxfsl/machine.py
CHANGED
@@ -5,14 +5,15 @@
|
|
5
5
|
from __future__ import print_function
|
6
6
|
import numpy as np
|
7
7
|
import logging
|
8
|
-
from .shape import Element, Circle, Arc, Line, Shape
|
9
|
-
from .corner import Corner
|
8
|
+
from femagtools.dxfsl.shape import Element, Circle, Arc, Line, Shape
|
9
|
+
from femagtools.dxfsl.corner import Corner
|
10
10
|
from femagtools.dxfsl.symmetry import Symmetry
|
11
|
-
|
12
|
-
from .functions import
|
13
|
-
from .functions import
|
14
|
-
from .functions import
|
15
|
-
from .functions import
|
11
|
+
import femagtools.dxfsl.area as AREA
|
12
|
+
from femagtools.dxfsl.functions import point, points_are_close, distance
|
13
|
+
from femagtools.dxfsl.functions import alpha_angle, normalise_angle, middle_angle, third_angle
|
14
|
+
from femagtools.dxfsl.functions import alpha_line, line_m, line_n, mirror_point
|
15
|
+
from femagtools.dxfsl.functions import within_interval, part_of_circle
|
16
|
+
from femagtools.dxfsl.functions import less, less_equal, greater, greater_equal
|
16
17
|
logger = logging.getLogger('femagtools.geom')
|
17
18
|
|
18
19
|
|
@@ -283,11 +284,6 @@ class Machine(object):
|
|
283
284
|
logger.debug("end of copy_mirror")
|
284
285
|
return machine
|
285
286
|
|
286
|
-
def has_mirrored_windings(self):
|
287
|
-
if not self.is_mirrored():
|
288
|
-
return False
|
289
|
-
return self.geom.area_close_to_endangle(2) > 0
|
290
|
-
|
291
287
|
def undo_mirror(self):
|
292
288
|
assert(self.is_mirrored())
|
293
289
|
assert(self.previous_machine)
|
@@ -533,7 +529,7 @@ class Machine(object):
|
|
533
529
|
def repair_hull_geom(self, geom, startangle, endangle):
|
534
530
|
logger.debug('begin repair_hull_geom (%s, %s)', startangle, endangle)
|
535
531
|
|
536
|
-
rtol = 1e-
|
532
|
+
rtol = 1e-3
|
537
533
|
atol = 1e-4
|
538
534
|
c_corner = Corner(self.center, self.center)
|
539
535
|
start_c_added, start_corners = geom.get_corner_list(self.center, startangle,
|
@@ -1138,6 +1134,11 @@ class Machine(object):
|
|
1138
1134
|
|
1139
1135
|
return 0.0
|
1140
1136
|
|
1137
|
+
def has_windings_in_the_middle(self):
|
1138
|
+
midangle = middle_angle(self.startangle,
|
1139
|
+
self.endangle)
|
1140
|
+
return self.geom.windings_in_the_middle(midangle)
|
1141
|
+
|
1141
1142
|
def create_mirror_lines_outside_windings(self):
|
1142
1143
|
logger.debug("create_mirror_lines_outside_windings")
|
1143
1144
|
|
femagtools/dxfsl/shape.py
CHANGED
femagtools/dxfsl/svgparser.py
CHANGED
@@ -37,10 +37,17 @@ def get_angles(sweep, center, p1, p2):
|
|
37
37
|
def get_shapes(path):
|
38
38
|
"""return list of node elements (A, L)"""
|
39
39
|
state = ''
|
40
|
+
prevstate = ''
|
40
41
|
p = []
|
41
|
-
for s in [s for s in re.split('([
|
42
|
+
for s in [s for s in re.split('([AMLHV])|,|\\s+', path) if s]:
|
42
43
|
if state == '':
|
43
|
-
|
44
|
+
s = s.upper()
|
45
|
+
if s in ('A','M','L','H','V'):
|
46
|
+
state = s
|
47
|
+
prevstate = s
|
48
|
+
else: # wild guess
|
49
|
+
p.append(float(s))
|
50
|
+
state = prevstate
|
44
51
|
elif state == 'M':
|
45
52
|
p.append(float(s))
|
46
53
|
if len(p) == 2:
|
@@ -52,7 +59,7 @@ def get_shapes(path):
|
|
52
59
|
if len(p) == 2:
|
53
60
|
p2 = np.array(p)
|
54
61
|
logger.debug("Line %s -> %s",
|
55
|
-
|
62
|
+
p1, p2)
|
56
63
|
yield Line(Element(start=p1, end=p2))
|
57
64
|
p1 = p2.copy()
|
58
65
|
p = []
|
@@ -66,7 +73,7 @@ def get_shapes(path):
|
|
66
73
|
center = get_center(r, p1, p2, sweep)
|
67
74
|
start, end = get_angles(sweep, center, p1, p2)
|
68
75
|
logger.debug("Arc center %s r %f %f -> %f",
|
69
|
-
|
76
|
+
center, r, start, end)
|
70
77
|
yield Arc(Element(center=center,
|
71
78
|
radius=r,
|
72
79
|
start_angle=start*180/np.pi,
|
@@ -74,14 +81,34 @@ def get_shapes(path):
|
|
74
81
|
p1 = p2.copy()
|
75
82
|
p = []
|
76
83
|
state = ''
|
84
|
+
elif state == 'H':
|
85
|
+
logger.debug("h %s", s)
|
86
|
+
p2 = np.array((float(s), 0))
|
87
|
+
yield Line(Element(start=p1, end=p2))
|
88
|
+
p1 = p2.copy()
|
89
|
+
p = []
|
90
|
+
state = ''
|
91
|
+
elif state == 'V':
|
92
|
+
logger.debug("V %s", s)
|
93
|
+
p2 = np.array((0, float(s)))
|
94
|
+
yield Line(Element(start=p1, end=p2))
|
95
|
+
p1 = p2.copy()
|
96
|
+
p = []
|
97
|
+
state = ''
|
77
98
|
else:
|
78
99
|
raise ValueError(f"unsupported path {state}")
|
79
100
|
|
80
101
|
|
81
102
|
def svgshapes(svgfile):
|
82
103
|
svg = ET.parse(svgfile)
|
104
|
+
bcolor = re.compile('fill:([^;]+)')
|
105
|
+
sr = 0
|
83
106
|
for p in svg.findall(".//{http://www.w3.org/2000/svg}path"):
|
107
|
+
m = bcolor.search(p.get('style'))
|
108
|
+
if m:
|
109
|
+
logger.info("subregion %d: %s", sr, m.groups()[0])
|
84
110
|
yield from get_shapes(p.get('d'))
|
111
|
+
sr += 1
|
85
112
|
for p in svg.findall(".//{http://www.w3.org/2000/svg}line"):
|
86
113
|
yield Line(Element(start=[float(p.get('x1')), float(p.get('y1'))],
|
87
114
|
end=[float(p.get('x2')), float(p.get('y2'))]))
|