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.
- femagtools/__init__.py +1 -1
- femagtools/dxfsl/area.py +65 -0
- femagtools/dxfsl/conv.py +5 -0
- femagtools/dxfsl/converter.py +34 -1
- femagtools/dxfsl/functions.py +14 -6
- femagtools/dxfsl/geom.py +12 -12
- femagtools/dxfsl/journal.py +1 -1
- femagtools/dxfsl/symmetry.py +28 -8
- femagtools/femag.py +64 -61
- femagtools/fsl.py +5 -2
- femagtools/isa7.py +3 -2
- femagtools/machine/afpm.py +43 -23
- femagtools/machine/effloss.py +29 -18
- femagtools/machine/sizing.py +4 -3
- femagtools/machine/sm.py +34 -36
- femagtools/mcv.py +56 -26
- femagtools/multiproc.py +79 -80
- femagtools/parstudy.py +10 -4
- femagtools/semi_fea.py +108 -0
- femagtools/templates/basic_modpar.mako +0 -3
- femagtools/templates/fe-contr.mako +18 -18
- femagtools/templates/ld_lq_fast.mako +3 -0
- femagtools/templates/mult_cal_fast.mako +3 -0
- femagtools/templates/pm_sym_f_cur.mako +4 -1
- femagtools/templates/pm_sym_fast.mako +3 -0
- femagtools/templates/pm_sym_loss.mako +3 -0
- femagtools/templates/psd_psq_fast.mako +3 -0
- femagtools/templates/torq_calc.mako +3 -0
- femagtools/tks.py +23 -20
- femagtools/zmq.py +213 -0
- {femagtools-1.8.2.dist-info → femagtools-1.8.3.dist-info}/METADATA +3 -3
- {femagtools-1.8.2.dist-info → femagtools-1.8.3.dist-info}/RECORD +40 -38
- {femagtools-1.8.2.dist-info → femagtools-1.8.3.dist-info}/WHEEL +1 -1
- tests/test_afpm.py +15 -6
- tests/test_femag.py +1 -1
- tests/test_fsl.py +4 -4
- tests/test_mcv.py +20 -14
- {femagtools-1.8.2.dist-info → femagtools-1.8.3.dist-info}/LICENSE +0 -0
- {femagtools-1.8.2.dist-info → femagtools-1.8.3.dist-info}/entry_points.txt +0 -0
- {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.
|
83
|
-
|
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
|
-
|
93
|
-
|
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
|
-
|
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
|
-
|
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',
|
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
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
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
|
-
|
221
|
-
|
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
|
-
|
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
|
-
|
254
|
-
|
251
|
+
self.stopThreads()
|
252
|
+
|
255
253
|
# terminate pool
|
256
254
|
try:
|
257
|
-
self.pool
|
258
|
-
|
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 = ${
|
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('
|
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
|
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
|
-
'
|
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
|
-
|
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"""
|