JModelica 和并发期货
JModelica and Concurrent Futures
我正在使用 JModelica 在后台使用 IPOPT 优化模型。
我想运行并行进行许多优化。此刻我正在做
这使用多处理模块。
现在,代码如下。它执行参数扫描
变量 T
和 So
并将结果写入以这些命名的输出文件
参数。输出文件还包含在
模型以及 运行 结果。
#!/usr/local/jmodelica/bin/jm_python.sh
import itertools
import multiprocessing
import numpy as np
import time
import sys
import signal
import traceback
import StringIO
import random
import cPickle as pickle
def PrintResToFile(filename,result):
def StripMX(x):
return str(x).replace('MX(','').replace(')','')
varstr = '#Variable Name={name: <10}, Unit={unit: <7}, Val={val: <10}, Col={col:< 5}, Comment="{comment}"\n'
with open(filename,'w') as fout:
#Print all variables at the top of the file, along with relevant information
#about them.
for var in result.model.getAllVariables():
if not result.is_variable(var.getName()):
val = result.initial(var.getName())
col = -1
else:
val = "Varies"
col = result.get_column(var.getName())
unit = StripMX(var.getUnit())
if not unit:
unit = "X"
fout.write(varstr.format(
name = var.getName(),
unit = unit,
val = val,
col = col,
comment = StripMX(var.getAttribute('comment'))
))
#Ensure that time variable is printed
fout.write(varstr.format(
name = 'time',
unit = 's',
val = 'Varies',
col = 0,
comment = 'None'
))
#The data matrix contains only time-varying variables. So fetch all of
#these, couple them in tuples with their column number, sort by column
#number, and then extract the name of the variable again. This results in a
#list of variable names which are guaranteed to be in the same order as the
#data matrix.
vkeys_in_order = [(result.get_column(x),x) for x in result.keys() if result.is_variable(x)]
vkeys_in_order = map(lambda x: x[1], sorted(vkeys_in_order))
for vk in vkeys_in_order:
fout.write("{0:>13},".format(vk))
fout.write("\n")
sio = StringIO.StringIO()
np.savetxt(sio, result.data_matrix, delimiter=',', fmt='%13.5f')
fout.write(sio.getvalue())
def RunModel(params):
T = params[0]
So = params[1]
try:
import pyjmi
signal.signal(signal.SIGINT, signal.SIG_IGN)
#For testing what happens if an error occurs
# import random
# if random.randint(0,100)<50:
# raise "Test Exception"
op = pyjmi.transfer_optimization_problem("ModelClass", "model.mop")
op.set('a', 0.20)
op.set('b', 1.00)
op.set('f', 0.05)
op.set('h', 0.05)
op.set('S0', So)
op.set('finalTime', T)
# Set options, see: http://www.jmodelica.org/api-docs/usersguide/1.13.0/ch07s06.html
opt_opts = op.optimize_options()
opt_opts['n_e'] = 40
opt_opts['IPOPT_options']['tol'] = 1e-10
opt_opts['IPOPT_options']['output_file'] = '/z/err_'+str(T)+'_'+str(So)+'_info.dat'
opt_opts['IPOPT_options']['linear_solver'] = 'ma27' #See: http://www.coin-or.org/Ipopt/documentation/node50.html
res = op.optimize(options=opt_opts)
result_file_name = 'out_'+str(T)+'_'+str(So)+'.dat'
PrintResToFile(result_file_name, res)
return (True,(T,So))
except:
ex_type, ex, tb = sys.exc_info()
return (False,(T,So),traceback.extract_tb(tb))
try:
fstatus = open('status','w')
except:
print("Could not open status file!")
sys.exit(-1)
T = map(float,[10,20,30,40,50,60,70,80,90,100,110,120,130,140])
So = np.arange(0.1,30.1,0.1)
tspairs = list(itertools.product(T,So))
random.shuffle(tspairs)
pool = multiprocessing.Pool()
mapit = pool.imap_unordered(RunModel,tspairs)
pool.close()
completed = 0
while True:
try:
res = mapit.next(timeout=2)
pickle.dump(res,fstatus)
fstatus.flush()
completed += 1
print(res)
print "{0: >4} of {1: >4} ({2: >4} left)".format(completed,len(tspairs),len(tspairs)-completed)
except KeyboardInterrupt:
pool.terminate()
pool.join()
sys.exit(0)
except multiprocessing.TimeoutError:
print "{0: >4} of {1: >4} ({2: >4} left)".format(completed,len(tspairs),len(tspairs)-completed)
except StopIteration:
break
使用模型:
optimization ModelClass(objective=-S(finalTime), startTime=0, finalTime=100)
parameter Real S0 = 2;
parameter Real F0 = 0;
parameter Real a = 0.2;
parameter Real b = 1;
parameter Real f = 0.05;
parameter Real h = 0.05;
output Real F(start=F0, fixed=true, min=0, max=100, unit="kg");
output Real S(start=S0, fixed=true, min=0, max=100, unit="kg");
input Real u(min=0, max=1);
equation
der(F) = u*(a*F+b);
der(S) = f*F/(1+h*F)-u*(a*F+b);
end ModelClass;
这样安全吗?
不。 截至 02015-11-09 似乎不安全。
以上代码根据输入参数命名输出文件。输出文件还包含用于 运行 模型的输入参数。
4核出现两种情况:
- 偶尔会在文件
/usr/local/jmodelica/Python/pyjmi/common/io.py
中引发错误 Inconsistent number of lines in the result data.
。
- 输出文件在内部显示一组参数,但以另一组参数命名,这表明脚本认为正在处理的参数与实际正在处理的参数不一致。
24核:
/usr/local/jmodelica/Python/pyjmi/common/io.py
重复出现错误 The result does not seem to be of a supported format.
。
总之,此信息表明 JModelica 正在使用中间文件,但中间文件的名称存在重叠,导致最好的情况是错误,最坏的情况是不正确的结果。
有人可能会假设这是在某处 tempfile
函数中生成错误随机数的结果,但与此相关的错误是 resolved on 02011-11-25。也许 PRNG 是根据系统时钟或常数播种的,因此会同步进行?
然而,情况似乎并非如此,因为以下不会产生冲突:
#!/usr/bin/env python
import time
import tempfile
import os
import collections
from multiprocessing import Pool
def f(x):
tf = tempfile.NamedTemporaryFile(delete=False)
print(tf.name)
return tf.name
p = Pool(24)
ret = p.map(f, range(2000))
counts = collections.Counter(ret)
print(counts)
不,这不安全。 op.optimize()
将使用从模型名称派生的文件名存储优化结果,然后将结果加载到 return 数据中,因此当您尝试 运行 一次进行多个优化时,您将获得竞争条件。为避免这种情况,您可以在 opt_opts['result_file_name']
.
中提供不同的结果文件名
我正在使用 JModelica 在后台使用 IPOPT 优化模型。
我想运行并行进行许多优化。此刻我正在做 这使用多处理模块。
现在,代码如下。它执行参数扫描
变量 T
和 So
并将结果写入以这些命名的输出文件
参数。输出文件还包含在
模型以及 运行 结果。
#!/usr/local/jmodelica/bin/jm_python.sh
import itertools
import multiprocessing
import numpy as np
import time
import sys
import signal
import traceback
import StringIO
import random
import cPickle as pickle
def PrintResToFile(filename,result):
def StripMX(x):
return str(x).replace('MX(','').replace(')','')
varstr = '#Variable Name={name: <10}, Unit={unit: <7}, Val={val: <10}, Col={col:< 5}, Comment="{comment}"\n'
with open(filename,'w') as fout:
#Print all variables at the top of the file, along with relevant information
#about them.
for var in result.model.getAllVariables():
if not result.is_variable(var.getName()):
val = result.initial(var.getName())
col = -1
else:
val = "Varies"
col = result.get_column(var.getName())
unit = StripMX(var.getUnit())
if not unit:
unit = "X"
fout.write(varstr.format(
name = var.getName(),
unit = unit,
val = val,
col = col,
comment = StripMX(var.getAttribute('comment'))
))
#Ensure that time variable is printed
fout.write(varstr.format(
name = 'time',
unit = 's',
val = 'Varies',
col = 0,
comment = 'None'
))
#The data matrix contains only time-varying variables. So fetch all of
#these, couple them in tuples with their column number, sort by column
#number, and then extract the name of the variable again. This results in a
#list of variable names which are guaranteed to be in the same order as the
#data matrix.
vkeys_in_order = [(result.get_column(x),x) for x in result.keys() if result.is_variable(x)]
vkeys_in_order = map(lambda x: x[1], sorted(vkeys_in_order))
for vk in vkeys_in_order:
fout.write("{0:>13},".format(vk))
fout.write("\n")
sio = StringIO.StringIO()
np.savetxt(sio, result.data_matrix, delimiter=',', fmt='%13.5f')
fout.write(sio.getvalue())
def RunModel(params):
T = params[0]
So = params[1]
try:
import pyjmi
signal.signal(signal.SIGINT, signal.SIG_IGN)
#For testing what happens if an error occurs
# import random
# if random.randint(0,100)<50:
# raise "Test Exception"
op = pyjmi.transfer_optimization_problem("ModelClass", "model.mop")
op.set('a', 0.20)
op.set('b', 1.00)
op.set('f', 0.05)
op.set('h', 0.05)
op.set('S0', So)
op.set('finalTime', T)
# Set options, see: http://www.jmodelica.org/api-docs/usersguide/1.13.0/ch07s06.html
opt_opts = op.optimize_options()
opt_opts['n_e'] = 40
opt_opts['IPOPT_options']['tol'] = 1e-10
opt_opts['IPOPT_options']['output_file'] = '/z/err_'+str(T)+'_'+str(So)+'_info.dat'
opt_opts['IPOPT_options']['linear_solver'] = 'ma27' #See: http://www.coin-or.org/Ipopt/documentation/node50.html
res = op.optimize(options=opt_opts)
result_file_name = 'out_'+str(T)+'_'+str(So)+'.dat'
PrintResToFile(result_file_name, res)
return (True,(T,So))
except:
ex_type, ex, tb = sys.exc_info()
return (False,(T,So),traceback.extract_tb(tb))
try:
fstatus = open('status','w')
except:
print("Could not open status file!")
sys.exit(-1)
T = map(float,[10,20,30,40,50,60,70,80,90,100,110,120,130,140])
So = np.arange(0.1,30.1,0.1)
tspairs = list(itertools.product(T,So))
random.shuffle(tspairs)
pool = multiprocessing.Pool()
mapit = pool.imap_unordered(RunModel,tspairs)
pool.close()
completed = 0
while True:
try:
res = mapit.next(timeout=2)
pickle.dump(res,fstatus)
fstatus.flush()
completed += 1
print(res)
print "{0: >4} of {1: >4} ({2: >4} left)".format(completed,len(tspairs),len(tspairs)-completed)
except KeyboardInterrupt:
pool.terminate()
pool.join()
sys.exit(0)
except multiprocessing.TimeoutError:
print "{0: >4} of {1: >4} ({2: >4} left)".format(completed,len(tspairs),len(tspairs)-completed)
except StopIteration:
break
使用模型:
optimization ModelClass(objective=-S(finalTime), startTime=0, finalTime=100)
parameter Real S0 = 2;
parameter Real F0 = 0;
parameter Real a = 0.2;
parameter Real b = 1;
parameter Real f = 0.05;
parameter Real h = 0.05;
output Real F(start=F0, fixed=true, min=0, max=100, unit="kg");
output Real S(start=S0, fixed=true, min=0, max=100, unit="kg");
input Real u(min=0, max=1);
equation
der(F) = u*(a*F+b);
der(S) = f*F/(1+h*F)-u*(a*F+b);
end ModelClass;
这样安全吗?
不。 截至 02015-11-09 似乎不安全。
以上代码根据输入参数命名输出文件。输出文件还包含用于 运行 模型的输入参数。
4核出现两种情况:
- 偶尔会在文件
/usr/local/jmodelica/Python/pyjmi/common/io.py
中引发错误Inconsistent number of lines in the result data.
。 - 输出文件在内部显示一组参数,但以另一组参数命名,这表明脚本认为正在处理的参数与实际正在处理的参数不一致。
24核:
/usr/local/jmodelica/Python/pyjmi/common/io.py
重复出现错误The result does not seem to be of a supported format.
。
总之,此信息表明 JModelica 正在使用中间文件,但中间文件的名称存在重叠,导致最好的情况是错误,最坏的情况是不正确的结果。
有人可能会假设这是在某处 tempfile
函数中生成错误随机数的结果,但与此相关的错误是 resolved on 02011-11-25。也许 PRNG 是根据系统时钟或常数播种的,因此会同步进行?
然而,情况似乎并非如此,因为以下不会产生冲突:
#!/usr/bin/env python
import time
import tempfile
import os
import collections
from multiprocessing import Pool
def f(x):
tf = tempfile.NamedTemporaryFile(delete=False)
print(tf.name)
return tf.name
p = Pool(24)
ret = p.map(f, range(2000))
counts = collections.Counter(ret)
print(counts)
不,这不安全。 op.optimize()
将使用从模型名称派生的文件名存储优化结果,然后将结果加载到 return 数据中,因此当您尝试 运行 一次进行多个优化时,您将获得竞争条件。为避免这种情况,您可以在 opt_opts['result_file_name']
.