Advertisement
Guest User

janaf.py - code to calculate janaf thermodynamics (v1.1)

a guest
Dec 31st, 2015
569
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.33 KB | None | 0 0
  1. #!/usr/bin/python
  2.  
  3. import sys, scipy, os, re, math, random
  4. from scipy.optimize import minimize
  5.  
  6. if len(sys.argv) != 5:
  7. print "Usage: janaf.py <file> <minimum_temp> <common_temp> <maximum_temp>"
  8. sys.exit(1)
  9.  
  10. R = 8.314459848 # J/K/mol
  11.  
  12. elements = {
  13. "H" : 1.00794,
  14. "Li" : 6.941,
  15. "B" : 10.811,
  16. "Be" : 9.012182,
  17. "C" : 12.0107,
  18. "N" : 14.0067,
  19. "O" : 15.9994049,
  20. "F" : 18.998403,
  21. "Na" : 22.98976,
  22. "Mg" : 24.3050,
  23. "Al" : 26.98153851111,
  24. "Si" : 28.0855,
  25. "P" : 30.97696,
  26. "S" : 32.065,
  27. "Cl" : 35.453,
  28. "K" : 39.0983,
  29. "Ca" : 40.078,
  30. "Cr" : 51.9962,
  31. "Fe" : 55.845,
  32. "Co" : 58.93319,
  33. "Zn" : 65.38,
  34. "Ga" : 69.723,
  35. "Br" : 79.904,
  36. "I" : 126.09044,
  37. }
  38. low = float(sys.argv[2])
  39. common = float(sys.argv[3])
  40. high = float(sys.argv[4])
  41. reference = 298.15
  42. zero = 0.0
  43.  
  44. def read(category):
  45. lines = open(sys.argv[1]).readlines()
  46. state = "Searching"
  47. data = []
  48. data2 = []
  49. index = 0
  50. name = "UNKNOWN"
  51. for line in lines:
  52. if state == "Searching":
  53. if re.match('^\s*"name":\s*"%s",\s*\n$' % category, line):
  54. state = "values"
  55. else:
  56. match = re.match('^\s*"chemicalFormula":\s*"(.*)",\s*\n$', line)
  57. if match:
  58. name = match.group(1)
  59. elif state == "values":
  60. if re.match('^\s*"name":\s*"Temperature",\s*\n$', line):
  61. state = "temperatures"
  62. else:
  63. match = re.match('^\s*"value":\s*"(-?\d*\.?\d+)"\n$', line)
  64. if match:
  65. data.append(float(match.group(1)))
  66. elif state == "temperatures":
  67. if re.match('^\s*"name":\s*".*",\s*\n$', line):
  68. break
  69. else:
  70. match = re.match('^\s*"value":\s*"(-?\d*\.?\d+)"\n$', line)
  71. if match:
  72. data2.append( (float(match.group(1)), data[index]) )
  73. index += 1
  74. else:
  75. print "Unknown state!"
  76. sys.exit(1)
  77. return data2, name
  78.  
  79. tmp = read("Specific heat capacity")
  80. specific_heat = tmp[0]
  81. name = tmp[1]
  82. enthalpy = read("Relative standard enthalpy")[0]
  83. entropy = read("Standard entropy")[0]
  84.  
  85. molweight = 0.0;
  86. keys = elements.keys()
  87. keys.sort(key=len, reverse=True)
  88. element_string = "|".join(keys)
  89. matches = re.findall('(%s)(\d*)' % element_string, name)
  90. for match in matches:
  91. count = 1
  92. if match[1] != "":
  93. count = float(match[1])
  94. molweight += elements[match[0]] * count
  95.  
  96. low_point = len(specific_heat)
  97. low_specific_heat = None
  98. for i in range(len(specific_heat)):
  99. if specific_heat[i][0] >= low - 0.000001:
  100. low_point = i
  101. low_specific_heat = specific_heat[i][1]
  102. break
  103.  
  104. common_point = len(specific_heat)
  105. common_specific_heat = None
  106. for i in range(len(specific_heat)):
  107. if specific_heat[i][0] >= common - 0.000001:
  108. common_point = i
  109. common_specific_heat = specific_heat[i][1]
  110. break
  111.  
  112. high_point = len(specific_heat)
  113. high_specific_heat = None
  114. for i in range(len(specific_heat)):
  115. if specific_heat[i][0] >= high - 0.000001:
  116. high_point = i
  117. high_specific_heat = specific_heat[i][1]
  118. break
  119.  
  120. dataset_low = specific_heat[low_point:common_point] + ([specific_heat[common_point]] * 9)
  121. dataset_high = ([specific_heat[common_point]] * 10) + specific_heat[common_point:high_point]
  122.  
  123. entropy_low = len(entropy)
  124. entropy_common = len(entropy)
  125. entropy_high = len(entropy)
  126. for i in range(len(specific_heat)):
  127. if entropy_low == len(entropy):
  128. if entropy[i][0] >= low - 0.000001:
  129. entropy_low = entropy[i][1]
  130. elif entropy_common == len(entropy):
  131. if entropy[i][0] >= common - 0.000001:
  132. entropy_common = entropy[i][1]
  133. else:
  134. if entropy[i][0] >= high - 0.000001:
  135. entropy_high = entropy[i][1]
  136. break
  137.  
  138. enthalpy_low = len(enthalpy)
  139. enthalpy_common = len(enthalpy)
  140. enthalpy_high = len(enthalpy)
  141. for i in range(len(specific_heat)):
  142. if enthalpy_low == len(enthalpy):
  143. if enthalpy[i][0] >= low - 0.000001:
  144. enthalpy_low = enthalpy[i][1]
  145. elif enthalpy_common == len(enthalpy):
  146. if enthalpy[i][0] >= common - 0.000001:
  147. enthalpy_common = enthalpy[i][1]
  148. else:
  149. if enthalpy[i][0] >= high - 0.000001:
  150. enthalpy_high = enthalpy[i][1]
  151. break
  152.  
  153. def calculate_specific_heat(T, a):
  154. return R * ((((a[4]*T + a[3])*T + a[2])*T + a[1])*T + a[0])
  155.  
  156. def evaluate(a, dataset):
  157. total_error = 0.0
  158. # print a
  159. for i in dataset:
  160. T = i[0]
  161. x = calculate_specific_heat(T, a)
  162. if x < 0:
  163. return 999999999999999.9
  164. error = math.pow(math.fabs(x - i[1]), 2) / len(dataset)
  165. total_error += error
  166. # print " %f: %6f/%6f (%f)" % (T, x, i[1], math.fabs(x - i[1]))
  167. return total_error
  168.  
  169. def optimize(dataset):
  170. params = [1e1, 8e-3, 6e-6, 4e-9, 2e-12]
  171. best = evaluate(params, dataset)
  172. i = 0
  173. while i < 60 * math.sqrt(best):
  174. # print "Cycle %d" % i
  175. trial = list(params)
  176. while True:
  177. if random.random() < math.pow(1.0 / (len(trial) + 1), 0.4):
  178. break
  179. choice = random.randrange(len(trial))
  180. trial[choice] += trial[choice] * math.pow(random.random()/(random.random() + 0.0000001), 0.3) - trial[choice] * math.pow(random.random()/(random.random() + 0.0000001), 0.3)
  181. trial[choice] *= math.pow(random.random()/(random.random() + 0.2), 0.3)
  182. res = minimize(evaluate, list(trial), method='Nelder-Mead', args=(dataset,), options={"maxiter": 1000})
  183. val = evaluate(res.x, dataset)
  184. # print "%f, %f" % (val, best)
  185. if val < best:
  186. best = val
  187. params = list(res.x)
  188. # print "", params
  189. i += 1
  190. return best, params
  191.  
  192. low_results = optimize(dataset_low)
  193. high_results = optimize(dataset_high)
  194.  
  195. sys.stderr.write("Errors: low=%f, high=%f\n" % (low_results[0], high_results[0]))
  196. if low_results[0] >= 0.03:
  197. sys.stderr.write(" Warning: low-Cp error is very high - consider raising Tlow.\n")
  198. elif low_results[0] >= 0.01:
  199. sys.stderr.write(" Warning: low-Cp error is somewhat high - consider raising Tlow.\n")
  200. if high_results[0] >= 0.03:
  201. sys.stderr.write(" Warning: high-Cp error is very high - consider raising Tcommon or lowering Thigh.\n")
  202. elif high_results[0] >= 0.01:
  203. sys.stderr.write(" Warning: high-Cp error is somewhat high - consider raising Tcommon or lowering Thigh.\n")
  204.  
  205. zero_enthalpy = None
  206. for entry in enthalpy:
  207. if entry[0] >= zero - 0.000001:
  208. if entry[0] <= zero + 0.000001:
  209. zero_enthalpy = entry[1]
  210. break
  211. else:
  212. print "ERROR - enthalpy-zero not found: %f, %f" % (zero, entry[0])
  213. sys.exit(1)
  214.  
  215. low_enthalpy = None
  216. for entry in enthalpy:
  217. if entry[0] >= low - 0.000001:
  218. if entry[0] <= low + 0.000001:
  219. low_enthalpy = entry[1]
  220. break
  221. else:
  222. print "ERROR - enthalpy-low not found: %f, %f" % (low, entry[0])
  223. sys.exit(1)
  224.  
  225. reference_enthalpy = None
  226. for entry in enthalpy:
  227. if entry[0] >= reference - 0.000001:
  228. if entry[0] <= reference + 0.000001:
  229. reference_enthalpy = entry[1]
  230. break
  231. else:
  232. print "ERROR - enthalpy-reference not found: %f, %f" % (reference, entry[0])
  233. sys.exit(1)
  234.  
  235. common_enthalpy = None
  236. for entry in enthalpy:
  237. if entry[0] >= common - 0.000001:
  238. if entry[0] <= common + 0.000001:
  239. common_enthalpy = entry[1]
  240. break
  241. else:
  242. print "ERROR - enthalpy-common not found: %f, %f" % (common, entry[0])
  243. sys.exit(1)
  244.  
  245. high_enthalpy = None
  246. for entry in enthalpy:
  247. if entry[0] >= high - 0.000001:
  248. if entry[0] <= high + 0.000001:
  249. high_enthalpy = entry[1]
  250. break
  251. else:
  252. print "ERROR - enthalpy-high not found: %f, %f" % (high, entry[0])
  253. sys.exit(1)
  254.  
  255. zero_enthalpy *= 1000
  256. low_enthalpy *= 1000
  257. reference_enthalpy *= 1000
  258. common_enthalpy *= 1000
  259. high_enthalpy *= 1000
  260.  
  261. def calculate_enthalpy(T, a):
  262. return R * (a[4]*math.pow(T, 5)/5 + a[3]*math.pow(T, 4)/4 + a[2]*math.pow(T, 3)/3 + a[1]*math.pow(T, 2)/2 + a[0]*T)
  263.  
  264. low_enthalpy_offset = 0.0
  265. high_enthalpy_offset = 0.0
  266. last_temperature = None
  267. last_calculated_enthalpy = None
  268. last_enthalpy_difference = None
  269. last_enthalpy = None
  270.  
  271. for entry in enthalpy:
  272. temperature = entry[0]
  273. cur_enthalpy = entry[1] * 1000
  274. calculated_enthalpy = None
  275. enthalpy_difference = None
  276. if temperature >= low - 0.000001:
  277. if temperature <= common + 0.000001:
  278. calculated_enthalpy = calculate_enthalpy(temperature, low_results[1])
  279. enthalpy_difference = cur_enthalpy - calculated_enthalpy
  280. if last_enthalpy_difference != None:
  281. average_enthalpy_difference = (last_enthalpy_difference + enthalpy_difference) / 2
  282. low_enthalpy_offset += average_enthalpy_difference * (temperature - last_temperature) / R
  283. if temperature >= common - 0.000001:
  284. calculated_enthalpy = calculate_enthalpy(temperature, high_results[1])
  285. enthalpy_difference = cur_enthalpy - calculated_enthalpy
  286. average_enthalpy_difference = (last_enthalpy_difference + enthalpy_difference) / 2
  287. if temperature >= common + 0.000001:
  288. high_enthalpy_offset += average_enthalpy_difference * (temperature - last_temperature) / R
  289. if temperature >= high - 0.000001:
  290. break
  291. last_temperature = temperature
  292. last_calculated_enthalpy = calculated_enthalpy
  293. last_enthalpy_difference = enthalpy_difference
  294. last_enthalpy = cur_enthalpy
  295.  
  296. low_enthalpy_offset /= (common - low)
  297. high_enthalpy_offset /= (high - common)
  298.  
  299. zero_entropy = None
  300. for entry in entropy:
  301. if entry[0] >= zero - 0.000001:
  302. if entry[0] <= zero + 0.000001:
  303. zero_entropy = entry[1]
  304. break
  305. else:
  306. print "ERROR - entropy-zero not found: %f, %f" % (zero, entry[0])
  307. sys.exit(1)
  308.  
  309. low_entropy = None
  310. for entry in entropy:
  311. if entry[0] >= low - 0.000001:
  312. if entry[0] <= low + 0.000001:
  313. low_entropy = entry[1]
  314. break
  315. else:
  316. print "ERROR - entropy-low not found: %f, %f" % (low, entry[0])
  317. sys.exit(1)
  318.  
  319. reference_entropy = None
  320. for entry in entropy:
  321. if entry[0] >= reference - 0.000001:
  322. if entry[0] <= reference + 0.000001:
  323. reference_entropy = entry[1]
  324. break
  325. else:
  326. print "ERROR - entropy-high not found: %f, %f" % (reference, entry[0])
  327. sys.exit(1)
  328.  
  329. common_entropy = None
  330. for entry in entropy:
  331. if entry[0] >= common - 0.000001:
  332. if entry[0] <= common + 0.000001:
  333. common_entropy = entry[1]
  334. break
  335. else:
  336. print "ERROR - entropy-high not found: %f, %f" % (common, entry[0])
  337. sys.exit(1)
  338.  
  339. high_entropy = None
  340. for entry in entropy:
  341. if entry[0] >= high - 0.000001:
  342. if entry[0] <= high + 0.000001:
  343. high_entropy = entry[1]
  344. break
  345. else:
  346. print "ERROR - entropy-high not found: %f, %f" % (high, entry[0])
  347. sys.exit(1)
  348.  
  349. def calculate_entropy(T, a):
  350. if T == 0.0:
  351. return 1.0
  352. return R * (a[4]*math.pow(T, 4)/4 + a[3]*math.pow(T, 3)/3 + a[2]*math.pow(T, 2)/2 + a[1]*T + a[0]*math.log(T))
  353.  
  354. low_entropy_offset = 0.0
  355. high_entropy_offset = 0.0
  356. last_temperature = None
  357. last_calculated_entropy = None
  358. last_entropy_difference = None
  359.  
  360. for entry in entropy:
  361. temperature = entry[0]
  362. cur_entropy = entry[1]
  363. calculated_entropy = None
  364. entropy_difference = None
  365. if temperature >= low - 0.000001:
  366. if temperature <= common + 0.000001:
  367. calculated_entropy = calculate_entropy(temperature, low_results[1])
  368. entropy_difference = cur_entropy - calculated_entropy
  369. if last_entropy_difference != None:
  370. average_entropy_difference = (last_entropy_difference + entropy_difference) / 2
  371. low_entropy_offset += average_entropy_difference * (temperature - last_temperature) / R
  372. if temperature >= common - 0.000001:
  373. calculated_entropy = calculate_entropy(temperature, high_results[1])
  374. entropy_difference = cur_entropy - calculated_entropy
  375. average_entropy_difference = (last_entropy_difference + entropy_difference) / 2
  376. if temperature >= common + 0.000001:
  377. high_entropy_offset += average_entropy_difference * (temperature - last_temperature) / R
  378. if temperature >= high - 0.000001:
  379. break
  380. last_temperature = temperature
  381. last_calculated_entropy = calculated_entropy
  382. last_entropy_difference = entropy_difference
  383.  
  384. low_entropy_offset /= (common - low)
  385. high_entropy_offset /= (high - common)
  386.  
  387. sys.stderr.write("Specific heat checks, low: %9.2f %9.2f / %9.2f %9.2f\n" % (calculate_specific_heat(low, low_results[1]), low_specific_heat, calculate_specific_heat(common, low_results[1]), common_specific_heat))
  388. sys.stderr.write("Specific heat checks, high: %9.2f %9.2f / %9.2f %9.2f\n" % (calculate_specific_heat(common, high_results[1]), common_specific_heat, calculate_specific_heat(high, high_results[1]), high_specific_heat))
  389. sys.stderr.write("Enthalpy checks, low: %9.2f %9.2f / %9.2f %9.2f\n" % (calculate_enthalpy(low, low_results[1]) + low_enthalpy_offset * R, low_enthalpy, calculate_enthalpy(common, low_results[1]) + low_enthalpy_offset * R, common_enthalpy))
  390. sys.stderr.write("Enthalpy checks, low: %9.2f %9.2f / %9.2f %9.2f\n" % (calculate_enthalpy(common, high_results[1]) + high_enthalpy_offset * R, common_enthalpy, calculate_enthalpy(high, high_results[1]) + high_enthalpy_offset * R, high_enthalpy))
  391. sys.stderr.write("Entropy checks, low: %9.2f %9.2f / %9.2f %9.2f\n" % (calculate_entropy(low, low_results[1]) + low_entropy_offset * R, low_entropy, calculate_entropy(common, low_results[1]) + low_entropy_offset * R, common_entropy))
  392. sys.stderr.write("Entropy checks, low: %9.2f %9.2f / %9.2f %9.2f\n" % (calculate_entropy(common, high_results[1]) + high_entropy_offset * R, common_entropy, calculate_entropy(high, high_results[1]) + high_entropy_offset * R, high_entropy))
  393.  
  394. print "%s" % name
  395. print "{"
  396. print " specie"
  397. print " {"
  398. print " nMoles 1;"
  399. print " molWeight %s;" % molweight
  400. print " }"
  401. print " thermodynamics"
  402. print " {"
  403. print " Tlow %f;" % low
  404. print " Thigh %f;" % high
  405. print " Tcommon %f;" % common
  406. print " highCpCoeffs ( %g %g %g %g %g %g %g );" % (high_results[1][0], high_results[1][1], high_results[1][2], high_results[1][3], high_results[1][4], high_enthalpy_offset, high_entropy_offset)
  407. print " lowCpCoeffs ( %g %g %g %g %g %g %g );" % (low_results[1][0], low_results[1][1], low_results[1][2], low_results[1][3], low_results[1][4], low_enthalpy_offset, low_entropy_offset)
  408. print " }"
  409. #print " transport"
  410. #print " {"
  411. #print " As 1.67212e-06;"
  412. #print " Ts 170.672;"
  413. #print " }"
  414. print "}"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement