def setUp(self):
        m = {
            'state': [{'id':'S'}, {'id':'I', 'tag': ['remainder', 'infectious']}, {'id': 'R'}],
            'parameter': [{'id':'r0'}, {'id':'v'}, {'id':'l'}, {'id':'e'}, {'id':'d'}, {'id':'sto'}, {'id':'alpha'}, {'id':'mu_b'}, {'id':'mu_d'}, {'id':'vol'}, {'id':'g'}],
            'model': [ 
                {'from': 'U', 'to': 'S',  'rate': 'mu_b*N'},
                {'from': 'S', 'to': 'E',  'rate': 'r0/N*v*(1.0+e*sin_t(d))*I', 'tag': 'transmission'},
                
                {'from': 'E', 'to': 'I', 'rate': '(1-alpha)*correct_rate(l)'},
                ##Here we split the reaction from E->U as we only observe a subpart
                {'from': 'E', 'to': 'U',  'rate': 'alpha*correct_rate(l)'},
                {'from': 'E', 'to': 'U',  'rate': 'mu_d'},
                
                {'from': 'S', 'to': 'U',  'rate': 'mu_d'},
                {'from': 'R', 'to': 'S',  'rate': 'g'},
                {'from': 'I', 'to': 'R', 'rate': '(1-alpha)*correct_rate(v)'},
                {'from': 'I', 'to': 'U',  'rate': 'alpha*correct_rate(v) + mu_d'}
            ],
            'diffusion': [{'parameter':'r0', 'volatility': 'vol', 'drift': 0.0}],
            'white_noise': [{'reaction': [{'from':'S', 'to': 'E'}], 'sd': 'sto'}]
        }
        
        ##context elements needed for Cmodel
        c = {
            'data': {},
            'metadata': [{'id': 'mu_b'}, {'id': 'mu_d'}, {'id': 'N'}, {'id': 'prop'}]
        }

        ##link elements needed for Cmodel
        l = {
            'observed': [
                {'id': 'Prev', 'definition': ['I'], 'model_id': 'common'},
                {'id': 'SI', 'definition': ['S', 'I'], 'model_id': 'common'},
                ##we have to specify a rate to the incidence E->U as we only observed a subpart of this reaction
                {'id': 'Inc_out', 'definition': [{'from':'I', 'to':'R'}, {'from':'E', 'to':'U', 'rate': 'mu_d'}], 'model_id': 'common'},
                {'id': 'Inc_in', 'definition': [{'from':'S', 'to':'E'}], 'model_id': 'common'},
                {'id': 'Inc_weird', 'definition': [{'from':'R', 'to':'S'}], 'model_id': 'common'}
            ],
            'observation': [{'id': 'common', 
                             'parameter': [{'id': 'rep','comment': 'reporting rate'}, 
                                           {'id': 'phi',  'comment': 'over-dispertion'},
                                           {"id": "prop",  "comment": "proportion of the population under surveillance"}],
                             'model': {'distribution': 'discretized_normal',
                                       'mean': 'rep*prop*x',
                                       'var': 'rep*(1.0-rep)*prop*x + (rep*phi*prop*x)**2'}}]
        }


        #other model with different remainder
        m2 = copy.deepcopy(m)
        m2['state'] = [{'id':'S'}, {'id':'I', 'tag': 'infectious'}, {'id': 'R', 'tag': 'remainder'}]

        #no remainder
        m3 = copy.deepcopy(m)
        m3['state'] = [{'id':'S'}, {'id':'I', 'tag': 'infectious'}, {'id': 'R'}]

        self.m = Cmodel(c, m, l) 
        self.m2 = Cmodel(c, m2, l) 
        self.m3 = Cmodel(c, m3, l) 
Ejemplo n.º 2
0
 def setUp(self):
     dpkgRoot = os.path.join('..', 'examples', 'foo')
     dpkg = json.load(open(os.path.join(dpkgRoot, 'ssm.json')))
     self.m = Cmodel(dpkgRoot, dpkg)
Ejemplo n.º 3
0
class TestCmodel(unittest.TestCase):
    def setUp(self):
        dpkgRoot = os.path.join('..', 'examples', 'foo')
        dpkg = json.load(open(os.path.join(dpkgRoot, 'ssm.json')))
        self.m = Cmodel(dpkgRoot, dpkg)

    def test_change_user_input(self):
        x = self.m.change_user_input('r0*2*correct_rate(v)')
        self.assertEqual(x,
                         ['r0', '*', '2', '*', 'correct_rate', '(', 'v', ')'])

    def test_par_sv(self):
        self.assertEqual(self.m.par_sv,
                         ['I_nyc', 'I_paris', 'S_nyc', 'S_paris'])

    def test_remainder(self):
        self.assertEqual(self.m.remainder, ['R_nyc', 'R_paris'])

    def test_par_proc(self):
        self.assertEqual(self.m.par_proc, ['r0_nyc', 'r0_paris', 'v'])

    def test_par_disp(self):
        self.assertEqual(self.m.par_disp, ['vol'])

    def test_par_obs(self):
        self.assertEqual(self.m.par_obs, [
            'phi', 'rep_all_CDC_inc', 'rep_all_google_inc', 'rep_nyc_CDC_inc',
            'rep_paris_CDC_prev'
        ])

    def test_par_forced(self):
        self.assertEqual(self.m.par_forced, [
            'N_nyc', 'N_paris', 'mu_b_nyc', 'mu_b_paris', 'mu_d_nyc',
            'mu_d_paris', 'prop_all_CDC_inc', 'prop_all_google_inc',
            'prop_nyc_CDC_inc', 'prop_paris_CDC_prev'
        ])

    def test_par_diff(self):
        self.assertEqual(self.m.par_diff, ['diff__r0_nyc', 'diff__r0_paris'])

    def test_par_inc(self):
        self.assertEqual(self.m.par_inc, ['Inc_in_nyc', 'Inc_out'])

    def test_par_noise(self):
        self.assertEqual(self.m.par_noise, ['sto'])

    def test_par_other(self):
        self.assertEqual(self.m.par_other, [])

    def test_pow2star(self):
        self.assertEqual(self.m.pow2star('pow(x, 2)'), '(x)**(2)')
        self.assertEqual(self.m.pow2star('pow(pow(x,2), pow(2, 3))'),
                         '((x)**(2))**((2)**(3))')
        self.assertEqual(
            self.m.pow2star('a+ sin((x))+pow(pow(x,2), pow(2, 3))+cos(x)'),
            'a+sin((x))+((x)**(2))**((2)**(3))+cos(x)')

    def test_make_C_term(self):
        terms = [
            {
                'x':
                'mu_b_paris*(1.0+v*sin((v/N_paris+(mu_b_paris)))) + r0_paris',  #input
                'h':
                'mu_b_paris*(v*sin(mu_b_paris+v/N_paris)+1.0)+r0_paris',  #expected human output
                'c':
                'gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])*(gsl_vector_get(par,ORDER_v)*sin(gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])+gsl_vector_get(par,ORDER_v)/gsl_spline_eval(calc->spline[ORDER_N_paris],t,calc->acc[ORDER_N_paris]))+1.0)+diffed[ORDER_diff__r0_paris]'
            },  #expected C output
            {
                'x':
                'N_paris-S_paris-I_paris+S_paris+I_paris',
                'h':
                'N_paris',
                'c':
                'gsl_spline_eval(calc->spline[ORDER_N_paris],t,calc->acc[ORDER_N_paris])'
            },
            {
                'x':
                'rep_all_CDC_inc*(1.0-rep_all_CDC_inc)*prop_all_CDC_inc*x + (rep_all_CDC_inc*phi*prop_all_CDC_inc*x)**2',
                'h':
                'pow(phi,2)*pow(prop_all_CDC_inc,2)*pow(rep_all_CDC_inc,2)*pow(x,2)+prop_all_CDC_inc*rep_all_CDC_inc*x*(-rep_all_CDC_inc+1.0)',
                'c':
                'pow(gsl_vector_get(par,ORDER_phi),2)*pow(gsl_spline_eval(calc->spline[ORDER_prop_all_CDC_inc],t,calc->acc[ORDER_prop_all_CDC_inc]),2)*pow(gsl_vector_get(par,ORDER_rep_all_CDC_inc),2)*pow(x,2)+gsl_spline_eval(calc->spline[ORDER_prop_all_CDC_inc],t,calc->acc[ORDER_prop_all_CDC_inc])*gsl_vector_get(par,ORDER_rep_all_CDC_inc)*x*(-gsl_vector_get(par,ORDER_rep_all_CDC_inc)+1.0)'
            },
        ]

        for t in terms:
            self.assertEqual(self.m.make_C_term(t['x'], False, human=True),
                             t['h'])
            self.assertEqual(self.m.make_C_term(t['x'], False, human=False),
                             t['c'])

    def test_make_C_term_nested(self):
        self.assertEqual(
            self.m.make_C_term('correct_rate(correct_rate(x))',
                               False,
                               human=False),
            'ssm_correct_rate(ssm_correct_rate(x,dt),dt)')
        self.assertEqual(
            self.m.make_C_term('pow(correct_rate(correct_rate(x)),2)',
                               False,
                               human=False),
            'pow(ssm_correct_rate(ssm_correct_rate(x,dt),dt),2)')
        self.assertEqual(
            self.m.make_C_term('(correct_rate(correct_rate(x)))**(2)',
                               False,
                               human=False),
            'pow(ssm_correct_rate(ssm_correct_rate(x,dt),dt),2)')
        self.assertEqual(
            self.m.make_C_term(
                'correct_rate(x) + correct_rate(correct_rate(x))',
                False,
                human=False),
            'ssm_correct_rate(x,dt)+ssm_correct_rate(ssm_correct_rate(x,dt),dt)'
        )
        self.assertEqual(
            self.m.make_C_term(
                'correct_rate(correct_rate(x))+ sin(v*x+(3*sin(r0_paris)))',
                False,
                human=False),
            'ssm_correct_rate(ssm_correct_rate(x,dt),dt)+sin(gsl_vector_get(par,ORDER_v)*x+3*sin(diffed[ORDER_diff__r0_paris]))'
        )

    def test_make_C_term_derivate(self):
        x = 'sin(2*PI*(t +r0_paris))'
        h = '2*PI*cos(2*PI*(r0_paris+t))'
        c = '2*PI*cos(2*PI*(diffed[ORDER_diff__r0_paris]+t))'

        self.assertEqual(
            self.m.make_C_term(x, False, human=True, derivate='r0_paris'), h)
        self.assertEqual(
            self.m.make_C_term(x, False, human=False, derivate='r0_paris'), c)

    def test_make_C_term_skip_correct_rate(self):
        #correct_rate is only skipped for C code

        x = 'mu_b_paris*(1.0+correct_rate(v)*sin((correct_rate(v)/N_paris+(mu_b_paris)))) + r0_paris'
        c = 'gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])*((gsl_vector_get(par,ORDER_v))*sin(gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])+(gsl_vector_get(par,ORDER_v))/gsl_spline_eval(calc->spline[ORDER_N_paris],t,calc->acc[ORDER_N_paris]))+1.0)+diffed[ORDER_diff__r0_paris]'

        self.assertEqual(self.m.make_C_term(x, True, human=False), c)

    def test_make_C_term_extra_terms(self):
        terms = [
            {
                'x': 'heaviside(t-v)',
                'c': 'heaviside(t-gsl_vector_get(par,ORDER_v))'
            },
            {
                'x': 'heaviside((t-v))',
                'c': 'heaviside(t-gsl_vector_get(par,ORDER_v))'
            },
            {
                'x': 'ramp(t-v)',
                'c': 'ramp(t-gsl_vector_get(par,ORDER_v))'
            },
            {
                'x': 'correct_rate(v)',
                'c': 'ssm_correct_rate(gsl_vector_get(par,ORDER_v),dt)'
            },
        ]

        for t in terms:
            self.assertEqual(self.m.make_C_term(t['x'], False, human=False),
                             t['c'])
Ejemplo n.º 4
0
 def __init__(self, dpkgRoot, dpkg,  **kwargs):
     Cmodel.__init__(self, dpkgRoot, dpkg,  **kwargs)
Ejemplo n.º 5
0
 def __init__(self, dpkgRoot, dpkg, **kwargs):
     Cmodel.__init__(self, dpkgRoot, dpkg, **kwargs)
Ejemplo n.º 6
0
    def __init__(self, context, process, link,  **kwargs):
        Cmodel.__init__(self, context, process, link,  **kwargs)

        self.set_par_fixed = set(self.par_fixed)
        self.all_par = self.par_sv + [self.remainder] + self.drift_par_proc + self.par_proc +  self.par_obs + ['x'] + ['N'] + ['t']
Ejemplo n.º 7
0
 def setUp(self):
     dpkgRoot = os.path.join("..", "examples", "foo")
     dpkg = json.load(open(os.path.join(dpkgRoot, "ssm.json")))
     self.m = Cmodel(dpkgRoot, dpkg)
Ejemplo n.º 8
0
class TestCmodel(unittest.TestCase):
    def setUp(self):
        dpkgRoot = os.path.join("..", "examples", "foo")
        dpkg = json.load(open(os.path.join(dpkgRoot, "ssm.json")))
        self.m = Cmodel(dpkgRoot, dpkg)

    def test_change_user_input(self):
        x = self.m.change_user_input("r0*2*correct_rate(v)")
        self.assertEqual(x, ["r0", "*", "2", "*", "correct_rate", "(", "v", ")"])

    def test_par_sv(self):
        self.assertEqual(self.m.par_sv, ["I_nyc", "I_paris", "S_nyc", "S_paris"])

    def test_remainder(self):
        self.assertEqual(self.m.remainder, ["R_nyc", "R_paris"])

    def test_par_proc(self):
        self.assertEqual(self.m.par_proc, ["r0_nyc", "r0_paris", "v"])

    def test_par_disp(self):
        self.assertEqual(self.m.par_disp, ["vol"])

    def test_par_obs(self):
        self.assertEqual(
            self.m.par_obs, ["phi", "rep_all_CDC_inc", "rep_all_google_inc", "rep_nyc_CDC_inc", "rep_paris_CDC_prev"]
        )

    def test_par_forced(self):
        self.assertEqual(
            self.m.par_forced,
            [
                "N_nyc",
                "N_paris",
                "mu_b_nyc",
                "mu_b_paris",
                "mu_d_nyc",
                "mu_d_paris",
                "prop_all_CDC_inc",
                "prop_all_google_inc",
                "prop_nyc_CDC_inc",
                "prop_paris_CDC_prev",
            ],
        )

    def test_par_diff(self):
        self.assertEqual(self.m.par_diff, ["diff__r0_nyc", "diff__r0_paris"])

    def test_par_inc(self):
        self.assertEqual(self.m.par_inc, ["Inc_in_nyc", "Inc_out"])

    def test_par_noise(self):
        self.assertEqual(self.m.par_noise, ["sto"])

    def test_par_other(self):
        self.assertEqual(self.m.par_other, [])

    def test_pow2star(self):
        self.assertEqual(self.m.pow2star("pow(x, 2)"), "(x)**(2)")
        self.assertEqual(self.m.pow2star("pow(pow(x,2), pow(2, 3))"), "((x)**(2))**((2)**(3))")
        self.assertEqual(
            self.m.pow2star("a+ sin((x))+pow(pow(x,2), pow(2, 3))+cos(x)"), "a+sin((x))+((x)**(2))**((2)**(3))+cos(x)"
        )

    def test_make_C_term(self):
        terms = [
            {
                "x": "mu_b_paris*(1.0+v*sin((v/N_paris+(mu_b_paris)))) + r0_paris",  # input
                "h": "mu_b_paris*(v*sin(mu_b_paris+v/N_paris)+1.0)+r0_paris",  # expected human output
                "c": "gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])*(gsl_vector_get(par,ORDER_v)*sin(gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])+gsl_vector_get(par,ORDER_v)/gsl_spline_eval(calc->spline[ORDER_N_paris],t,calc->acc[ORDER_N_paris]))+1.0)+diffed[ORDER_diff__r0_paris]",
            },  # expected C output
            {
                "x": "N_paris-S_paris-I_paris+S_paris+I_paris",
                "h": "N_paris",
                "c": "gsl_spline_eval(calc->spline[ORDER_N_paris],t,calc->acc[ORDER_N_paris])",
            },
            {
                "x": "rep_all_CDC_inc*(1.0-rep_all_CDC_inc)*prop_all_CDC_inc*x + (rep_all_CDC_inc*phi*prop_all_CDC_inc*x)**2",
                "h": "pow(phi,2)*pow(prop_all_CDC_inc,2)*pow(rep_all_CDC_inc,2)*pow(x,2)+prop_all_CDC_inc*rep_all_CDC_inc*x*(-rep_all_CDC_inc+1.0)",
                "c": "pow(gsl_vector_get(par,ORDER_phi),2)*pow(gsl_spline_eval(calc->spline[ORDER_prop_all_CDC_inc],t,calc->acc[ORDER_prop_all_CDC_inc]),2)*pow(gsl_vector_get(par,ORDER_rep_all_CDC_inc),2)*pow(x,2)+gsl_spline_eval(calc->spline[ORDER_prop_all_CDC_inc],t,calc->acc[ORDER_prop_all_CDC_inc])*gsl_vector_get(par,ORDER_rep_all_CDC_inc)*x*(-gsl_vector_get(par,ORDER_rep_all_CDC_inc)+1.0)",
            },
        ]

        for t in terms:
            self.assertEqual(self.m.make_C_term(t["x"], False, human=True), t["h"])
            self.assertEqual(self.m.make_C_term(t["x"], False, human=False), t["c"])

    def test_make_C_term_nested(self):
        self.assertEqual(
            self.m.make_C_term("correct_rate(correct_rate(x))", False, human=False),
            "ssm_correct_rate(ssm_correct_rate(x,dt),dt)",
        )
        self.assertEqual(
            self.m.make_C_term("pow(correct_rate(correct_rate(x)),2)", False, human=False),
            "pow(ssm_correct_rate(ssm_correct_rate(x,dt),dt),2)",
        )
        self.assertEqual(
            self.m.make_C_term("(correct_rate(correct_rate(x)))**(2)", False, human=False),
            "pow(ssm_correct_rate(ssm_correct_rate(x,dt),dt),2)",
        )
        self.assertEqual(
            self.m.make_C_term("correct_rate(x) + correct_rate(correct_rate(x))", False, human=False),
            "ssm_correct_rate(x,dt)+ssm_correct_rate(ssm_correct_rate(x,dt),dt)",
        )
        self.assertEqual(
            self.m.make_C_term("correct_rate(correct_rate(x))+ sin(v*x+(3*sin(r0_paris)))", False, human=False),
            "ssm_correct_rate(ssm_correct_rate(x,dt),dt)+sin(gsl_vector_get(par,ORDER_v)*x+3*sin(diffed[ORDER_diff__r0_paris]))",
        )

    def test_make_C_term_derivate(self):
        x = "sin(2*PI*(t +r0_paris))"
        h = "2*PI*cos(2*PI*(r0_paris+t))"
        c = "2*PI*cos(2*PI*(diffed[ORDER_diff__r0_paris]+t))"

        self.assertEqual(self.m.make_C_term(x, False, human=True, derivate="r0_paris"), h)
        self.assertEqual(self.m.make_C_term(x, False, human=False, derivate="r0_paris"), c)

    def test_make_C_term_skip_correct_rate(self):
        # correct_rate is only skipped for C code

        x = "mu_b_paris*(1.0+correct_rate(v)*sin((correct_rate(v)/N_paris+(mu_b_paris)))) + r0_paris"
        c = "gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])*((gsl_vector_get(par,ORDER_v))*sin(gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])+(gsl_vector_get(par,ORDER_v))/gsl_spline_eval(calc->spline[ORDER_N_paris],t,calc->acc[ORDER_N_paris]))+1.0)+diffed[ORDER_diff__r0_paris]"

        self.assertEqual(self.m.make_C_term(x, True, human=False), c)

    def test_make_C_term_extra_terms(self):
        terms = [
            {"x": "heaviside(t-v)", "c": "heaviside(t-gsl_vector_get(par,ORDER_v))"},
            {"x": "heaviside((t-v))", "c": "heaviside(t-gsl_vector_get(par,ORDER_v))"},
            {"x": "ramp(t-v)", "c": "ramp(t-gsl_vector_get(par,ORDER_v))"},
            {"x": "correct_rate(v)", "c": "ssm_correct_rate(gsl_vector_get(par,ORDER_v),dt)"},
        ]

        for t in terms:
            self.assertEqual(self.m.make_C_term(t["x"], False, human=False), t["c"])
Ejemplo n.º 9
0
 def setUp(self):
     dpkgRoot = os.path.join('..' ,'examples', 'foo')
     dpkg = json.load(open(os.path.join(dpkgRoot, 'package.json')))
     self.m = Cmodel(dpkgRoot, dpkg)
Ejemplo n.º 10
0
class TestCmodel(unittest.TestCase):

    def setUp(self):
        dpkgRoot = os.path.join('..' ,'examples', 'foo')
        dpkg = json.load(open(os.path.join(dpkgRoot, 'package.json')))
        self.m = Cmodel(dpkgRoot, dpkg)

    def test_change_user_input(self):
        x = self.m.change_user_input('r0*2*correct_rate(v)')
        self.assertEqual(x, ['r0', '*', '2', '*', 'correct_rate', '(', 'v', ')'])

    def test_par_sv(self):
        self.assertEqual(self.m.par_sv, ['I_nyc', 'I_paris', 'S_nyc', 'S_paris'])

    def test_remainder(self):
        self.assertEqual(self.m.remainder, ['R_nyc', 'R_paris'])

    def test_par_proc(self):
        self.assertEqual(self.m.par_proc, ['r0_nyc', 'r0_paris', 'v'])

    def test_par_disp(self):
        self.assertEqual(self.m.par_disp, ['vol'])

    def test_par_obs(self):
        self.assertEqual(self.m.par_obs, ['phi', 'rep_all_CDC_inc', 'rep_all_google_inc', 'rep_nyc_CDC_inc', 'rep_paris_CDC_prev'])

    def test_par_forced(self):
        self.assertEqual(self.m.par_forced, ['N_nyc', 'N_paris', 'mu_b_nyc', 'mu_b_paris', 'mu_d_nyc', 'mu_d_paris', 'prop_all_CDC_inc', 'prop_all_google_inc', 'prop_nyc_CDC_inc', 'prop_paris_CDC_prev'])

    def test_par_diff(self):
        self.assertEqual(self.m.par_diff, ['diff__r0_nyc', 'diff__r0_paris'])

    def test_par_inc(self):
        self.assertEqual(self.m.par_inc, ['Inc_in_nyc', 'Inc_out'])

    def test_par_noise(self):
        self.assertEqual(self.m.par_noise, ['sto'])

    def test_par_other(self):
        self.assertEqual(self.m.par_other, [])

    def test_pow2star(self):
        self.assertEqual(self.m.pow2star('pow(x, 2)'), '(x)**(2)')
        self.assertEqual(self.m.pow2star('pow(pow(x,2), pow(2, 3))'), '((x)**(2))**((2)**(3))')
        self.assertEqual(self.m.pow2star('a+ sin((x))+pow(pow(x,2), pow(2, 3))+cos(x)'), 'a+sin((x))+((x)**(2))**((2)**(3))+cos(x)')

    def test_make_C_term(self):
        terms = [
            {'x': 'mu_b_paris*(1.0+v*sin((v/N_paris+(mu_b_paris)))) + r0_paris', #input
             'h': 'mu_b_paris*(v*sin(mu_b_paris+v/N_paris)+1.0)+r0_paris', #expected human output
             'c': 'gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])*(gsl_vector_get(par,ORDER_v)*sin(gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])+gsl_vector_get(par,ORDER_v)/gsl_spline_eval(calc->spline[ORDER_N_paris],t,calc->acc[ORDER_N_paris]))+1.0)+diffed[ORDER_diff__r0_paris]'}, #expected C output

            {'x': 'N_paris-S_paris-I_paris+S_paris+I_paris',
             'h': 'N_paris',
             'c': 'gsl_spline_eval(calc->spline[ORDER_N_paris],t,calc->acc[ORDER_N_paris])'},

            {'x': 'rep_all_CDC_inc*(1.0-rep_all_CDC_inc)*prop_all_CDC_inc*x + (rep_all_CDC_inc*phi*prop_all_CDC_inc*x)**2',
             'h': 'pow(phi,2)*pow(prop_all_CDC_inc,2)*pow(rep_all_CDC_inc,2)*pow(x,2)+prop_all_CDC_inc*rep_all_CDC_inc*x*(-rep_all_CDC_inc+1.0)',
             'c': 'pow(gsl_vector_get(par,ORDER_phi),2)*pow(gsl_spline_eval(calc->spline[ORDER_prop_all_CDC_inc],t,calc->acc[ORDER_prop_all_CDC_inc]),2)*pow(gsl_vector_get(par,ORDER_rep_all_CDC_inc),2)*pow(x,2)+gsl_spline_eval(calc->spline[ORDER_prop_all_CDC_inc],t,calc->acc[ORDER_prop_all_CDC_inc])*gsl_vector_get(par,ORDER_rep_all_CDC_inc)*x*(-gsl_vector_get(par,ORDER_rep_all_CDC_inc)+1.0)'},
        ]

        for t in terms:
            self.assertEqual(self.m.make_C_term(t['x'], False, human=True), t['h'])
            self.assertEqual(self.m.make_C_term(t['x'], False, human=False), t['c'])


    def test_make_C_term_nested(self):
        self.assertEqual(self.m.make_C_term('correct_rate(correct_rate(x))', False, human=False), 'ssm_correct_rate(ssm_correct_rate(x,dt),dt)')
        self.assertEqual(self.m.make_C_term('pow(correct_rate(correct_rate(x)),2)', False, human=False), 'pow(ssm_correct_rate(ssm_correct_rate(x,dt),dt),2)')
        self.assertEqual(self.m.make_C_term('(correct_rate(correct_rate(x)))**(2)', False, human=False), 'pow(ssm_correct_rate(ssm_correct_rate(x,dt),dt),2)')
        self.assertEqual(self.m.make_C_term('correct_rate(x) + correct_rate(correct_rate(x))', False, human=False), 'ssm_correct_rate(x,dt)+ssm_correct_rate(ssm_correct_rate(x,dt),dt)')
        self.assertEqual(self.m.make_C_term('correct_rate(correct_rate(x))+ sin(v*x+(3*sin(r0_paris)))', False, human=False), 'ssm_correct_rate(ssm_correct_rate(x,dt),dt)+sin(gsl_vector_get(par,ORDER_v)*x+3*sin(diffed[ORDER_diff__r0_paris]))')


    def test_make_C_term_derivate(self):
        x = 'sin(2*PI*(t +r0_paris))'
        h = '2*PI*cos(2*PI*(r0_paris+t))'
        c = '2*PI*cos(2*PI*(diffed[ORDER_diff__r0_paris]+t))'

        self.assertEqual(self.m.make_C_term(x, False, human=True, derivate='r0_paris'), h)
        self.assertEqual(self.m.make_C_term(x, False, human=False, derivate='r0_paris'), c)

    def test_make_C_term_skip_correct_rate(self):
        #correct_rate is only skipped for C code

        x = 'mu_b_paris*(1.0+correct_rate(v)*sin((correct_rate(v)/N_paris+(mu_b_paris)))) + r0_paris'
        c = 'gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])*((gsl_vector_get(par,ORDER_v))*sin(gsl_spline_eval(calc->spline[ORDER_mu_b_paris],t,calc->acc[ORDER_mu_b_paris])+(gsl_vector_get(par,ORDER_v))/gsl_spline_eval(calc->spline[ORDER_N_paris],t,calc->acc[ORDER_N_paris]))+1.0)+diffed[ORDER_diff__r0_paris]'

        self.assertEqual(self.m.make_C_term(x, True, human=False), c)

    def test_make_C_term_extra_terms(self):
        terms = [
            {'x': 'heaviside(t-v)', 
             'c': 'heaviside(t-gsl_vector_get(par,ORDER_v))'}, 
            
            {'x': 'heaviside((t-v))', 
             'c': 'heaviside(t-gsl_vector_get(par,ORDER_v))'}, 

            {'x': 'ramp(t-v)', 
             'c': 'ramp(t-gsl_vector_get(par,ORDER_v))'}, 
            
            {'x': 'correct_rate(v)', 
             'c': 'ssm_correct_rate(gsl_vector_get(par,ORDER_v),dt)'}, 
        ]
            
        for t in terms:
            self.assertEqual(self.m.make_C_term(t['x'], False, human=False), t['c'])
class TestCmodel(unittest.TestCase):

    def setUp(self):
        m = {
            'state': [{'id':'S'}, {'id':'I', 'tag': ['remainder', 'infectious']}, {'id': 'R'}],
            'parameter': [{'id':'r0'}, {'id':'v'}, {'id':'l'}, {'id':'e'}, {'id':'d'}, {'id':'sto'}, {'id':'alpha'}, {'id':'mu_b'}, {'id':'mu_d'}, {'id':'vol'}, {'id':'g'}],
            'model': [ 
                {'from': 'U', 'to': 'S',  'rate': 'mu_b*N'},
                {'from': 'S', 'to': 'E',  'rate': 'r0/N*v*(1.0+e*sin_t(d))*I', 'tag': 'transmission'},
                
                {'from': 'E', 'to': 'I', 'rate': '(1-alpha)*correct_rate(l)'},
                ##Here we split the reaction from E->U as we only observe a subpart
                {'from': 'E', 'to': 'U',  'rate': 'alpha*correct_rate(l)'},
                {'from': 'E', 'to': 'U',  'rate': 'mu_d'},
                
                {'from': 'S', 'to': 'U',  'rate': 'mu_d'},
                {'from': 'R', 'to': 'S',  'rate': 'g'},
                {'from': 'I', 'to': 'R', 'rate': '(1-alpha)*correct_rate(v)'},
                {'from': 'I', 'to': 'U',  'rate': 'alpha*correct_rate(v) + mu_d'}
            ],
            'diffusion': [{'parameter':'r0', 'volatility': 'vol', 'drift': 0.0}],
            'white_noise': [{'reaction': [{'from':'S', 'to': 'E'}], 'sd': 'sto'}]
        }
        
        ##context elements needed for Cmodel
        c = {
            'data': {},
            'metadata': [{'id': 'mu_b'}, {'id': 'mu_d'}, {'id': 'N'}, {'id': 'prop'}]
        }

        ##link elements needed for Cmodel
        l = {
            'observed': [
                {'id': 'Prev', 'definition': ['I'], 'model_id': 'common'},
                {'id': 'SI', 'definition': ['S', 'I'], 'model_id': 'common'},
                ##we have to specify a rate to the incidence E->U as we only observed a subpart of this reaction
                {'id': 'Inc_out', 'definition': [{'from':'I', 'to':'R'}, {'from':'E', 'to':'U', 'rate': 'mu_d'}], 'model_id': 'common'},
                {'id': 'Inc_in', 'definition': [{'from':'S', 'to':'E'}], 'model_id': 'common'},
                {'id': 'Inc_weird', 'definition': [{'from':'R', 'to':'S'}], 'model_id': 'common'}
            ],
            'observation': [{'id': 'common', 
                             'parameter': [{'id': 'rep','comment': 'reporting rate'}, 
                                           {'id': 'phi',  'comment': 'over-dispertion'},
                                           {"id": "prop",  "comment": "proportion of the population under surveillance"}],
                             'model': {'distribution': 'discretized_normal',
                                       'mean': 'rep*prop*x',
                                       'var': 'rep*(1.0-rep)*prop*x + (rep*phi*prop*x)**2'}}]
        }


        #other model with different remainder
        m2 = copy.deepcopy(m)
        m2['state'] = [{'id':'S'}, {'id':'I', 'tag': 'infectious'}, {'id': 'R', 'tag': 'remainder'}]

        #no remainder
        m3 = copy.deepcopy(m)
        m3['state'] = [{'id':'S'}, {'id':'I', 'tag': 'infectious'}, {'id': 'R'}]

        self.m = Cmodel(c, m, l) 
        self.m2 = Cmodel(c, m2, l) 
        self.m3 = Cmodel(c, m3, l) 


    def test_change_user_input(self):
        x = self.m.change_user_input('r0*2*correct_rate(v)')
        self.assertEqual(x, ['r0', '*', '2', '*', 'correct_rate', '(', 'v', ')'])


    def test_par_sv(self):
        self.assertEqual(set(self.m.par_sv), set(['S','R']))
        self.assertEqual(set(self.m2.par_sv), set(['S','I']))
        self.assertEqual(set(self.m3.par_sv), set(['S','I', 'R']))

    def test_remaider(self):
        self.assertEqual(self.m.remainder, 'I')
        self.assertEqual(self.m2.remainder, 'R')
        self.assertEqual(self.m3.remainder, None)

    def test_par_proc(self):
        self.assertEqual(set(self.m.par_proc), set(['r0', 'v', 'l', 'e', 'd', 'sto', 'alpha', 'vol', 'g']))

    def test_par_obs(self):
        self.assertEqual(set(self.m.par_obs), set(['rep','phi']))

    def test_par_fixed(self):
        self.assertEqual(set(self.m.par_fixed), set(['N', 'prop', 'mu_b', 'mu_d']))

    def test_par_fixed_obs(self):
        self.assertEqual(self.m.par_fixed_obs, set(['prop']))

    def test_drift_par_proc(self):
        self.assertEqual(set(self.m.drift_par_proc), set(['r0']))

    def test_vol_par_proc(self):
        self.assertEqual(set(self.m.vol_par_proc), set(['vol']))

    def test_drift_par_obs(self):
        self.assertEqual(self.m.drift_par_obs, [])

    def test_vol_par_obs(self):
        self.assertEqual(self.m.vol_par_obs, [])

    def test_drift_var(self):
        self.assertEqual(set(self.m.drift_var), set(['drift__par_proc__r0']))

    def test_proc_model(self):

        expected = [
            {'from': 'U', 'to': 'S',  'rate': 'mu_b*N'},
            {'from': 'S', 'to': 'E',  'rate': 'r0/N*v*(1.0+e*sin_t(d))*(N-S-R)', "tag": 'transmission', 'white_noise': {'name': 'white_noise__0', 'sd': 'sto'}}, #change  
            {'from': 'E', 'to': 'I', 'rate': '(1-alpha)*correct_rate(l)'},
            {'from': 'E', 'to': 'U',  'rate': 'alpha*correct_rate(l)'},
            {'from': 'E', 'to': 'U',  'rate': 'mu_d'},            
            {'from': 'S', 'to': 'U',  'rate': 'mu_d'},
            {'from': 'R', 'to': 'S',  'rate': 'g'},
            {'from': 'I', 'to': 'R', 'rate': '((1-alpha)*correct_rate(v))*(N-S-R)'}, #change
            {'from': 'I', 'to': 'U',  'rate': '(alpha*correct_rate(v)+mu_d)*(N-S-R)'} #change
        ]

        expected2 = [
            {'from': 'U', 'to': 'S',  'rate': 'mu_b*N'},
            {'from': 'S', 'to': 'E',  'rate': 'r0/N*v*(1.0+e*sin_t(d))*I', "tag": 'transmission', 'white_noise': {'name': 'white_noise__0', 'sd': 'sto'}}, #change  
            {'from': 'E', 'to': 'I', 'rate': '(1-alpha)*correct_rate(l)'},
            {'from': 'E', 'to': 'U',  'rate': 'alpha*correct_rate(l)'},
            {'from': 'E', 'to': 'U',  'rate': 'mu_d'},            
            {'from': 'S', 'to': 'U',  'rate': 'mu_d'},
            {'from': 'R', 'to': 'S',  'rate': '(g)*(N-S-I)'}, #change
            {'from': 'I', 'to': 'R', 'rate': '(1-alpha)*correct_rate(v)'},
            {'from': 'I', 'to': 'U',  'rate': 'alpha*correct_rate(v)+mu_d'}
        ]


        expected3 = [
            {'from': 'U', 'to': 'S',  'rate': 'mu_b*(S+I+R)'}, #change  
            {'from': 'S', 'to': 'E',  'rate': 'r0/(S+I+R)*v*(1.0+e*sin_t(d))*I', "tag": 'transmission', 'white_noise': {'name': 'white_noise__0', 'sd': 'sto'}}, #change  
            {'from': 'E', 'to': 'I', 'rate': '(1-alpha)*correct_rate(l)'},
            {'from': 'E', 'to': 'U',  'rate': 'alpha*correct_rate(l)'},
            {'from': 'E', 'to': 'U',  'rate': 'mu_d'},            
            {'from': 'S', 'to': 'U',  'rate': 'mu_d'},
            {'from': 'R', 'to': 'S',  'rate': 'g'},
            {'from': 'I', 'to': 'R', 'rate': '(1-alpha)*correct_rate(v)'},
            {'from': 'I', 'to': 'U',  'rate': 'alpha*correct_rate(v)+mu_d'}
        ]



        self.assertEqual(self.m.proc_model, expected)
        self.assertEqual(self.m2.proc_model, expected2)
        self.assertEqual(self.m3.proc_model, expected3)


    def test_obs_var(self):
        self.assertEqual(self.m.obs_var, ['Inc_out', 'Inc_in', 'Inc_weird', 'Prev', 'SI'])

    def test_obs_var_def(self):
        expected = [
            [{'from': 'I', 'to': 'R', 'rate': '((1-alpha)*correct_rate(v))*(N-S-R)'}, {'from': 'E', 'to': 'U', 'rate': 'mu_d'}],
            [{'from': 'S', 'to': 'E', 'rate': 'r0/N*v*(1.0+e*sin_t(d))*(N-S-R)', 'white_noise': {'name': 'white_noise__0', 'sd': 'sto'}}],
            [{'from': 'R', 'to': 'S', 'rate': 'g'}],
            ['I'],
            ['S', 'I']
        ]

        expected2 = [
            [{'from': 'I', 'to': 'R', 'rate': '(1-alpha)*correct_rate(v)'}, {'from': 'E', 'to': 'U', 'rate': 'mu_d'}],
            [{'from': 'S', 'to': 'E', 'rate': 'r0/N*v*(1.0+e*sin_t(d))*I', 'white_noise': {'name': 'white_noise__0', 'sd': 'sto'}}],
            [{'from': 'R', 'to': 'S', 'rate': '(g)*(N-S-I)'}],
            ['I'],
            ['S', 'I']
        ]

        expected3 = [
            [{'from': 'I', 'to': 'R', 'rate': '(1-alpha)*correct_rate(v)'}, {'from': 'E', 'to': 'U', 'rate': 'mu_d'}],
            [{'from': 'S', 'to': 'E', 'rate': 'r0/(S+I+R)*v*(1.0+e*sin_t(d))*I', 'white_noise': {'name': 'white_noise__0', 'sd': 'sto'}}],
            [{'from': 'R', 'to': 'S', 'rate': 'g'}],
            ['I'],
            ['S', 'I']
        ]

        self.assertEqual(self.m.obs_var_def, expected)
        self.assertEqual(self.m2.obs_var_def, expected2)
        self.assertEqual(self.m3.obs_var_def, expected3)