femagtools 1.6.0__py3-none-any.whl → 1.6.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.6.0'
5
+ __version__ = '1.6.2'
6
6
  __author__ = 'Ronald Tanner'
7
7
  __license__ = 'BSD'
8
8
  __copyright__ = 'Copyright 2016-2022 SEMAFOR Informatik & Energie AG'
femagtools/bch.py CHANGED
@@ -269,6 +269,28 @@ class Reader:
269
269
  self.weight['conductor'] = sum(w[1])
270
270
  self.weight['magnet'] = sum(w[2])
271
271
  self.weight['total'] = sum([sum(l) for l in w])
272
+
273
+ # check if cogging and fft
274
+ try:
275
+ if (self.type.startswith('Fast cogging')
276
+ and not self.torque_fft):
277
+ from .utils import fft
278
+ # calc frequency sepctrum (assume a full period)
279
+ f = fft(self.torque[0]['angle'],
280
+ self.torque[0]['torque'], pmod=2)
281
+ slots = self.machine['Q']
282
+ poles = 2*self.machine['p']
283
+ n = np.lcm(slots, poles)
284
+ nue = np.arange(0, 5*n).tolist()
285
+ order, tq = np.array(
286
+ [(n, b)
287
+ for n, b in zip(nue, f['nue']) if b > 1e-15 and 2*n % poles == 0]).T
288
+ self.torque_fft = [
289
+ {'order': order.tolist(),
290
+ 'torque': tq.tolist()}]
291
+ except (KeyError, IndexError):
292
+ pass
293
+
272
294
  return self
273
295
 
274
296
  def __findNums(self, l):
@@ -1006,9 +1028,9 @@ class Reader:
1006
1028
  e.g. : idList[-450, -350, -250, -150, -50, 0]
1007
1029
  idList[-500, -400, -300, -200, -100, 0, 0]
1008
1030
  '''
1031
+ diff = np.floor(np.abs(np.diff(idList)))
1009
1032
  if idList[-1] == 0 and len(idList) > 2 and \
1010
- int(idList[-1] - idList[0]) / (len(idList)-1) != \
1011
- int(idList[-2] - idList[0]) / (len(idList)-2):
1033
+ not np.all(diff == diff[0]):
1012
1034
  idList = idList[:-1]
1013
1035
  return idList
1014
1036
 
@@ -1172,7 +1194,7 @@ class Reader:
1172
1194
  cols += [s+'_hyst', s+'_eddy']
1173
1195
  if m:
1174
1196
  # FEMAG-2024.2
1175
- if len(m[0]) > len(subregs[:-1])*2+2:
1197
+ if len(m[0]) > len(subregs[:-1])*2+2:
1176
1198
  cols = []
1177
1199
  for s in subregs[:-2] + ['rotor', 'magnet']:
1178
1200
  cols += [s+'_hyst', s+'_eddy', s+'_excess']
femagtools/dxfsl/conv.py CHANGED
@@ -119,9 +119,13 @@ def main():
119
119
  dest='debug',
120
120
  action="store_true")
121
121
  argparser.add_argument('-l', '--log',
122
- help='print information in logfile',
122
+ help='print information in logfile and set --debug',
123
123
  dest='debug',
124
124
  action="store_true")
125
+ argparser.add_argument('--logfile',
126
+ help='print information in logfile',
127
+ dest='logfile',
128
+ action="store_true")
125
129
  argparser.add_argument('--version',
126
130
  help='show version of some packages',
127
131
  dest='version',
@@ -137,6 +141,7 @@ def main():
137
141
  loglevel = logging.INFO
138
142
  if args.debug:
139
143
  loglevel = logging.DEBUG
144
+ if args.debug or args.logfile:
140
145
  logfilename = 'debugger.log'
141
146
  print("see log-messages in {}".format(logfilename))
142
147
 
@@ -11,6 +11,7 @@ from __future__ import print_function
11
11
  import logging
12
12
  import numpy as np
13
13
  import copy
14
+ import time
14
15
 
15
16
  logger = logging.getLogger('femagtools.functions')
16
17
 
@@ -112,9 +113,11 @@ def round_point(p, n):
112
113
  return (round(p[0], n), round(p[1], n))
113
114
 
114
115
 
115
- def line_m(p1, p2):
116
+ def line_m(p1, p2, none_val=None, dec=0):
116
117
  if np.isclose(p2[0]-p1[0], 0.0):
117
- return None
118
+ return none_val
119
+ if dec > 0:
120
+ return round((p2[1]-p1[1]) / (p2[0]-p1[0]), dec)
118
121
  return (p2[1]-p1[1]) / (p2[0]-p1[0])
119
122
 
120
123
 
@@ -241,6 +244,14 @@ def points_are_close(p1, p2, rtol=1e-05, atol=1e-08):
241
244
  np.isclose(p1[1], p2[1], rtol, atol))
242
245
 
243
246
 
247
+ def point_greater_equal(p1, p2, rtol=1e-05, atol=1e-08):
248
+ if not (p1 and p2):
249
+ return False
250
+ if np.isclose(p1[0], p2[0], rtol, atol): # x equal
251
+ return greater_equal(p1[1], p2[1], rtol, atol) # y >= equal
252
+ return greater_equal(p1[0], p2[0], rtol, atol) # x >= equal
253
+
254
+
244
255
  def nodes_are_equal(n1, n2):
245
256
  if not (n1 and n2):
246
257
  return False
@@ -275,6 +286,14 @@ def normalise_angle(alpha):
275
286
  return alpha
276
287
 
277
288
 
289
+ def positive_angle(alpha):
290
+ """ returns a positive value for angle alpha
291
+ """
292
+ while alpha < 0.0:
293
+ alpha += 2*np.pi
294
+ return alpha
295
+
296
+
278
297
  def is_same_angle(angle1, angle2, atol=0.001):
279
298
  """ returns true if angles are equal
280
299
  """
@@ -404,3 +423,31 @@ def points_on_arc(center, radius, startangle, endangle, parts=8):
404
423
  for alpha in angles_on_arc(start, end, parts=parts):
405
424
  yield (center[0] + radius * np.cos(alpha),
406
425
  center[1] + radius * np.sin(alpha))
426
+
427
+
428
+ class Timer(object):
429
+ def __init__(self, start_it=False):
430
+ self.starttime = None
431
+ if start_it:
432
+ self.start()
433
+
434
+ def __str__(self):
435
+ if self.starttime is None:
436
+ return "Timer is not running"
437
+ stop = time.perf_counter()
438
+ return "Timer is already running for %0.4f seconds" % (stop - self.starttime)
439
+
440
+ def start(self):
441
+ if self.starttime is not None:
442
+ logger.error("Timer is already on")
443
+ self.starttime = time.perf_counter()
444
+
445
+ def stop(self, fmt=None):
446
+ if self.starttime is None:
447
+ logger.error("Timer is not running")
448
+ stop = time.perf_counter()
449
+ sec = stop - self.starttime
450
+ self.starttime = None
451
+ if fmt:
452
+ logger.info(fmt, sec)
453
+ return sec
femagtools/dxfsl/geom.py CHANGED
@@ -135,49 +135,50 @@ def add_or_join(geom, n1, n2, entity, rtol, atol):
135
135
  "Tiny element with same node on both sides ignored: %s", n1)
136
136
  logger.debug(
137
137
  " -- element: %s", entity)
138
+ return
138
139
 
139
- else:
140
- e = geom.get_edge_element(n1, n2)
141
- if e:
142
- logger.debug("Duplicate connection: %s <--> %s", n1, n2)
143
- if is_Line(e):
144
- if is_Line(entity):
145
- logger.debug("add_or_join(): Duplicate Lines ignored")
140
+ e = geom.get_edge_element(n1, n2)
141
+ if not e: # no duplicates
142
+ geom.add_edge(n1, n2, entity)
143
+ return
144
+
145
+ logger.debug("Duplicate connection: %s <--> %s", n1, n2)
146
+ if is_Line(e):
147
+ if is_Line(entity):
148
+ logger.debug("add_or_join(): Duplicate Lines ignored")
149
+ return # its ok
150
+
151
+ if is_Arc(e):
152
+ if is_Arc(entity):
153
+ if points_are_close(e.center, entity.center, rtol=rtol, atol=atol):
154
+ if points_are_close(e.p1, entity.p1):
155
+ logger.debug("add_or_join(): Duplicate Arcs ignored")
146
156
  return # its ok
147
157
 
148
- if is_Arc(e):
149
- if is_Arc(entity):
150
- if points_are_close(e.center, entity.center, rtol=rtol, atol=atol):
151
- if points_are_close(e.p1, entity.p1):
152
- logger.debug("add_or_join(): Duplicate Arcs ignored")
153
- return # its ok
158
+ if is_Circle(entity):
159
+ if is_Circle(e):
160
+ logger.debug("add_or_join(): Duplicate Circle ignored")
161
+ return # its ok
154
162
 
155
- if is_Circle(entity):
156
- if is_Circle(e):
157
- logger.debug("add_or_join(): Duplicate Circle ignored")
158
- return # its ok
163
+ if is_Circle(entity) or is_Circle(e):
164
+ e1, e2 = entity.cut_into_halves()
165
+ logger.debug("===== add_or_join(): Element near circle is cut into halves =====")
166
+ add_element(geom, e1, rtol, atol)
167
+ add_element(geom, e2, rtol, atol)
168
+ return # halves installed
159
169
 
160
- if is_Circle(entity) or is_Circle(e):
161
- e1, e2 = entity.cut_into_halves()
162
- logger.debug("===== add_or_join(): Element near circle is cut into halves =====")
163
- add_element(geom, e1, rtol, atol)
164
- add_element(geom, e2, rtol, atol)
165
- return # halves installed
166
-
167
- m1 = e.center_of_connection()
168
- m2 = entity.center_of_connection()
169
- logger.debug("midpoints: %s -- %s", m1, m2)
170
- if points_are_close(m1, m2, rtol, 1e-2):
171
- logger.debug("Elements are close together")
172
- return # ok
173
-
174
- e1, e2 = entity.cut_into_halves()
175
- logger.debug("===== add_or_join(): cut into halves =====")
176
- add_element(geom, e1, rtol, atol)
177
- add_element(geom, e2, rtol, atol)
178
- return # halves installed
170
+ m1 = e.center_of_connection()
171
+ m2 = entity.center_of_connection()
172
+ logger.debug("midpoints: %s -- %s", m1, m2)
173
+ if points_are_close(m1, m2, rtol, 1e-2):
174
+ logger.debug("Elements are close together")
175
+ return # ok
179
176
 
180
- geom.add_edge(n1, n2, entity)
177
+ e1, e2 = entity.cut_into_halves()
178
+ logger.debug("===== add_or_join(): cut into halves =====")
179
+ add_element(geom, e1, rtol, atol)
180
+ add_element(geom, e2, rtol, atol)
181
+ return # halves installed
181
182
 
182
183
 
183
184
  def get_nodes_of_paths(g, c):
@@ -1108,12 +1109,13 @@ class Geometry(object):
1108
1109
  # Linie als Corner-Objekte.
1109
1110
  corners = [Corner(center, c)
1110
1111
  for c in self.angle_nodes(center, angle, rtol, atol)]
1112
+ center_added = len(corners) == 1
1111
1113
  if len(corners) == 1:
1112
1114
  logger.debug('get_corner_list: the center is a corner')
1113
1115
  corners.append(Corner(center, tuple(center)))
1114
1116
  if len(corners) > 1:
1115
1117
  corners.sort()
1116
- return corners
1118
+ return center_added, corners
1117
1119
 
1118
1120
  def start_min_corner(self, i):
1119
1121
  return self.start_corners[0][i]
@@ -1204,11 +1206,13 @@ class Geometry(object):
1204
1206
  end_pts = [p for p in reversed(self.end_corners)]
1205
1207
  return area_size(pts + end_pts)
1206
1208
 
1207
- def repair_hull_line(self, center, angle, corners, with_center):
1209
+ def repair_hull_line(self, center, angle, corners, with_center, rtol=None, atol=None):
1208
1210
  # We need to set our own tolerance range
1209
1211
  # to find the right points
1210
- rtol = 1e-4
1211
- atol = 1e-4
1212
+ if not rtol:
1213
+ rtol = 1e-3
1214
+ if not atol:
1215
+ atol = 1e-3
1212
1216
 
1213
1217
  logger.debug("begin repair_hull_line(center=%s, angle=%s)", center, angle)
1214
1218
 
@@ -1270,7 +1274,7 @@ class Geometry(object):
1270
1274
  logger.warn("Warning: %s", e)
1271
1275
 
1272
1276
  # Rebuild Corner-list after correction
1273
- corners = self.get_corner_list(center, angle, rtol, atol)
1277
+ center_added, corners = self.get_corner_list(center, angle, rtol, atol)
1274
1278
  for c in corners:
1275
1279
  logger.debug("Correct Corner: %s", c)
1276
1280
 
@@ -1309,7 +1313,7 @@ class Geometry(object):
1309
1313
  if not self.center:
1310
1314
  raise ValueError("FATAL ERROR: no center in Geometry")
1311
1315
 
1312
- corners = self.get_corner_list(self.center, angle)
1316
+ center_added, corners = self.get_corner_list(self.center, angle)
1313
1317
  assert(corners)
1314
1318
  c_min = Corner(self.center, point(self.center, self.min_radius, angle, ndec))
1315
1319
  c_max = Corner(self.center, point(self.center, self.max_radius, angle, ndec))
@@ -1362,7 +1366,7 @@ class Geometry(object):
1362
1366
  rtol = 1e-4
1363
1367
  atol = 1e-4
1364
1368
 
1365
- corners = self.get_corner_list(center, angle, rtol, atol)
1369
+ center_added, corners = self.get_corner_list(center, angle, rtol, atol)
1366
1370
  if len(corners) < 2:
1367
1371
  return () # not enough corners
1368
1372
  return (corners[0].point(), corners[len(corners)-1].point())
@@ -1903,6 +1907,9 @@ class Geometry(object):
1903
1907
  radius=e.radius,
1904
1908
  start_angle=alpha_start*180/np.pi,
1905
1909
  end_angle=alpha_end*180/np.pi))
1910
+ if points_are_close(a.p1, a.p2, rtol=1e-02, atol=1e-02):
1911
+ logger.debug("ATTENTION: creation of a tiny arc")
1912
+ a.set_attribute("tiny")
1906
1913
  new_elements.append(a)
1907
1914
  alpha_start = alpha_end
1908
1915
  p1 = p2
@@ -1998,7 +2005,8 @@ class Geometry(object):
1998
2005
  atol=0.0,
1999
2006
  append_inner=False,
2000
2007
  append_outer=False,
2001
- delete_appendices=False):
2008
+ delete_appendices=False,
2009
+ concatenate_tiny_el=False):
2002
2010
  """ Die Funktion kopiert die Teile von Shape-Objekten, welche sich in
2003
2011
  der durch die Parameter definierten Teilkreisfläche befinden.
2004
2012
  """
@@ -2099,6 +2107,11 @@ class Geometry(object):
2099
2107
  new_elements.append(arc)
2100
2108
  p1 = p2
2101
2109
 
2110
+ if concatenate_tiny_el:
2111
+ ok, new_elements = self.concatenate_tiny_elements(new_elements)
2112
+ if ok:
2113
+ split = True
2114
+
2102
2115
  if delete_appendices:
2103
2116
  center = []
2104
2117
  else:
@@ -2183,6 +2196,78 @@ class Geometry(object):
2183
2196
  return False
2184
2197
  return True
2185
2198
 
2199
+ def concatenate_arc_elements(self, el, elements):
2200
+ if not is_Arc(el):
2201
+ return False
2202
+
2203
+ def match(e1, e2):
2204
+ if e2.has_attribute("del"):
2205
+ return False
2206
+ if e2.has_attribute("tiny"):
2207
+ return False
2208
+ if not points_are_close(e1.center, e2.center):
2209
+ return False
2210
+ return np.isclose(e1.radius, e2.radius)
2211
+
2212
+ elmts = [(e.p1, e) for e in elements if is_Arc(e) and match(el, e)]
2213
+ elmts.sort()
2214
+
2215
+ ok = False
2216
+ for p, e in elmts:
2217
+ el_new = el.concatenate(None, None, e)
2218
+ if el_new:
2219
+ el.set_attribute("del")
2220
+ e.set_attribute("del")
2221
+ elements.append(el_new)
2222
+ el = el_new
2223
+ ok = True
2224
+ return ok
2225
+
2226
+ def concatenate_line_elements(self, el, elements):
2227
+ if not is_Line(el):
2228
+ return False
2229
+
2230
+ def match(e1, e2):
2231
+ if e2.has_attribute("del"):
2232
+ return False
2233
+ if e2.has_attribute("tiny"):
2234
+ return False
2235
+ return np.isclose(e1.m(999999.0), e2.m(999999.0))
2236
+
2237
+ elmts = [(e.p1, e) for e in elements if is_Line(e) and match(el, e)]
2238
+ elmts.sort()
2239
+
2240
+ ok = False
2241
+ for p, e in elmts:
2242
+ el_new = el.concatenate(None, None, e)
2243
+ if el_new:
2244
+ el.set_attribute("del")
2245
+ e.set_attribute("del")
2246
+ elements.append(el_new)
2247
+ el = el_new
2248
+ ok = True
2249
+ return ok
2250
+
2251
+ def concatenate_tiny_elements(self, new_elements):
2252
+ logger.debug("begin concatenate_tiny_elements")
2253
+ tiny_elements = [e for e in new_elements if e.has_attribute("tiny")]
2254
+ if not tiny_elements:
2255
+ logger.debug("end concatenate_tiny_elements: (%s elements)", 0)
2256
+ return False, new_elements
2257
+
2258
+ count = 0
2259
+ for e_tiny in tiny_elements:
2260
+ if is_Line(e_tiny):
2261
+ if self.concatenate_line_elements(e_tiny, new_elements):
2262
+ count += 1
2263
+ elif is_Arc(e_tiny):
2264
+ if self.concatenate_arc_elements(e_tiny, new_elements):
2265
+ count += 1
2266
+
2267
+ new_list = [e for e in new_elements if not e.has_attribute("del")]
2268
+ logger.debug("end concatenate_tiny_elements: (%s elements)", count)
2269
+ return count>0, new_list
2270
+
2186
2271
  def find_symmetry(self, radius,
2187
2272
  startangle, endangle, sym_tolerance):
2188
2273
  arealist = self.list_of_areas()
@@ -171,7 +171,8 @@ class Machine(object):
171
171
 
172
172
  def copy(self, startangle, endangle,
173
173
  airgap=False, inside=True, split=False,
174
- delete_appendices=False):
174
+ delete_appendices=False,
175
+ concatenate_tiny_el=False):
175
176
  if airgap and self.airgap_radius > 0.0:
176
177
  if inside:
177
178
  if self.airgap2_radius > 0.0:
@@ -182,7 +183,8 @@ class Machine(object):
182
183
  startangle, endangle,
183
184
  0.0, new_radius,
184
185
  split=split,
185
- delete_appendices=delete_appendices)
186
+ delete_appendices=delete_appendices,
187
+ concatenate_tiny_el=concatenate_tiny_el)
186
188
  else:
187
189
  new_radius = self.radius
188
190
  gap_radius = max(self.airgap_radius, self.airgap2_radius)
@@ -190,7 +192,8 @@ class Machine(object):
190
192
  startangle, endangle,
191
193
  gap_radius, self.radius+9999,
192
194
  split=split,
193
- delete_appendices=delete_appendices)
195
+ delete_appendices=delete_appendices,
196
+ concatenate_tiny_el=concatenate_tiny_el)
194
197
 
195
198
  circ = Circle(Element(center=self.center,
196
199
  radius=self.airgap_radius))
@@ -201,7 +204,8 @@ class Machine(object):
201
204
  startangle, endangle, 0.0,
202
205
  self.radius+9999,
203
206
  split=split,
204
- delete_appendices=delete_appendices)
207
+ delete_appendices=delete_appendices,
208
+ concatenate_tiny_el=concatenate_tiny_el)
205
209
 
206
210
  if not np.isclose(normalise_angle(startangle),
207
211
  normalise_angle(endangle), 0.0):
@@ -267,10 +271,18 @@ class Machine(object):
267
271
  def undo_mirror(self):
268
272
  assert(self.is_mirrored())
269
273
  assert(self.previous_machine)
270
- self.set_alfa_and_corners()
274
+ self.previous_machine.clear_mirror()
275
+ self.previous_machine.set_alfa_and_corners()
271
276
  self.previous_machine.set_kind(self.geom.kind)
272
277
  return self.previous_machine
273
278
 
279
+ def clear_mirror(self):
280
+ self.mirror_orig_geom = None
281
+ self.mirror_geom = None
282
+ self.mirror_startangle = 0.0
283
+ self.mirror_endangle = 0.0
284
+ self.geom.mirror_corners = []
285
+
274
286
  def rotate_to(self, new_startangle):
275
287
  if np.isclose(new_startangle, self.startangle):
276
288
  return
@@ -324,9 +336,12 @@ class Machine(object):
324
336
 
325
337
  if len(self.airgaps) > 0:
326
338
  airgap_candidates = []
339
+ prv_radius = 0
327
340
  for g in self.airgaps:
328
341
  gap_radius = round((g[0]+g[1])/2.0, 6)
329
342
  gap_dist = g[1] - g[0]
343
+ prv_dist = g[0] - prv_radius
344
+ prv_radius = g[1]
330
345
  circle = Circle(Element(center=self.center,
331
346
  radius=gap_radius))
332
347
  ok, borders = self.geom.is_airgap(self.center,
@@ -337,12 +352,10 @@ class Machine(object):
337
352
  if not ok:
338
353
  logger.error("FATAL: No Airgap with radius {}".
339
354
  format(gap_radius))
340
- print("FATAL: No Airgap with radius {}".
341
- format(gap_radius))
342
355
  self.geom.airgaps.append(circle)
343
356
  return True # bad exit
344
357
 
345
- airgap_candidates.append((borders, circle, gap_dist))
358
+ airgap_candidates.append((borders, circle, gap_dist, prv_dist))
346
359
  self.geom.airgaps.append(circle)
347
360
 
348
361
  if correct_airgap > 0.0:
@@ -375,7 +388,7 @@ class Machine(object):
375
388
  logger.debug("end airgap: radius=%s", self.airgap_radius)
376
389
  return False # correct airgap set
377
390
 
378
- gaps = [c for b, c, d in airgap_candidates if b == 0]
391
+ gaps = [c for b, c, d, prv_d in airgap_candidates if b == 0]
379
392
 
380
393
  if len(gaps) == 1: # one candidate without border intersection
381
394
  self.airgap_radius = gaps[0].radius
@@ -403,7 +416,7 @@ class Machine(object):
403
416
  dist = 999
404
417
  circle = None
405
418
  pos_list = []
406
- for b, c, d in airgap_candidates:
419
+ for b, c, d, prv_d in airgap_candidates:
407
420
  if get_one:
408
421
  logger.info(" --- {} (width={})".format(c.radius, d))
409
422
  else:
@@ -415,10 +428,14 @@ class Machine(object):
415
428
  inner_pc = (c.radius - self.geom.min_radius) / \
416
429
  (self.geom.max_radius - self.geom.min_radius)
417
430
  pos = np.abs(inner_pc * 100 - 50)
418
- logger.debug("Abstand Mitte = {} %".format(pos))
431
+ logger.debug("Abstand Mitte in % = {}".format(pos))
432
+ prv_dist_percent = int(round(prv_d / self.geom.max_radius, 2) * 100)
433
+ logger.debug("Abstand Vorheriger abs=%s in prz=%s (%s)",
434
+ prv_d, prv_dist_percent, self.geom.max_radius)
419
435
  if pos < 20:
420
436
  pos_list.append([pos, d, c])
421
-
437
+ elif prv_dist_percent <= 1:
438
+ pos_list.append([prv_dist_percent, d, c])
422
439
  if get_one:
423
440
  if pos_list:
424
441
  dist_list = [[d, c] for pos, d, c in pos_list]
@@ -479,16 +496,29 @@ class Machine(object):
479
496
  def repair_hull_geom(self, geom, startangle, endangle):
480
497
  logger.debug('begin repair_hull_geom (%s, %s)', startangle, endangle)
481
498
 
499
+ rtol = 1e-4
500
+ atol = 1e-4
482
501
  c_corner = Corner(self.center, self.center)
483
- start_corners = geom.get_corner_list(self.center, startangle)
484
- end_corners = geom.get_corner_list(self.center, endangle)
502
+ start_c_added, start_corners = geom.get_corner_list(self.center, startangle,
503
+ rtol=rtol, atol=atol)
504
+ end_c_added, end_corners = geom.get_corner_list(self.center, endangle,
505
+ rtol=rtol, atol=atol)
506
+ if start_c_added or end_c_added:
507
+ rtol = 1e-3
508
+ atol = 1e-3
509
+ start_c_added, start_corners = geom.get_corner_list(self.center, startangle,
510
+ rtol=rtol, atol=atol)
511
+ end_c_added, end_corners = geom.get_corner_list(self.center, endangle,
512
+ rtol=rtol, atol=atol)
485
513
 
486
514
  geom.repair_hull_line(self.center,
487
515
  startangle, start_corners,
488
- c_corner in end_corners)
516
+ c_corner in end_corners,
517
+ rtol=rtol, atol=atol)
489
518
  geom.repair_hull_line(self.center,
490
519
  endangle, end_corners,
491
- c_corner in start_corners)
520
+ c_corner in start_corners,
521
+ rtol=rtol, atol=atol)
492
522
  logger.debug('end of repair_hull_geom')
493
523
 
494
524
  def create_stator_auxiliary_lines(self):
@@ -666,7 +696,8 @@ class Machine(object):
666
696
  return None
667
697
 
668
698
  machine_slice = self.copy(self.geom.symmetry_startangle(),
669
- self.geom.symmetry_endangle())
699
+ self.geom.symmetry_endangle(),
700
+ concatenate_tiny_el=True)
670
701
  machine_slice.clear_cut_lines()
671
702
  machine_slice.repair_hull()
672
703
  machine_slice.rotate_to(0.0)
femagtools/dxfsl/shape.py CHANGED
@@ -853,9 +853,11 @@ class Arc(Circle):
853
853
  if np.isclose(self.startangle, el.endangle):
854
854
  start_angle = el.startangle
855
855
  end_angle = self.endangle
856
- else:
856
+ elif np.isclose(el.startangle, self.endangle):
857
857
  start_angle = self.startangle
858
858
  end_angle = el.endangle
859
+ else:
860
+ return None
859
861
 
860
862
  logger.debug("concatenate_arc: start=%s, end=%s",
861
863
  start_angle,
@@ -1234,8 +1236,20 @@ class Line(Shape):
1234
1236
  return l1, l2
1235
1237
 
1236
1238
  def concatenate_line(self, n1, n2, el):
1237
- if np.isclose(self.m(999999.0), el.m(999999.0)):
1239
+ if not np.isclose(self.m(999999.0), el.m(999999.0)):
1240
+ return None
1241
+
1242
+ if n1 and n2:
1238
1243
  return Line(Element(start=n1, end=n2))
1244
+
1245
+ if points_are_close(self.p1, el.p1):
1246
+ return Line(Element(start=self.p2, end=el.p2))
1247
+ if points_are_close(self.p1, el.p2):
1248
+ return Line(Element(start=self.p2, end=el.p1))
1249
+ if points_are_close(self.p2, el.p1):
1250
+ return Line(Element(start=self.p1, end=el.p2))
1251
+ if points_are_close(self.p2, el.p2):
1252
+ return Line(Element(start=self.p1, end=el.p1))
1239
1253
  return None
1240
1254
 
1241
1255
  def is_point_inside(self, point,
femagtools/isa7.py CHANGED
@@ -868,9 +868,17 @@ class Isa7(object):
868
868
  except AttributeError:
869
869
  pass
870
870
 
871
- try:
872
- el_fe_ind = [np.array(reader.el_fe_induction_1).T/1000,
873
- np.array(reader.el_fe_induction_2).T/1000]
871
+ try:
872
+ flx_fac = 1000
873
+ if isinstance(reader.el_fe_induction_1, list):
874
+ pass
875
+ else:
876
+ if reader.el_fe_induction_1.dtype == 'int16':
877
+ flx_fac = 1000
878
+ else:
879
+ flx_fac = 1
880
+ el_fe_ind = [np.array(reader.el_fe_induction_1).T/flx_fac,
881
+ np.array(reader.el_fe_induction_2).T/flx_fac]
874
882
  eddy_cu_vpot = np.array(reader.eddy_cu_vpot).T/1000
875
883
  if len(el_fe_ind[0].shape) == 4:
876
884
  pdim = self.pos_el_fe_induction.shape[0]
@@ -891,8 +899,9 @@ class Isa7(object):
891
899
  n += 1
892
900
  if n > 0:
893
901
  shape.append(n)
894
- el_fe_ind = [np.array([[reader.el_fe_induction_1[0][0][:shape[0]]]]).T/1000,
895
- np.array([[reader.el_fe_induction_2[0][0][:shape[0]]]]).T/1000]
902
+
903
+ el_fe_ind = [np.array([[reader.el_fe_induction_1[0][0][:shape[0]]]]).T/flx_fac,
904
+ np.array([[reader.el_fe_induction_2[0][0][:shape[0]]]]).T/flx_fac]
896
905
  eddy_cu_vpot = np.array([[reader.eddy_cu_vpot[0][0][:shape[0]]]]).T/1000
897
906
 
898
907
  self.el_fe_induction_1 = el_fe_ind[0]
@@ -33,7 +33,7 @@ def create_from_eecpars(temp, eecpars, lfe=1, wdg=1):
33
33
  rlfe = lfe
34
34
  rwdg = wdg
35
35
  opts = {k: eecpars[k] for k in ('zeta1', 'gam', 'kh', 'kpfe',
36
- 'kfric_b') if k in eecpars}
36
+ 'kfric_b', 'kpmag') if k in eecpars}
37
37
  try:
38
38
  opts['rotor_mass'] = rlfe*eecpars['rotor_mass']
39
39
  except KeyError:
@@ -309,7 +309,7 @@ def efficiency_losses_map(eecpars, u1, T, temp, n, npoints=(60, 40),
309
309
  if isinstance(m, (PmRelMachine, SynchronousMachine)):
310
310
  plfe1 = m.kpfe*m.iqd_plfe1(*iqd, f1)
311
311
  plfe2 = m.kpfe*m.iqd_plfe2(iqd[0], iqd[1], f1)
312
- plmag = m.iqd_plmag(iqd[0], iqd[1], f1)
312
+ plmag = m.kpmag*m.iqd_plmag(iqd[0], iqd[1], f1)
313
313
  plcu1 = m.iqd_plcu1(iqd[0], iqd[1], 2*np.pi*f1)
314
314
  plcu2 = m.iqd_plcu2(*iqd)
315
315
  tfric = m.tfric
femagtools/machine/pm.py CHANGED
@@ -203,7 +203,7 @@ class PmRelMachine(object):
203
203
  if n > 1e-3:
204
204
  f1 = self.p*n
205
205
  plfe = self.kpfe * (self.iqd_plfe1(iq, id, f1) + self.iqd_plfe2(iq, id, f1))
206
- pmag = self.iqd_plmag(iq, id, f1)
206
+ pmag = self.kpmag * self.iqd_plmag(iq, id, f1)
207
207
  return (plfe + pmag + self.pfric(n))/(2*np.pi*n)
208
208
  return 0
209
209
 
@@ -1261,7 +1261,14 @@ class PmRelMachineLdq(PmRelMachine):
1261
1261
  return self.betai1_plfe2(*betai1(iq, id), f1)
1262
1262
 
1263
1263
  def betai1_plmag(self, beta, i1, f1):
1264
- return self._losses['magnet'](beta, i1)*(f1/self.fo)**2
1264
+ r = self._losses['magnet'](beta, i1)*(f1/self.fo)**2
1265
+ try:
1266
+ idx = np.argwhere(r < 0)
1267
+ if len(idx.squeeze()):
1268
+ r[idx.squeeze()] = 0.0
1269
+ except:
1270
+ pass
1271
+ return r
1265
1272
 
1266
1273
  def iqd_plmag(self, iq, id, f1):
1267
1274
  return self.betai1_plmag(*betai1(iq, id), f1)
femagtools/machine/sm.py CHANGED
@@ -546,7 +546,7 @@ class SynchronousMachine(object):
546
546
  w10)[0]
547
547
 
548
548
  def characteristics(self, T, n, u1max, nsamples=50,
549
- with_tmech=True, with_torque_corr=False):
549
+ with_tmech=True, with_torque_corr=False, **kwargs):
550
550
  """calculate torque speed characteristics.
551
551
  return dict with list values of
552
552
  n, T, u1, i1, beta, cosphi, pmech, n_type
femagtools/utils.py CHANGED
@@ -17,7 +17,7 @@ def fft(pos, y, pmod=0):
17
17
  else:
18
18
  #negative_periodic = np.abs(y[0] - y[-1])/np.max(y) > 1
19
19
  # count zero crossings
20
- ypos = np.asarray(y) > 0
20
+ ypos = np.asarray(y[:-1]) > 0
21
21
  nypos = ~ypos
22
22
  nzc = len(((ypos[:-1] & nypos[1:])
23
23
  | (nypos[:-1] & ypos[1:])).nonzero()[0])
@@ -40,12 +40,12 @@ def fft(pos, y, pmod=0):
40
40
  i = np.argmax(np.abs(Y[:N//2]))
41
41
 
42
42
  a = 2*np.abs(Y[i])/N
43
- freq = np.fft.fftfreq(N, d=pos[1]-pos[0])
43
+ freq = np.fft.fftfreq(N, d=360/N)
44
44
  nmax = min(18*ntiles, N//2)
45
45
  T0 = 0
46
46
  if abs(freq[i]) > 0:
47
47
  T0 = np.abs(1/freq[i])
48
- npoles = 2*int(np.ceil(360/T0))
48
+ npoles = 2*int(360/T0)
49
49
  nmax = min(9*npoles, N//2)
50
50
 
51
51
  alfa0 = np.angle(Y[i])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: femagtools
3
- Version: 1.6.0
3
+ Version: 1.6.2
4
4
  Summary: Python API for FEMAG
5
5
  Author-email: Ronald Tanner <tar@semafor.ch>, Dapu Zhang <dzhang@gtisoft.com>, Beat Holm <hob@semafor.ch>, Günther Amsler <amg@semafor.ch>, Nicolas Mauchle <mau@semafor.ch>
6
6
  License: Copyright (c) 2016-2023, Semafor Informatik & Energie AG, Basel
@@ -1,9 +1,9 @@
1
- femagtools/__init__.py,sha256=R-39ZdZxxAmDeGzV4v9pKcYF3Wpacyx6PJMK6Zk8WdA,1615
1
+ femagtools/__init__.py,sha256=UUpTqpPxTE9-KNmWFDhqdB2Sy56sR68HZdRSYl0X3BA,1615
2
2
  femagtools/airgap.py,sha256=ZCIZTYf6BbuNYx68y9fUDBQo3taN8RuGl8q-jJ7ygiA,1577
3
3
  femagtools/amazon.py,sha256=O1ICuv21XDAJi1qK1Sigs2TdS6hDZP19OzvmE2t76wU,12069
4
4
  femagtools/amela.py,sha256=pHjfXzpANI-7oz8MtrqNcyDZ6PxVM91vCJuvYhHy1rk,13891
5
5
  femagtools/asm.py,sha256=CiL0KWaF4P7O6-VwmGLdva_icwmPrPiI-TFQ19XYTKk,7660
6
- femagtools/bch.py,sha256=5WTs9YjSj-XRFqXeHdf5Ps3jECwn_5-5j6QoVMDqWdE,70841
6
+ femagtools/bch.py,sha256=lw90KDHoC2NNHLYBupUXrJQRt-8yDeV-7usH4ZwkFJk,71680
7
7
  femagtools/bchxml.py,sha256=KrRjAdrUPZXmiWvonu9HhpG_NvImMBpiXWTL4iSr4kE,3142
8
8
  femagtools/condor.py,sha256=J8z9iBdvrGu3I1eFNoyKV8AXzRoTEPGLSak6cXUQxAM,10766
9
9
  femagtools/conductor.py,sha256=rXO7c7Qh_s7JpgILmLd4IbG64vP6Eh143YF9u25Mdwg,1076
@@ -23,7 +23,7 @@ femagtools/gmsh.py,sha256=IKhNiviIBji4cMxAhxaYXNqBRMNAPSKsBGdnGyxkyQw,3903
23
23
  femagtools/google.py,sha256=ugRyHY1zBjHR4aNfbA7GeF-ZU_NgleuVTZaWpi_XLT4,17144
24
24
  femagtools/grid.py,sha256=s7LfKKLm2H4-cza2kSEANq6vwxq10Su3TJl3kHShHRA,1561
25
25
  femagtools/hxy.py,sha256=PkiZ_-CRhtvtpkmLAP8iMtwvzh7CjKGGcAbOhFb4Nls,6275
26
- femagtools/isa7.py,sha256=5v0f2wF9quf3ZTFSbLnQuQW1kIETvVwSVHwhMi0PNTk,58044
26
+ femagtools/isa7.py,sha256=cUZx9fpxZgkw2G-cnveR-X-_lWP7Z1Q88MCysLl9MFI,58336
27
27
  femagtools/jhb.py,sha256=stJxkmzHpfUIBVcFw7jWbV5KN9_EFqzOCgacyhUqWvM,1779
28
28
  femagtools/job.py,sha256=dOatzr10nIda76CjVRSS0SfEWC8_BAw0kowli523qbY,11320
29
29
  femagtools/losscoeffs.py,sha256=dlSYDS13RqpPHLdv_EPWIA9liwhqjbxUiN7t7GFPZhw,5397
@@ -42,29 +42,29 @@ femagtools/parstudy.py,sha256=oP6ukKBCcAjwPK_DzbUEmo5ay2TINamao2aV42FbgP8,18799
42
42
  femagtools/poc.py,sha256=MN5DRL4vHycNzXSTt9kjuZP1yZ2I02NmrKQFsmRcbF0,6536
43
43
  femagtools/tks.py,sha256=FuEKiWcSnOW2Hp2NxCq1hBeQdRFkHutaJuctrhxh8Ws,6228
44
44
  femagtools/ts.py,sha256=x9aCMVASjdBZuyI2pJGMyi1dveGFd_pWQ20cZ-l_moc,47216
45
- femagtools/utils.py,sha256=W7RuLLnSIMqfhHi2UmY_W7bM6zLOJ7CUo_mFZnfB14w,1593
45
+ femagtools/utils.py,sha256=1SX5s21xyW8u0NF_Hjs7DByyCTdLm9VRArLburTyHR0,1581
46
46
  femagtools/vbf.py,sha256=9XGfhftmD9carU8ByQ5DwqoR4daq5mJ39eMqruwml0Q,2444
47
47
  femagtools/vtu.py,sha256=Sf83dHIfCKY2km-MIUHKKoj-JKN4PDX7kkPLZXyIYY4,10723
48
48
  femagtools/windings.py,sha256=6ioABZRWQ3xA4kmEz2NUkXh-C-FmW9YYkjQKs5YakQs,22197
49
49
  femagtools/dxfsl/__init__.py,sha256=MywcCdpKPKs4qJBJJgeDsikJFJ2P48dbTuNk303f5pM,76
50
50
  femagtools/dxfsl/area.py,sha256=ohs6J_X-c6y-FrSd2LFjMc3024N9RcOpDKgsXIsuoNs,57818
51
- femagtools/dxfsl/conv.py,sha256=xOCj0vPlyRVP1FVNPLtKx_Fe88emjaht_DD4bfycD6A,8990
51
+ femagtools/dxfsl/conv.py,sha256=j17gjZ7XjoP6QmEO50ZMA-jyYrcMQEgpDH0hZN26RbM,9236
52
52
  femagtools/dxfsl/converter.py,sha256=6BCwlVp0PiSZ4Wj-YDgl7ynWNN2SBuwxw5VnNQ55Y9w,20821
53
53
  femagtools/dxfsl/corner.py,sha256=UI1MLlVmiTBURywsOnXnXV7eBABoENc6ortkW_3GYH8,1266
54
54
  femagtools/dxfsl/dumprenderer.py,sha256=n4AvInjvGIaC2iKZtQaYXXDyJVSQ3uEOFOLD4-xfKRY,1861
55
55
  femagtools/dxfsl/fslrenderer.py,sha256=C4oonLPzKb_9IKvpm-fMvbhQZqtP_7xWG5bzpq8P1CY,23377
56
- femagtools/dxfsl/functions.py,sha256=Y861cXEWTLVpC5iKOSDqRQ4Idbk4OqQQD-qFK-s8_20,10107
57
- femagtools/dxfsl/geom.py,sha256=DELZXyCOpaNUmzOoL5NHQi9kjtq0qXc4Ry26G2_KHgg,160283
58
- femagtools/dxfsl/machine.py,sha256=sK4N8JHEqxZ-gHWKjlInezxEhTHpFAkopGvUaqAsjgg,40429
56
+ femagtools/dxfsl/functions.py,sha256=5G1MSAVaC4NOpQ_YBZ1SHPsmnvbQsnmg3rLjN3d5mBs,11463
57
+ femagtools/dxfsl/geom.py,sha256=bAZtk_GIO7anaBeZKZhWHGyt9L-t_F1YglCgRc0oU48,163051
58
+ femagtools/dxfsl/machine.py,sha256=ftqLiwCyrzekUSvAOVD9AIM4hrPrIpId7PhLKwvSpWs,42158
59
59
  femagtools/dxfsl/plotrenderer.py,sha256=dIOM8p3UNTlqypxuPcLCegOaK19j3-ahelZ8hneLJ6k,12710
60
- femagtools/dxfsl/shape.py,sha256=H18nAtoOladnQIM-XKiIDHFpZbls4cs5cVJ-j7yAriM,47755
61
- femagtools/machine/__init__.py,sha256=xMypyugPeEe7qHBAn2UWjiHdVYYfP6eoO56k1ZIEBss,7165
60
+ femagtools/dxfsl/shape.py,sha256=4onAfXaVUWxC9C2WXVLYi3UH6w2lhUHxuLjdFgQOqks,48302
61
+ femagtools/machine/__init__.py,sha256=U8W65K7jr7jDdC1KnJh0WjYd8DFaLnIFVvlh-TKcV94,7174
62
62
  femagtools/machine/afpm.py,sha256=hNyDFRLGmCuWRPZl_u1ztJ4pA-Y_mxLaVvg3UJkzRuE,24766
63
- femagtools/machine/effloss.py,sha256=aaSmmxKd_KWMasHUHipYDcZOw-fvTHNa38MWFnpVock,13130
63
+ femagtools/machine/effloss.py,sha256=I8s2Fog6klhgcRYw3448qfGvzaQ0AQUJXFdNoeDyhfE,13138
64
64
  femagtools/machine/im.py,sha256=ScIOLrlc4CPLYFNx2MmJqkpmbky_HXxFGZbMWUNGBrk,37881
65
- femagtools/machine/pm.py,sha256=cGOdcUzMyBYJotQB8_tj93_2pwK9tml4GuSet80HgnM,56042
65
+ femagtools/machine/pm.py,sha256=R8RWzQrMI_fNaUU7ruHnQxg3-Lubh1vp-6EG6z5QbRk,56229
66
66
  femagtools/machine/sizing.py,sha256=aN_OahewjTTBHnpRNfLh1AGFhqnoeZVuMBeb_3MCIVI,23096
67
- femagtools/machine/sm.py,sha256=hfJA8_C-uuDIKnjR12H9LkVocxnNoSkJaH2R_-8-2zQ,34310
67
+ femagtools/machine/sm.py,sha256=pkik913kU41PPiUpwDy_6BEKfCIhvY6FEp-fbU2Lqew,34320
68
68
  femagtools/machine/utils.py,sha256=g9q4j9KxUWdb_iUOUQDuaAwwJx8XM0kZMpgnwsNz8hU,18616
69
69
  femagtools/moo/__init__.py,sha256=zinmWEOrsEz6DmMX0Dbn4t6_1UR-p4bEGqyR1wUQk_Q,175
70
70
  femagtools/moo/algorithm.py,sha256=lNEf0Bur4yFpIJeLtAC3oIus8sOMWTb7jepFlD28YzE,5445
@@ -200,9 +200,9 @@ tests/moo/__init__.py,sha256=l8HD-AY8EwxOoo_VrG3HgEZb2MaHypvnhKCVSkR-DTA,808
200
200
  tests/moo/test_algorithm.py,sha256=Em8sFm2vzPmuIzRrBBnUQLU_TYuJHSf-kEeozw0XeX4,2563
201
201
  tests/moo/test_population.py,sha256=FvX9LRCxQx0_E2GxHQ5vKwOYFBQiNbT6Lmv5GmNWjTQ,5471
202
202
  tests/moo/test_problem.py,sha256=ALeP4u7g-dFhfwWL8vxivdrrYzVKPjHMCAXzzgyNZbs,467
203
- femagtools-1.6.0.dist-info/LICENSE,sha256=V5OED7AzEaOtvbfgNheKOSUeNtijvKQuo84FtSJNkJU,1316
204
- femagtools-1.6.0.dist-info/METADATA,sha256=D6-oFfERwRA-hlS9Pyjw6fqyz_Dsl9Q7htgd5-VcmR4,5685
205
- femagtools-1.6.0.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
206
- femagtools-1.6.0.dist-info/entry_points.txt,sha256=UXpu6KnrykN89sCUaFAIIzn_dYwuxizUS0GcPdoekro,195
207
- femagtools-1.6.0.dist-info/top_level.txt,sha256=Ri4YWtU8MZTzNje9IKyXhTakNbsrCynuWdon4Yq94Dc,17
208
- femagtools-1.6.0.dist-info/RECORD,,
203
+ femagtools-1.6.2.dist-info/LICENSE,sha256=V5OED7AzEaOtvbfgNheKOSUeNtijvKQuo84FtSJNkJU,1316
204
+ femagtools-1.6.2.dist-info/METADATA,sha256=_Fn2D61D0C-a96X_49iBhYauUSoeaM6AAR28-QDL1is,5685
205
+ femagtools-1.6.2.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
206
+ femagtools-1.6.2.dist-info/entry_points.txt,sha256=UXpu6KnrykN89sCUaFAIIzn_dYwuxizUS0GcPdoekro,195
207
+ femagtools-1.6.2.dist-info/top_level.txt,sha256=Ri4YWtU8MZTzNje9IKyXhTakNbsrCynuWdon4Yq94Dc,17
208
+ femagtools-1.6.2.dist-info/RECORD,,