femagtools 1.8.4__py3-none-any.whl → 1.8.6__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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  """
4
4
  __title__ = 'femagtools'
5
- __version__ = '1.8.4'
5
+ __version__ = '1.8.6'
6
6
  __author__ = 'Ronald Tanner'
7
7
  __license__ = 'BSD'
8
8
  __copyright__ = 'Copyright 2023-2024 Gamma Technology'
femagtools/bch.py CHANGED
@@ -618,8 +618,8 @@ class Reader:
618
618
 
619
619
  def __read_peak_winding_currents(self, content):
620
620
  self.scData['peakWindingCurrents'] = [float(x)
621
- for x in re.findall(r'[-0-9.]+',
622
- ''.join(content))]
621
+ for x in self._numPattern.findall(
622
+ ''.join(content))]
623
623
 
624
624
  def __read_general_machine_data(self, content):
625
625
  mcfiles = []
@@ -1771,6 +1771,9 @@ class Reader:
1771
1771
  def __getattr__(self, k):
1772
1772
  return self.__dict__[k]
1773
1773
 
1774
+ def asdict(self):
1775
+ return {k[0]: k[1] for k in self.items()}
1776
+
1774
1777
  def items(self):
1775
1778
  return [(k, self.get(k)) for k in ('version',
1776
1779
  'type',
femagtools/dxfsl/area.py CHANGED
@@ -435,6 +435,9 @@ class Area(object):
435
435
  self.type == TYPE_WINDINGS or \
436
436
  self.type == TYPE_FD_WINDINGS
437
437
 
438
+ def is_field_winding(self):
439
+ return self.type == TYPE_FD_WINDINGS
440
+
438
441
  def is_magnet(self):
439
442
  return self.type == TYPE_MAGNET_AIRGAP or self.type == TYPE_MAGNET_RECT
440
443
 
femagtools/dxfsl/conv.py CHANGED
@@ -180,12 +180,6 @@ def main():
180
180
  help='create full model (fsl only)',
181
181
  dest='full_model',
182
182
  action="store_true")
183
- argparser.add_argument('--no_processing',
184
- help=(argparse.SUPPRESS if not super_help else
185
- "omit multiprocessing"),
186
- dest='no_processing',
187
- action="store_true",
188
- default=False)
189
183
 
190
184
  args = argparser.parse_args()
191
185
 
@@ -282,8 +276,7 @@ def main():
282
276
  write_id=args.write_id,
283
277
  debug_mode=args.debugger,
284
278
  full_model=args.full_model,
285
- write_journal=args.journal,
286
- no_processing=args.no_processing)
279
+ write_journal=args.journal)
287
280
  keys = ('tot_num_slot', 'num_sl_gen', 'num_poles', 'nodedist',
288
281
  'dy1', 'da1', 'da2', 'dy2', 'agndst', 'name')
289
282
  logger.info("%s", {k: res[k] for k in keys if k in res})
@@ -10,7 +10,7 @@ from femagtools.dxfsl.shape import Shape
10
10
  from femagtools.dxfsl.fslrenderer import FslRenderer, agndst
11
11
  from femagtools.dxfsl.plotrenderer import PlotRenderer
12
12
  from femagtools.dxfsl.concat import Concatenation
13
- from femagtools.dxfsl.functions import Timer, SimpleProcess, middle_angle
13
+ from femagtools.dxfsl.functions import Timer, middle_angle
14
14
  from femagtools.dxfsl.journal import Journal, getJournal
15
15
  from femagtools.dxfsl.area import TYPE_WINDINGS
16
16
  from femagtools.dxfsl.areabuilder import disable_logging, enable_logging
@@ -18,10 +18,8 @@ import logging
18
18
  import logging.config
19
19
  import numpy as np
20
20
  import sys
21
- import multiprocessing
22
21
 
23
22
  logger = logging.getLogger(__name__)
24
- journal = None
25
23
 
26
24
 
27
25
  def plot_geom(doit, plt, geom, title="Plot", areas=True):
@@ -44,117 +42,6 @@ def plot_geom(doit, plt, geom, title="Plot", areas=True):
44
42
  fill_areas=areas)
45
43
 
46
44
 
47
- class SymSearchProcess(SimpleProcess):
48
- def __init__(self,
49
- name=None,
50
- queue=None,
51
- machine=None,
52
- plt=None, # plotter
53
- kind="",
54
- mindist=0.01,
55
- symtol=0.0,
56
- sympart=0,
57
- is_inner=False,
58
- is_outer=False,
59
- show_plots=True,
60
- debug_mode=False,
61
- rows=1,
62
- cols=1,
63
- num=1,
64
- no_processing=False):
65
- SimpleProcess.__init__(self,
66
- name=name,
67
- no_processing=no_processing)
68
- self.queue = queue
69
- self.mach_in = machine
70
- self.mach_out = None
71
- self.plt = plt
72
- self.kind = kind
73
- self.mindist = mindist
74
- self.symtol = symtol
75
- self.sympart = sympart
76
- self.is_inner = is_inner
77
- self.is_outer = is_outer
78
- self.show_plots = show_plots
79
- self.debug_mode = debug_mode
80
- self.rows = rows
81
- self.cols = cols
82
- self.num = num
83
- pass
84
-
85
- def run(self):
86
- if not self.without_processing():
87
- logger.info("Process is running")
88
- self.plt = None
89
- self.show_plots = False
90
- else:
91
- logger.info("without multiprocessing")
92
-
93
- try:
94
- self.mach_out = symmetry_search(
95
- self.mach_in,
96
- plt=self.plt,
97
- kind=self.kind,
98
- mindist=self.mindist,
99
- symtol=self.symtol,
100
- sympart=self.sympart,
101
- is_inner=self.is_inner,
102
- is_outer=self.is_outer,
103
- show_plots=self.show_plots,
104
- debug_mode=self.debug_mode,
105
- rows=self.rows,
106
- cols=self.cols,
107
- num=self.num)
108
- except Exception as e:
109
- logger.warning("Exception in symmetry_search: %s", e)
110
- if not self.mach_out:
111
- logger.error("NO MACHINE AFTER PROCESS")
112
- self.queue.put(self.mach_out)
113
- if not self.without_processing():
114
- logger.info("Process is finished")
115
-
116
-
117
- class BuildInnerProcess(SimpleProcess):
118
- def __init__(self,
119
- name=None,
120
- queue=None,
121
- machine=None,
122
- mindist=0.01,
123
- plt=None, # plotter
124
- EESM=False,
125
- no_processing=False):
126
- SimpleProcess.__init__(self,
127
- name=name,
128
- no_processing=no_processing)
129
- self.queue = queue
130
- self.mach_in = machine
131
- self.mach_out = None
132
- self.plt = plt
133
- self.mindist = mindist
134
- self.EESM = EESM
135
- pass
136
-
137
- def run(self):
138
- if not self.without_processing():
139
- logger.info("Process is running")
140
- self.plt = None
141
- else:
142
- logger.info("without multiprocessing")
143
-
144
- try:
145
- self.mach_out = build_inner_machine(
146
- self.mach_in,
147
- mindist=self.mindist,
148
- plt=self.plt,
149
- EESM=self.EESM)
150
- except Exception as e:
151
- logger.warning("Exception in symmetry_search: %s", e)
152
-
153
- self.queue.put(self.mach_out)
154
- if not self.without_processing():
155
- logger.info("Process is finished")
156
-
157
-
158
45
  def symmetry_search(machine,
159
46
  plt=None, # plotter
160
47
  kind="single",
@@ -279,7 +166,6 @@ def symmetry_search(machine,
279
166
 
280
167
 
281
168
  def build_machine_rotor(machine, inner, mindist, plt, EESM=False, single=False):
282
- global journal
283
169
  logger.debug("Begin of build_machine_rotor")
284
170
 
285
171
  if machine.has_windings():
@@ -357,7 +243,6 @@ def build_machine_rotor(machine, inner, mindist, plt, EESM=False, single=False):
357
243
 
358
244
 
359
245
  def build_machine_stator(machine, inner, mindist, plt, EESM=False, single=False):
360
- global journal
361
246
  logger.debug("Begin of build_machine_stator")
362
247
  timer = Timer(start_it=True)
363
248
 
@@ -509,8 +394,7 @@ def convert(dxfile,
509
394
  write_id=False,
510
395
  full_model=False,
511
396
  debug_mode=False,
512
- write_journal=False,
513
- no_processing=False):
397
+ write_journal=False):
514
398
  global journal
515
399
  layers = ()
516
400
  conv = {}
@@ -729,23 +613,19 @@ def convert(dxfile,
729
613
  machine_outer.set_outer()
730
614
 
731
615
  start_timer.stop("-- first part in %0.4f seconds --", info=True)
616
+
732
617
  process_timer = Timer(start_it=True)
733
618
  # inner part
734
- inner_queue = multiprocessing.Queue()
735
- inner_proc = SymSearchProcess(name="Inner", # for logger
736
- queue=inner_queue,
737
- machine=machine_inner,
738
- plt=None, # plot
739
- kind=inner_name,
740
- is_inner=True,
741
- mindist=mindist,
742
- symtol=symtol,
743
- show_plots=show_plots,
744
- rows=3, # rows
745
- cols=2, # columns
746
- num=3, # start num
747
- no_processing=no_processing)
748
- inner_proc.start_task()
619
+ machine_inner = symmetry_search(machine=machine_inner,
620
+ plt=p, # plot
621
+ kind=inner_name,
622
+ is_inner=True,
623
+ mindist=mindist,
624
+ symtol=symtol,
625
+ show_plots=show_plots,
626
+ rows=3, # rows
627
+ cols=2, # columns
628
+ num=3) # start num
749
629
 
750
630
  # outer part
751
631
  machine_outer = symmetry_search(machine_outer,
@@ -759,29 +639,20 @@ def convert(dxfile,
759
639
  cols=2, # columns
760
640
  num=4) # start num
761
641
 
762
- machine_inner = inner_queue.get()
763
- inner_proc.wait()
764
642
  process_timer.stop("-- symmetry search in %0.4f seconds --", info=True)
765
643
 
766
644
  machine_inner.sync_with_counterpart(machine_outer)
767
645
 
768
646
  final_timer = Timer(start_it=True)
769
- inner_queue = multiprocessing.Queue()
770
- inner_proc = BuildInnerProcess(name="Inner", # for logger
771
- queue=inner_queue,
772
- machine=machine_inner,
773
- mindist=mindist,
774
- plt=p,
775
- EESM=EESM,
776
- no_processing=no_processing)
777
- inner_proc.start_task()
647
+ machine_inner = build_inner_machine(machine_inner,
648
+ mindist=mindist,
649
+ plt=p,
650
+ EESM=EESM)
778
651
 
779
652
  machine_outer = build_outer_machine(machine_outer,
780
653
  mindist,
781
654
  p,
782
655
  EESM=EESM)
783
- machine_inner = inner_queue.get()
784
- inner_proc.wait()
785
656
  final_timer.stop("-- final part in %0.4f seconds --", info=True)
786
657
 
787
658
  machine_inner.sync_with_counterpart(machine_outer)
@@ -963,7 +834,7 @@ def convert(dxfile,
963
834
  r_out = 0.0
964
835
  r_in = 0.0
965
836
  if machine.cut_is_possible(r_in, r_out):
966
- logger.info("make a cut")
837
+ logger.debug("make a cut")
967
838
  machine = machine.cut(r_in, r_out)
968
839
 
969
840
  if part:
@@ -1085,6 +956,37 @@ def convert(dxfile,
1085
956
  return conv
1086
957
 
1087
958
 
959
+ def _create_rotor_parameters(machine):
960
+ rotor = {
961
+ 'min_radius': machine.geom.min_radius,
962
+ 'max_radius': machine.geom.max_radius,
963
+ 'mags': machine.geom.magnets_minmax_list(),
964
+ 'fd_wnds': machine.geom.fd_windings_minmax_list()
965
+ }
966
+ shaft_min, shaft_max = machine.geom.shaft_minmax()
967
+ if shaft_max > 0.0:
968
+ rotor['shaft_min'] = shaft_min
969
+ rotor['shaft_max'] = shaft_max
970
+ if shaft_max > rotor['min_radius']:
971
+ rotor['min_radius'] = shaft_max
972
+ return rotor
973
+
974
+
975
+ def _create_stator_parameters(machine):
976
+ stator = {
977
+ 'min_radius': machine.geom.min_radius,
978
+ 'max_radius': machine.geom.max_radius,
979
+ 'wnds': machine.geom.windings_minmax_list()
980
+ }
981
+ shaft_min, shaft_max = machine.geom.shaft_minmax()
982
+ if shaft_max > 0.0:
983
+ stator['shaft_min'] = shaft_min
984
+ stator['shaft_max'] = shaft_max
985
+ if shaft_max > stator['min_radius']:
986
+ stator['min_radius'] = shaft_max
987
+ return stator
988
+
989
+
1088
990
  def create_femag_parameters(m_inner, m_outer, nodedist=1):
1089
991
  if not (m_inner and m_outer):
1090
992
  logger.warning("inner %s outer %s", m_inner, m_outer)
@@ -1127,6 +1029,13 @@ def create_femag_parameters(m_inner, m_outer, nodedist=1):
1127
1029
  params['alfa_slot'] = alfa_slot
1128
1030
  params['alfa_pole'] = alfa_pole
1129
1031
 
1032
+ if m_inner.geom.is_rotor():
1033
+ params['rotor'] = _create_rotor_parameters(m_inner)
1034
+ params['stator'] = _create_stator_parameters(m_outer)
1035
+ else:
1036
+ params['rotor'] = _create_rotor_parameters(m_outer)
1037
+ params['stator'] = _create_stator_parameters(m_inner)
1038
+
1130
1039
  if num_slots == 0 or num_poles == 0:
1131
1040
  if num_slots == 0:
1132
1041
  logger.warning("No slots found")
@@ -1154,6 +1063,8 @@ def create_femag_parameters_stator(motor, position):
1154
1063
  params['dy1'] = 2*motor.geom.max_radius
1155
1064
  params['da1'] = 2*motor.geom.min_radius
1156
1065
  params['slot_area'] = motor.slot_area()
1066
+ params['stator'] = _create_stator_parameters(motor)
1067
+ params['machine'] = motor
1157
1068
  return params
1158
1069
 
1159
1070
 
@@ -1168,4 +1079,6 @@ def create_femag_parameters_rotor(motor, position):
1168
1079
  params['dy1'] = 2*motor.geom.max_radius
1169
1080
  params['da1'] = 2*motor.geom.min_radius
1170
1081
  params['slot_area'] = motor.slot_area()
1082
+ params['rotor'] = _create_rotor_parameters(motor)
1083
+ params['machine'] = motor
1171
1084
  return params
femagtools/dxfsl/geom.py CHANGED
@@ -4528,6 +4528,55 @@ class Geometry(object):
4528
4528
  add_element(e)
4529
4529
  self.area_list += area_list
4530
4530
 
4531
+ def areas_minmax_list(self, area_list):
4532
+ if not area_list:
4533
+ return []
4534
+
4535
+ dist_list = []
4536
+ for n, a in enumerate(area_list):
4537
+ dist_list.append((a.min_dist, a.max_dist, n))
4538
+ dist_list.sort()
4539
+
4540
+ minmax_list = []
4541
+ d1_this, d2_this, n = dist_list [0]
4542
+ for d1_next, d2_next, n in dist_list[1:]:
4543
+ if d1_next > d2_this:
4544
+ minmax_list.append((d1_this, d2_this))
4545
+ d1_this = d1_next
4546
+ d2_this = d2_next
4547
+ else:
4548
+ d2_this = max(d2_this, d2_next)
4549
+ minmax_list.append((d1_this, d2_this))
4550
+ return minmax_list
4551
+
4552
+ def magnets_minmax_list(self):
4553
+ magnets = [a for a in self.list_of_areas()
4554
+ if a.is_magnet()]
4555
+ return self.areas_minmax_list(magnets)
4556
+
4557
+ def windings_minmax_list(self):
4558
+ windings = [a for a in self.list_of_areas()
4559
+ if a.is_winding()]
4560
+ return self.areas_minmax_list(windings)
4561
+
4562
+ def fd_windings_minmax_list(self):
4563
+ windings = [a for a in self.list_of_areas()
4564
+ if a.is_field_winding()]
4565
+ return self.areas_minmax_list(windings)
4566
+
4567
+ def shaft_minmax(self):
4568
+ shafts = [a for a in self.list_of_areas()
4569
+ if a.is_shaft()]
4570
+ if not shafts:
4571
+ return (0.0, 0.0)
4572
+
4573
+ dmin = shafts[0].min_dist
4574
+ dmax = shafts[0].max_dist
4575
+ for s in shafts[1:]:
4576
+ dmin = min(dmin, s.min_dist)
4577
+ dmax = max(dmax, s.max_dist)
4578
+ return (dmin, dmax)
4579
+
4531
4580
  def check_airgap_connecting_nodes(self, geom, startangle, endangle):
4532
4581
  logger.info("check_airgap_connecting_nodes")
4533
4582
 
femagtools/femag.py CHANGED
@@ -802,8 +802,10 @@ class ZmqFemag(BaseFemag):
802
802
  """attaches a notify function"""
803
803
  logger.info("Subscribe on '%s' port %d", self.femaghost, self.port+1)
804
804
  if self.subscriber is None:
805
+ # progress/xyplot at a configured timestep published
806
+ header = [b'progress', b'xyplot', b'license']
805
807
  self.subscriber = femagtools.zmq.SubscriberTask(
806
- port=self.port+1, host=self.femaghost, notify=notify)
808
+ port=self.port+1, host=self.femaghost, notify=notify, header=header)
807
809
  self.subscriber.start()
808
810
  else:
809
811
  # reattach?
@@ -1087,7 +1089,7 @@ class ZmqFemag(BaseFemag):
1087
1089
  response = self.send_request(
1088
1090
  ['CONTROL', f'getfile = {filename}'], timeout=1000)
1089
1091
  return [response[0].decode('latin1'),
1090
- response[1] if len(response) else b'']
1092
+ response[1] if len(response) > 1 else b'']
1091
1093
 
1092
1094
  def exportsvg(self, fslcmds, timeout=10000):
1093
1095
  """get svg format from fsl commands (if any graphic created)
@@ -1156,6 +1158,7 @@ class ZmqFemag(BaseFemag):
1156
1158
  logger.info("Interrupt %s", self.femaghost)
1157
1159
  ctrl.send_string('interrupt')
1158
1160
  ctrl.close()
1161
+ femagtools.zmq.SubscriberTask.clear()
1159
1162
 
1160
1163
  def copy_winding_file(self, name, wdg):
1161
1164
  wdg.write(name, self.workdir)