Beispiel #1
0
def poission_model():
    module = Module("poission process")
    module.addConstant(Constant('r', None))

    # variable definition
    v = Variable('n', 0, None, int, False)  # n: int init 0;
    module.addVariable(v)
    # command definition

    comm = Command('', lambda vs, cs: True,
                   lambda vs, cs: vs['n'].setValue(vs['n'].getValue() + 1),
                   module, module.getConstant("r"), CommandKind.NONE, None)
    module.addCommand(comm)

    # 增加label表示n>=4这个ap
    labels = dict()

    def nge4(vs, cs):
        return vs['n'] >= 4

    labels['nge4'] = nge4

    model = ModulesFile.ModulesFile(ModelType.CTMC,
                                    modules=[module],
                                    labels=labels)
    return model
Beispiel #2
0
    def _s3rmodule(self):
        config = self.config
        module = Module('S3R')
        module.addConstant(config.getParam('S3R_K'))
        module.addConstant(config.getParam('S3R_A_MU'))
        module.addConstant(config.getParam('S3R_A_SIGMA'))
        module.addConstant(config.getParam('S3R_B'))
        module.addConstant(config.getParam('S3R_DELTAV_THRESHOLD'))

        module.addVariable(Variable('s3r_status', 1, range(2), int))

        def guard(vs, cs):
            # the sb_status and s3r_status must both be 1 for this transition
            # to happen
            return vs['timer_turn'] == False and vs['s3r_status'] == 1 and vs[
                'sb_status'] == 1 and vs['bcr_status'] == 1 and vs[
                    'bdr_status'] == 1

        def faction(vs, cs):
            vs['s3r_status'].setValue(0)
            vs['timer_turn'].setValue(True)

        def naction(vs, cs):
            vs['timer_turn'].setValue(True)

        def f(day_var):
            def inner():
                day = day_var.getValue()
                dose = module.getConstant('S3R_K') / config.getParam(
                    'SCREEN_THICKNESS') * (day / 365.0)
                x = config.getParam('S3R_DELTAV_THRESHOLD') / (
                    config.getParam('S3R_B') *
                    pow(e,
                        config.getParam('S3R_B') * dose))
                std_x = (-config.getParam('S3R_A_MU') + x) / \
                    config.getParam('S3R_A_SIGMA').getValue()
                p = 1 - pcf(std_x)
                logger.info('day:{0}, s3r failure prob:{1}'.format(day, p))
                return p

            return inner

        def n(day_var):
            def inner():
                ff = f(day_var)
                return 1 - ff()

            return inner

        if not hasattr(self, 'timer'):
            self.timer = self._timermodule()

        module.addCommand(
            Command('s3r_fail_cmd', guard, faction, module,
                    f(self.timer.getVariable('day'))))

        module.addCommand(
            Command('s3r_nrl_cmd', guard, naction, module,
                    n(self.timer.getVariable('day'))))
        return module
Beispiel #3
0
    def _sbmodule(self):
        config = self.config
        module = Module('SB')
        module.addConstant(config.getParam('SB_K'))
        module.addConstant(config.getParam('SB_A_MU'))
        module.addConstant(config.getParam('SB_A_SIGMA'))
        module.addConstant(config.getParam('SB_B'))
        module.addConstant(config.getParam('SB_P_THRESHOLD'))

        module.addVariable(Variable('sb_status', 1, range(2), int))

        def guard(vs, cs):
            # sb_status and s3r_status must both be 1, e.g. the system has not
            # failed.
            return vs['timer_turn'] == False and vs['sb_status'] == 1 and vs[
                's3r_status'] == 1 and vs['bcr_status'] == 1 and vs[
                    'bdr_status'] == 1

        # failure action
        def faction(vs, cs):
            vs['sb_status'].setValue(0)
            vs['timer_turn'].setValue(True)

        # normal action
        def naction(vs, cs):
            vs['timer_turn'].setValue(True)

        def f(day_var):
            def inner():
                day = day_var.getValue()
                dose = module.getConstant('SB_K') * config.getParam(
                    'SCREEN_THICKNESS') * day / 365.0
                x = (-module.getConstant('SB_P_THRESHOLD') + 1) / \
                    (log(module.getConstant('SB_B') * dose + 1))
                std_x = 1.0 / (module.getConstant('SB_A_SIGMA') /
                               (-module.getConstant('SB_A_MU') + x))
                return 1 - pcf(std_x)

            return inner

        def n(day_var):
            def inner():
                ff = f(day_var)
                return 1 - ff()

            return inner

        if not hasattr(self, 'timer'):
            self.timer = self._timermodule()

        module.addCommand(
            Command('sb_fail_cmd', guard, faction, module,
                    f(self.timer.getVariable('day'))))

        module.addCommand(
            Command('sb_nrl_cmd', guard, naction, module,
                    n(self.timer.getVariable('day'))))
        return module
Beispiel #4
0
    def _timermodule(self):
        config = self.config
        module = Module('TIME')
        module.addVariable(
            Variable('day', 1, range(1,
                                     config.getParam('DURATION_IN_DAY') + 1),
                     int))
        module.addVariable(
            Variable('timer_turn', True, set([True, False]), bool))

        def guard(vs, cs):
            day_val = vs['day'].getValue()
            DAY_MAX = self.config.getParam("DURATION_IN_DAY")
            t_turn = vs['timer_turn'].getValue()
            return day_val < DAY_MAX and t_turn is True

        def action(vs, cs):
            vs['day'].setValue(vs['day'].getValue() + 1)
            vs['timer_turn'].setValue(False)

        module.addCommand(
            Command('inc day', guard, action, module, lambda: 1.0))
        return module
Beispiel #5
0
class BasicParser(object):
    FRML_FUNC_PREFIX = "FRML"
    VAR_FUNC_PREFIX = "VAR"
    SPLIT = ":"

    def __init__(self):
        # 表示当前是否正在解析module模块
        # 用途: 值为false时,对boolean_expression的解析不会将结果保存为guard
        self.moduledefbegin = False
        '''
        当parser分析到一行Command时,可能最后会解析成多个Command对象
        每个Command对象包含以下信息:name, guard, prob, action, module
        目前默认不设置Command的name,即name为空
        module在每次解析到LB时进行初始化表示当前正在生成的module
        prob在解析到prob_expr的时候进行设置,prob是一个函数对象,因为需要根据判定对象(变量)的值进行实时计算
        最重要的Command对象在解析到prob_update时进行初始化,因为从Command的构成上讲,
        一个prob + update就构成了一个Command对象。
        之所以要在BasicParser中保存module和guard对象是因为
        它们是被多个Command对象所共享的。
        '''
        self.module = None  # 当前正在解析的module对象
        self.guard = None  # 表示当前Command对象的guard属性
        self.binary_op_map = {
            '+': lambda x, y: x + y,
            '-': lambda x, y: x - y,
            '*': lambda x, y: x * y,
            '/': lambda x, y: x / y
        }
        self.func_map = {'stdcdf': pcf}
        # name : value storage structure for constants
        self.cmap = defaultdict(lambda: None)
        # name : func object storage structure for variables and formula
        self.logger = logging.getLogger("BasicParser logging")
        self.logger.addHandler(
            logging.FileHandler(LogHelper.get_logging_root() +
                                "BasicParser.log"))
        self.logger.setLevel(logging.INFO)
        self.vcf_map = defaultdict(lambda: None)
        self.vc_map = defaultdict(lambda: None)

    def p_statement(self, p):
        '''statement : model_type_statement
                     | const_value_statement
                     | module_def_begin_statement
                     | module_def_end_statement
                     | module_var_def_statement
                     | module_command_statement
                     | formula_statement
                     | label_statement'''
        # print "slice: {}".format(p.slice)
        pass

    def p_model_type(self, p):
        '''model_type_statement : DTMC
                      | CTMC'''
        model_type = ModelType.CTMC
        if p[1] == 'dtmc':
            model_type = ModelType.DTMC
        ModelConstructor.model = ModulesFile(modeltype=model_type)

    def p_module_def_begin_statement(self, p):
        '''module_def_begin_statement : MODULE NAME'''
        self.moduledefbegin = True
        self.module = Module(p[2])

    def p_module_def_end_statement(self, p):
        '''module_def_end_statement : ENDMODULE'''
        if self.moduledefbegin:
            self.moduledefbegin = False
            ModelConstructor.model.addModule(self.module)

    def p_const_expression(self, p):
        '''const_value_statement : CONST INT NAME ASSIGN NUM SEMICOLON
                                 | CONST DOUBLE NAME ASSIGN NUM SEMICOLON
                                 | CONST BOOL NAME ASSIGN NUM SEMICOLON'''
        name = p[3]
        value = self.resolvetype(p[5], p[2])
        obj = Constant(name, value)
        ModelConstructor.model.setConstant(name, obj)
        self.vcf_map[p[3]] = obj
        self.logger.info("Constant added: {} = {}".format(name, value))

    def p_const_expression1(self, p):
        '''const_value_statement : CONST INT NAME SEMICOLON
                             | CONST DOUBLE NAME SEMICOLON
                             | CONST BOOL NAME SEMICOLON'''
        # 支持解析不确定的常量表达式
        name = p[3]
        obj = Constant(name)
        ModelConstructor.model.addConstant(name, obj)
        self.vcf_map[name] = obj
        self.logger.info("Unspecified constant added: {}".format(name))

    def p_const_expression2(self, p):
        '''const_value_statement : CONST INT NAME ASSIGN expr SEMICOLON
                                 | CONST DOUBLE NAME ASSIGN expr SEMICOLON
                                 | CONST BOOL NAME ASSIGN expr SEMICOLON'''
        name = p[3]
        value = self.resolvetype(p[5](), p[2])
        obj = Constant(name, value)
        ModelConstructor.model.addConstant(name, obj)
        self.vcf_map[name] = obj
        self.logger.info("Constant added: {} = {}".format(name, value))

    def p_module_var_def_statement(self, p):
        '''module_var_def_statement : NAME COLON LB expr COMMA expr RB INIT NUM SEMICOLON'''
        #  让var的lowbound和upperbound支持expression
        tokens = copy.copy(p.slice)
        min = tokens[4].value()
        max = tokens[6].value()
        var = Variable(p[1], p[len(p) - 2], range(min, max + 1),
                       int)  # 目前默认变量的类型是int p[index] index不能是负数
        self.module.addVariable(var)
        self.vcf_map[var.getName()] = var
        self.logger.info(
            "Variable_{} added to Module_{}. init={}, range=[{}, {}]".format(
                var.getName(), str(self.module), var.initVal, var.valRange[0],
                var.valRange[-1]))

    def p_module_command_statement(self, p):
        '''module_command_statement : LB RB boolean_expression THEN updates SEMICOLON'''
        self.logger.info("command.tokens : {}".format(p.slice))

    def p_updates(self, p):
        '''updates : updates ADD prob_update'''
        pass

    def p_updates1(self, p):
        '''updates : prob_update'''
        pass

    def p_prob_update(self, p):
        '''prob_update : DQ NAME DQ expr COLON actions'''
        prob = p[4]  # prob_expr is a function
        action = p[6]  # actions is a function
        name = copy.copy(p[2])
        command = Command(name, self.guard, action, self.module, prob)
        self.module.addCommand(command)
        self.logger.info("Command_{} added.".format(name))

    def p_actions(self, p):
        '''actions : actions AND assignment'''
        f1 = p[1]
        f2 = p[3]

        def f(vs, cs):
            f1(vs, cs)
            f2(vs, cs)

        p[0] = f

    def p_actions2(self, p):
        '''actions : assignment'''
        p[0] = p[
            1]  # a assignment is a function that udpate the variable in model.localVars

    def p_assignment(self, p):
        '''assignment : NAME ASSIGN expr'''
        update_func = copy.deepcopy(p[3])
        var_name = copy.copy(p[1])

        def f(vs, cs):
            var = vs[var_name]
            if not var or not isinstance(var, Variable):
                raise Exception("invalid variable name")
            var.setValue(update_func())

        p[0] = f

    def p_assignment1(self, p):
        '''assignment : LP NAME ASSIGN expr RP'''
        update_func = copy.deepcopy(p[4])
        key = p[2]

        def f(vs, cs):
            var = vs[key]
            if not var or not isinstance(var, Variable):
                raise Exception("invalid variable name: {}".format(key))
            var.setValue(update_func())

        p[0] = f

    def p_expr(self, p):
        '''expr : expr ADD term
                | expr MINUS term'''
        slice_copy = copy.copy(p.slice)
        op = slice_copy[2].value

        def f():
            '''binary expression function'''
            v1 = slice_copy[1].value()
            v2 = slice_copy[3].value()
            if op == '-':
                return v1 - v2
            else:
                return v1 + v2

        p[0] = f

    def p_expr2(self, p):
        '''expr : term'''
        p[0] = p[1]

    # def p_expr3(self, p):
    #     '''expr : LP expr RP'''
    #     p[0] = p[2]

    def p_term(self, p):
        '''term : term MUL factor
                | term DIV factor'''
        slice_copy = copy.copy(p.slice)
        op = slice_copy[2].value

        def f():
            v1 = slice_copy[1].value()
            v2 = slice_copy[3].value()
            if op == "*":
                return v1 * v2
            else:
                return v1 / v2

        p[0] = f

    def p_term1(self, p):
        '''term : factor'''
        p[0] = p[1]

    def p_factor(self, p):
        '''factor : NUM'''
        num = p[1]

        def f():
            return num

        f.func_doc = "return {}".format(str(num))
        p[0] = f

    def p_factor1(self, p):
        '''factor : NAME'''
        slice_cpy = copy.copy(p.slice)
        name = slice_cpy[1].value

        def f():
            obj = self.vcf_map[name]
            if callable(obj):
                return obj()
            return obj.getValue()

        p[0] = f

    def p_factor2(self, p):
        '''factor : NAME LP expr RP'''
        slice = copy.copy(p.slice)
        func = ExpressionHelper.func_map.get(slice[1].value, None)

        # if not func:
        #     raise Exception("Not supported function {}".format(slice[1].value))

        def f():
            return func(slice[3].value())

        f.func_doc = "func_{}".format(func.__name__)
        p[0] = f

    def p_factor3(self, p):
        '''factor : LP expr RP'''
        p[0] = p[2]

    def p_boolean_expression(self, p):
        '''boolean_expression : boolean_expression AND boolean_expression_unit
                              | boolean_expression OR boolean_expression_unit
                              | boolean_expression_unit'''
        print "boolean_expression detached."
        slices = copy.copy(p.slice)
        if len(slices) == 4:
            if slices[2].value == "&":

                def f(vs, cs):
                    return slices[1].value(vs, cs) and slices[3].value(vs, cs)

            if slices[2].value == "|":

                def f(vs, cs):
                    return slices[1].value(vs, cs) or slices[3].value(vs, cs)

            p[0] = f
        elif len(p) == 2:
            p[0] = p[1]
        if self.moduledefbegin:
            # 如果当前正在解析command
            # 否则要么是解析formula,要么是label
            self.guard = p[0]

    def p_boolean_expression_unit(self, p):
        '''boolean_expression_unit : NAME GT NUM
                                   | NAME LT NUM
                                   | NAME GE NUM
                                   | NAME LE NUM
                                   | NAME EQ NUM
                                   | NAME NEQ NUM'''
        # 解析单个变量与某个常量进行比较
        tokens = copy.copy(p.slice)

        def f(tokens):
            def inner(vs, cs):
                var = vs[tokens[1].value]
                # if not var or not isinstance(var, Variable):
                #     raise Exception("invalid variable name")
                val1 = var.getValue()
                val2 = tokens[3]
                op = tokens[2]
                if '<' == op:
                    return val1 < val2
                if '>' == op:
                    return val1 > val2
                if '>=' == op:
                    return val1 >= val2
                if '<=' == op:
                    return val1 <= val2
                if '==' == op:
                    return val1 == val2
                if '!=' == op:
                    return val1 != val2

            return inner

        p[0] = f(tokens)

    def p_boolean_expression_unit1(self, p):
        '''boolean_expression_unit : NAME GT expr
                                   | NAME LT expr
                                   | NAME GE expr
                                   | NAME LE expr
                                   | NAME EQ expr
                                   | NAME NEQ expr'''
        # 解析某个变量与一个表达式进行比较
        tokens = copy.copy(p.slice)

        def f(t):
            # handler is a boolean_expression_resolver : handler(val1, val2,
            # op)
            def inner(vs, cs):
                var = vs[t[1].value]
                # if not var or not isinstance(var, Variable):
                #     raise Exception("invalid var name")
                val1 = var.getValue()
                val2 = t[3].value()
                op = t[2].value
                if '<' == op:
                    return val1 < val2
                if '>' == op:
                    return val1 > val2
                if '>=' == op:
                    return val1 >= val2
                if '<=' == op:
                    return val1 <= val2
                if '==' == op:
                    return val1 == val2
                if '!=' == op:
                    return val1 != val2

            return inner

        p[0] = f(tokens)

    def p_formula_statement(self, p):
        '''formula_statement : FORMULA NAME ASSIGN expr SEMICOLON'''
        slices = copy.copy(p.slice)
        frml_name = slices[2].value
        self.vcf_map[frml_name] = slices[4].value
        self.logger.info("Formula_{} added.".format(slices[2].value))

    def p_label_statement(self, p):
        '''label_statement : LABEL NAME ASSIGN boolean_expression SEMICOLON'''
        lbl_name = p[2]
        lbl_func = p[4]
        ModelConstructor.model.labels[lbl_name] = lbl_func

    def resolvetype(self, strval, type):
        if 'int' == type:
            return int(strval)
        if 'double' == type:
            return float(strval)
        if 'bool' == type:
            return bool(strval)

    def resolvenum(self, strval):
        if strval.find(r"\.") == -1:
            return int(strval)
        return float(strval)

    def parse_model(self, filepath):
        commentremoved = clear_comment(filepath)
        self.logger.info("Parsing model file : {}".format(commentremoved))
        lines = []

        with open(commentremoved) as f:
            for l in f:
                lines.append(l)
        if self.parser:
            myLexer = MyLexer()
            lexer = myLexer.lexer
            for line in lines:
                # tokens = []
                # if line.find("[]") != -1:
                # lexer.input(line)
                # for token in lexer:
                #     tokens.append(token)
                # print tokens
                self.parser.parse(line, lexer=lexer)

    def build(self):
        self.tokens = MyLexer.tokens
        self.parser = yacc.yacc(module=self)
Beispiel #6
0
def sps_model_dtmc(duration):
    # duration: timer.day的最大值:天数
    # timer module of the system
    timer = Module('timer_module')
    timer.addConstant(Constant('TIME_LIMIT', duration))
    day = Variable('day', 1,
                   range(timer.getConstant('TIME_LIMIT').getValue() + 1), int,
                   True)
    timer_turn = Variable('timer_turn', True, set([True, False]), bool, True)
    timer.addVariable(day)
    timer.addVariable(timer_turn)

    def incdayaction(vs, cs):
        vs['day'].setValue(vs['day'].getValue() + 1)
        vs['timer_turn'].setValue(False)

    inc_day = Command(
        'inc day', lambda vs, cs: vs['timer_turn'] == True and vs['day'] <
        timer.getConstant('TIME_LIMIT').getValue(), incdayaction, timer, 1.0)
    timer.addCommand(inc_day)

    # solar battery module of the system
    sb = Module("solar battery module")

    # set initial value None to denote uncertainty
    screenthick = Constant('SCREEN_THICKNESS', None)
    sb.addConstant(screenthick)
    # the dose of one year: dose = K_SB * thickness
    sb.addConstant(Constant('SB_K', 0.0039))
    sb.addConstant(Constant('SB_B', 12))
    sb.addConstant(Constant('SB_P_THRESHOLD', 0.7))
    sb.addConstant(Constant('SB_A_MU', 0.1754))
    sb.addConstant(Constant('SB_A_SIGMA', 0.02319029 * 21))

    # variables
    sb_status = Variable('sb_status', 1, range(2), int, True)
    sb.addVariable(sb_status)

    def failaction(vs, cs):
        vs['sb_status'].setValue(0)
        vs['timer_turn'].setValue(True)

    # use closure to delay the computation of fail rate
    def f1(day_var):
        def failprobsb():
            # return the failure probability of solar battery after day-dose
            niel_dose = sb.getConstant('SB_K').getValue() * sb.getConstant(
                'SCREEN_THICKNESS').getValue() * (day_var.getValue() / 365.0)
            x = (1 - sb.getConstant('SB_P_THRESHOLD').getValue()) / \
                log(1 + niel_dose * sb.getConstant('SB_B').getValue())
            std_x = (x - sb.getConstant('SB_A_MU').getValue() /
                     sb.getConstant('SB_A_SIGMA').getValue())
            temp = pcf(std_x)
            i = id(day_var)
            return 1 - temp

        return failprobsb

    def f1n(day_var):
        def normalprobsb():
            niel_dose = sb.getConstant('SB_K').getValue() * sb.getConstant(
                'SCREEN_THICKNESS').getValue() * (day_var.getValue() / 365.0)
            x = (1 - sb.getConstant('SB_P_THRESHOLD').getValue()) / \
                log(1 + niel_dose * sb.getConstant('SB_B').getValue())
            std_x = (x - sb.getConstant('SB_A_MU').getValue() /
                     sb.getConstant('SB_A_SIGMA').getValue())
            return pcf(std_x)

        return normalprobsb

    comm_fail = Command(
        'solar battery failure command',
        lambda vs, cs: vs['sb_status'] == 1 and vs['timer_turn'] == False,
        failaction,
        sb,
        f1(timer.getVariable('day')),
        kind=CommandKind.FAILURE)
    sb.addCommand(comm_fail)

    comm_normal = Command(
        'solar battery stay-normal command',
        lambda vs, cs: vs['sb_status'] == 1 and vs['timer_turn'] == False,
        lambda vs, cs: vs['timer_turn'].setValue(True), sb,
        f1n(timer.getVariable('day')))
    sb.addCommand(comm_normal)

    s3r = Module('S3R模块')
    s3r.addConstant(screenthick)
    s3r.addConstant(Constant('S3R_K', 200.5 / 3.0))  # s3r, bdr, bcr三个模块均摊电离能损
    s3r.addConstant(Constant('S3R_DELTAV_THRESHOLD', 450))
    s3r.addConstant(Constant('S3R_A_MU', 570.8 * 18))
    s3r.addConstant(Constant('S3R_A_SIGMA', 6.7471 * 120))
    s3r.addConstant(Constant('S3R_B', 0.01731))

    s3r_status = Variable('s3r_status', 1, range(2), int, True)
    s3r.addVariable(s3r_status)

    def s3rfailaction(vs, cs):
        vs['s3r_status'].setValue(0)
        vs['timer_turn'].setValue(True)

    def f2(day_var):
        def failprobs3r():
            iel_dose = day_var.getValue() / 365.0 * (s3r.getConstant('S3R_K').getValue() / \
                                        s3r.getConstant('SCREEN_THICKNESS').getValue())
            x = s3r.getConstant('S3R_DELTAV_THRESHOLD').getValue() / (
                s3r.getConstant('S3R_B').getValue() *
                pow(e,
                    s3r.getConstant('S3R_B').getValue() * iel_dose))
            std_x = (x - s3r.getConstant('S3R_A_MU').getValue()) / \
                s3r.getConstant('S3R_A_SIGMA').getValue()
            return 1 - pcf(std_x)

        return failprobs3r

    def f2n(day_var):
        def normalprobs3r():
            iel_dose = day_var.getValue() / 365.0 * (s3r.getConstant('S3R_K').getValue() / \
                                                     s3r.getConstant('SCREEN_THICKNESS').getValue())
            x = s3r.getConstant('S3R_DELTAV_THRESHOLD').getValue() / (
                s3r.getConstant('S3R_B').getValue() *
                pow(e,
                    s3r.getConstant('S3R_B').getValue() * iel_dose))
            std_x = (x - s3r.getConstant('S3R_A_MU').getValue()) / \
                    s3r.getConstant('S3R_A_SIGMA').getValue()
            return pcf(std_x)

        return normalprobs3r

    s3r_comm_fail = Command(
        's3r failure command',
        lambda vs, cs: vs['s3r_status'] == 1 and vs['timer_turn'] == False,
        s3rfailaction, s3r, f2(timer.getVariable('day')), CommandKind.FAILURE)
    s3r.addCommand(s3r_comm_fail)
    s3r_comm_norm = Command(
        's3r normal command',
        lambda vs, cs: vs['timer_turn'] == False and vs['s3r_status'] == 1,
        lambda vs, cs: vs['timer_turn'].setValue(True), s3r,
        f2n(timer.getVariable('day')))
    s3r.addCommand(s3r_comm_norm)

    def failureif(vs, cs):
        return vs['s3r_status'] == 0 or vs['sb_status'] == 0

    labels = dict()
    labels['up'] = lambda vs, cs: vs['s3r_status'] == 1 and vs['sb_status'
                                                               ] == 1
    labels['failure'] = lambda vs, cs: vs['s3r_status'] == 0 or vs['sb_status'
                                                                   ] == 0

    i = id(timer.getVariable('day'))

    model = ModulesFile.ModulesFile(ModelType.DTMC,
                                    modules=[timer, sb, s3r],
                                    failureCondition=failureif,
                                    labels=labels,
                                    stopCondition=failureif)

    ii = id(model.localVars['day'])
    assert i == ii
    return model