def test_script_data_clamp_opt(tmp_path):
    """Convert code with data clamp opt"""
    LOGGER.info('Testing multiple models\n')
    tmp_path = str(tmp_path)
    model_name = 'grandi_pasqualini_bers_2010_ss'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    target = os.path.join(tmp_path, model_name + '.cellml')
    shutil.copyfile(model_file, target)

    testargs = ['chaste_codegen', '--use-model-factory', '--skip-singularity-fixes', '--cvode-data-clamp', '--opt',
                target]
    # Call commandline script
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    reference = os.path.join(os.path.join(TESTS_FOLDER), 'chaste_reference_models')
    reference_opt = os.path.join(os.path.join(TESTS_FOLDER), 'chaste_reference_models')

    compare_file_against_reference(os.path.join(reference, 'CVODE_DATA_CLAMP',
                                                model_name + 'CvodeDataClamp.hpp'),
                                   os.path.join(tmp_path, model_name + 'CvodeDataClamp.hpp'))
    compare_file_against_reference(os.path.join(reference, 'CVODE_DATA_CLAMP',
                                                model_name + 'CvodeDataClamp.cpp'),
                                   os.path.join(tmp_path, model_name + 'CvodeDataClamp.cpp'))

    compare_file_against_reference(os.path.join(reference_opt, 'CVODE_DATA_CLAMP_OPT',
                                                model_name + 'CvodeDataClampOpt.hpp'),
                                   os.path.join(tmp_path, model_name + 'CvodeDataClampOpt.hpp'))
    compare_file_against_reference(os.path.join(reference_opt, 'CVODE_DATA_CLAMP_OPT',
                                                model_name + 'CvodeDataClampOpt.cpp'),
                                   os.path.join(tmp_path, model_name + 'CvodeDataClampOpt.cpp'))
def test_script_opt(tmp_path):
    """Convert an optimised normal model type"""
    # If using --opt with no output file and not dynamic it will generate both non-opt and opt models
    # this version does not have the ModelFactory stuff
    LOGGER.info('Testing model with options --normal --opt and -o for command line script\n')
    tmp_path = str(tmp_path)
    model_name = 'aslanidi_Purkinje_model_2009'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    target = os.path.join(tmp_path, model_name + '.cellml')
    shutil.copyfile(model_file, target)

    # Call commandline script
    testargs = ['chaste_codegen', '--skip-singularity-fixes', target, '--normal', '--opt', '--use-modifiers']

    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    # Check output
    reference = os.path.join(os.path.join(TESTS_FOLDER), 'chaste_reference_models')
    compare_file_against_reference(os.path.join(reference, 'Opt', 'non_dynamic_aslanidi_Purkinje_model_2009.hpp'),
                                   os.path.join(tmp_path, 'aslanidi_Purkinje_model_2009Opt.hpp'))
    compare_file_against_reference(os.path.join(reference, 'Opt', 'non_dynamic_aslanidi_Purkinje_model_2009.cpp'),
                                   os.path.join(tmp_path, 'aslanidi_Purkinje_model_2009Opt.cpp'))
    compare_file_against_reference(os.path.join(reference, 'Normal', 'non_dynamic_aslanidi_Purkinje_model_2009.hpp'),
                                   os.path.join(tmp_path, 'aslanidi_Purkinje_model_2009.hpp'))
    compare_file_against_reference(os.path.join(reference, 'Normal', 'non_dynamic_aslanidi_Purkinje_model_2009.cpp'),
                                   os.path.join(tmp_path, 'aslanidi_Purkinje_model_2009.cpp'))
def load_model_with_conversions(model_file,
                                use_modifiers=False,
                                quiet=False,
                                skip_singularity_fixes=False,
                                skip_conversions=False):
    if quiet:
        LOGGER.setLevel(logging.ERROR)
    try:
        model = cellmlmanip.load_model(model_file)
    except Exception as e:
        raise CodegenError('Could not load cellml model: \n    ' + str(e))
    if not skip_singularity_fixes:
        V = model.get_variable_by_ontology_term((OXMETA, 'membrane_voltage'))
        tagged = set(
            model.get_variables_by_rdf((PYCMLMETA, 'modifiable-parameter'),
                                       'yes',
                                       sort=False))
        annotated = set(
            filter(lambda q: model.has_ontology_annotation(q, OXMETA),
                   model.variables()))
        excluded = (tagged | annotated) - set(
            model.get_derived_quantities(sort=False))

        model.remove_fixable_singularities(V, exclude=excluded)
    if not skip_conversions:
        add_conversions(model, use_modifiers=use_modifiers)
    return model
def _get_stimulus(model, skip_chaste_stimulus_conversion):
    """ Store the stimulus currents in the model"""
    stim_params_orig, stim_params, return_stim_eqs = set(), set(), set()
    if not skip_chaste_stimulus_conversion:
        try:  # Get required stimulus parameters
            for tag, unit, required in STIM_PARAM_TAGS:
                param = model.get_variable_by_ontology_term((OXMETA, tag))
                stim_params_orig.add(param)  # originals ones
                stim_params.add(
                    model.convert_variable(
                        param, model.conversion_units.get_unit(unit),
                        DataDirectionFlow.INPUT))
        except KeyError:
            if required:  # Optional params are allowed to be missing
                LOGGER.info('The model has no default stimulus params tagged.')
                return set(), []
        except TypeError as e:
            if str(
                    e
            ) == "unsupported operand type(s) for /: 'HeartConfig::Instance()->GetCapacitance' and 'NoneType'":
                e = CodegenError(
                    "Membrane capacitance is required to be able to apply conversion to stimulus current!"
                )
            raise (e)

        return_stim_eqs = get_equations_for(
            model, stim_params, filter_modifiable_parameters_lhs=False)
    return stim_params | stim_params_orig, return_stim_eqs
def test_script_lookup_table_check_non_existing_tag_ignored(caplog, tmp_path):
    """Check non-existing metadata tags are ignored"""
    LOGGER.info('Testing custom lookup tables, for command line script\n')
    tmp_path = str(tmp_path)
    model_name = 'beeler_reuter_model_1977'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    outfile = os.path.join(tmp_path, 'beeler_reuter_model_1977_lookup_tables.cpp')
    # Call commandline script
    testargs = ['chaste_codegen', '--skip-singularity-fixes', model_file, '--opt', '-o', outfile,
                '--lookup-table', 'membrane_voltage', '-150.0001', '199.9999', '0.01',
                '--lookup-table', 'cytosolic_calcium_concentration', '0.00001', '30.00001', '0.0001',
                '--lookup-table', 'non_existing_tag', '-150.0001', '199.9999', '0.01']

    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()

    assert 'WARNING' in caplog.text
    assert "A lookup table was specified for non_existing_tag but it is not tagged in the model, skipping!" \
        in caplog.text

    # Check output
    reference = os.path.join(os.path.join(TESTS_FOLDER), 'chaste_reference_models', 'Opt')
    compare_file_against_reference(os.path.join(reference, 'beeler_reuter_model_1977_lookup_tables.hpp'),
                                   os.path.join(tmp_path, 'beeler_reuter_model_1977_lookup_tables.hpp'))
    compare_file_against_reference(os.path.join(reference, 'beeler_reuter_model_1977_lookup_tables.cpp'),
                                   os.path.join(tmp_path, 'beeler_reuter_model_1977_lookup_tables.cpp'))
    def __init__(self, model, lookup_params=DEFAULT_LOOKUP_PARAMETERS):
        """ Initialise a LookUpTables instance
        :param model: A :class:`cellmlmanip.Model` object.
        :param lookup_params: Optional collection of lists: [[<metadata tag>, mTableMins, mTableMaxs, mTableSteps]]
        """
        self._lookup_parameters = tuple({
            'metadata_tag': param[0],
            'mTableMins': param[1],
            'mTableMaxs': param[2],
            'mTableSteps': param[3],
            'table_used_in_methods': set(),
            'var': None,
            'lookup_epxrs': []
        } for param in lookup_params)
        self._model = model
        self._lookup_variables = set()
        self._lookup_table_expr = collections.OrderedDict()
        self._lookup_params_processed, self._lookup_params_printed = False, False

        self._method_printed = None

        for param in self._lookup_parameters:
            try:
                var = self._model.get_variable_by_ontology_term(
                    (OXMETA, param['metadata_tag']))
                self._lookup_variables.add(var)
                param['var'] = var
            except KeyError:
                LOGGER.warning('A lookup table was specified for ' +
                               param['metadata_tag'] +
                               ' but it is not tagged in the model, skipping!')
def _get_membrane_stimulus_current(model):
    """ Find the membrane_stimulus_current variable if it exists"""
    try:  # get membrane_stimulus_current
        return model.get_variable_by_ontology_term(
            (OXMETA, 'membrane_stimulus_current'))
    except KeyError:
        LOGGER.info('The model has no membrane_stimulus_current tagged.')
        return None
def _tag_ionic_vars(model):
    """ Get the ionic variables, defining the ionic derivatives"""
    # figure out the currents (by finding variables with the same units as the stimulus)
    # Only equations with the same (lhs) units as the STIMULUS_CURRENT are kept.
    # Also exclude membrane_stimulus_current variable itself, and default_stimulus equations (if model has those)
    # Manually recurse down the equation graph (bfs style) if no currents are found

    # If we don't have a stimulus_current we look for a set of default unit dimensions
    stimulus_unit_dims = [u.dimensionality for u in model.stimulus_units]
    if model.membrane_stimulus_current_orig is not None:
        stimulus_unit_dims = [
            model.membrane_stimulus_current_orig.units.dimensionality
        ] + stimulus_unit_dims

    stimulus_params = set()
    for tag, _, _ in STIM_PARAM_TAGS:
        try:
            stimulus_params.add(
                model.get_variable_by_ontology_term((OXMETA, tag)))
        except KeyError:
            pass  # doesn't need to have all params

    ionic_var_eqs = []
    for dim in stimulus_unit_dims:
        if len(ionic_var_eqs) > 0:
            break
        equations, old_equations = list(filter(None, [model.dvdt])), None
        while len(ionic_var_eqs) == 0 and old_equations != equations:
            old_equations = equations
            equations = get_equations_for(
                model,
                equations,
                recurse=False,
                filter_modifiable_parameters_lhs=False,
                optimise=False)
            ionic_var_eqs = \
                [eq for eq in equations for eq in equations
                 if eq.lhs not in (model.membrane_stimulus_current_orig, stimulus_params)
                 and model.units.evaluate_units(eq.lhs).dimensionality == dim and eq.lhs is not model.dvdt]

            equations = [eq.lhs for eq in equations]

    for eq in ionic_var_eqs:
        set_is_metadata(model, eq.lhs, 'ionic-current_chaste_codegen')

    assert len(model.dvdt_eq) <= 1, "Multiple dvdt equations found"
    if len(model.dvdt_eq) == 1:
        model.ionic_stimulus_sign = _stimulus_sign(model,
                                                   model.dvdt_eq[0].rhs, [],
                                                   stimulus_current=None)
    else:
        LOGGER.warning(
            model.name +
            ' has no ionic currents you may have trouble generating valid chaste code without.'
        )
        model.ionic_stimulus_sign = 1
def test_non_existing_cellml(caplog):
    """Test converting non-existing cellml file"""
    LOGGER.info('Testing non-existing cellml\n')

    testargs = ["chaste_codegen", "bla.cellml"]
    # Call commandline script
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    assert 'ERROR' in caplog.text
    assert "Could not find cellml file bla.cellml" in caplog.text
def test_script_load_non_existing_file(caplog):
    """Check non-existing metadata tags are ignored"""
    LOGGER.info('Testing loading a file that does not exist\n')
    model_file = "bla.txt"
    # Call commandline script
    testargs = ['chaste_codegen', model_file]

    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    print(caplog.text)
    assert 'ERROR' in caplog.text
    assert "Could not find cellml file bla.txt" in caplog.text
def test_script_version(capsys):
    """Test version number message"""
    LOGGER.info('Testing version for command line script\n')
    testargs = ["chaste_codegen", "--version"]
    with mock.patch.object(sys, 'argv', testargs):
        try:
            chaste_codegen()
        except SystemExit:
            pass  # We expect this to print usage and exit
        captured = capsys.readouterr()
        # compare to expected
        assert str(captured.out) == 'chaste_codegen ' + cg.__version__ + '\n', str(captured.out)
def test_script_load_non_cellml_file(caplog):
    """Check non-existing metadata tags are ignored"""
    LOGGER.info('Testing loading a file that is not a cellml file\n')
    model_file = os.path.join(TESTS_FOLDER, 'test_console_script_usage.txt')
    # Call commandline script
    testargs = ['chaste_codegen', model_file]

    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()

    assert 'ERROR' in caplog.text
    assert "Could not load cellml model:" in caplog.text
def test_script_RL_C_double_type(caplog):
    """Check error message"""
    LOGGER.info('Testing model with options --rush-larsen-C and --opt\n')
    model_name = 'aslanidi_Purkinje_model_2009'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    # Call commandline script
    testargs = ['chaste_codegen', model_file, '--rush-larsen-c', '--cvode']
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    assert 'ERROR' in caplog.text
    assert "--rush-larsen-labview and --rush-larsen-c cannot be used in combination with other model convertion types" \
        in caplog.text
def test_usage(capsys):
    """Test script usage message"""
    LOGGER.info('Testing illegal combination of options for jacobians on command line\n')
    testargs = ["chaste_codegen"]
    with mock.patch.object(sys, 'argv', testargs):
        try:
            chaste_codegen()
        except SystemExit:
            pass  # We expect this to print usage and exit
        captured = capsys.readouterr()
        # compare to expected
        expected = open(os.path.join(TESTS_FOLDER, 'test_console_script_usage.txt'), 'r').read()
        assert str(captured.err) == expected, str(captured.err)
def test_script_help(capsys):
    """Test help message"""
    LOGGER.info('Testing help for command line script\n')
    testargs = ["chaste_codegen", "-h"]
    with mock.patch.object(sys, 'argv', testargs):
        try:
            chaste_codegen()
        except SystemExit:
            pass  # We expect this to print usage and exit
        captured = capsys.readouterr()
        # compare to expected
        expected = open(os.path.join(TESTS_FOLDER, 'test_console_script_help.txt'), 'r').read()
        assert str(captured.out) == expected, str(captured.out)
def test_script_double_type_output2(caplog):
    """Convert multiple model types"""
    LOGGER.info('Testing multiple models\n')
    model_name = 'grandi_pasqualini_bers_2010_ss'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)

    testargs = ['chaste_codegen', '--cvode-data-clamp', '--backward-euler', model_file, '--dynamically-loadable']
    # Call commandline script
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    assert 'ERROR' in caplog.text
    assert "Only one model type may be specified if creating a dynamic library!" in caplog.text
def test_script_double_type_output(caplog):
    """Convert multiple model types"""
    LOGGER.info('Testing multiple models\n')
    model_name = 'grandi_pasqualini_bers_2010_ss'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)

    testargs = ['chaste_codegen', '--cvode-data-clamp', '--backward-euler', model_file, '-o', 'bla.cpp']
    # Call commandline script
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    assert 'ERROR' in caplog.text
    assert "-o cannot be used when multiple model types have been selected!" in caplog.text
def test_script_o_output_dif(caplog):
    """Convert a normal model via command line script"""
    LOGGER.info('Testing --show-output\n')
    model_name = 'grandi_pasqualini_bers_2010_ss'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)

    testargs = ["chaste_codegen", '--cvode-data-clamp', '--backward-euler', model_file, '--show-output',
                '-o', '/bla.cppp', '--output-dir', '/']
    # Call commandline script
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    assert 'ERROR' in caplog.text
    assert "-o and --output-dir cannot be used together!" in caplog.text
def test_script_double_show_output(capsys):
    """Convert a normal model via command line script"""
    LOGGER.info('Testing --show-output\n')
    model_name = 'grandi_pasqualini_bers_2010_ss'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')

    testargs = ["chaste_codegen", '--cvode-data-clamp', '--backward-euler', model_file, '--show-output']
    # Call commandline script
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
        captured = capsys.readouterr()
        output = str(captured.out)
        assert "grandi_pasqualini_bers_2010_ssCvodeDataClamp.cpp" in output
        assert "grandi_pasqualini_bers_2010_ssCvodeDataClamp.hpp" in output
        assert "grandi_pasqualini_bers_2010_ssBackwardEuler.hpp" in output
def test_script_lookup_table_wrong_args2(caplog):
    """Convert a model with custom lookup table"""
    LOGGER.info('Testing custom lookup tables,  for command line script\n')
    model_name = 'beeler_reuter_model_1977'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    outfile = 'beeler_reuter_model_1977_lookup_tables.cpp'
    # Call commandline script
    testargs = ['chaste_codegen', '--skip-singularity-fixes', model_file, '--opt', '-o', outfile,
                '--lookup-table', 'membrane_voltage', 'membrane_voltage', '199.9999', '0.01']

    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    assert 'ERROR' in caplog.text
    assert "Lookup tables are expecting the following 4 values: <metadata tag> min max step" in caplog.text
def test_script_RL_labview(tmp_path):
    """Convert a RushLarsen model type in labview output"""
    LOGGER.info('Testing model with options --rush-larsen-labview\n')
    tmp_path = str(tmp_path)
    model_name = 'aslanidi_Purkinje_model_2009'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    outfile = os.path.join(tmp_path, 'aslanidi_atrial_model_2009.txt')
    # Call commandline script
    testargs = ['chaste_codegen', model_file, '--rush-larsen-labview', '-o', outfile]
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    # Check output
    reference = os.path.join(os.path.join(TESTS_FOLDER), 'chaste_reference_models', 'RL_labview')
    compare_file_against_reference(os.path.join(reference, 'aslanidi_atrial_model_2009.txt'),
                                   os.path.join(tmp_path, 'aslanidi_atrial_model_2009.txt'))
def test_script_lookup_table_no_opt(caplog):
    """Convert a model with custom lookup table"""
    LOGGER.info('Testing custom lookup tables,  for command line script\n')
    model_name = 'beeler_reuter_model_1977'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    outfile = 'beeler_reuter_model_1977_lookup_tables.cpp'
    # Call commandline script
    testargs = ['chaste_codegen', model_file, '-o', outfile,
                '--lookup-table', 'membrane_voltage', '-150.0001', '199.9999', '0.01',
                '--lookup-table', 'cytosolic_calcium_concentration', '0.00001', '30.00001', '0.0001']

    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    assert 'ERROR' in caplog.text
    assert "Can only use lookup tables in combination with --opt" in caplog.text
def _get_membrane_capacitance(model):
    """ Find membrane_capacitance if the model has it and convert it to uF / uF_per_cm2 if necessary
        Try to convert the capacitance and converts it to appropriate units.
        see: https://chaste.cs.ox.ac.uk/trac/ticket/1364

        units converted to:
        Dimensions of current        Dimensions of capacitance
        amps per unit area           farads per unit area
        amps per unit capacitance    We don't care
        amps                         farads
    """
    try:
        capacitance = model.get_variable_by_ontology_term(
            (OXMETA, 'membrane_capacitance'))
    except KeyError:
        LOGGER.info('The model has no capacitance tagged.')
        return None

    try:
        capacitance = model.convert_variable(
            capacitance, model.conversion_units.get_unit('uF'),
            DataDirectionFlow.OUTPUT)
    except DimensionalityError:
        try:
            capacitance = model.convert_variable(
                capacitance, model.conversion_units.get_unit('uF_per_cm2'),
                DataDirectionFlow.OUTPUT)
        except DimensionalityError:
            pass

    # Check units match up with what is expected
    if model.membrane_stimulus_current_orig is not None:
        uA_dim = model.conversion_units.get_unit('uA').dimensionality
        uA_per_cm2_dim = model.conversion_units.get_unit(
            'uA_per_cm2').dimensionality
        uF_dim = model.conversion_units.get_unit('uF').dimensionality
        uF_per_cm2_dim = model.conversion_units.get_unit(
            'uF_per_cm2').dimensionality

        current_dim = model.membrane_stimulus_current_orig.units.dimensionality
        capac_dim = capacitance.units.dimensionality

        if (current_dim == uA_dim and not capac_dim == uF_dim) or \
                (current_dim == uA_per_cm2_dim and not capac_dim == uF_per_cm2_dim):
            LOGGER.warning(model.name +
                           ' The model has capacitance in incompatible units.')
    return capacitance
def _get_cytosolic_calcium_concentration_var(model, convert=True):
    """ Find the cytosolic_calcium_concentration variable if it exists"""
    try:
        calcium = model.get_variable_by_ontology_term(
            (OXMETA, 'cytosolic_calcium_concentration'))
        if not convert:
            return calcium
        calcium = model.convert_variable(
            calcium, model.conversion_units.get_unit('millimolar'),
            DataDirectionFlow.INPUT)
    except KeyError:
        LOGGER.info('The model has no cytosolic_calcium_concentration tagged.')
        return None
    except DimensionalityError:
        pass  # Conversion is optional
    annotate_if_not_statevar(
        model, calcium)  # If not state var annotate as appropriate
    return calcium
def test_script_cvode_jacobian(tmp_path):
    """Convert a CVODE model type with jacobian"""
    LOGGER.info('Testing model with options --cvode and -o for command line script\n')
    tmp_path = str(tmp_path)
    model_name = 'shannon_wang_puglisi_weber_bers_2004'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    outfile = os.path.join(tmp_path, 'dynamic_Shannon2004.cpp')
    # Call commandline script
    testargs = ['chaste_codegen', '--use-model-factory', '--skip-singularity-fixes', model_file, '--cvode',
                '-o', outfile, '--use-analytic-jacobian', '--dynamically-loadable']
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    # Check output
    reference = os.path.join(os.path.join(TESTS_FOLDER), 'chaste_reference_models', 'Cvode_with_jacobian')
    compare_file_against_reference(os.path.join(reference, 'dynamic_Shannon2004.hpp'),
                                   os.path.join(tmp_path, 'dynamic_Shannon2004.hpp'))
    compare_file_against_reference(os.path.join(reference, 'dynamic_Shannon2004.cpp'),
                                   os.path.join(tmp_path, 'dynamic_Shannon2004.cpp'))
def test_script_dynamic_BEopt(tmp_path):
    """Convert a BackwardsEuler model type"""
    LOGGER.info('Testing model with options --backward-euler, --dynamically-loadable, --opt for command line script\n')
    tmp_path = str(tmp_path)
    model_name = 'courtemanche_ramirez_nattel_1998'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    outfile = os.path.join(tmp_path, 'dynamic_courtemanche_ramirez_nattel_1998.cpp')
    # Call commandline script
    testargs = ['chaste_codegen', '--use-model-factory', '--skip-singularity-fixes', model_file, '--backward-euler',
                '--opt', '-o', outfile, '--dynamically-loadable']
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    # Check output
    reference = os.path.join(os.path.join(TESTS_FOLDER), 'chaste_reference_models', 'BEopt')
    compare_file_against_reference(os.path.join(reference, 'dynamic_courtemanche_ramirez_nattel_1998.hpp'),
                                   os.path.join(tmp_path, 'dynamic_courtemanche_ramirez_nattel_1998.hpp'))
    compare_file_against_reference(os.path.join(reference, 'dynamic_courtemanche_ramirez_nattel_1998.cpp'),
                                   os.path.join(tmp_path, 'dynamic_courtemanche_ramirez_nattel_1998.cpp'))
def test_script_dynamic_RL(tmp_path):
    """Convert a RushLarsen model type"""
    LOGGER.info('Testing model with options --rush-larsen, and --dynamically-loadable for command line script\n')
    tmp_path = str(tmp_path)
    model_name = 'livshitz_rudy_2007'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    outfile = os.path.join(tmp_path, 'dynamic_livshitz_rudy_2007.cpp')
    # Call commandline script
    testargs = ['chaste_codegen', '--skip-singularity-fixes', model_file, '--rush-larsen', '-o', outfile,
                '--dynamically-loadable']
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    # Check output
    reference = os.path.join(os.path.join(TESTS_FOLDER), 'chaste_reference_models', 'RL')
    compare_file_against_reference(os.path.join(reference, 'dynamic_livshitz_rudy_2007.hpp'),
                                   os.path.join(tmp_path, 'dynamic_livshitz_rudy_2007.hpp'))
    compare_file_against_reference(os.path.join(reference, 'dynamic_livshitz_rudy_2007.cpp'),
                                   os.path.join(tmp_path, 'dynamic_livshitz_rudy_2007.cpp'))
def test_script_GRL2Opt(tmp_path):
    """Convert a Generalised RushLarsen First Order Opt model type"""
    LOGGER.info('Testing model Generalised RushLarsen First Order Opt ,  for command line script\n')
    tmp_path = str(tmp_path)
    model_name = 'viswanathan_model_1999_epi'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    outfile = os.path.join(tmp_path, 'dynamic_viswanathan_model_1999_epi.cpp')
    # Call commandline script
    testargs = ['chaste_codegen', '--use-model-factory', '--skip-singularity-fixes', model_file, '--grl2',
                '--opt', '-o', outfile, '--dynamically-loadable']
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    # Check output
    reference = os.path.join(os.path.join(TESTS_FOLDER), 'chaste_reference_models', 'GRL2Opt')
    compare_file_against_reference(os.path.join(reference, 'dynamic_viswanathan_model_1999_epi.hpp'),
                                   os.path.join(tmp_path, 'dynamic_viswanathan_model_1999_epi.hpp'))
    compare_file_against_reference(os.path.join(reference, 'dynamic_viswanathan_model_1999_epi.cpp'),
                                   os.path.join(tmp_path, 'dynamic_viswanathan_model_1999_epi.cpp'))
def test_script_CVODE_DATA_CLAMP_modifiers(tmp_path):
    """Convert a CVODE with data clamp and modifiers model type with modifiers"""
    LOGGER.info('Testing model CVODE with data clamp ,  for command line script\n')
    tmp_path = str(tmp_path)
    model_name = 'shannon_wang_puglisi_weber_bers_2004'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    outfile = os.path.join(tmp_path, 'Shannon2004_with_modifiers.cpp')
    # Call commandline script
    testargs = ['chaste_codegen', '--use-model-factory', '--skip-singularity-fixes', model_file, '--cvode-data-clamp',
                '-o', outfile, '--use-modifiers']
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    # Check output
    reference = os.path.join(os.path.join(TESTS_FOLDER), 'chaste_reference_models', 'CVODE_DATA_CLAMP')
    compare_file_against_reference(os.path.join(reference, 'Shannon2004_with_modifiers.hpp'),
                                   os.path.join(tmp_path, 'Shannon2004_with_modifiers.hpp'))
    compare_file_against_reference(os.path.join(reference, 'Shannon2004_with_modifiers.cpp'),
                                   os.path.join(tmp_path, 'Shannon2004_with_modifiers.cpp'))
def test_script_cvode(tmp_path):
    """Convert a CVODE model type"""
    LOGGER.info('Testing model with options -t CVODE and -o for command line script\n')
    tmp_path = str(tmp_path)
    model_name = 'mahajan_shiferaw_2008'
    model_file = os.path.join(CELLML_FOLDER, model_name + '.cellml')
    assert os.path.isfile(model_file)
    outfile = os.path.join(tmp_path, 'dynamic_mahajan_shiferaw_2008.cpp')
    # Call commandline script
    testargs = ['chaste_codegen', '--skip-singularity-fixes', model_file, '--cvode', '-o', outfile,
                '--dynamically-loadable']
    with mock.patch.object(sys, 'argv', testargs):
        chaste_codegen()
    # Check output
    reference = os.path.join(os.path.join(TESTS_FOLDER), 'chaste_reference_models', 'Cvode')
    compare_file_against_reference(os.path.join(reference, 'dynamic_mahajan_shiferaw_2008.hpp'),
                                   os.path.join(tmp_path, 'dynamic_mahajan_shiferaw_2008.hpp'))
    compare_file_against_reference(os.path.join(reference, 'dynamic_mahajan_shiferaw_2008.cpp'),
                                   os.path.join(tmp_path, 'dynamic_mahajan_shiferaw_2008.cpp'))