# from pysb import Model, Monomer, Parameter, Expression, Compartment, Rule, Observable, Initial, MatchOnce, Annotation, Tag, ANY, WILD
#
# Model()
#
# Monomer('Delta')
# Monomer('NICD', ['rbpj', 'loc'], {'loc': ['cyt', 'nuc']})
# Monomer('dHes1', ['Hbox', 'Hbox', 'Hbox', 'Rbox', 'Rbox'])
# Monomer('dNotch', ['Hbox', 'Rbox', 'Rbox'])
# Monomer('dRBPJ', ['Hbox', 'Hbox', 'Hbox', 'Rbox', 'Rbox', 'Rbox'])
# Monomer('mHes1')
# Monomer('mHes1_delayed')
# Monomer('mNotch')
# Monomer('mNotch_delayed')
# Monomer('mRBPJ')
# Monomer('mRBPJ_delayed')
# Monomer('pHes1', ['pHes1', 'Hbox', 'loc'], {'loc': ['cyt', 'nuc']})
# Monomer('pHes1_delayed')
# Monomer('pNotch')
# Monomer('pNotch_delayed')
# Monomer('pRBPJ', ['nicd', 'Rbox', 'loc'], {'loc': ['cyt', 'nuc']})
# Monomer('pRBPJ_delayed')
#
# Parameter('Delta_0', 0.0)
# Parameter('mHes1_0', 1.0)
# Parameter('pHes1_cyt_0', 35.0)
# Parameter('pHes1_nuc_0', 109.0)
# Parameter('dimHes1_nuc_0', 101.0)
# Parameter('mRBPJ_0', 1.0)
# Parameter('pRBPJ_cyt_0', 11.0)
# Parameter('pRBPJ_nuc_0', 447.0)
# Parameter('mNotch_0', 70.0)
# Parameter('pNotch_0', 8130.0)
# Parameter('dNotch_0', 2.0)
# Parameter('dHes1_0', 2.0)
# Parameter('dRBPJ_0', 2.0)
# Parameter('KdNm', 0.00035)
# Parameter('KdNp', 0.017)
# Parameter('KdHcm', 0.029)
# Parameter('KdHes1', 0.0315)
# Parameter('KdH2np', 0.0)
# Parameter('KdRcm', 0.0075)
# Parameter('KdRBPJ', 0.00231)
# Parameter('KtrHc', 4.5)
# Parameter('KtrN', 2.0)
# Parameter('KtrRc', 3.2)
# Parameter('KniRcp', 0.1)
# Parameter('KniHcp', 0.1)
# Parameter('KniNcp', 0.1)
# Parameter('KfNcp', 0.000276)
# Parameter('KaHp', 0.0507)
# Parameter('KrHp', 1.0)
# Parameter('Kr', 0.041)
# Parameter('Kr_r', 5.0)
# Parameter('Kn', 0.0254)
# Parameter('Kn_r', 5.0)
# Parameter('Ka', 0.0127)
# Parameter('Ka_r', 5.0)
# Parameter('Vmaxh', 197.0)
# Parameter('Vmaxr', 79.0)
# Parameter('Vmaxn', 21.6)
# Parameter('Vbh', 4.5)
# Parameter('Vbr', 1.7)
# Parameter('Vbn', 0.5)
# Parameter('rNbox', 0.3)
# Parameter('rRbox', 0.2)
# Parameter('tc', 0.5)
# Parameter('TpNc', 21.0)
# Parameter('TpRc', 4.3)
# Parameter('TpHc', 2.35)
# Parameter('TmNc', 70.0)
# Parameter('TmRc', 20.0)
# Parameter('TmHc', 10.0)
#
# Expression('_rateLaw4', TpNc**(-1))
# Expression('_rateLaw5', TpHc**(-1))
# Expression('_rateLaw6', TpRc**(-1))
# Expression('_rateLaw7', TmNc**(-1))
# Expression('_rateLaw8', TmHc**(-1))
# Expression('_rateLaw9', TmRc**(-1))
#
# Observable('pHes1_cyt', pHes1(loc='cyt'))
# Observable('dNotch_pHes1', dNotch(Hbox=ANY))
# Observable('dNotch_pRBPJ', dNotch(Rbox=1) % pRBPJ(nicd=None, Rbox=1))
# Observable('dNotch_pNICD', dNotch(Rbox=1) % pRBPJ(nicd=ANY, Rbox=1))
# Observable('dHes1_pHes1', dHes1(Hbox=ANY))
# Observable('dHes1_pRBPJ', dHes1(Rbox=1) % pRBPJ(nicd=None, Rbox=1))
# Observable('dHes1_pNICD', dHes1(Rbox=1) % pRBPJ(nicd=ANY, Rbox=1))
# Observable('dRBPJ_pHes1', dRBPJ(Hbox=ANY))
# Observable('dRBPJ_pRBPJ', dRBPJ(Rbox=1) % pRBPJ(nicd=None, Rbox=1))
# Observable('dRBPJ_pNICD', dRBPJ(Rbox=1) % pRBPJ(nicd=ANY, Rbox=1))
# Observable('DeltaObs', Delta())
# Observable('Rcm', mRBPJ())
# Observable('Hcm', mHes1())
# Observable('Nm', mNotch())
# Observable('Rcp', pRBPJ(nicd=None, Rbox=None, loc='cyt'))
# Observable('Hcp', pHes1(pHes1=None, Hbox=None, loc='cyt'))
# Observable('Np', pNotch())
# Observable('Hnp', pHes1(pHes1=None, Hbox=None, loc='nuc'))
#
# Tag('x')
#
# Expression('KdNICD', 0.00385 - 0.00245*(pHes1_cyt > 100))
# Expression('ktrN', rNbox**dNotch_pHes1(x)*0.2**dNotch_pRBPJ(x)*(0.5 + 21.6*(dNotch_pNICD(x) > 0)*0.5**(2 - dNotch_pNICD(x))))
# Expression('ktrH', 0.3**dHes1_pHes1(x)*0.2**dHes1_pRBPJ(x)*(4.5 + 197.0*(dHes1_pNICD(x) > 0)*0.5**(2 - dHes1_pNICD(x))))
# Expression('ktrR', 0.3**dRBPJ_pHes1(x)*0.2**dRBPJ_pRBPJ(x)*(1.7 + 79.0*(dRBPJ_pNICD(x) > 0)*0.5**(3 - dRBPJ_pNICD(x))))
# Expression('_rateLaw1', ktrN(x))
# Expression('_rateLaw2', ktrH(x))
# Expression('_rateLaw3', ktrR(x))
#
# Rule('mNotch_transcription', dNotch() @ x >> dNotch() @ x + mNotch_delayed(), _rateLaw1)
# Rule('mHes1_transcription', dHes1() @ x >> dHes1() @ x + mHes1_delayed(), _rateLaw2)
# Rule('mRBPJ_transcription', dRBPJ() @ x >> dRBPJ() @ x + mRBPJ_delayed(), _rateLaw3)
# Rule('mNotch_appears', mNotch_delayed() >> mNotch(), _rateLaw4)
# Rule('mHes1_appears', mHes1_delayed() >> mHes1(), _rateLaw5)
# Rule('mRBPJ_appears', mRBPJ_delayed() >> mRBPJ(), _rateLaw6)
# Rule('Hes1_dimerization', pHes1(pHes1=None, Hbox=None, loc='nuc') + pHes1(pHes1=None, Hbox=None, loc='nuc') | pHes1(pHes1=1, Hbox=None, loc='nuc') % pHes1(pHes1=1, Hbox=None, loc='nuc'), KaHp, KrHp)
# Rule('mNotch_translation', mNotch() >> mNotch() + pNotch_delayed(), KtrN)
# Rule('mHes1_translation', mHes1() >> mHes1() + pHes1_delayed(), KtrHc)
# Rule('mRBPJ_translation', mRBPJ() >> mRBPJ() + pRBPJ_delayed(), KtrRc)
# Rule('pNotch_appears', pNotch_delayed() >> pNotch(), _rateLaw7)
# Rule('pHes1_appears', pHes1_delayed() >> pHes1(pHes1=None, Hbox=None, loc='cyt'), _rateLaw8)
# Rule('pRBPJ_appears', pRBPJ_delayed() >> pRBPJ(nicd=None, Rbox=None, loc='cyt'), _rateLaw9)
# Rule('Delta_Notch_to_NICD', Delta() + pNotch() >> NICD(rbpj=None, loc='cyt'), KfNcp)
# Rule('mNotch_degradation', mNotch() >> None, KdNm)
# Rule('pNotch_degradation', pNotch() >> None, KdNp)
# Rule('mHes1_degradation', mHes1() >> None, KdHcm)
# Rule('pHes1_monomer_degradation', pHes1(pHes1=None, Hbox=None) >> None, KdHes1)
# Rule('pHes1_dimer_degradation', pHes1(pHes1=ANY, Hbox=None, loc='nuc') >> None, KdH2np)
# Rule('NICD_degradation', NICD(rbpj=None) >> None, KdNICD)
# Rule('mRBPJ_degradation', mRBPJ() >> None, KdRcm)
# Rule('pRBPJ_degradation', pRBPJ(nicd=None, Rbox=None) >> None, KdRBPJ)
# Rule('NICD_nuclear_transport', NICD(rbpj=None, loc='cyt') >> NICD(rbpj=None, loc='nuc'), KniNcp)
# Rule('RBPJ_nuclear_transport', pRBPJ(nicd=None, Rbox=None, loc='cyt') >> pRBPJ(nicd=None, Rbox=None, loc='nuc'), KniRcp)
# Rule('Hes1_nuclear_transport', pHes1(pHes1=None, Hbox=None, loc='cyt') >> pHes1(pHes1=None, Hbox=None, loc='nuc'), KniHcp)
# Rule('dNotch_bind_Rbox', dNotch(Rbox=None) + pRBPJ(nicd=None, Rbox=None, loc='nuc') | dNotch(Rbox=1) % pRBPJ(nicd=None, Rbox=1, loc='nuc'), Kr, Kr_r)
# Rule('dNotch_bind_Hes1_dimer', dNotch(Hbox=None) + pHes1(pHes1=1, Hbox=None, loc='nuc') % pHes1(pHes1=1, Hbox=None, loc='nuc') | dNotch(Hbox=[1, 2]) % pHes1(pHes1=3, Hbox=1, loc='nuc') % pHes1(pHes1=3, Hbox=2, loc='nuc'), Kn, Kn_r)
# Rule('dNotch_pRBPJ_bind_NICD', dNotch(Rbox=1) % pRBPJ(nicd=None, Rbox=1, loc='nuc') + NICD(rbpj=None, loc='nuc') | dNotch(Rbox=1) % pRBPJ(nicd=2, Rbox=1, loc='nuc') % NICD(rbpj=2, loc='nuc'), Ka, Ka_r)
# Rule('dHes1_bind_Rbox', dHes1(Rbox=None) + pRBPJ(nicd=None, Rbox=None, loc='nuc') | dHes1(Rbox=1) % pRBPJ(nicd=None, Rbox=1, loc='nuc'), Kr, Kr_r)
# Rule('dHes1_bind_Hes1_dimer', dHes1(Hbox=None) + pHes1(pHes1=1, Hbox=None, loc='nuc') % pHes1(pHes1=1, Hbox=None, loc='nuc') | dHes1(Hbox=[1, 2]) % pHes1(pHes1=3, Hbox=1, loc='nuc') % pHes1(pHes1=3, Hbox=2, loc='nuc'), Kn, Kn_r)
# Rule('dHes1_pRBPJ_bind_NICD', dHes1(Rbox=1) % pRBPJ(nicd=None, Rbox=1, loc='nuc') + NICD(rbpj=None, loc='nuc') | dHes1(Rbox=1) % pRBPJ(nicd=2, Rbox=1, loc='nuc') % NICD(rbpj=2, loc='nuc'), Ka, Ka_r)
# Rule('dRBPJ_bind_Rbox', dRBPJ(Rbox=None) + pRBPJ(nicd=None, Rbox=None, loc='nuc') | dRBPJ(Rbox=1) % pRBPJ(nicd=None, Rbox=1, loc='nuc'), Kr, Kr_r)
# Rule('dRBPJ_bind_Hes1_dimer', dRBPJ(Hbox=None) + pHes1(pHes1=1, Hbox=None, loc='nuc') % pHes1(pHes1=1, Hbox=None, loc='nuc') | dRBPJ(Hbox=[1, 2]) % pHes1(pHes1=3, Hbox=1, loc='nuc') % pHes1(pHes1=3, Hbox=2, loc='nuc'), Kn, Kn_r)
# Rule('dRBPJ_pRBPJ_bind_NICD', dRBPJ(Rbox=1) % pRBPJ(nicd=None, Rbox=1, loc='nuc') + NICD(rbpj=None, loc='nuc') | dRBPJ(Rbox=1) % pRBPJ(nicd=2, Rbox=1, loc='nuc') % NICD(rbpj=2, loc='nuc'), Ka, Ka_r)
#
# Initial(Delta(), Delta_0)
# Initial(mHes1(), mHes1_0)
# Initial(pHes1(pHes1=None, Hbox=None, loc='cyt'), pHes1_cyt_0)
# Initial(pHes1(pHes1=None, Hbox=None, loc='nuc'), pHes1_nuc_0)
# Initial(pHes1(pHes1=1, Hbox=None, loc='nuc') % pHes1(pHes1=1, Hbox=None, loc='nuc'), dimHes1_nuc_0)
# Initial(mRBPJ(), mRBPJ_0)
# Initial(pRBPJ(nicd=None, Rbox=None, loc='cyt'), pRBPJ_cyt_0)
# Initial(pRBPJ(nicd=None, Rbox=None, loc='nuc'), pRBPJ_nuc_0)
# Initial(mNotch(), mNotch_0)
# Initial(pNotch(), pNotch_0)
# Initial(dNotch(Hbox=None, Rbox=(None, None)), dNotch_0)
# Initial(dHes1(Hbox=(None, None, None), Rbox=(None, None)), dHes1_0)
# Initial(dRBPJ(Hbox=(None, None, None), Rbox=(None, None, None)), dRBPJ_0)
#
# # from pysb.bng import generate_equations
# # generate_equations(model)
# # from pysb.simulator import ScipyOdeSimulator
# # ScipyOdeSimulator(model, tspan=range(100)).run()
#
# # Leonard simulation protocol
# import numpy as np
# import matplotlib.pyplot as plt
# from pysb.simulator import ScipyOdeSimulator, BngSimulator
# sim = ScipyOdeSimulator(model, verbose=False, atol=1e-8, rtol=1e-8)
# sim_bng = BngSimulator(model, verbose=False)
#
# tspan1 = np.linspace(0, 10000, 10001)
# x = sim.run(tspan=tspan1)
# x_bng = sim_bng.run(tspan=tspan1, method='ode')
#
# # for obs in ['DeltaObs', 'Rcm', 'Hcm', 'Nm', 'Rcp', 'Hcp', 'Np', 'Hnp']:
# #     plt.figure(obs)
# #     plt.plot(tspan1, x_bng.observables[obs], lw=2, label=obs)
# #     plt.legend()
#
# import pandas as pd
# # print(x.dataframe['Rcm'])
# for obs in ['DeltaObs', 'Rcm', 'Hcm', 'Nm', 'Rcp', 'Hcp', 'Np', 'Hnp']:
#     print(np.allclose(x.dataframe[obs], x_bng.dataframe[obs], rtol=1e-2, atol=1e-2))
#
# t_end = 10000
# tspan2 = np.linspace(750, t_end, (t_end - 750) + 1)
# initials = x.species[-1]
# initials[0] = 10000
# x = sim.run(tspan=tspan2, initials=initials)
#
# # initials_bng = x_bng.species[-1]
# # initials_bng[0] = 10000
# # print(len(model.species))
# # print(model.species[16])
# x_bng = sim_bng.run(tspan=tspan2, initials=initials, method='ode')
#
# for obs in ['DeltaObs', 'Rcm', 'Hcm', 'Nm', 'Rcp', 'Hcp', 'Np', 'Hnp']:
#     print(np.allclose(x.dataframe[obs], x_bng.dataframe[obs], rtol=1e-2, atol=1e-2))
#
#
# # print(pd.DataFrame({'initials':initials, 'sp':x.species[0], 'bng':x_bng.species[0]}))
# #
# # print(len(tspan2))
# print(pd.DataFrame({'sp': x.dataframe['Rcm'], 'bng': x_bng.dataframe['Rcm']}).to_string())
# # print(x_bng.tout)
#
# # for obs in ['DeltaObs', 'Rcm', 'Hcm', 'Nm', 'Rcp', 'Hcp', 'Np', 'Hnp']:
# #     plt.figure(obs)
# #     plt.plot(x_bng.tout[0], x_bng.observables[obs], lw=2)
# #
# # plt.show()
