|
39 | 39 | "%matplotlib inline"
|
40 | 40 | ]
|
41 | 41 | },
|
| 42 | + { |
| 43 | + "cell_type": "code", |
| 44 | + "execution_count": null, |
| 45 | + "metadata": {}, |
| 46 | + "outputs": [], |
| 47 | + "source": [ |
| 48 | + "MassAction.inactive_reactants_modulation = lambda self, variables, backend=math, reaction=None: 1" |
| 49 | + ] |
| 50 | + }, |
42 | 51 | {
|
43 | 52 | "cell_type": "markdown",
|
44 | 53 | "metadata": {},
|
|
149 | 158 | "rsys = ReactionSystem(\n",
|
150 | 159 | " eq_dis.as_reactions(kb=kinetics_as, new_name='ligand-protein association') +\n",
|
151 | 160 | " eq_u.as_reactions(kb=kinetics_f, new_name='protein folding') +\n",
|
152 |
| - " (r_agg,), substances, name='4-state CETSA system')" |
| 161 | + " (r_agg,), substances, name='4-state CETSA system')\n", |
| 162 | + "print(rsys.string(with_param=False))" |
153 | 163 | ]
|
154 | 164 | },
|
155 | 165 | {
|
|
257 | 267 | "def pretty_replace(s, subs=None):\n",
|
258 | 268 | " if subs is None:\n",
|
259 | 269 | " subs = {\n",
|
260 |
| - " 'Ha_(\\w+)': r'\\\\Delta_{\\1}H^{\\\\neq}',\n", |
261 |
| - " 'Sa_(\\w+)': r'\\\\Delta_{\\1}S^{\\\\neq}',\n", |
262 |
| - " 'He_(\\w+)': r'\\\\Delta_{\\1}H^\\\\circ',\n", |
263 |
| - " 'Se_(\\w+)': r'\\\\Delta_{\\1}S^\\\\circ',\n", |
264 |
| - " 'Cp_(\\w+)': r'\\\\Delta_{\\1}\\,C_p',\n", |
265 |
| - " 'Tref_(\\w+)': r'T^{\\\\circ}_{\\1}',\n", |
| 270 | + " r'Ha_(\\w+)': r'\\\\Delta_{\\\\rm \\1}H^{\\\\neq}',\n", |
| 271 | + " r'Sa_(\\w+)': r'\\\\Delta_{\\\\rm \\1}S^{\\\\neq}',\n", |
| 272 | + " r'He_(\\w+)': r'\\\\Delta_{\\\\rm \\1}H^\\\\circ',\n", |
| 273 | + " r'Se_(\\w+)': r'\\\\Delta_{\\\\rm \\1}S^\\\\circ',\n", |
| 274 | + " r'Cp_(\\w+)': r'\\\\Delta_{\\\\rm \\1}\\,C_p',\n", |
| 275 | + " r'Tref_(\\w+)': r'T^{\\\\circ}_{\\\\rm \\1}',\n", |
| 276 | + " 'k_B': r'k_{\\\\rm B}',\n", |
| 277 | + " 'Tmelt': r'T_{\\\\rm m}',\n", |
266 | 278 | " }\n",
|
267 | 279 | " for pattern, repl in subs.items():\n",
|
268 | 280 | " s = re.sub(pattern, repl, s)\n",
|
269 | 281 | " return s\n",
|
270 | 282 | "\n",
|
| 283 | + "_created = {}\n", |
271 | 284 | "def mk_Symbol(key):\n",
|
272 | 285 | " if key in substances:\n",
|
273 | 286 | " arg = substances[key].latex_name\n",
|
274 | 287 | " else:\n",
|
275 | 288 | " arg = pretty_replace(key.replace('temperature', 'T'))\n",
|
| 289 | + " if key == 'T' or 'temperature' in key or key.startswith(\"Tref\") or key.startswith(\"Tmelt\"):\n", |
| 290 | + " positive = True\n", |
| 291 | + " else:\n", |
| 292 | + " positive = None\n", |
| 293 | + " _created[key] = sympy.Symbol(arg, real=True, positive=positive)\n", |
| 294 | + " return _created[key]\n", |
276 | 295 | "\n",
|
277 |
| - " return sympy.Symbol(arg)\n", |
| 296 | + "def smart_factor(expr):\n", |
| 297 | + " numer, denom = expr.as_numer_denom()\n", |
| 298 | + " if denom != 1:\n", |
| 299 | + " return (smart_factor(numer)/denom).expand(deep=False)\n", |
| 300 | + " if expr.is_Mul and len(expr.args) > 1:\n", |
| 301 | + " return reduce(mul, map(smart_factor, expr.args))\n", |
| 302 | + " const, nonconst = expr.as_coeff_Add()\n", |
| 303 | + " cand0 = sympy.factor(nonconst) + const\n", |
| 304 | + " candidates = {cand0: cand0.count_ops()}\n", |
| 305 | + " for fs in expr.free_symbols:\n", |
| 306 | + " i, d = expr.as_independent(fs, as_Add=True)\n", |
| 307 | + " cand = sympy.factor(i) + sympy.factor(d)\n", |
| 308 | + " candidates[cand] = cand.count_ops()\n", |
| 309 | + " #print(f\"{candidates=}\") # debug print, remove in production\n", |
| 310 | + " result = min(candidates, key=candidates.__getitem__)\n", |
| 311 | + " const, terms = result.as_coeff_add()\n", |
| 312 | + " if len(terms) > 1:\n", |
| 313 | + " return const + reduce(add, map(smart_factor, terms))\n", |
| 314 | + " return result\n", |
| 315 | + " \n", |
278 | 316 | "\n",
|
| 317 | + "def log_simp(e):\n", |
| 318 | + " e = sympy.logcombine(e)\n", |
| 319 | + " def _log(*args):\n", |
| 320 | + " arg, = args\n", |
| 321 | + " pdict = arg.as_powers_dict()\n", |
| 322 | + " pv = list(pdict.values())\n", |
| 323 | + " if len(pv) == 1:\n", |
| 324 | + " ret = pv[0]*sympy.log(*pdict.keys())\n", |
| 325 | + " elif all(_ == pv[0] for _ in pv[1:]):\n", |
| 326 | + " ret = pv[0]*sympy.log(reduce(mul, pdict.keys()))\n", |
| 327 | + " else:\n", |
| 328 | + " ret = sympy.log(arg)\n", |
| 329 | + " #print(f\"{arg=} {pdict=} {ret=}\")\n", |
| 330 | + " return ret\n", |
| 331 | + " e = e.replace(sympy.log, _log)\n", |
| 332 | + " return e\n", |
| 333 | + "x,y,z=sympy.symbols('x,y,z',real=True, positive=True)\n", |
| 334 | + "_ = log_simp(z*(sympy.log(x/y)-sympy.log(z/y)))\n", |
| 335 | + "assert _ == z*sympy.log(x/z)\n", |
| 336 | + "assert _.is_Mul\n", |
| 337 | + " \n", |
| 338 | + "from operator import mul, add\n", |
| 339 | + "from functools import reduce\n", |
279 | 340 | "autosymbols = defaultkeydict(mk_Symbol)\n",
|
280 | 341 | "rnames = {}\n",
|
| 342 | + "lbl = {\n", |
| 343 | + " 'ligand-protein dissociation': r'\\ref{eq:e_NL}, \\mathrm{fwd}',\n", |
| 344 | + " 'ligand-protein association': r'\\ref{eq:e_NL}, \\mathrm{rev}',\n", |
| 345 | + " 'protein unfolding': r'\\ref{eq:e_N__U}, \\mathrm{fwd}',\n", |
| 346 | + " 'protein folding' : r'\\ref{eq:e_N__U}, \\mathrm{rev}',\n", |
| 347 | + " 'protein aggregation': r'\\ref{eq:r_U}'\n", |
| 348 | + "}\n", |
| 349 | + "lstrs = []\n", |
281 | 350 | "for rxn in rsys.rxns:\n",
|
282 | 351 | " rnames[rxn.name] = rxn.name.replace(' ', '~').replace('-','-')\n",
|
283 |
| - " rate_expr_str = sympy.latex(rxn.rate_expr()(autosymbols, backend=sympy, reaction=rxn))\n", |
284 |
| - " lstr = r'$r(\\mathrm{%s}) = %s$' % (rnames[rxn.name], rate_expr_str)\n", |
285 |
| - " display(Latex(lstr))" |
| 352 | + " e1 = rxn.rate_expr()(autosymbols, backend=sympy, reaction=rxn)\n", |
| 353 | + " if 'Se_u' in _created:\n", |
| 354 | + " Tm = autosymbols['Tmelt']\n", |
| 355 | + " dCp = autosymbols['Cp_u']\n", |
| 356 | + " T0 = autosymbols['Tref_u']\n", |
| 357 | + " _Se_u = autosymbols['He_u']/Tm + (Tm-T0)*dCp/Tm - dCp*sympy.log(Tm/T0)\n", |
| 358 | + " e1=e1.subs(_created['Se_u'], _Se_u)\n", |
| 359 | + " e2 = sympy.powsimp(e1.expand())\n", |
| 360 | + " e3 = e2.replace(sympy.exp, lambda arg: sympy.exp(smart_factor(arg)).expand(deep=False))\n", |
| 361 | + " other = [[],[]]\n", |
| 362 | + " exps = defaultdict(list)\n", |
| 363 | + " for i, numden in enumerate(e3.as_numer_denom()):\n", |
| 364 | + " for fact in numden.as_ordered_factors():\n", |
| 365 | + " if fact.func is sympy.exp:\n", |
| 366 | + " arg, = fact.args\n", |
| 367 | + " exnum, exdenom = arg.as_numer_denom()\n", |
| 368 | + " exps[exdenom].append((-1)**i * exnum)\n", |
| 369 | + " else:\n", |
| 370 | + " other[i].append(fact)\n", |
| 371 | + " #print(f\"{denom=}\")\n", |
| 372 | + " #print(f\"{other=}\")\n", |
| 373 | + " #print(f\"{exps=}\")\n", |
| 374 | + " e4 = reduce(mul, other[0]+[sympy.exp(sum(v)/k) for k, v in exps.items()])/reduce(mul, other[1])\n", |
| 375 | + " e5 = e4.replace(lambda arg: arg.func is sympy.exp, lambda arg: sympy.exp(smart_factor(arg.args[0].as_numer_denom()[0])/arg.args[0].as_numer_denom()[1]))\n", |
| 376 | + " kB_T__h = autosymbols['k_B']*autosymbols['T']/autosymbols['h']\n", |
| 377 | + " e6 = log_simp(e5/kB_T__h)\n", |
| 378 | + " assert (e6*kB_T__h - e1).expand().factor().simplify() == 0\n", |
| 379 | + " display(Latex(r'$r(\\mathrm{%s}) = %s$' % (rnames[rxn.name], sympy.latex(e6*sympy.UnevaluatedExpr(kB_T__h)))))\n", |
| 380 | + " lstrs.append(r\"r_{%s} &= %s\" % (lbl[rxn.name], sympy.latex(e6).replace(r'\\neq', r'\\ddag').replace(\n", |
| 381 | + " '] e^{', r'] \\frac{k_{\\rm B} T}{%s} e^{' % {2: r'h c^\\circ', 1: 'h'}[len(rxn.reac)])))\n", |
| 382 | + "with open('protein_binding_unfolding_4state_model.txt', 'wt') as ofh:\n", |
| 383 | + " ofh.write('\\\\\\\\\\n'.join(lstrs))" |
286 | 384 | ]
|
287 | 385 | },
|
288 | 386 | {
|
|
291 | 389 | "metadata": {},
|
292 | 390 | "outputs": [],
|
293 | 391 | "source": [
|
294 |
| - "ratexs = [autosymbols['r(\\mathrm{%s})' % rnames[rxn.name]] for rxn in rsys.rxns]\n", |
| 392 | + "!cat protein_binding_unfolding_4state_model.txt" |
| 393 | + ] |
| 394 | + }, |
| 395 | + { |
| 396 | + "cell_type": "code", |
| 397 | + "execution_count": null, |
| 398 | + "metadata": {}, |
| 399 | + "outputs": [], |
| 400 | + "source": [ |
| 401 | + "ratexs = [autosymbols[r'r(\\mathrm{%s})' % rnames[rxn.name]] for rxn in rsys.rxns]\n", |
295 | 402 | "rates = rsys.rates(autosymbols, backend=sympy, ratexs=ratexs)\n",
|
296 | 403 | "for k, v in rates.items():\n",
|
297 | 404 | " display(Latex(r'$\\frac{[%s]}{dt} = %s$' % (k, sympy.latex(v))))"
|
|
824 | 931 | "outputs": [],
|
825 | 932 | "source": [
|
826 | 933 | "native_tLN = NativeCvodeSys.from_other(tsysLN)\n",
|
827 |
| - "_, _, info_tLN = integrate_and_plot(native_tLN, first_step=1e-9, nsteps=18000, atol=1e-9, rtol=1e-9)\n", |
| 934 | + "_, _, info_tLN = integrate_and_plot(native_tLN, first_step=1e-9, nsteps=18000, atol=1e-9, rtol=1e-11)\n", |
828 | 935 | "{k: info_tLN[k] for k in ('nfev', 'njev', 'n_steps')}"
|
829 | 936 | ]
|
830 | 937 | },
|
|
834 | 941 | "metadata": {},
|
835 | 942 | "outputs": [],
|
836 | 943 | "source": [
|
837 |
| - "_, _, info_tLN = integrate_and_plot(tsysLN, first_step=1e-9, nsteps=18000, atol=1e-8, rtol=1e-8)\n", |
| 944 | + "_, _, info_tLN = integrate_and_plot(tsysLN, first_step=1e-9, nsteps=18000, atol=1e-9, rtol=1e-11)\n", |
838 | 945 | "{k: info_tLN[k] for k in ('nfev', 'njev', 'n_steps')}"
|
839 | 946 | ]
|
840 | 947 | },
|
|
861 | 968 | "metadata": {},
|
862 | 969 | "outputs": [],
|
863 | 970 | "source": [
|
864 |
| - "print(open(next(filter(lambda s: s.endswith('.cpp'), native2._native._written_files))).read())" |
| 971 | + "cpp_file = next(filter(lambda s: s.endswith('.cpp'), native2._native._written_files))\n", |
| 972 | + "print(open(cpp_file).read())" |
| 973 | + ] |
| 974 | + }, |
| 975 | + { |
| 976 | + "cell_type": "code", |
| 977 | + "execution_count": null, |
| 978 | + "metadata": {}, |
| 979 | + "outputs": [], |
| 980 | + "source": [ |
| 981 | + "!clang-format <$cpp_file" |
865 | 982 | ]
|
| 983 | + }, |
| 984 | + { |
| 985 | + "cell_type": "code", |
| 986 | + "execution_count": null, |
| 987 | + "metadata": {}, |
| 988 | + "outputs": [], |
| 989 | + "source": [] |
866 | 990 | }
|
867 | 991 | ],
|
868 | 992 | "metadata": {
|
|
885 | 1009 | "name": "python",
|
886 | 1010 | "nbconvert_exporter": "python",
|
887 | 1011 | "pygments_lexer": "ipython3",
|
888 |
| - "version": "3.8.10" |
| 1012 | + "version": "3.12.8" |
889 | 1013 | }
|
890 | 1014 | },
|
891 | 1015 | "nbformat": 4,
|
|
0 commit comments