femagtools 1.6.5__py3-none-any.whl → 1.6.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.
@@ -12,9 +12,10 @@ import logging
12
12
  import sys
13
13
  from femagtools.dxfsl.shape import Element, Line
14
14
  from femagtools.dxfsl.area import Area
15
- from femagtools.dxfsl.functions import alpha_angle, positive_angle
15
+ from femagtools.dxfsl.functions import alpha_angle, positive_angle, is_same_angle
16
16
  from femagtools.dxfsl.functions import min_angle, max_angle, gcd, point
17
- from femagtools.dxfsl.functions import less_equal, less
17
+ from femagtools.dxfsl.functions import less_equal, less, points_are_close
18
+ from femagtools.dxfsl.functions import line_m, line_n, mirror_point
18
19
 
19
20
  logger = logging.getLogger('femagtools.symmetry')
20
21
 
@@ -38,10 +39,18 @@ class Symmetry(object):
38
39
  self.geom = geom
39
40
  self.startangle = startangle
40
41
  self.endangle = endangle
42
+ self.delta_check_count = 0
43
+ self.delta_angle_korr = 0.0
41
44
  self.rtol = rtol
42
45
  self.atol = atol
43
-
44
- logger.debug("Symmetry(rtol=%s, atol=%s)", rtol, atol)
46
+ self.full = False
47
+ if np.isclose(self.startangle, self.endangle):
48
+ self.alpha = 2.0*np.pi
49
+ self.full = True
50
+ else:
51
+ self.alpha = alpha_angle(self.startangle, self.endangle)
52
+ self.full = False
53
+ logger.debug("Symmetry(alpha=%s, rtol=%s, atol=%s)", self.alpha, rtol, atol)
45
54
 
46
55
  def __str__(self):
47
56
  return "rtol: {}\n".format(self.rtol) + \
@@ -62,6 +71,10 @@ class Symmetry(object):
62
71
  return False
63
72
  return True
64
73
 
74
+ def calc_mid_angle(self, a):
75
+ return positive_angle(alpha_angle(self.startangle,
76
+ a.get_mid_angle(self.geom.center)))
77
+
65
78
  def find_symmetry(self):
66
79
  arealist = self.geom.list_of_areas()
67
80
  logger.debug("begin of Symmetry::find_symmetry: %s areas available", len(arealist))
@@ -71,18 +84,17 @@ class Symmetry(object):
71
84
 
72
85
  areas = []
73
86
  for a in arealist:
74
- areas.append((a.get_alpha(),
75
- a.get_mid_angle(),
76
- a.min_dist,
77
- a.height,
87
+ areas.append((round(a.get_alpha(self.geom.center), 3),
88
+ round(a.min_dist, 1),
89
+ round(a.height, 1),
90
+ self.calc_mid_angle(a),
78
91
  a))
79
- areas.sort()
80
- parts_possible = None
92
+ areas.sort(reverse=True)
81
93
 
82
- a0_alpha, a0_mid_angle, a0_min_dist, a0_height, a0 = areas[0]
94
+ a0_alpha, a0_min_dist, a0_height, a0_mid_angle, a0 = areas[0]
83
95
  equal_areas = [(a0_mid_angle, a0)]
84
-
85
- for a1_alpha, a1_mid_angle, a1_min_dist, a1_height, a1 in areas[1:]:
96
+ check_rslt = []
97
+ for a1_alpha, a1_min_dist, a1_height, a1_mid_angle, a1 in areas[1:]:
86
98
  if self.equal_area(a0_min_dist, a0_height, a0_alpha,
87
99
  a1_min_dist, a1_height, a1_alpha,
88
100
  rtol=0.01, atol=0.05):
@@ -92,10 +104,8 @@ class Symmetry(object):
92
104
  equal_areas.append((a1_mid_angle, a1))
93
105
  else:
94
106
  parts = self.check_delta(equal_areas)
95
- if parts_possible is None:
96
- parts_possible = parts
97
- else:
98
- parts_possible = self.calc_parts(parts_possible, parts)
107
+ check_rslt.append((a0.area_size(), parts, len(equal_areas), a0))
108
+
99
109
  equal_areas = [(a1_mid_angle, a1)]
100
110
  a0_min_dist = a1_min_dist
101
111
  a0_height = a1_height
@@ -103,105 +113,119 @@ class Symmetry(object):
103
113
  a0 = a1
104
114
 
105
115
  parts = self.check_delta(equal_areas)
106
- if parts_possible is None:
107
- parts_possible = parts
108
- else:
109
- parts_possible = self.calc_parts(parts_possible, parts)
116
+ check_rslt.append((a0.area_size(), parts, len(equal_areas), a0))
110
117
 
111
- if parts_possible is None:
112
- parts_possible = 0
113
- if parts_possible < 2:
118
+ parts = self.get_symmetry_parts(check_rslt)
119
+ if parts < 2:
114
120
  logger.debug("end of Symmetry::find_symmetry: no symmetry")
115
- return parts_possible
116
-
121
+ return parts
122
+
117
123
  self.geom.clear_cut_lines()
118
- for alpha in self.symmetry_lines(parts_possible,
124
+ for alpha in self.symmetry_lines(parts,
119
125
  self.startangle,
120
126
  self.endangle):
121
- min_radius = max(10, self.geom.min_radius - 10)
127
+ plus = self.geom.max_radius / 10
128
+ min_radius = max(10, self.geom.min_radius - plus)
122
129
  p1 = point(self.geom.center, min_radius, alpha)
123
- p2 = point(self.geom.center, self.geom.max_radius+10, alpha)
130
+ p2 = point(self.geom.center, self.geom.max_radius + plus, alpha)
124
131
  line = Line(Element(start=p1, end=p2))
125
132
  line.init_attributes(color='green')
126
133
  self.geom.add_cut_line(line)
127
-
128
- logger.debug("end of Symmetry::find_symmetry")
129
- return parts_possible
134
+
135
+ logger.debug("end of Symmetry::find_symmetry: -> %s", parts)
136
+ return parts
130
137
 
131
138
  def check_delta(self, area_list):
132
- logger.debug("==> %s equal areas", len(area_list))
139
+ logger.debug("begin of check_delta: %s equal areas", len(area_list))
133
140
  if not area_list:
141
+ logger.debug("end of check_delta: no areas")
134
142
  return None
135
143
 
136
144
  if len(area_list) == 1:
137
145
  mid_angle, a = area_list[0]
138
- if np.isclose(a.min_angle, self.startangle) and \
139
- np.isclose(a.max_angle, self.endangle):
146
+ alpha = a.get_alpha(self.geom.center)
147
+ if np.isclose(alpha, self.alpha):
148
+ logger.debug("end of check_delta: one area from start to end")
140
149
  return None # ok
141
150
 
151
+ self.delta_check_count += 1
142
152
  area_list.sort()
143
- start = self.startangle
144
- mid_angle, a = area_list[0]
145
153
 
146
- delta = alpha_angle(start, mid_angle) * 2
154
+ mid_angle, a = area_list[0]
155
+ delta = positive_angle(mid_angle * 2)
156
+ delta_total = mid_angle
147
157
  delta_list = [delta]
148
- logger.debug("geom: start=%s, end=%s", self.startangle, self.endangle)
158
+
159
+ logger.debug("First mid = %s, delta = %s", mid_angle, delta)
149
160
  logger.debug("%s: d=%s, h=%s, a=%s, mid=%s, delta=%s",
150
161
  a.identifier(),
151
162
  a.min_dist,
152
163
  a.height,
153
- a.get_alpha(),
154
- a.get_mid_angle(),
164
+ a.get_alpha(self.geom.center),
165
+ mid_angle,
155
166
  delta)
156
- logger.debug(" min=%s, max%s",
157
- a.min_angle,
158
- a.max_angle)
159
167
 
160
- start = mid_angle
168
+ geom_alpha = alpha_angle(self.startangle, self.endangle)
169
+ geom_alpha = positive_angle(geom_alpha)
170
+
171
+ start_angle = mid_angle
161
172
  for mid_angle, a in area_list[1:]:
162
- delta = alpha_angle(start, mid_angle)
173
+ delta_angle = alpha_angle(start_angle, mid_angle)
174
+ delta = positive_angle(delta_angle)
175
+ delta_total += delta_angle
163
176
  delta_list.append(delta)
164
177
 
165
178
  logger.debug("%s: d=%s, h=%s, a=%s, mid=%s, delta=%s",
166
179
  a.identifier(),
167
180
  a.min_dist,
168
181
  a.height,
169
- a.get_alpha(),
170
- a.get_mid_angle(),
182
+ a.get_alpha(self.geom.center),
183
+ mid_angle,
171
184
  delta)
172
- logger.debug(" min=%s, max%s",
173
- a.min_angle,
174
- a.max_angle)
175
-
176
- start = mid_angle
185
+ start_angle = mid_angle
177
186
 
178
- delta = alpha_angle(start, self.endangle) * 2
187
+ delta_angle = alpha_angle(start_angle, geom_alpha)
188
+ delta = positive_angle(delta_angle * 2)
189
+ delta_total += delta_angle
179
190
  delta_list.append(delta)
180
191
  logger.debug("final delta=%s", delta)
181
192
 
193
+ if not np.isclose(geom_alpha, delta_total):
194
+ logger.debug("-- deltas: %s", delta_list)
195
+ logger.debug("end of check_delta: BAD DELTA %s, (expected %s)",
196
+ delta_angle, geom_alpha)
197
+ return 0 # very bad
198
+
182
199
  sz = len(delta_list)
183
200
  mid = int(sz / 2)
184
201
  ix1 = 0
185
202
  ix2 = sz - 1
203
+ first_last_bad = False
186
204
  for ix1 in range(0, mid):
187
205
  if not np.isclose(delta_list[ix1], delta_list[ix2], rtol=1e-3, atol=1e-3):
188
- logger.debug("NO SYM")
189
- return 0
206
+ if self.full and \
207
+ self.delta_check_count == 1 and \
208
+ ix1 == 0 and \
209
+ self.delta_angle_korr == 0.0:
210
+ first_last_bad = True
211
+ else:
212
+ logger.debug("end of check_delta: NO SYM")
213
+ return 0
190
214
  ix2 -= 1
191
215
 
192
- geom_alpha = alpha_angle(self.startangle, self.endangle)
193
- delta_alpha = 0.0
194
- for d in delta_list:
195
- delta_alpha += d
196
-
197
- geom_alpha = positive_angle(geom_alpha)
198
-
199
- delta_alpha -= delta_list[0] / 2
200
- delta_alpha -= delta_list[-1] / 2
201
- delta_alpha = positive_angle(delta_alpha)
202
- if not np.isclose(geom_alpha, delta_alpha):
203
- logger.debug("BAD DELTA ?!?")
204
- return 0 # very bad
216
+ if first_last_bad:
217
+ delta_korr = (delta_list[0] + delta_list[-1]) / 2.0
218
+ logger.debug("STARTANGLE CORRECTION")
219
+ self.delta_angle_korr = (delta_korr - delta_list[0]) / 2
220
+ logger.debug("-- delta[0] from %s to %s", delta_list[0], delta_korr)
221
+ logger.debug("Delta Angle Korr = %s", self.delta_angle_korr)
222
+ delta_list[0] = delta_korr
223
+ delta_list[-1] = delta_korr
224
+ assert(self.full)
225
+ self.startangle = self.startangle - self.delta_angle_korr
226
+ self.endangle = self.endangle - self.delta_angle_korr
227
+ logger.debug("New startangle = %s", self.startangle)
228
+ logger.debug("Delta List: %s", delta_list)
205
229
 
206
230
  d1 = delta_list[0]
207
231
  d1_count = 1
@@ -212,9 +236,10 @@ class Symmetry(object):
212
236
  d1_count += 1
213
237
 
214
238
  if d1_count == len(delta_list):
215
- logger.debug("SYMMETRY FOUND")
239
+ logger.debug("end of check_delta: SYMMETRY FOUND")
216
240
  return d1_count -1 # very simple
217
241
  if len(delta_list) < 2:
242
+ logger.debug("end of check_delta: One delta only ?!")
218
243
  return 0
219
244
 
220
245
  logger.debug("index of delta %s = %s", d1, inx_list)
@@ -227,15 +252,51 @@ class Symmetry(object):
227
252
  return 0
228
253
  x1 = x2
229
254
 
230
- logger.debug("SYMMETRY FOUND")
255
+ logger.debug("end of check_delta: SYMMETRY FOUND")
231
256
  return len(inx_list) -1
232
257
 
258
+ def get_symmetry_parts(self, check_rslt):
259
+ max_size = 0
260
+ max_areas = 0
261
+ parts_possible = None
262
+
263
+ check_rslt.sort(reverse=True)
264
+ for size, parts, count, area in check_rslt:
265
+ logger.debug("Result: %s, %s, %s", size, parts, count)
266
+
267
+ for size, parts, count, area in check_rslt:
268
+ if parts is not None and parts > 0:
269
+ max_size = max(max_size, size)
270
+ max_areas = max(max_areas, count)
271
+
272
+ logger.debug("max size: %s, max areas: %s", max_size, max_areas)
273
+
274
+ for size, parts, count, area in check_rslt:
275
+ if parts is not None and parts <= 1: # critical
276
+ if count <= max(1, max_areas / 5):
277
+ if size < max_size / 25:
278
+ parts = None
279
+
280
+ parts_possible = self.calc_parts(parts_possible, parts)
281
+
282
+ if parts_possible is None:
283
+ parts_possible = 0
284
+ return parts_possible
285
+
233
286
  def calc_parts(self, parts1, parts2):
234
287
  logger.debug("Calc symmetry Parts (%s, %s)", parts1, parts2)
235
288
  if parts2 is None:
289
+ logger.debug("return %s parts", parts1)
236
290
  return parts1
237
-
238
- return gcd(parts1, parts2)
291
+ if parts1 is None:
292
+ logger.debug("return %s parts", parts2)
293
+ return parts2
294
+ if parts1 == 0 or parts2 == 0:
295
+ logger.debug("return %s parts", 0)
296
+ return 0
297
+ parts = gcd(parts1, parts2)
298
+ logger.debug("return %s parts", parts)
299
+ return parts
239
300
 
240
301
  def symmetry_lines(self, parts, startangle, endangle):
241
302
  logger.debug("begin symmetry_lines from %s to %s",
@@ -249,7 +310,10 @@ class Symmetry(object):
249
310
  while less(start, endangle):
250
311
  yield start
251
312
  start += delta
252
-
313
+
314
+ if is_same_angle(startangle, endangle):
315
+ yield start
316
+
253
317
  # Damit man anschliessend ohne Umstände schneiden kann.
254
318
  self.geom.sym_startangle = startangle
255
319
  self.geom.sym_endangle = startangle + delta
@@ -259,3 +323,48 @@ class Symmetry(object):
259
323
  self.geom.sym_area.sym_startangle = self.geom.sym_startangle
260
324
  self.geom.sym_area.sym_endangle = self.geom.sym_endangle
261
325
  logger.debug("end symmetry_lines")
326
+
327
+ def check_symmetry_of_mirror(self, mirror_geom, mirrorangle):
328
+ logger.debug("begin of Symmetry::check_symmetry_of_mirror")
329
+ assert(mirror_geom is not None)
330
+
331
+ axis_p = point(self.geom.center, self.geom.max_radius, mirrorangle)
332
+ axis_m = line_m(self.geom.center, axis_p)
333
+ axis_n = line_n(self.geom.center, axis_m)
334
+
335
+ def counterpart_found(node, nodes, rtol, atol):
336
+ hits = 0
337
+ for n in nodes:
338
+ if points_are_close(node, n, rtol, atol):
339
+ logger.debug(" ---- %s is %s", node, n)
340
+ return True
341
+ return False
342
+
343
+ def check_differences(geom, mirror_geom):
344
+ geom_ag_nodes = []
345
+ geom_nodes = [n for n in geom.g.nodes() if not (n in geom_ag_nodes)]
346
+
347
+ hit = 0
348
+ for n in geom_nodes:
349
+ mirror_n = mirror_point(n, geom.center, axis_m, axis_n)
350
+ if counterpart_found(mirror_n,
351
+ mirror_geom.g.nodes(),
352
+ self.rtol,
353
+ self.atol):
354
+ hit += 1
355
+ min_nodes = min(len(geom_nodes), int(len(geom_nodes) * 0.95) + 1)
356
+ logger.debug("Nodes=%s, Counterparts=%s", len(geom_nodes), hit)
357
+ if hit < min_nodes:
358
+ return hit / len(geom_nodes)
359
+ else:
360
+ return 1.0
361
+
362
+ # ----------------
363
+ logger.debug("check geom - mirror")
364
+ f1 = check_differences(self.geom, mirror_geom)
365
+ logger.debug("check mirror - geom")
366
+ f2 = check_differences(mirror_geom, self.geom)
367
+ logger.debug("Factor 1: %s, 2: %s", f1, f2)
368
+ ok = f1 > 0.97 and f2 > 0.97
369
+ logger.debug("end of Symmetry::check_symmetry_of_mirror => %s", ok)
370
+ return ok
femagtools/isa7.py CHANGED
@@ -868,14 +868,14 @@ class Isa7(object):
868
868
  except AttributeError:
869
869
  pass
870
870
 
871
- try:
871
+ try:
872
872
  flx_fac = 1000
873
- if isinstance(reader.el_fe_induction_1, list):
873
+ if isinstance(reader.el_fe_induction_1, list):
874
874
  pass
875
- else:
876
- if reader.el_fe_induction_1.dtype == 'int16':
875
+ else:
876
+ if reader.el_fe_induction_1.dtype == 'int16':
877
877
  flx_fac = 1000
878
- else:
878
+ else:
879
879
  flx_fac = 1
880
880
  el_fe_ind = [np.array(reader.el_fe_induction_1).T/flx_fac,
881
881
  np.array(reader.el_fe_induction_2).T/flx_fac]
@@ -1432,6 +1432,7 @@ class Element(BaseEntity):
1432
1432
  """return temperature of this element"""
1433
1433
  return sum([v.vpot[1] for v in self.vertices])/len(self.vertices)
1434
1434
 
1435
+
1435
1436
  class SuperElement(BaseEntity):
1436
1437
  def __init__(self, key, sr_key, elements, nodechains, color,
1437
1438
  nc_keys, mcvtype, condtype, conduc, length,
@@ -238,7 +238,7 @@ def efficiency_losses_map(eecpars, u1, T, temp, n, npoints=(60, 40),
238
238
  with_pmconst=with_pmconst, with_tmech=with_tmech) # braking mode
239
239
 
240
240
  if kwargs.get('mesh_func', 0):
241
- ntmesh = kwargs['mesh_func'](r['n'], r['T'],
241
+ ntmesh = kwargs['mesh_func'](r['n_type'], r['n'], r['T'],
242
242
  rb['n'], rb['T'], npoints)
243
243
  else:
244
244
  ntmesh = _generate_mesh(r['n'], r['T'],
femagtools/machine/im.py CHANGED
@@ -622,6 +622,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
622
622
  i_max_fact: (float) factor for maximum current to calculate no_load flux (default=2.5)
623
623
  templatedirs: (list of str) names of directories to search for templates
624
624
  """
625
+ cmd = kwargs.get("cmd", None)
625
626
  CON = {'open': 0, 'wye': 1, 'star': 1, 'delta': 2}
626
627
  p = machine['poles']//2
627
628
  slip = 1e-2
@@ -676,7 +677,7 @@ def parident(workdir, engine, f1, u1, wdgcon,
676
677
 
677
678
  parstudy = femagtools.parstudy.ParameterStudy(
678
679
  workdir, condMat=condMat,
679
- magnetizingCurves=magnetizingCurves)
680
+ magnetizingCurves=magnetizingCurves, cmd=cmd)
680
681
 
681
682
  builder = femagtools.fsl.Builder(kwargs.get('templatedirs', []))
682
683
  model = femagtools.model.MachineModel(m)
femagtools/machine/pm.py CHANGED
@@ -69,6 +69,7 @@ class PmRelMachine(object):
69
69
  self.rotor_mass = 0
70
70
  self.kth1 = KTH
71
71
  self.bertotti = False
72
+ self.max_torque = 0.0
72
73
  self.losskeys = ['styoke_hyst', 'stteeth_hyst',
73
74
  'styoke_eddy', 'stteeth_eddy',
74
75
  'rotor_hyst', 'rotor_eddy',
@@ -165,6 +166,46 @@ class PmRelMachine(object):
165
166
  return iq, 0, self.torque_iqd(iq, 0)
166
167
 
167
168
  def iqd_tmech(self, torque, n, iqd0=0, with_mtpa=True):
169
+ """return minimum d-q-current for shaft torque"""
170
+ if np.abs(torque) < 1e-2:
171
+ return (0, 0)
172
+ if np.isscalar(iqd0):
173
+ tx = self.tmech_iqd(self.io[0], 0, n)
174
+ iq0 = min(0.9*self.i1range[1]/np.sqrt(2),
175
+ np.abs(torque)/tx*self.io[0])
176
+ if torque < 0:
177
+ i0 = (-iq0, 0)
178
+ else:
179
+ i0 = (iq0, 0)
180
+ logger.debug("initial guess i0 %f -> %s tx %f torque %f",
181
+ self.io[0], i0, tx, torque)
182
+ else:
183
+ i0 = iqd0
184
+
185
+ if with_mtpa:
186
+ k=0
187
+ while k < 6:
188
+ res = so.minimize(
189
+ lambda iqd: la.norm(iqd), i0, method='SLSQP',
190
+ constraints=({'type': 'eq',
191
+ 'fun': lambda iqd:
192
+ self.tmech_iqd(*iqd, n) - torque}))
193
+ if res.success:
194
+ return res.x
195
+ # make new initial guess:
196
+ tx = self.tmech_iqd(*i0, n)
197
+ logger.debug("k %d new guess i0 %s tx %f torque %f",
198
+ k, i0, tx, torque)
199
+ i0=(min(0.9*self.i1range[1]/np.sqrt(2), torque/tx*i0[0]), 0)
200
+ k += 1
201
+ raise ValueError(
202
+ f'Torque {torque} speed {n} {i0} {res.message}')
203
+ def tqiq(iq):
204
+ return torque - self.tmech_iqd(float(iq), 0, n)
205
+ iq = so.fsolve(tqiq, (i0[0],))[0]
206
+ return iq, 0, self.tmech_iqd(iq, 0, n)
207
+
208
+ def iqd_tmech0(self, torque, n, iqd0=0, with_mtpa=True):
168
209
  """return minimum d-q-current for shaft torque"""
169
210
  if np.abs(torque) < 1e-2:
170
211
  return (0, 0)
@@ -681,17 +722,24 @@ class PmRelMachine(object):
681
722
  iq, id, T = self.mtpa(i1max)
682
723
  w1type = self.w1_umax(u1max, iq, id)
683
724
  Pmax = w1type/self.p*T
684
- w1max = 2*np.pi*speedmax*self.p
685
725
  # check max speed:
686
- if with_pmconst:
687
- iq, id, tq = self.iqd_pmech_imax_umax(
688
- speedmax, Pmax, i1max, u1max,
689
- with_mtpa, with_tmech)
690
- else:
691
- iq, id, tq = self.iqd_imax_umax(
692
- i1max, w1max, u1max,
693
- T, with_mtpv=False,
694
- with_tmech=with_tmech)
726
+ sp = speedmax
727
+ while sp > w1type/2/np.pi/self.p:
728
+ w1max = 2*np.pi*sp*self.p
729
+ try:
730
+ if with_pmconst:
731
+ iq, id, tq = self.iqd_pmech_imax_umax(
732
+ sp, Pmax, i1max, u1max,
733
+ with_mtpa, with_tmech)
734
+ else:
735
+ iq, id, tq = self.iqd_imax_umax(
736
+ i1max, w1max, u1max,
737
+ T, with_mtpv=False,
738
+ with_tmech=with_tmech)
739
+ break
740
+ except ValueError:
741
+ sp -= 5e-2*speedmax
742
+ speedmax = sp
695
743
  i1 = betai1(iq, id)[1]
696
744
  if (abs(i1max) >= i1
697
745
  and round(u1max, 1) >= round(np.linalg.norm(
@@ -843,7 +891,7 @@ class PmRelMachine(object):
843
891
  def characteristics(self, T, n, u1max, nsamples=60,
844
892
  with_mtpv=True, with_mtpa=True,
845
893
  with_pmconst=True, with_tmech=True,
846
- with_torque_corr=False):
894
+ with_torque_corr=False, **kwargs):
847
895
  """calculate torque speed characteristics.
848
896
  return dict with list values of
849
897
  id, iq, n, T, ud, uq, u1, i1,
@@ -863,6 +911,9 @@ class PmRelMachine(object):
863
911
  r = dict(id=[], iq=[], uq=[], ud=[], u1=[], i1=[], T=[],
864
912
  beta=[], gamma=[], phi=[], cosphi=[], pmech=[], n=[])
865
913
 
914
+ if kwargs.get('i1max', 0):
915
+ w1type, T = self.w1_imax_umax(kwargs['i1max'], u1max)
916
+
866
917
  if np.isscalar(T):
867
918
  tmax = self.torquemax(self.i1range[1])
868
919
  tmin = 0
@@ -923,6 +974,9 @@ class PmRelMachine(object):
923
974
  if speedrange[-1] < speedrange[-2]:
924
975
  speedrange = speedrange[:-1]
925
976
  logger.info("Speedrange T=%g Nm %s", Tf, speedrange)
977
+ if speedrange[-1] < nmax:
978
+ logger.warning("adjusted nmax %f -> %f", nmax, speedrange[-1])
979
+
926
980
  n3 = speedrange[-1]
927
981
  nstab = [int(nsamples*(x1-x2)/n3)
928
982
  for x1, x2 in zip(speedrange[1:],
@@ -1135,7 +1189,12 @@ class PmRelMachineLdq(PmRelMachine):
1135
1189
  if np.any(beta[beta > np.pi]):
1136
1190
  beta[beta > np.pi] = beta - 2*np.pi
1137
1191
 
1138
- self.io = iqd((np.min(beta)+max(beta))/2, np.max(i1)/2)
1192
+ self.betarange = min(beta), max(beta)
1193
+ if min(beta) < -np.pi/2 and max(beta) > -np.pi/2:
1194
+ self.io = iqd(-np.pi/4, np.max(i1)/2)
1195
+ else:
1196
+ self.io = iqd((np.min(beta)+max(beta))/2, np.max(i1)/2)
1197
+
1139
1198
  kx = ky = 3
1140
1199
  if len(i1) < 4:
1141
1200
  ky = len(i1)-1
femagtools/machine/sm.py CHANGED
@@ -46,6 +46,7 @@ def parident(workdir, engine, machine,
46
46
  speed: rotor speed in 1/s (default 160/p)
47
47
  i1_max: maximum current in A rms (default approx 3*i1nom)
48
48
  """
49
+ cmd = kwargs.get('cmd', None)
49
50
  da1 = machine['outer_diam']
50
51
  Q1 = machine['stator']['num_slots']
51
52
  if 'statorRotor3' in machine['stator']:
@@ -59,7 +60,7 @@ def parident(workdir, engine, machine,
59
60
  N = machine[wdgk]['num_wires']
60
61
  i1_max = round(0.28*np.pi*hs*(da1+hs)/Q1/N*Jmax*1e5)*10 * \
61
62
  machine[wdgk].get('num_par_wdgs', 1)
62
-
63
+
63
64
  ifnom = machine['rotor']['ifnom']
64
65
  exc_logspace = True
65
66
  if exc_logspace:
@@ -78,7 +79,7 @@ def parident(workdir, engine, machine,
78
79
 
79
80
  parvar = parstudy.List(
80
81
  workdir, condMat=condMat,
81
- magnetizingCurves=magnetizingCurves)
82
+ magnetizingCurves=magnetizingCurves, cmd=cmd)
82
83
 
83
84
  simulation = dict(
84
85
  calculationMode=kwargs.get('calculationMode',
@@ -240,6 +241,7 @@ class SynchronousMachine(object):
240
241
  self.kth1 = KTH
241
242
  self.kth2 = KTH
242
243
  self.skin_resistance = [None, None]
244
+ self.kpmag = 1
243
245
  # here you can set user defined functions for calculating the skin-resistance,
244
246
  # according to the current frequency w. First function in list is for stator, second for rotor.
245
247
  # If None, the femagtools intern default implementation is used.
femagtools/plot/nc.py CHANGED
@@ -149,8 +149,7 @@ def __elements_of_subreg(isa, subreg):
149
149
  else:
150
150
  sr = [subreg]
151
151
  for s in sr:
152
- for e in isa.get_subregion(s).elements():
153
- yield e
152
+ yield from isa.get_subregion(s).elements()
154
153
  else:
155
154
  for e in isa.elements:
156
155
  yield e
@@ -232,7 +231,8 @@ def flux_density_pos(isa, ipos, subreg=[], icur=-1, ibeta=-1, cmap=DEFAULT_CMAP,
232
231
  ibeta: beta angle index or last index if -1
233
232
 
234
233
  """
235
- elements = [e for e in __elements_of_subreg(isa, subreg)]
234
+ elements = [e for e in __elements_of_subreg(isa, subreg)
235
+ if e not in isa.airgap_center_elements]
236
236
  b = []
237
237
  for e in elements:
238
238
  fd = isa.flux_density(e, icur, ibeta)