femagtools 1.8.2__py3-none-any.whl → 1.8.3__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.
Files changed (40) hide show
  1. femagtools/__init__.py +1 -1
  2. femagtools/dxfsl/area.py +65 -0
  3. femagtools/dxfsl/conv.py +5 -0
  4. femagtools/dxfsl/converter.py +34 -1
  5. femagtools/dxfsl/functions.py +14 -6
  6. femagtools/dxfsl/geom.py +12 -12
  7. femagtools/dxfsl/journal.py +1 -1
  8. femagtools/dxfsl/symmetry.py +28 -8
  9. femagtools/femag.py +64 -61
  10. femagtools/fsl.py +5 -2
  11. femagtools/isa7.py +3 -2
  12. femagtools/machine/afpm.py +43 -23
  13. femagtools/machine/effloss.py +29 -18
  14. femagtools/machine/sizing.py +4 -3
  15. femagtools/machine/sm.py +34 -36
  16. femagtools/mcv.py +56 -26
  17. femagtools/multiproc.py +79 -80
  18. femagtools/parstudy.py +10 -4
  19. femagtools/semi_fea.py +108 -0
  20. femagtools/templates/basic_modpar.mako +0 -3
  21. femagtools/templates/fe-contr.mako +18 -18
  22. femagtools/templates/ld_lq_fast.mako +3 -0
  23. femagtools/templates/mult_cal_fast.mako +3 -0
  24. femagtools/templates/pm_sym_f_cur.mako +4 -1
  25. femagtools/templates/pm_sym_fast.mako +3 -0
  26. femagtools/templates/pm_sym_loss.mako +3 -0
  27. femagtools/templates/psd_psq_fast.mako +3 -0
  28. femagtools/templates/torq_calc.mako +3 -0
  29. femagtools/tks.py +23 -20
  30. femagtools/zmq.py +213 -0
  31. {femagtools-1.8.2.dist-info → femagtools-1.8.3.dist-info}/METADATA +3 -3
  32. {femagtools-1.8.2.dist-info → femagtools-1.8.3.dist-info}/RECORD +40 -38
  33. {femagtools-1.8.2.dist-info → femagtools-1.8.3.dist-info}/WHEEL +1 -1
  34. tests/test_afpm.py +15 -6
  35. tests/test_femag.py +1 -1
  36. tests/test_fsl.py +4 -4
  37. tests/test_mcv.py +20 -14
  38. {femagtools-1.8.2.dist-info → femagtools-1.8.3.dist-info}/LICENSE +0 -0
  39. {femagtools-1.8.2.dist-info → femagtools-1.8.3.dist-info}/entry_points.txt +0 -0
  40. {femagtools-1.8.2.dist-info → femagtools-1.8.3.dist-info}/top_level.txt +0 -0
femagtools/multiproc.py CHANGED
@@ -12,6 +12,8 @@ import pathlib
12
12
  import logging
13
13
  from .job import Job
14
14
  import femagtools.config as cfg
15
+ import femagtools.zmq
16
+ from femagtools.zmq import SubscriberTask
15
17
  try:
16
18
  from subprocess import DEVNULL
17
19
  except ImportError:
@@ -19,86 +21,40 @@ except ImportError:
19
21
 
20
22
  logger = logging.getLogger(__name__)
21
23
 
22
- numpat = re.compile(r'([+-]?\d+(?:\.\d+)?(?:[eE][+-]\d+)?)\s*')
23
-
24
24
  class LicenseError(Exception):
25
25
  pass
26
26
 
27
- class ProtFile:
28
- def __init__(self, dirname, num_cur_steps):
29
- self.size = 0
30
- self.looplen = 0
31
- self.cur_steps = [1, num_cur_steps]
32
- self.n = 0
33
- self.num_loops = 0
34
- self.dirname = dirname
35
- self.name = 'samples'
36
-
37
- def percent(self):
38
- if self.looplen > 0:
39
- return min(100 * self.n / self.looplen, 100)
40
- return 0
41
-
42
- def update(self):
43
- p = list(pathlib.Path(self.dirname).glob('*.PROT'))
44
- if p:
45
- buf = ''
46
- if self.size < p[0].stat().st_size:
47
- with p[0].open() as fp:
48
- fp.seek(self.size)
49
- buf = fp.read()
50
- return self.append(buf)
51
- return ''
52
-
53
- def append(self, buf):
54
- self.size += len(buf)
55
- for line in [l.strip() for l in buf.split('\n') if l]:
56
- if line.startswith('Loop'):
57
- self.n = 0
58
- try:
59
- cur_steps = self.cur_steps[self.num_loops]
60
- except IndexError:
61
- cur_steps = 1
62
- x0, x1, dx, nbeta = [float(f)
63
- for f in re.findall(numpat, line)][:4]
64
- move_steps = round((x1-x0)/dx+1)
65
- beta_steps = int(nbeta)
66
- self.looplen = cur_steps*beta_steps*move_steps
67
- self.num_loops += 1
68
- elif (line.startswith('Cur') or
69
- line.startswith('Id')):
70
- self.n += 1
71
- elif line.startswith('Number movesteps Fe-Losses'):
72
- return ''
73
- elif line.startswith('begin'):
74
- self.name = line.split()[1].strip()
75
-
76
- return f'{self.percent():3.1f}%' # {self.n}/{self.looplen}'
77
-
78
-
79
27
  class ProgressLogger(threading.Thread):
80
- def __init__(self, dirs, num_cur_steps, timestep):
28
+ def __init__(self, dirs, num_cur_steps, timestep, notify):
81
29
  threading.Thread.__init__(self)
82
- self.dirs = dirs
83
- self.num_cur_steps = num_cur_steps
30
+ self.protfiles = [femagtools.zmq.ProtFile(d, num_cur_steps)
31
+ for d in dirs]
32
+ self.numTot = len(dirs)
84
33
  self.running = False
85
34
  self.timestep = timestep
35
+ self.notify = notify
86
36
 
87
37
  def run(self):
88
38
  self.running = True
89
- protfiles = [ProtFile(d, self.num_cur_steps)
90
- for d in self.dirs]
91
39
  while self.running:
92
- time.sleep(self.timestep)
93
- logmsg = [p.update() for p in protfiles]
40
+ if self.timestep > 0:
41
+ time.sleep(self.timestep)
42
+ logmsg = [p.update() for p in self.protfiles]
94
43
  summary = [l # f'<{i}> {l}'
95
44
  for i, l in enumerate(logmsg)
96
45
  if l]
97
46
  if summary:
98
- labels = set([p.name for p in protfiles])
47
+ labels = set([p.name for p in self.protfiles])
99
48
  logger.info('%s: %s',
100
49
  ', '.join(labels),
101
50
  ', '.join(summary))
51
+ if self.notify:
52
+ numOf = f"{summary.count('100.0%')} of {self.numTot}"
53
+ percent = sum([float(i[:-1])
54
+ for i in summary]) / self.numTot
55
+ self.notify(
56
+ ["progress_logger",
57
+ f"{self.numTot}:{numOf}:{percent}:{' '.join(summary)}"])
102
58
  else:
103
59
  logger.info('collecting FE losses ...')
104
60
  return
@@ -107,7 +63,7 @@ class ProgressLogger(threading.Thread):
107
63
  self.running = False
108
64
 
109
65
 
110
- def run_femag(cmd, workdir, fslfile):
66
+ def run_femag(cmd, workdir, fslfile, port):
111
67
  """Start the femag command as subprocess.
112
68
 
113
69
  :internal:
@@ -120,7 +76,8 @@ def run_femag(cmd, workdir, fslfile):
120
76
  with open(os.path.join(workdir, "femag.out"), "wb") as out, \
121
77
  open(os.path.join(workdir, "femag.err"), "wb") as err:
122
78
  try:
123
- proc = subprocess.Popen(cmd + ['-b', fslfile],
79
+ args = ['-b', str(port), fslfile] if port else ['-b', fslfile]
80
+ proc = subprocess.Popen(cmd + args,
124
81
  shell=False,
125
82
  stdin=DEVNULL,
126
83
  stdout=out,
@@ -163,11 +120,16 @@ class Engine:
163
120
  cmd: the program (executable image) to be run
164
121
  (femag dc is used if None)
165
122
  process_count: number of processes (cpu_count() if None)
166
- progress_timestep: time step in seconds for progress log messages if > 0)
123
+ timestep: time step in seconds for progress log messages if > 0)
167
124
  """
168
125
 
169
126
  def __init__(self, **kwargs):
170
127
  self.process_count = kwargs.get('process_count', None)
128
+ self.notify = kwargs.get('notify', None)
129
+ # cogg_calc mode, subscribe xyplot
130
+ self.calc_mode = kwargs.get('calc_mode')
131
+ self.port = kwargs.get('port', 0)
132
+ self.curve_label = kwargs.get('curve_label')
171
133
  cmd = kwargs.get('cmd', '')
172
134
  if cmd:
173
135
  self.cmd = [cmd]
@@ -175,7 +137,10 @@ class Engine:
175
137
  self.cmd.append('-m')
176
138
 
177
139
  self.progressLogger = 0
178
- self.progress_timestep = kwargs.get('timestep', 5)
140
+ self.progress_timestep = kwargs.get('timestep', -1)
141
+ self.subscriber = None
142
+ self.job = None
143
+ self.tasks = []
179
144
 
180
145
  def create_job(self, workdir):
181
146
  """Create a FEMAG :py:class:`Job`
@@ -209,20 +174,41 @@ class Engine:
209
174
  t.cmd = [cfg.get_executable(
210
175
  t.stateofproblem)] + args
211
176
 
212
- self.pool = multiprocessing.Pool(self.process_count)
213
- self.tasks = [self.pool.apply_async(run_femag,
214
- args=(t.cmd,
215
- t.directory,
216
- t.fsl_file))
217
- for t in self.job.tasks]
177
+ num_proc = self.process_count
178
+ if not num_proc and multiprocessing.cpu_count() > 1:
179
+ num_proc = min(multiprocessing.cpu_count()-1, len(self.job.tasks))
180
+ self.pool = multiprocessing.Pool(num_proc)
181
+ if self.port:
182
+ header = [b'progress']
183
+ if self.calc_mode == 'cogg_calc':
184
+ header +=[b'xyplot']
185
+ self.subscriber = [SubscriberTask(port=self.port + i * 5,
186
+ host='127.0.0.1',
187
+ notify=self.notify,
188
+ header=header,
189
+ curve_label=self.curve_label,
190
+ num_cur_steps=self.job.num_cur_steps,
191
+ timestep=self.progress_timestep
192
+ )
193
+ for i, t in enumerate(self.job.tasks)]
194
+ [s.start() for s in self.subscriber]
195
+ self.tasks = [self.pool.apply_async(
196
+ run_femag, args=(t.cmd, t.directory, t.fsl_file, self.port + i * 5))
197
+ for i, t in enumerate(self.job.tasks)]
198
+ else:
199
+ self.tasks = [self.pool.apply_async(
200
+ run_femag, args=(t.cmd, t.directory, t.fsl_file, 0))
201
+ for t in self.job.tasks]
218
202
  self.pool.close()
219
203
 
220
- if (self.progress_timestep and
221
- self.job.num_cur_steps):
204
+ # only works on linux
205
+ if (self.progress_timestep and not self.port and
206
+ self.job.num_cur_steps):
222
207
  self.progressLogger = ProgressLogger(
223
208
  [t.directory for t in self.job.tasks],
224
209
  num_cur_steps=self.job.num_cur_steps,
225
- timestep=self.progress_timestep)
210
+ timestep=self.progress_timestep,
211
+ notify=self.notify)
226
212
  self.progressLogger.start()
227
213
  return len(self.tasks)
228
214
 
@@ -244,17 +230,30 @@ class Engine:
244
230
  if t.errmsg:
245
231
  logger.error(t.errmsg)
246
232
  status.append(t.status)
233
+ self.stopThreads()
234
+ self.pool = None # garbage collector deletes threads
235
+ return status
236
+
237
+ def stopThreads(self):
238
+ """ stop all running treads
239
+ """
247
240
  if self.progressLogger:
248
241
  self.progressLogger.stop()
249
- return status
242
+ if self.port and self.subscriber:
243
+ [s.stop() for s in self.subscriber]
244
+ SubscriberTask.clear()
245
+ self.subscriber = None
250
246
 
251
247
  def terminate(self):
248
+ """ terminate all
249
+ """
252
250
  logger.info("terminate Engine")
253
- if self.progressLogger:
254
- self.progressLogger.stop()
251
+ self.stopThreads()
252
+
255
253
  # terminate pool
256
254
  try:
257
- self.pool.terminate()
258
- self.pool.close()
255
+ if self.pool:
256
+ self.pool.terminate()
257
+ self.pool = None # garbage collector deletes threads
259
258
  except AttributeError as e:
260
259
  logger.warn("%s", e)
femagtools/parstudy.py CHANGED
@@ -105,10 +105,10 @@ class ParameterStudy(object):
105
105
  raise ValueError("directory {} is not empty".format(dirname))
106
106
  self.reportdir = dirname
107
107
 
108
- def setup_model(self, builder, model, recsin=''):
108
+ def setup_model(self, builder, model, recsin='', feloss=''):
109
109
  """builds model in current workdir and returns its filenames"""
110
110
  # get and write mag curves
111
- mc_files = self.femag.copy_magnetizing_curves(model, recsin=recsin)
111
+ mc_files = self.femag.copy_magnetizing_curves(model, recsin=recsin, feloss=feloss)
112
112
 
113
113
  if model.is_complete():
114
114
  logger.info("setup model in %s", self.femag.workdir)
@@ -192,7 +192,8 @@ class ParameterStudy(object):
192
192
  objective_vars)
193
193
 
194
194
  if immutable_model:
195
- modelfiles = self.setup_model(builder, model, recsin=fea.recsin)
195
+ modelfiles = self.setup_model(builder, model, recsin=fea.recsin,
196
+ feloss=simulation.get('feloss', ''))
196
197
  logger.info("Files %s", modelfiles+extra_files)
197
198
  logger.info("model %s", model.props())
198
199
  for k in ('name', 'poles', 'outer_diam', 'airgap', 'bore_diam',
@@ -262,6 +263,10 @@ class ParameterStudy(object):
262
263
  p, int(np.ceil(len(par_range)/popsize)),
263
264
  np.shape(f))
264
265
  job.cleanup()
266
+ try:
267
+ feloss = fea.calc_fe_loss
268
+ except AttributeError:
269
+ feloss = ''
265
270
  for k, x in enumerate(population):
266
271
  task = job.add_task(self.result_func)
267
272
  for fn in extra_files:
@@ -284,7 +289,8 @@ class ParameterStudy(object):
284
289
  for mc in self.femag.copy_magnetizing_curves(
285
290
  model,
286
291
  dir=task.directory,
287
- recsin=fea.recsin):
292
+ recsin=fea.recsin,
293
+ feloss=feloss):
288
294
  task.add_file(mc)
289
295
  set_magnet_properties(model, fea, self.femag.magnets)
290
296
  task.add_file(
femagtools/semi_fea.py ADDED
@@ -0,0 +1,108 @@
1
+ import numpy as np
2
+ from .utils import fft
3
+ import logging
4
+
5
+ logger = logging.getLogger('femagtools.semi_fea')
6
+
7
+ def shift_array(v, idx):
8
+ '''shift array by index'''
9
+ return v[idx::] + v[0:idx]
10
+
11
+ def fft_filter(result_fft, perc=0.01):
12
+ '''filter FFT result with amplitude'''
13
+ result = {"order": [], "y":[]}
14
+ base_amp = result_fft['a']
15
+ for i, j in enumerate(result_fft['nue']):
16
+ if j >= perc*base_amp:
17
+ result['order'].append(i)
18
+ result['y'].append(j)
19
+ return result
20
+
21
+ def fast_skew_cogg(result, skew_setup):
22
+ '''Calculate cogging torque/Back-EMF with step skewing based on unskewed result
23
+ Arguments:
24
+ result: BCH objects
25
+ skew_setup(dict): {"skew_angle": 10, "nu_skew_steps": 2}
26
+ '''
27
+ skew_angle = skew_setup['skew_angle']
28
+ num_skew_steps =skew_setup['num_skew_steps']
29
+ skew_angle_intern = 0.0
30
+ skew_angle_array = []
31
+ T_slice = []
32
+ bemf = {"1": [], "2": [], "3": []}
33
+ bemf_slice = {"1": [], "2": [], "3": []}
34
+ bemf_skew = {"1": [], "2": [], "3": []}
35
+ bemf_skew_fft = {"1": [], "2": [], "3": []}
36
+
37
+ keyset = ('1', '2', '3')
38
+
39
+ # check if skew steps equals 2
40
+ if num_skew_steps == 2:
41
+ skew_angle_intern = skew_angle
42
+ skew_angle_array = [-skew_angle_intern/2, skew_angle_intern/2]
43
+ else:
44
+ skew_angle_intern = skew_angle/num_skew_steps*(num_skew_steps-1)/2
45
+ skew_angle_array = np.linspace(-skew_angle_intern, skew_angle_intern,
46
+ num_skew_steps, endpoint=True).tolist()
47
+
48
+ angle = result.torque[-1]['angle']
49
+ T = result.torque[-1]['torque'][0:-1]
50
+ # get back-emf from BCH
51
+ for i in keyset:
52
+ bemf[i] = result.flux[i][-1]['voltage_dpsi'][0:-1]
53
+
54
+ angl_resl = angle[1]
55
+ tmp = np.unique(np.abs(skew_angle_array))
56
+ skew_angl_resl = 0.0
57
+ if np.amin(tmp) == 0.0:
58
+ skew_angl_resl = tmp[1]
59
+ else:
60
+ skew_angl_resl = tmp[0]
61
+
62
+ divider = skew_angl_resl/angl_resl
63
+ if divider - np.floor(divider) > 1e-15:
64
+ # TODO: Interpolation if angle resolution doesn't match
65
+ logger.warning("Wrong Mesh Size in the airgap mesh")
66
+ else:
67
+ logger.info(f"number of element shifted {divider}")
68
+
69
+ for i in skew_angle_array:
70
+ idx = int(i/angl_resl)
71
+ if i != 0:
72
+ T_slice.append(shift_array(T, idx))
73
+ for j in keyset:
74
+ bemf_slice[j].append(shift_array(bemf[j], idx))
75
+ else:
76
+ # do nothing
77
+ T_slice.append(T)
78
+ for j in keyset:
79
+ bemf_slice[j].append(bemf[j])
80
+
81
+ # average torque
82
+ T_sum = 0
83
+ for i in T_slice:
84
+ T_sum += np.array(i)
85
+ T_skew = (T_sum/num_skew_steps).tolist()
86
+ T_skew += [T_skew[0]]
87
+ T_fft = fft_filter(fft(angle, T_skew, pmod=2))
88
+
89
+ # average back-emf
90
+ for j in keyset:
91
+ flx_skew = 0
92
+ for k in bemf_slice[j]:
93
+ flx_skew+=np.array(k)
94
+ bemf_skew[j] = (flx_skew/num_skew_steps).tolist()
95
+ bemf_skew[j] += [bemf_skew[j][0]]
96
+ bemf_skew_fft[j] = fft_filter(fft(angle, bemf_skew[j], pmod=2))
97
+
98
+ for i in range(len(T_slice)):
99
+ T_slice[i] = (np.array(T_slice[i])/num_skew_steps).tolist()
100
+ T_slice[i]+=[T_slice[i][0]]
101
+
102
+ return {"angle": angle,
103
+ "cogging_torque": T_skew,
104
+ "cogging_torque_fft": T_fft,
105
+ "BEMF": bemf_skew,
106
+ "BEMF_fft": bemf_skew_fft,
107
+ "cogging_torque_slice": T_slice}
108
+
@@ -88,9 +88,6 @@ m.pole_width = ${model['pole_width']*1e3}
88
88
  % if hasattr(model, 'lfe'):
89
89
  m.arm_length = ${model.get(['lfe'])*1e3}
90
90
  % endif
91
- % if hasattr(model, 'lfe'):
92
- m.arm_length = ${model.get(['lfe'])*1e3}
93
- % endif
94
91
  % if hasattr(model, 'winding'):
95
92
  % if 'num_par_wdgs' in model.winding:
96
93
  m.num_par_wdgs = ${model.winding['num_par_wdgs']}
@@ -1,20 +1,20 @@
1
- m.hc_min = ${'%12.3f' % model.get('hc_min', 95.0)} -- Limit demagnetisa > 0:[%]Hc,<0:[kA/m]
2
- m.con_hdcopy = ${'%12.3f' % model.get('con_hdcopy', 0)} -- Hc-copy:Name:auto:0,intact:1, none:-1
3
- m.b_max = ${'%12.3f' % model.get('b_max', 2.4)} -- Max Induction [T] in colorgradation
4
- m.b_min = ${'%12.3f' % model.get('move_inside')} -- Move inside: 0 , Move outside: > 0
5
- m.calc_fe_loss = ${'%12.3f' % model.get('calc_fe_loss', 1)} -- Calc. FE-Loss:0:no, 1:yes, 2:m-output
6
- m.eval_force = ${'%12.3f' % model.get('eval_force', 0)} -- Eval. force density > 0, no <= 0
7
- m.allow_draw = ${'%12.3f' % model.get('allow_draw', 1)} -- Draw Graphics :> 0: yes, 0: no
8
- m.fline_dens = ${'%12.3f' % model.get('fline_dens', 4)} -- F-Lines: 1: small, 2: medium, 3:thick
9
- m.num_flines = ${'%12.3f' % model.get('num_flines', 20)} -- Number of Field-lines: < 100 > 2
10
- m.name_bch_log = ${'%12.3f' % model.get('name_bch_log', 0)} -- Name bch-file in Logfile:> 0:yes,0:no
11
- m.st_size_move = ${'%12.3f' % model.get('st_size_move', 0)} -- Step size move: r/ph:[degr], x/y:[mm]
12
- m.num_nonl_it = ${'%12.3f' % model.get('num_nonl_it', 300)} -- Number of nonlinear Iterations < 99
13
- m.perm_mode = ${'%12.3f' % model.get('perm_mode', 0)} -- Permeability mode:>0:restore,0:actual
14
- m.error_perm = ${'%12.3f' % model.get('error_perm', 0.005)} -- Rel. Permeability error < 0.1 [%]
15
- m.allow_demagn = ${'%12.3f' % model.get('allow_demagn', 0)} -- Allow Demagnetisation:= 1:yes,= 0:no
16
- m.maenergy = ${'%12.3f' % model.get('maenergy', 0)} -- Force from magn energy 1 :yes,= 0:no
17
- m.el_order_ag = ${'%12.3f' % model.get('el_order_ag', 1)} -- El. order in air gap: lin=1: quadr=2
18
- m.export_scrpt = ${'%12.3f' % model.get('export_scrpt', 0)} -- Export parameters in script: yes > 0
1
+ m.hc_min = ${'%12.3f' % model.get('hc_min', 95.0)} -- Limit demagnetisa > 0:[%]Hc,<0:[kA/m]
2
+ m.con_hdcopy = ${'%12.3f' % model.get('con_hdcopy', 0)} -- Hc-copy:Name:auto:0,intact:1, none:-1
3
+ m.b_max = ${'%12.3f' % model.get('b_max', 2.4)} -- Max Induction [T] in colorgradation
4
+ m.b_min = ${'%12.3f' % model.get('move_inside')} -- Move inside: 0 , Move outside: > 0
5
+ m.calc_fe_loss = ${model.get('calc_fe_loss', 1)} -- Calc. FE-Loss:0:no, 1:yes, 2:m-output
6
+ m.eval_force = ${'%12.3f' % model.get('eval_force', 0)} -- Eval. force density > 0, no <= 0
7
+ m.allow_draw = ${'%12.3f' % model.get('allow_draw', 1)} -- Draw Graphics :> 0: yes, 0: no
8
+ m.fline_dens = ${'%12.3f' % model.get('fline_dens', 4)} -- F-Lines: 1: small, 2: medium, 3:thick
9
+ m.num_flines = ${'%12.3f' % model.get('num_flines', 20)} -- Number of Field-lines: < 100 > 2
10
+ m.name_bch_log = ${'%12.3f' % model.get('name_bch_log', 0)} -- Name bch-file in Logfile:> 0:yes,0:no
11
+ m.st_size_move = ${'%12.3f' % model.get('st_size_move', 0)} -- Step size move: r/ph:[degr], x/y:[mm]
12
+ m.num_nonl_it = ${'%12.3f' % model.get('num_nonl_it', 300)} -- Number of nonlinear Iterations < 99
13
+ m.perm_mode = ${'%12.3f' % model.get('perm_mode', 0)} -- Permeability mode:>0:restore,0:actual
14
+ m.error_perm = ${'%12.3f' % model.get('error_perm', 0.005)} -- Rel. Permeability error < 0.1 [%]
15
+ m.allow_demagn = ${'%12.3f' % model.get('allow_demagn', 0)} -- Allow Demagnetisation:= 1:yes,= 0:no
16
+ m.maenergy = ${'%12.3f' % model.get('maenergy', 0)} -- Force from magn energy 1 :yes,= 0:no
17
+ m.el_order_ag = ${'%12.3f' % model.get('el_order_ag', 1)} -- El. order in air gap: lin=1: quadr=2
18
+ m.export_scrpt = ${'%12.3f' % model.get('export_scrpt', 0)} -- Export parameters in script: yes > 0
19
19
 
20
20
  pre_models("FE-contr-data")
@@ -21,6 +21,9 @@ m.num_cur_steps = ${model['num_cur_steps']}
21
21
  m.nu_beta_steps = ${model['num_beta_steps']}
22
22
  m.beta_max = ${model['beta_max']}
23
23
  m.beta_min = ${model['beta_min']}
24
+ % if model.get('calc_fe_loss', 0):
25
+ m.calc_fe_loss = ${model['calc_fe_loss']}
26
+ % endif
24
27
  % if model.get('loss_funct',0):
25
28
  m.loss_funct = ${model.get('loss_funct')}
26
29
  % endif
@@ -22,6 +22,9 @@ m.fc_mult_move_type = 1.0 -- Type of move path in air gap
22
22
  m.fc_force_points = 0.0 -- number move points in air gap
23
23
  m.loss_funct = ${model.get('loss_funct', 0)} -- loss functon 0: own 1: ext
24
24
  m.loss_fact = ${model.get('loss_fact', 1)} -- loss multiplication factor
25
+ % if model.get('calc_fe_loss', 0):
26
+ m.calc_fe_loss = ${model['calc_fe_loss']}
27
+ % endif
25
28
 
26
29
  % if model.get('vtu_movie', 0):
27
30
  m.movie_type = 'vtu'
@@ -23,11 +23,14 @@ m.pocfilename = '${model.get('pocfilename', 'sin.poc')}'
23
23
  % if model.get('vtu_movie', 0):
24
24
  m.movie_type = 'vtu'
25
25
  %endif
26
+ % if model.get('calc_fe_loss'):
27
+ m.calc_fe_loss = ${'%d' % model['calc_fe_loss']}
28
+ % endif
26
29
  % if model.get('loss_funct',0):
27
30
  m.loss_funct = ${model.get('loss_funct')}
28
31
  % endif
29
32
  -- Excitation current
30
- m.nloa_ex_cur = ${model.get('nload_ex_cur', 0)} -- No Load Exciting current
33
+ m.nloa_ex_cur = ${model.get('noload_ex_cur', 0)} -- No Load Exciting current
31
34
  m.load_ex_cur = ${model.get('load_ex_cur', 0)} -- Load Exciting current
32
35
  m.wdgkeyex = 0 -- automatic winding selection
33
36
 
@@ -7,6 +7,9 @@ set_sim_data("explicit_mode", ${model.get('explicit_mode',0)})
7
7
  % if model.get('wind_temp',0):
8
8
  set_dev_data("cond_temp", ${model.get('wind_temp')}, ${model.get('wind_temp')})
9
9
  % endif
10
+ % if model.get('calc_fe_loss', 0):
11
+ m.calc_fe_loss = ${model['calc_fe_loss']}
12
+ % endif
10
13
  m.move_action = ${model.get('move_action', 0)}
11
14
  % if model.get('lfe',0):
12
15
  m.arm_length = ${model.get('lfe')*1e3}
@@ -20,6 +20,9 @@ m.winding_temp = ${model.get('wind_temp')}
20
20
  m.current = 1.0
21
21
  m.ntibfilename = model..'.ntib'
22
22
  m.period_frac = ${model.get('period_frac', 1)}
23
+ % if model.get('calc_fe_loss', 0):
24
+ m.calc_fe_loss = ${model['calc_fe_loss']}
25
+ % endif
23
26
  % if model.get('loss_funct',0):
24
27
  m.loss_funct = ${model.get('loss_funct')}
25
28
  % endif
@@ -24,6 +24,9 @@ m.delta_iq = ${model['delta_iq']}/m.num_par_wdgs
24
24
  % if model.get('load_ex_cur',0):
25
25
  m.load_ex_cur = ${model['load_ex_cur']}
26
26
  %endif
27
+ % if model.get('calc_fe_loss', 0):
28
+ m.calc_fe_loss = ${model['calc_fe_loss']}
29
+ % endif
27
30
  % if model.get('loss_funct',0):
28
31
  m.loss_funct = ${model.get('loss_funct')}
29
32
  % endif
@@ -2,6 +2,9 @@
2
2
  -- Torque/Force calculation
3
3
  --
4
4
  m.move_action = ${model.get('move_action', 0)}
5
+ % if model.get('calc_fe_loss', 0):
6
+ m.calc_fe_loss = ${model['calc_fe_loss']}
7
+ % endif
5
8
  % if model.get('loss_funct',0):
6
9
  m.loss_funct = ${model.get('loss_funct')}
7
10
  % endif
femagtools/tks.py CHANGED
@@ -22,15 +22,15 @@ HBpattern = re.compile(r'H.+\s+B')
22
22
  BPpattern = re.compile(r'B.+\s+P')
23
23
 
24
24
  _tranlate = {
25
- "ch": "Hysteresis Loss Factor",
26
- "cw": "Eddy Current Loss Factor",
27
- "ce": "Excess Loss Factor",
28
- "ch_freq": "Hyteresis Exponent",
29
- "cw_freq": "Eddy Current Exponent",
30
- "b_coeff": "Induction Loss Exponent",
25
+ "ch": "Hysteresis Loss Factor",
26
+ "cw": "Eddy Current Loss Factor",
27
+ "ce": "Excess Loss Factor",
28
+ "ch_freq": "Hyteresis Exponent",
29
+ "cw_freq": "Eddy Current Exponent",
30
+ "b_coeff": "Induction Loss Exponent",
31
31
  "alpha": "Induction Loss Exponent (Bertotti)",
32
- "Bo": "Reference Induction",
33
- "fo": "Reference Frequency",
32
+ "Bo": "Reference Induction",
33
+ "fo": "Reference Frequency",
34
34
  }
35
35
 
36
36
  def readlist(section):
@@ -134,15 +134,15 @@ class Reader(object):
134
134
  self.losses['cw_freq'] = z[1]
135
135
  self.losses['b_coeff'] = z[2]
136
136
 
137
- self.steinmetz = {'cw': z[0], 'cw_freq': z[1], 'b_coeff': z[2],
137
+ self.steinmetz = {'cw': z[0], 'cw_freq': z[1], 'b_coeff': z[2],
138
138
  'Bo': self.Bo, 'fo': self.fo}
139
139
 
140
140
  self.losses['Bo'] = self.Bo
141
141
  self.losses['fo'] = self.fo
142
142
  z = lc.fit_bertotti(self.losses['f'],
143
143
  self.losses['B'], pfe)
144
- self.bertotti = {'ch': z[0], 'cw': z[1], 'ce': z[2],
145
- 'alpha': 2.0, 'Bo': 1, 'fo': 1}
144
+ self.bertotti = {'ch': z[0], 'cw': z[1], 'ce': z[2],
145
+ 'b_coeff': 2.0, 'Bo': 1, 'fo': 1}
146
146
  logger.info("Bertotti loss coeffs %s", z)
147
147
 
148
148
  # must normalize pfe matrix:
@@ -171,9 +171,12 @@ class Reader(object):
171
171
  'cw_freq': self.cw_freq,
172
172
  'b_coeff': self.b_coeff,
173
173
  'rho': self.rho,
174
- 'losses': self.losses}
175
-
176
- def tableview(Reader):
174
+ 'losses': self.losses,
175
+ 'bertotti': self.bertotti,
176
+ 'steinmetz': self.steinmetz,
177
+ 'jordan': self.jordan}
178
+
179
+ def tableview(Reader):
177
180
  """pretty print loss coeff table"""
178
181
  losscoeff = [Reader.jordan, Reader.steinmetz, Reader.bertotti]
179
182
  # Title
@@ -181,18 +184,18 @@ def tableview(Reader):
181
184
  print('='*strlen)
182
185
  print('| {:^34} '.format(' ') + '| {:^18} | {:^18} | {:^18} |'.format(*["Jordan", "Steinmetz", 'Bertotti']))
183
186
  print('='*strlen)
184
- # data
185
- for key, item in _tranlate.items():
187
+ # data
188
+ for key, item in _tranlate.items():
186
189
  fout = ''
187
- for i in losscoeff:
188
- if key in i:
190
+ for i in losscoeff:
191
+ if key in i:
189
192
  fout += '| ' + f'{i[key]:^18.8e} '
190
- else:
193
+ else:
191
194
  tmp = '-'
192
195
  fout += '| ' + f'{tmp:^18} '
193
196
  print(f'| {item:^34}' + ' ' + fout + '|')
194
197
  print('='*strlen)
195
- return
198
+ return
196
199
 
197
200
  def read(filename, filecontent=None):
198
201
  """read Thyssen File TKS and return mc dict"""