femagtools 1.7.9__py3-none-any.whl → 1.8.1__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 +130 -26
- femagtools/dxfsl/conv.py +2 -14
- femagtools/dxfsl/converter.py +69 -12
- femagtools/dxfsl/fslrenderer.py +15 -13
- femagtools/dxfsl/geom.py +153 -82
- femagtools/dxfsl/journal.py +2 -2
- femagtools/dxfsl/machine.py +19 -15
- femagtools/dxfsl/shape.py +3 -0
- femagtools/ecloss.py +386 -2
- femagtools/femag.py +82 -9
- femagtools/fsl.py +52 -56
- femagtools/machine/pm.py +1 -1
- femagtools/machine/sm.py +16 -8
- femagtools/mcv.py +128 -124
- femagtools/me.py +13 -13
- femagtools/model.py +8 -2
- femagtools/plot/fieldlines.py +1 -1
- femagtools/plot/mcv.py +18 -0
- femagtools/plot/wdg.py +2 -2
- femagtools/svgfsl/converter.py +1 -1
- femagtools/templates/afm_rotor.mako +4 -0
- femagtools/templates/gen_hairpin_winding.mako +36 -45
- femagtools/templates/magnetIron.mako +1 -1
- femagtools/templates/magnetIron2.mako +1 -1
- femagtools/templates/magnetIron3.mako +1 -1
- femagtools/templates/magnetIron4.mako +1 -1
- femagtools/templates/magnetIron5.mako +1 -1
- femagtools/templates/magnetIronV.mako +1 -1
- femagtools/templates/magnetSector.mako +1 -1
- femagtools/templates/mesh-airgap.mako +12 -6
- femagtools/templates/prepare_thermal.mako +199 -61
- femagtools/windings.py +25 -20
- {femagtools-1.7.9.dist-info → femagtools-1.8.1.dist-info}/METADATA +20 -20
- {femagtools-1.7.9.dist-info → femagtools-1.8.1.dist-info}/RECORD +42 -43
- {femagtools-1.7.9.dist-info → femagtools-1.8.1.dist-info}/WHEEL +1 -1
- tests/test_mcv.py +106 -1
- tests/test_windings.py +5 -0
- tests/test_mcvwriter.py +0 -96
- {femagtools-1.7.9.dist-info → femagtools-1.8.1.dist-info}/LICENSE +0 -0
- {femagtools-1.7.9.dist-info → femagtools-1.8.1.dist-info}/entry_points.txt +0 -0
- {femagtools-1.7.9.dist-info → femagtools-1.8.1.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,37 +171,141 @@ class Area(object):
|
|
171
171
|
if e1.n1 == e2.n1 and e1.n2 == e2.n2:
|
172
172
|
yield e1
|
173
173
|
|
174
|
-
def
|
174
|
+
def reduce_line_nodes(self, geom, mindist=0.01):
|
175
175
|
"""reduces number of nodes (lines only)
|
176
176
|
https://rdp.readthedocs.io/en/latest
|
177
|
+
Note: this feature is deactivated silently
|
178
|
+
if the rdp package is not installed.
|
177
179
|
"""
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
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
|
187
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
|
188
221
|
lines = []
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
lines.append(e)
|
193
|
-
else:
|
194
|
-
reduced.append(e)
|
195
|
-
reduced += reduce_nodes_(lines, mindist)
|
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)
|
196
225
|
lines = []
|
197
|
-
|
198
|
-
|
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
|
199
242
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
return
|
204
|
-
|
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
|
205
309
|
|
206
310
|
def virtual_nodes(self, render=False, parts=64):
|
207
311
|
if len(self.area) < 2:
|
@@ -718,9 +822,9 @@ class Area(object):
|
|
718
822
|
mm[3] = max(mm[3], n[3])
|
719
823
|
return mm
|
720
824
|
|
721
|
-
def
|
825
|
+
def intersect_area(self, line):
|
722
826
|
for e in self.area:
|
723
|
-
if e.
|
827
|
+
if e.intersect_shape(line, include_end=True):
|
724
828
|
return True
|
725
829
|
return False
|
726
830
|
|
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,16 +245,11 @@ 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})
|
259
|
-
if args.write_fsl:
|
260
|
-
if res is not None:
|
261
|
-
basename = os.path.basename(args.dxfile).split('.')[0]
|
262
|
-
with io.open(basename + '.fsl', 'w', encoding='utf-8') as f:
|
263
|
-
f.write('\n'.join(res['fsl']))
|
264
|
-
journal.write_journal()
|
265
253
|
|
266
254
|
if __name__ == "__main__":
|
267
255
|
loglevel = logging.INFO
|
femagtools/dxfsl/converter.py
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
"""
|
4
4
|
import os
|
5
|
+
import io
|
5
6
|
from pathlib import Path
|
7
|
+
from femagtools import __version__
|
6
8
|
from femagtools.dxfsl.geom import Geometry
|
7
9
|
from femagtools.dxfsl.shape import Shape
|
8
10
|
from femagtools.dxfsl.fslrenderer import FslRenderer, agndst
|
@@ -159,12 +161,16 @@ def symmetry_search(machine,
|
|
159
161
|
|
160
162
|
|
161
163
|
def build_machine_rotor(machine, inner, mindist, plt, EESM=False, single=False):
|
164
|
+
global journal
|
162
165
|
logger.debug("Begin of build_machine_rotor")
|
166
|
+
|
163
167
|
if machine.has_windings():
|
164
168
|
logger.debug("do nothing here with windings in rotor")
|
165
169
|
logger.debug("End of build_machine_rotor")
|
166
170
|
return machine
|
167
171
|
|
172
|
+
timer = Timer(start_it=True)
|
173
|
+
|
168
174
|
if machine.is_mirrored():
|
169
175
|
logger.debug("Rotor is mirrored")
|
170
176
|
machine_temp = machine.undo_mirror()
|
@@ -206,41 +212,77 @@ def build_machine_rotor(machine, inner, mindist, plt, EESM=False, single=False):
|
|
206
212
|
machine_temp.create_inner_corner_areas()
|
207
213
|
|
208
214
|
if not machine_temp.is_mirrored():
|
209
|
-
|
215
|
+
plot_geom(False, # for developer
|
216
|
+
plt, machine_temp.geom,
|
217
|
+
title="Rotor before Boundery Corr")
|
218
|
+
machine_temp.create_boundary_nodes()
|
210
219
|
|
211
220
|
plot_geom(False, # for developer
|
212
221
|
plt, machine_temp.geom,
|
213
222
|
title="Final Rotor")
|
223
|
+
|
224
|
+
t = timer.stop("-- rotor created in %0.4f seconds --")
|
225
|
+
journal.put('time_rotor_created', t)
|
226
|
+
|
214
227
|
logger.debug("End of build_machine_rotor")
|
215
228
|
return machine_temp
|
216
229
|
|
217
230
|
|
218
231
|
def build_machine_stator(machine, inner, mindist, plt, EESM=False, single=False):
|
232
|
+
global journal
|
219
233
|
logger.debug("Begin of build_machine_stator")
|
234
|
+
timer = Timer(start_it=True)
|
235
|
+
|
220
236
|
if not machine.geom.is_stator():
|
221
237
|
logger.debug("Rotor with windings")
|
222
238
|
|
223
|
-
if machine.
|
239
|
+
if machine.is_mirrored():
|
240
|
+
plot_geom(False, # for developer
|
241
|
+
plt, machine.previous_machine.geom,
|
242
|
+
title="Mirrored Stator",
|
243
|
+
areas=True)
|
244
|
+
|
224
245
|
logger.debug("undo mirrored windings")
|
225
246
|
machine_temp = machine.undo_mirror()
|
226
247
|
machine_temp.delete_tiny_elements(mindist)
|
227
248
|
machine_temp.geom.set_stator()
|
228
249
|
machine_temp.search_stator_subregions(single=single)
|
229
|
-
machine_temp.
|
250
|
+
if not machine_temp.has_windings_in_the_middle():
|
251
|
+
logger.debug("Back to the mirrored machine")
|
252
|
+
machine_temp = machine # undo
|
253
|
+
else:
|
254
|
+
machine_temp.create_mirror_lines_outside_windings()
|
230
255
|
else:
|
231
256
|
machine_temp = machine
|
257
|
+
|
258
|
+
if machine_temp.geom.reduce_element_nodes(mindist):
|
259
|
+
machine_temp.rebuild_subregions(EESM, single=single)
|
260
|
+
plot_geom(False, # for developer
|
261
|
+
plt, machine_temp.geom,
|
262
|
+
title="Nodes reduced")
|
263
|
+
|
232
264
|
if machine_temp.create_auxiliary_lines():
|
233
265
|
machine_temp.rebuild_subregions(EESM, single=single)
|
266
|
+
plot_geom(False, # for developer
|
267
|
+
plt, machine_temp.geom,
|
268
|
+
title="Stator with Auxiliary Lines")
|
234
269
|
|
235
270
|
if inner:
|
236
271
|
machine_temp.create_inner_corner_areas()
|
237
272
|
|
238
273
|
if not machine_temp.is_mirrored():
|
239
|
-
|
274
|
+
plot_geom(False, # for developer
|
275
|
+
plt, machine_temp.geom,
|
276
|
+
title="Stator before Boundery Corr")
|
277
|
+
machine_temp.create_boundary_nodes()
|
240
278
|
|
241
279
|
plot_geom(False, # for developer
|
242
280
|
plt, machine_temp.geom,
|
243
281
|
title="Final Stator")
|
282
|
+
|
283
|
+
t = timer.stop("-- stator created in %0.4f seconds --")
|
284
|
+
journal.put('time_stator_created', t)
|
285
|
+
|
244
286
|
logger.debug("End of build_machine_stator")
|
245
287
|
return machine_temp
|
246
288
|
|
@@ -270,7 +312,9 @@ def convert(dxfile,
|
|
270
312
|
write_png=False,
|
271
313
|
write_id=False,
|
272
314
|
full_model=False,
|
273
|
-
debug_mode=False
|
315
|
+
debug_mode=False,
|
316
|
+
write_journal=False):
|
317
|
+
global journal
|
274
318
|
layers = ()
|
275
319
|
conv = {}
|
276
320
|
|
@@ -281,14 +325,19 @@ def convert(dxfile,
|
|
281
325
|
|
282
326
|
basename = input_file.stem
|
283
327
|
if part:
|
284
|
-
logger.info("***** start processing %s (%s) *****",
|
328
|
+
logger.info("***** start processing %s (%s) [%s] *****",
|
329
|
+
basename,
|
330
|
+
part,
|
331
|
+
__version__)
|
285
332
|
else:
|
286
|
-
logger.info("***** start processing %s *****",
|
333
|
+
logger.info("***** start processing %s [%s] *****",
|
334
|
+
basename,
|
335
|
+
__version__)
|
287
336
|
timer = Timer(start_it=True)
|
288
337
|
|
289
|
-
journal = getJournal(name='
|
338
|
+
journal = getJournal(name='converter_journal', aktiv=write_journal)
|
290
339
|
journal.get_journal(input_file.name)
|
291
|
-
journal.
|
340
|
+
journal.set_filename(str(input_file.resolve()))
|
292
341
|
journal.set('success', False)
|
293
342
|
journal.write_journal()
|
294
343
|
|
@@ -533,7 +582,6 @@ def convert(dxfile,
|
|
533
582
|
EESM=EESM)
|
534
583
|
|
535
584
|
if machine_outer.geom.is_stator() or machine_outer.has_windings():
|
536
|
-
machine_outer.geom.reduce_winding_nodes()
|
537
585
|
machine_outer = build_machine_stator(machine_outer,
|
538
586
|
False,
|
539
587
|
mindist,
|
@@ -719,7 +767,6 @@ def convert(dxfile,
|
|
719
767
|
p,
|
720
768
|
EESM=EESM,
|
721
769
|
single=True)
|
722
|
-
machine.geom.reduce_winding_nodes()
|
723
770
|
params = create_femag_parameters_stator(machine,
|
724
771
|
part[1])
|
725
772
|
else:
|
@@ -794,14 +841,24 @@ def convert(dxfile,
|
|
794
841
|
|
795
842
|
mtype = 'EESM' if EESM else 'PMSM'
|
796
843
|
fslrenderer = FslRenderer(basename, mtype)
|
797
|
-
conv['fsl'] = fslrenderer.render(machine, inner, outer)
|
844
|
+
conv['fsl'] = fslrenderer.render(machine, inner, outer, standalone=True)
|
798
845
|
|
799
846
|
if params is not None:
|
800
847
|
conv.update(params)
|
848
|
+
|
849
|
+
if write_fsl:
|
850
|
+
logger.debug("Write fsl")
|
851
|
+
if conv and conv['fsl']:
|
852
|
+
with io.open(basename + '.fsl', 'w', encoding='utf-8') as f:
|
853
|
+
f.write('\n'.join(conv['fsl']))
|
854
|
+
else:
|
855
|
+
logger.warning("No fsl data available")
|
856
|
+
|
801
857
|
conv['name'] = basename
|
802
858
|
t = timer.stop("-- all done in %0.4f seconds --", info=True)
|
803
859
|
journal.put('time_total', t)
|
804
860
|
journal.set('success', True)
|
861
|
+
journal.write_journal()
|
805
862
|
return conv
|
806
863
|
|
807
864
|
|
femagtools/dxfsl/fslrenderer.py
CHANGED
@@ -154,7 +154,7 @@ class FslRenderer(object):
|
|
154
154
|
return sorted([(abs(r - np.linalg.norm(e.center_of_connection())), e)
|
155
155
|
for e in geom.elements(Shape)])
|
156
156
|
|
157
|
-
def render(self, machine, inner=False, outer=False):
|
157
|
+
def render(self, machine, inner=False, outer=False, standalone=False):
|
158
158
|
'''create fsl statements with nodechains'''
|
159
159
|
machine.set_alfa_and_corners()
|
160
160
|
geom = machine.geom
|
@@ -162,20 +162,22 @@ class FslRenderer(object):
|
|
162
162
|
geom.split_all_lines_longer_than(split_len)
|
163
163
|
self.content = []
|
164
164
|
|
165
|
+
if standalone:
|
166
|
+
self.content += ['if (agndst == nil) then',
|
167
|
+
' agndst = 0.5',
|
168
|
+
' m.npols_gen = 2',
|
169
|
+
' m.num_sl_gen = 2',
|
170
|
+
' new_model_force("{}","Test")'.format(self.model),
|
171
|
+
'end']
|
172
|
+
|
165
173
|
MAXDST=4.0
|
166
174
|
NUMLEVELS=10
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
(0.40, 3.1),
|
174
|
-
(0.50, 3.5),
|
175
|
-
(0.70, 4.5),
|
176
|
-
(0.85, 5.5),
|
177
|
-
(1.10, 5.5)]
|
178
|
-
ndt_list = [(1.1*nl/NUMLEVELS, nl/NUMLEVELS*(MAXDST-1.1)+1.1)
|
175
|
+
NDT0=1.1
|
176
|
+
# ndt list format [ (rdistx, ndtx) ...]
|
177
|
+
# where
|
178
|
+
# - rdistx is rel dist from airgap (range 0 .. NUMLEVELS-1/NUMLEVELS)
|
179
|
+
# - ndtx nodedist (range NDT0 .. (NUMLEVELS-1/NUMLEVELS))*(MAXDST-1.1) + NDT0)
|
180
|
+
ndt_list = [(1.1*nl/NUMLEVELS, nl/NUMLEVELS*(MAXDST-1.1)+NDT0)
|
179
181
|
for nl in range(NUMLEVELS+1)]
|
180
182
|
|
181
183
|
dist = geom.max_radius - geom.min_radius
|