femagtools 1.8.0__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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  """
4
4
  __title__ = 'femagtools'
5
- __version__ = '1.8.0'
5
+ __version__ = '1.8.2'
6
6
  __author__ = 'Ronald Tanner'
7
7
  __license__ = 'BSD'
8
8
  __copyright__ = 'Copyright 2023-2024 Gamma Technology'
femagtools/dxfsl/area.py CHANGED
@@ -100,6 +100,9 @@ class Area(object):
100
100
  def elements(self):
101
101
  return self.area
102
102
 
103
+ def copy_of_elements(self):
104
+ return [e.clone() for e in self.elements() if e]
105
+
103
106
  def list_of_nodes(self):
104
107
  if len(self.area) < 1:
105
108
  return
@@ -822,9 +825,9 @@ class Area(object):
822
825
  mm[3] = max(mm[3], n[3])
823
826
  return mm
824
827
 
825
- def intersect_line(self, line):
828
+ def intersect_area(self, line):
826
829
  for e in self.area:
827
- if e.intersect_line(line):
830
+ if e.intersect_shape(line, include_end=True):
828
831
  return True
829
832
  return False
830
833
 
@@ -1208,6 +1211,7 @@ class Area(object):
1208
1211
 
1209
1212
  angles.sort(reverse=True)
1210
1213
  # calculate orientation (no rectangle check)
1214
+
1211
1215
  l, alpha = angles[0]
1212
1216
  phi = normalise_angle(alpha + np.pi/2)
1213
1217
  logger.debug("alpha = %s, phi = %s", alpha, phi)
@@ -1216,9 +1220,13 @@ class Area(object):
1216
1220
  angle = alpha_angle(mid, phi)
1217
1221
  logger.debug("phi=%s, mid=%s, angle=%s", phi, mid, angle)
1218
1222
 
1219
- if greater(angle, np.pi * 0.5, rtol=1e-5) and \
1223
+ if np.isclose(mid, alpha, rtol=1e-3, atol=1e-3):
1224
+ phi = mid
1225
+ logger.debug("correction of phi=%s", phi)
1226
+ elif greater(angle, np.pi * 0.5, rtol=1e-5) and \
1220
1227
  less(angle, np.pi * 1.5, rtol=1e-5):
1221
1228
  phi = normalise_angle(phi + np.pi)
1229
+ logger.debug("correction of phi=%s", phi)
1222
1230
 
1223
1231
  logger.debug("phi of magnet %s is %s", self.identifier(), phi)
1224
1232
  return phi
@@ -1321,6 +1329,32 @@ class Area(object):
1321
1329
  return np.isclose(angle, border_angle,
1322
1330
  rtol=1e-03, atol=1e-03)
1323
1331
 
1332
+ def set_subregion_parameters(self,
1333
+ is_inner,
1334
+ min_radius,
1335
+ max_radius,
1336
+ startangle,
1337
+ endangle):
1338
+ ag_delta = (max_radius - min_radius) / 500.0
1339
+ if is_inner:
1340
+ self.close_to_ag = greater_equal(self.max_dist + ag_delta, max_radius)
1341
+ close_to_opposition = np.isclose(min_radius, self.min_dist)
1342
+ airgap_radius = max_radius
1343
+ opposite_radius = min_radius
1344
+ else:
1345
+ self.close_to_ag = less_equal(self.min_dist - ag_delta, min_radius)
1346
+ close_to_opposition = np.isclose(max_radius, self.max_dist)
1347
+ airgap_radius = min_radius
1348
+ opposite_radius = max_radius
1349
+
1350
+ airgap_toleranz = (self.max_dist - self.min_dist) / 50.0 # 2%
1351
+
1352
+ self.close_to_startangle = np.isclose(self.min_angle, startangle,
1353
+ 1e-04, 1e-04)
1354
+ self.close_to_endangle = np.isclose(self.max_angle, endangle,
1355
+ 1e-04, 1e-04)
1356
+ self.surface = self.area_size()
1357
+
1324
1358
  def mark_stator_subregions(self,
1325
1359
  is_inner,
1326
1360
  stator_size,
@@ -1791,6 +1825,16 @@ class Area(object):
1791
1825
  for i in a.nested_areas_inside():
1792
1826
  yield i
1793
1827
 
1828
+ def mirror_area(self, center, axis_m, axis_n):
1829
+ elements = []
1830
+ for e in self.area:
1831
+ el = e.mirror_shape(center, axis_m, axis_n)
1832
+ if el:
1833
+ elements.append(el)
1834
+ area = Area(elements, center, 0.0)
1835
+ area.type = self.type
1836
+ return area
1837
+
1794
1838
  def __str__(self):
1795
1839
  return "Area {}\n".format(self.id) + \
1796
1840
  "distance...............: from {} to {}\n".\
@@ -338,7 +338,7 @@ class EdgeInfo(object):
338
338
  return True # two lines
339
339
 
340
340
  def arc_line_direction_lefthand(self, start_edge, line_edge, builder):
341
- logger.info("begin of arc_line_direction_lefthand")
341
+ logger.debug("begin of arc_line_direction_lefthand")
342
342
  if not self.is_arc():
343
343
  logger.critical("FATAL: unexpected %s at position %s", self.classname(), self.n1)
344
344
  sys.exit(1)
@@ -630,7 +630,7 @@ class AreaBuilder(object):
630
630
  logger.debug("begin of create_inner_corner_auxiliary_areas")
631
631
  if not self.geom.is_inner:
632
632
  logger.debug("end of create_inner_corner_auxiliary_areas: not inner")
633
- return
633
+ return False
634
634
 
635
635
  self.set_edge_attributes()
636
636
 
@@ -647,17 +647,18 @@ class AreaBuilder(object):
647
647
 
648
648
  if start_exists and end_exists:
649
649
  logger.debug("end of create_inner_corner_auxiliary_areas: no aktion")
650
- return
650
+ return False
651
651
 
652
652
  airgap_line, airgap_el = self.get_inner_airgap_line()
653
653
  if not airgap_el:
654
654
  logger.debug("end of create_inner_corner_auxiliary_areas: no airgapline found")
655
- return
655
+ return False
656
656
 
657
657
  logger.debug("airgapline found !!")
658
658
  airgap_nodes = [n for n in airgap_line[1:]]
659
659
  del airgap_nodes[-1]
660
660
 
661
+ created = False
661
662
  if not start_exists:
662
663
  cp = self.geom.start_corners[-1]
663
664
  logger.debug("Start Corner: %s -- %s", cp, start_cp)
@@ -683,6 +684,7 @@ class AreaBuilder(object):
683
684
  n,
684
685
  color='red',
685
686
  linestyle='dotted')
687
+ created = True
686
688
  start_node = self.geom.get_node(start_cp)
687
689
  self.geom.add_edge(cp, start_node, start_line)
688
690
  result = self.get_new_area(start_node, n)
@@ -715,6 +717,7 @@ class AreaBuilder(object):
715
717
  self.geom.add_line(end_cp, n,
716
718
  color='red',
717
719
  linestyle='dotted')
720
+ created = True
718
721
  end_node = self.geom.get_node(end_cp)
719
722
  self.geom.add_edge(cp, end_node, end_line)
720
723
  result = self.get_new_area(n, end_node)
@@ -725,81 +728,126 @@ class AreaBuilder(object):
725
728
  break
726
729
 
727
730
  logger.debug("end of create_inner_corner_auxiliary_areas")
731
+ return created
728
732
 
729
- def get_inner_airgap_line(self):
730
- logger.debug("begin of get_inner_airgap_line")
731
- assert(self.geom.is_inner)
732
- assert(self.geom.area_list)
733
-
734
- area = [a for a in self.geom.area_list if a.close_to_ag_endcorner]
735
- if len(area) != 1:
736
- logger.debug("end of get_inner_airgap_line: %s areas found", len(area))
737
- return [], []
733
+ def get_airgap_line(self, start_node, end_node, area):
734
+ logger.debug("get_airgap_line")
738
735
 
739
- end_corner = self.geom.end_corners[-1]
740
- logger.debug("END CORNER %s", end_corner)
736
+ self.set_edge_attributes()
741
737
 
742
- nodes = [n for n in area[0].list_of_nodes()]
738
+ nodes = [n for n in area.list_of_nodes()]
743
739
  if not nodes:
744
- logger.debug("end of get_inner_airgap_line: no nodes found")
740
+ logger.debug("end of get_airgap_line: no nodes found")
745
741
  return [], []
746
742
 
747
743
  n1 = nodes[0]
748
- if points_are_close(end_corner, n1):
744
+ if points_are_close(start_node, n1):
749
745
  n2 = nodes[-1]
750
746
  else:
751
747
  n2 = n1
752
748
  for n1 in nodes[1:]:
753
- if points_are_close(end_corner, n1):
749
+ if points_are_close(start_node, n1):
754
750
  break
755
751
  n2 = n1
756
752
 
757
- if not points_are_close(end_corner, n1):
758
- logger.debug("end of get_inner_airgap_line: not close to endcorner")
753
+ if not points_are_close(start_node, n1):
754
+ logger.debug("end of get_airgap_line: not close to start-node")
759
755
  return [], []
760
756
 
761
- start_corner = self.geom.start_corners[-1]
762
- logger.debug("START CORNER %s", end_corner)
763
-
764
- logger.debug("EDGE FOUND: %s - %s", n1, n2)
757
+ logger.debug("START EDGE FOUND: %s - %s", n1, n2)
765
758
  nodes = [n1, n2]
766
759
  info = self.get_edge_info(n1, n2)
767
760
  elements = [info.element]
768
761
 
769
- while not points_are_close(start_corner, n2):
762
+ while not points_are_close(end_node, n2):
770
763
  info.set_start_angle()
771
764
  info = self.next_edge_lefthand_side(info)
772
765
  if not info: # bad
773
- return []
766
+ return [], []
774
767
  n2 = info.n2
775
768
  nodes.append(n2)
776
769
  elements.append(info.element)
777
770
 
778
- logger.debug("end of get_inner_airgap_line #%s", len(nodes))
771
+ logger.debug("end of get_airgap_line #%s", len(nodes))
779
772
  return nodes, elements
780
773
 
781
- def get_element_line(self, start_node, end_node):
782
- logger.debug("begin of get_element_line")
774
+ def get_inner_airgap_line(self):
775
+ logger.debug("begin of get_inner_airgap_line")
776
+ assert(self.geom.is_inner)
783
777
  assert(self.geom.area_list)
784
778
 
785
- logger.debug("-- get line from %s to %s", start_node, end_node)
779
+ area = [a for a in self.geom.area_list if a.close_to_ag_endcorner]
780
+ if len(area) != 1:
781
+ logger.debug("end of get_inner_airgap_line: %s areas found", len(area))
782
+ return [], []
786
783
 
787
- logger.debug("EDGE FOUND: %s - %s", n1, n2)
788
- nodes = [n1, n2]
789
- info = self.get_edge_info(n1, n2)
790
- elements = [info.element]
784
+ start_node = self.geom.end_corners[-1]
785
+ logger.debug("START NODE %s", start_node)
786
+ end_node = self.geom.start_corners[-1]
787
+ logger.debug("END NODE %s", end_node)
791
788
 
792
- while not points_are_close(start_corner, n2):
793
- info.set_start_angle()
794
- info = self.next_edge_lefthand_side(info)
795
- if not info: # bad
796
- return []
797
- n2 = info.n2
798
- nodes.append(n2)
799
- elements.append(info.element)
789
+ return self.get_airgap_line(start_node, end_node, area[0])
800
790
 
801
- logger.debug("end of get_inner_airgap_line #%s", len(nodes))
802
- return nodes, elements
791
+ def close_outer_winding_areas(self):
792
+ logger.debug("close_outer_winding_areas")
793
+
794
+ airgap_line, airgap_el = self.get_outer_airgap_line()
795
+ logger.debug("Outer Airgap with %s Nodes", len(airgap_line))
796
+
797
+ if len(airgap_line) < 5:
798
+ return False
799
+
800
+ n1 = None
801
+ dist_n1 = 0.0
802
+
803
+ e_prev = None
804
+ n_prev = airgap_line[0]
805
+ dist_prev = distance(self.geom.center, n_prev)
806
+ alpha_prev = alpha_line(self.geom.center, n_prev)
807
+ alpha_start = alpha_prev
808
+
809
+ lines_created = 0
810
+ for n in airgap_line[1:]:
811
+ dist = distance(self.geom.center, n)
812
+ alpha = alpha_line(self.geom.center, n)
813
+ if not n1:
814
+ if dist > dist_prev and alpha < alpha_prev:
815
+ n1 = n_prev
816
+ dist_n1 = dist_prev
817
+ else:
818
+ if np.isclose(dist_n1, dist, rtol=1e-3, atol=1e-3):
819
+ line = Line(Element(start=n1, end=n))
820
+ if e_prev.intersect_line(line):
821
+ logger.debug("___LINE NOT POSSIBLE___")
822
+ else:
823
+ self.geom.add_line(n1, n, color='red')
824
+ lines_created += 1
825
+ n1 = None
826
+ dist_n1 = 0.0
827
+ if not n1:
828
+ e_prev = self.geom.get_edge_element(n_prev, n)
829
+ n_prev = n
830
+ dist_prev = dist
831
+ alpha_prev = alpha
832
+
833
+ return lines_created > 0
834
+
835
+ def get_outer_airgap_line(self):
836
+ logger.debug("begin of get_outer_airgap_line")
837
+ assert(self.geom.is_outer)
838
+ assert(self.geom.area_list)
839
+
840
+ area = [a for a in self.geom.area_list if a.close_to_ag_startcorner]
841
+ if len(area) != 1:
842
+ logger.debug("end of get_outer_airgap_line: %s areas found", len(area))
843
+ return [], []
844
+
845
+ start_node = self.geom.start_corners[0]
846
+ logger.debug("START NODE %s", start_node)
847
+ end_node = self.geom.end_corners[0]
848
+ logger.debug("END NODE %s", end_node)
849
+
850
+ return self.get_airgap_line(start_node, end_node, area[0])
803
851
 
804
852
  def create_one_area_group(self, areas):
805
853
  logger.debug("begin of create_one_area_group")
femagtools/dxfsl/conv.py CHANGED
@@ -250,11 +250,6 @@ def main():
250
250
  keys = ('tot_num_slot', 'num_sl_gen', 'num_poles', 'nodedist',
251
251
  'dy1', 'da1', 'da2', 'dy2', 'agndst', 'name')
252
252
  logger.info("%s", {k: res[k] for k in keys if k in res})
253
- if args.write_fsl:
254
- if res is not None:
255
- basename = os.path.basename(args.dxfile).split('.')[0]
256
- with io.open(basename + '.fsl', 'w', encoding='utf-8') as f:
257
- f.write('\n'.join(res['fsl']))
258
253
 
259
254
  if __name__ == "__main__":
260
255
  loglevel = logging.INFO
@@ -2,6 +2,7 @@
2
2
 
3
3
  """
4
4
  import os
5
+ import io
5
6
  from pathlib import Path
6
7
  from femagtools import __version__
7
8
  from femagtools.dxfsl.geom import Geometry
@@ -11,6 +12,7 @@ from femagtools.dxfsl.plotrenderer import PlotRenderer
11
12
  from femagtools.dxfsl.concat import Concatenation
12
13
  from femagtools.dxfsl.functions import Timer, middle_angle
13
14
  from femagtools.dxfsl.journal import Journal, getJournal
15
+ from femagtools.dxfsl.area import TYPE_WINDINGS
14
16
  import logging
15
17
  import logging.config
16
18
  import numpy as np
@@ -160,12 +162,16 @@ def symmetry_search(machine,
160
162
 
161
163
 
162
164
  def build_machine_rotor(machine, inner, mindist, plt, EESM=False, single=False):
165
+ global journal
163
166
  logger.debug("Begin of build_machine_rotor")
167
+
164
168
  if machine.has_windings():
165
169
  logger.debug("do nothing here with windings in rotor")
166
170
  logger.debug("End of build_machine_rotor")
167
171
  return machine
168
172
 
173
+ timer = Timer(start_it=True)
174
+
169
175
  if machine.is_mirrored():
170
176
  logger.debug("Rotor is mirrored")
171
177
  machine_temp = machine.undo_mirror()
@@ -175,15 +181,25 @@ def build_machine_rotor(machine, inner, mindist, plt, EESM=False, single=False):
175
181
  else:
176
182
  machine_temp = machine
177
183
 
178
- midangle = middle_angle(machine_temp.startangle,
179
- machine_temp.endangle)
180
-
181
184
  plot_geom(False, # for developer
182
185
  plt, machine_temp.geom,
183
- title="Inner Rotor check magnets {}".format(midangle))
186
+ title="Inner Rotor check magnets")
187
+
188
+ machine_slice = machine_temp.get_forced_magnet_slice()
189
+ if machine_slice:
190
+ plot_geom(False, # for developer
191
+ plt, machine_slice.geom,
192
+ title="Rotor Magnet Slice")
193
+
194
+ machine_temp = machine_slice
195
+ machine_temp.geom.set_rotor()
196
+ machine_temp.rebuild_subregions(EESM, single=single)
197
+ plot_geom(False, # for developer
198
+ plt, machine_temp.geom,
199
+ title="Rotor Magnet Slice after Rebuild")
184
200
 
185
201
  rebuild = False
186
- if machine_temp.geom.magnets_in_the_middle(midangle):
202
+ if machine_temp.has_magnets_in_the_middle():
187
203
  logger.debug("Magnets cut")
188
204
  rebuild = machine_temp.create_mirror_lines_outside_magnets()
189
205
  else:
@@ -194,7 +210,7 @@ def build_machine_rotor(machine, inner, mindist, plt, EESM=False, single=False):
194
210
  else:
195
211
  rebuild = machine_temp.create_mirror_lines_outside_magnets()
196
212
  if rebuild:
197
- machine_temp.geom.area_list = []
213
+ machine_temp.geom.create_list_of_areas(delete=True)
198
214
 
199
215
  if machine_temp.create_auxiliary_lines():
200
216
  logger.debug("Auxiliary Lines created: rebuild subregions")
@@ -207,25 +223,34 @@ def build_machine_rotor(machine, inner, mindist, plt, EESM=False, single=False):
207
223
  machine_temp.create_inner_corner_areas()
208
224
 
209
225
  if not machine_temp.is_mirrored():
210
- machine_temp.create_boundery_nodes()
226
+ plot_geom(False, # for developer
227
+ plt, machine_temp.geom,
228
+ title="Rotor before Boundery Corr")
229
+ machine_temp.create_boundary_nodes()
211
230
 
212
231
  plot_geom(False, # for developer
213
232
  plt, machine_temp.geom,
214
233
  title="Final Rotor")
234
+
235
+ t = timer.stop("-- rotor created in %0.4f seconds --")
236
+ journal.put('time_rotor_created', t)
237
+
215
238
  logger.debug("End of build_machine_rotor")
216
239
  return machine_temp
217
240
 
218
241
 
219
242
  def build_machine_stator(machine, inner, mindist, plt, EESM=False, single=False):
243
+ global journal
220
244
  logger.debug("Begin of build_machine_stator")
245
+ timer = Timer(start_it=True)
246
+
221
247
  if not machine.geom.is_stator():
222
248
  logger.debug("Rotor with windings")
223
249
 
224
250
  if machine.is_mirrored():
225
251
  plot_geom(False, # for developer
226
252
  plt, machine.previous_machine.geom,
227
- title="Mirrored Stator",
228
- areas=True)
253
+ title="Mirrored Stator")
229
254
 
230
255
  logger.debug("undo mirrored windings")
231
256
  machine_temp = machine.undo_mirror()
@@ -240,25 +265,50 @@ def build_machine_stator(machine, inner, mindist, plt, EESM=False, single=False)
240
265
  else:
241
266
  machine_temp = machine
242
267
 
243
- rebuild = machine_temp.create_auxiliary_lines()
244
268
  if machine_temp.geom.reduce_element_nodes(mindist):
269
+ machine_temp.rebuild_subregions(EESM, single=single)
245
270
  plot_geom(False, # for developer
246
271
  plt, machine_temp.geom,
247
- title="Nodes reduced",
248
- areas=False)
249
- rebuild = True
250
- if rebuild:
272
+ title="Nodes reduced")
273
+
274
+ machine_slice = machine_temp.get_forced_winding_slice()
275
+ if machine_slice:
276
+ plot_geom(False, # for developer
277
+ plt, machine_slice.geom,
278
+ title="Stator Winding Slice")
279
+
280
+ machine_temp = machine_slice
281
+ machine_temp.geom.set_stator()
251
282
  machine_temp.rebuild_subregions(EESM, single=single)
283
+ if machine_temp.has_windings_in_the_middle():
284
+ machine_temp.create_mirror_lines_outside_windings()
285
+
286
+ plot_geom(False, # for developer
287
+ plt, machine_temp.geom,
288
+ title="Stator Winding Slice after Rebuild")
289
+
290
+ if machine_temp.create_auxiliary_lines():
291
+ machine_temp.rebuild_subregions(EESM, single=single)
292
+ plot_geom(False, # for developer
293
+ plt, machine_temp.geom,
294
+ title="Stator with Auxiliary Lines")
252
295
 
253
296
  if inner:
254
297
  machine_temp.create_inner_corner_areas()
255
298
 
256
299
  if not machine_temp.is_mirrored():
257
- machine_temp.create_boundery_nodes()
300
+ plot_geom(False, # for developer
301
+ plt, machine_temp.geom,
302
+ title="Stator before Boundary Corr")
303
+ machine_temp.create_boundary_nodes()
258
304
 
259
305
  plot_geom(False, # for developer
260
306
  plt, machine_temp.geom,
261
307
  title="Final Stator")
308
+
309
+ t = timer.stop("-- stator created in %0.4f seconds --")
310
+ journal.put('time_stator_created', t)
311
+
262
312
  logger.debug("End of build_machine_stator")
263
313
  return machine_temp
264
314
 
@@ -290,6 +340,7 @@ def convert(dxfile,
290
340
  full_model=False,
291
341
  debug_mode=False,
292
342
  write_journal=False):
343
+ global journal
293
344
  layers = ()
294
345
  conv = {}
295
346
 
@@ -816,10 +867,19 @@ def convert(dxfile,
816
867
 
817
868
  mtype = 'EESM' if EESM else 'PMSM'
818
869
  fslrenderer = FslRenderer(basename, mtype)
819
- conv['fsl'] = fslrenderer.render(machine, inner, outer)
870
+ conv['fsl'] = fslrenderer.render(machine, inner, outer, standalone=True)
820
871
 
821
872
  if params is not None:
822
873
  conv.update(params)
874
+
875
+ if write_fsl:
876
+ logger.debug("Write fsl")
877
+ if conv and conv['fsl']:
878
+ with io.open(basename + '.fsl', 'w', encoding='utf-8') as f:
879
+ f.write('\n'.join(conv['fsl']))
880
+ else:
881
+ logger.warning("No fsl data available")
882
+
823
883
  conv['name'] = basename
824
884
  t = timer.stop("-- all done in %0.4f seconds --", info=True)
825
885
  journal.put('time_total', t)
@@ -840,30 +900,29 @@ def create_femag_parameters(m_inner, m_outer, nodedist=1):
840
900
  parts_inner = int(m_inner.get_symmetry_part())
841
901
  parts_outer = int(m_outer.get_symmetry_part())
842
902
 
843
- slot_area = 0
844
- if parts_inner > parts_outer:
845
- from .area import TYPE_WINDINGS
846
- slot_area = geom_inner.area_size_of_type(TYPE_WINDINGS)
847
- num_slots = int(parts_inner)
848
- num_poles = int(parts_outer)
849
- num_sl_gen = int(geom_inner.get_symmetry_copies()+1)
850
- alfa_slot = geom_inner.get_alfa()
851
- alfa_pole = geom_outer.get_alfa()
903
+ if m_inner.geom.is_rotor():
904
+ geom_slots = geom_outer
905
+ geom_poles = geom_inner
906
+ num_slots = int(m_outer.get_symmetry_part())
907
+ num_poles = int(m_inner.get_symmetry_part())
852
908
  else:
853
- from .area import TYPE_WINDINGS
854
- slot_area = geom_outer.area_size_of_type(TYPE_WINDINGS)
855
- num_slots = int(parts_outer)
856
- num_poles = int(parts_inner)
857
- num_sl_gen = int(geom_outer.get_symmetry_copies()+1)
858
- alfa_slot = geom_outer.get_alfa()
859
- alfa_pole = geom_inner.get_alfa()
909
+ geom_slots = geom_inner
910
+ geom_poles = geom_outer
911
+ num_slots = int(m_inner.get_symmetry_part())
912
+ num_poles = int(m_outer.get_symmetry_part())
913
+
914
+ slot_area = 0
915
+ slot_area = geom_slots.area_size_of_type(TYPE_WINDINGS)
916
+ num_sl_gen = int(geom_slots.get_symmetry_copies()+1)
917
+ alfa_slot = geom_slots.get_alfa()
918
+ alfa_pole = geom_poles.get_alfa()
860
919
 
861
920
  params['tot_num_slot'] = num_slots
862
921
  params['slot_area'] = slot_area
863
922
  params['num_sl_gen'] = num_sl_gen
864
923
  params['num_poles'] = num_poles
865
924
  params['nodedist'] = nodedist
866
- params['external_rotor'] = parts_inner > parts_outer
925
+ params['external_rotor'] = m_outer.geom.is_rotor()
867
926
  params['dy1'] = 2*geom_outer.max_radius
868
927
  params['da1'] = 2*geom_outer.min_radius
869
928
  params['da2'] = 2*geom_inner.max_radius
@@ -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,6 +162,14 @@ 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
175
  NDT0=1.1
@@ -228,18 +236,19 @@ class FslRenderer(object):
228
236
  geom.start_max_corner(1)),
229
237
  'hair = 1.0',
230
238
  'parts = {}'.format(machine.get_num_parts()),
231
- 'r1 = {} + hair'.format(geom.max_radius),
239
+ 'rmax = {}'.format(geom.max_radius),
240
+ 'r1 = rmax + hair',
232
241
  'r, phi = c2pr(x0, y0)',
233
242
  'x1, y1 = pr2c(r1, phi)',
234
243
  'x2, y2 = pr2c(r1, {}*math.pi/parts)'.format(slice),
235
244
  f'-- end max corner {geom.end_corners[-1]}',
236
245
  f'-- center {geom.center}',
237
- f'r = {geom.dist_end_max_corner()}',
238
- 'x3, y3 = pr2c(r, {}*math.pi/parts)'.format(slice),
246
+ 'r2 = {}'.format(geom.dist_end_max_corner(mirrored=False)),
247
+ 'x3, y3 = pr2c(r2, {}*math.pi/parts)'.format(slice),
239
248
  'nc_line(x0, y0, x1, y1, 0)',
240
249
  'nc_circle_m(x1, y1, x2, y2, 0.0, 0.0, 0)',
241
250
  'nc_line(x2, y2, x3, y3, 0)',
242
- 'x0, y0 = pr2c(r1 - hair/2, math.pi/parts/2)',
251
+ 'x0, y0 = pr2c(rmax + hair/2, math.pi/parts/2)',
243
252
  'create_mesh_se(x0, y0)',
244
253
  '\n',
245
254
  'outer_da_start = {}'.format(