Пример #1
0
    def test_get_all_phases_ML_phases(self, base_path):

        phase_names = ['init', 'MLstart', 'ML', 'HeIgnition']

        # -- 2 Mass loss phases both with wind and rlof mass loss --
        data, _ = fileio.read_compressed_track(base_path / 'test_data/M2.341_M1.782_P8.01_Z0.01412.h5',
                                               return_profiles=False)

        # when asking for n_ml_phases = 0, only 1 ML phase should be returned, directly as a np.where structure.
        phases = evolution_phases.get_all_phases(phase_names, data, 0)
        assert len(phases) == 4
        for name in phase_names:
            assert name in phases

        assert type(phases['ML']) == tuple, \
               "When passing n_ml_phases=0, the result should be a np.where type structure"
        assert type(phases['ML'][0]) == np.ndarray,\
               "When passing n_ml_phases=0, the result should be a np.where type structure"

        # when asking for n_ml_phases = 1, only 1 ML phase should be returned, BUT as a list
        phases = evolution_phases.get_all_phases(phase_names, data, 1)
        assert type(phases['ML']) == list
        assert len(phases['ML']) == 1
        assert type(phases['ML'][0]) == tuple
        assert type(phases['ML'][0][0]) == np.ndarray

        # when asking for n_ml_phases = 2, 2 ML phases should be returned as a list
        phases = evolution_phases.get_all_phases(phase_names, data, 2)
        assert type(phases['ML']) == list
        assert len(phases['ML']) == 2
        assert type(phases['ML'][0]) == tuple
        assert type(phases['ML'][0][0]) == np.ndarray
        assert type(phases['ML'][1]) == tuple
        assert type(phases['ML'][1][0]) == np.ndarray
Пример #2
0
    def test_count_ml_phases(self, base_path):

        # 1 ML phase
        data, _ = fileio.read_compressed_track(
            base_path / 'test_data/M0.789_M0.304_P20.58_Z0.h5')
        n_ml_phases = extract_mesa.count_ml_phases(data)
        assert n_ml_phases == 1

        # 2 separate ML phases
        data, _ = fileio.read_compressed_track(
            base_path / 'test_data/M2.341_M1.782_P8.01_Z0.01412.h5')
        n_ml_phases = extract_mesa.count_ml_phases(data)
        assert n_ml_phases == 2

        # 1 ML phases and 3 other ML phases due to wind mass loss which should not get counted.
        data, _ = fileio.read_compressed_track(
            base_path / 'test_data/M1.276_M1.140_P333.11_Z0.h5')
        n_ml_phases = extract_mesa.count_ml_phases(data)
        assert n_ml_phases == 1
Пример #3
0
def data():
    data, _, profiles = fileio.read_compressed_track(
        base_path / 'test_data/M1.080_M0.502_P192.67_Z0.01129.h5',
        return_profiles=True)

    stable, ce_age = common_envelope.is_stable(data,
                                               criterion='Mdot',
                                               value=-2)
    data = data[data['age'] <= ce_age]
    return data
Пример #4
0
def test_apply_ce():
    data, _ = fileio.read_compressed_track(
        base_path / 'test_data/M1.205_M0.413_P505.12_Z0.h5')
    stable, ce_age = common_envelope.is_stable(data,
                                               criterion='J_div_Jdot_div_P',
                                               value=10)
    data = data[data['age'] <= ce_age]

    data = common_envelope.apply_ce(data, ce_formalism='iben_tutukov1984')

    assert data['period_days'][-1] == pytest.approx(25.62, abs=0.01)
    assert data['binary_separation'][-1] == pytest.approx(38.2451, abs=1e-4)
    assert data['star_1_mass'][-1] == pytest.approx(0.4477, abs=1e-4)
    assert data['envelope_mass'][-1] == 0
    assert data['star_2_mass'][-1] == pytest.approx(0.4278, abs=1e-4)
    assert data['mass_ratio'][-1] == pytest.approx(1.0465, abs=1e-4)
    assert data['rl_1'][-1] == pytest.approx(14.6426, abs=1e-4)
    assert data['rl_2'][-1] == pytest.approx(14.3415, abs=1e-4)
    assert data['CE_phase'][-1] == 1
    assert data['CE_phase'][-2] == 1
    assert data['CE_phase'][-3] == 0

    data, _, profiles = fileio.read_compressed_track(
        base_path / 'test_data/M1.080_M0.502_P192.67_Z0.01129.h5',
        return_profiles=True)
    stable, ce_age = common_envelope.is_stable(data,
                                               criterion='Mdot',
                                               value=-2)
    data = data[data['age'] <= ce_age]

    data = common_envelope.apply_ce(data,
                                    profiles=profiles,
                                    ce_formalism='dewi_tauris2000',
                                    a_th=0.5)

    assert data['binary_separation'][-1] == pytest.approx(6.394841,
                                                          abs=0.000001)
    assert data['star_1_mass'][-1] == pytest.approx(0.38572328, abs=0.000001)
    assert data['envelope_mass'][-1] > 0

    with pytest.raises(ValueError):
        data = common_envelope.apply_ce(data, ce_formalism='uk_formalism')
Пример #5
0
def test_check_error_flags(base_path):
    # check no errors
    data, _ = fileio.read_compressed_track(
        base_path /
        'test_data/error_models/M0.851_M0.305_P358.92_Z0.00129_no_problems.h5')
    error_flags = evolution_errors.check_error_flags(data, 'log_g_upper_limit')
    assert error_flags == []

    # check max_model error
    error_flags = evolution_errors.check_error_flags(data, 'max_model_number')
    assert 1 in error_flags

    # check accretor overflow error
    error_flags = evolution_errors.check_error_flags(
        data, 'accretor_overflow_terminate')
    assert 2 in error_flags

    # check ML and He ignition error
    data, _ = fileio.read_compressed_track(
        base_path /
        'test_data/error_models/M2.407_M0.432_P1.72_Z0.00706_He_ignition_problem.h5'
    )
    error_flags = evolution_errors.check_error_flags(data, '')
    assert 4 in error_flags

    # Check HeIgnition but no HeCoreBurning error
    data, _ = fileio.read_compressed_track(
        base_path /
        'test_data/error_models/M1.490_M1.380_P144.55_Z0.01427_Jz1.000_HeIgnition_but_no_Coreburning.h5'
    )
    error_flags = evolution_errors.check_error_flags(data, '')
    assert 4 in error_flags

    # check CO core formation error
    data, _ = fileio.read_compressed_track(
        base_path /
        'test_data/error_models/M1.699_M1.401_P260.07_Z0.02489_Jz1.000_HeCoreBurning_doesnt_finish.h5'
    )
    error_flags = evolution_errors.check_error_flags(data, '')
    assert 5 in error_flags
Пример #6
0
def test_is_stable():
    data, _ = fileio.read_compressed_track(
        base_path / 'test_data/M1.205_M0.413_P505.12_Z0.h5')

    stable, ce_age, ce_mn = common_envelope.is_stable(data,
                                                      criterion='Mdot',
                                                      value=-3,
                                                      return_model_number=True)
    assert stable is False
    assert ce_age == pytest.approx(5179376593.6, abs=0.1)
    assert ce_mn == 11928

    stable, ce_age, ce_mn = common_envelope.is_stable(data,
                                                      criterion='delta',
                                                      value=0.03,
                                                      return_model_number=True)
    assert stable is False
    assert ce_age == pytest.approx(5179376616.1, abs=0.1)
    assert ce_mn == 12057

    stable, ce_age, ce_mn = common_envelope.is_stable(
        data, criterion='J_div_Jdot_div_P', value=10, return_model_number=True)
    assert stable is False
    assert ce_age == pytest.approx(5179376617.0, abs=0.1)
    assert ce_mn == 12108

    stable, ce_age, ce_mn = common_envelope.is_stable(
        data,
        criterion='M_div_Mdot_div_P',
        value=100,
        return_model_number=True)
    assert stable is False
    assert ce_age == pytest.approx(5179376614.6, abs=0.1)
    assert ce_mn == 12021

    stable, ce_age, ce_mn = common_envelope.is_stable(data,
                                                      criterion='R_div_SMA',
                                                      value=0.5,
                                                      return_model_number=True)
    assert stable is False
    assert ce_age == pytest.approx(5179376602.9, abs=0.1)
    assert ce_mn == 11946

    with pytest.raises(ValueError):
        stable, ce_age = common_envelope.is_stable(data,
                                                   criterion='uk_criterion',
                                                   value=0.5)
Пример #7
0
    def test_extract_parameters(self, base_path):
        #TODO: improve this test case and add more checks

        # HB star with core and shell He burning
        data, _ = fileio.read_compressed_track(
            base_path / 'test_data/M1.276_M1.140_P333.11_Z0.h5')

        parameters = [
            'star_1_mass__init', 'period_days__final', 'rl_1__max',
            'rl_1__HeIgnition', 'age__ML__diff', 'he_core_mass__ML__rate',
            'star_1_mass__lg_mstar_dot_1_max'
        ]

        res = extract_mesa.extract_parameters(data, parameters)
        res = {k: v for k, v in zip(parameters, res)}

        assert res['star_1_mass__init'] == data['star_1_mass'][0]
        assert res['period_days__final'] == data['period_days'][-1]
        assert res['rl_1__max'] == np.max(data['rl_1'])
        #assert np.isnan(res['rl_1__HeIgnition'])

        # a1 = data['age'][data['lg_mstar_dot_1'] > -10][0]
        # a2 = data['age'][(data['age'] > a1) & (data['lg_mstar_dot_1'] <= -10)][0]
        # s = np.where((data['age'] >= a1) & (data['age'] <= a2))
        # assert res['age__ML__diff'] == data['age'][s][-1] - data['age'][s][0]

        # assert res['he_core_mass__ML__rate'] == (data['he_core_mass'][s][-1] - data['he_core_mass'][s][0]) / \
        #                                         (data['age'][s][-1] - data['age'][s][0])

        assert res['rl_1__HeIgnition'] == pytest.approx(152.8606, abs=0.0001)

        assert res['star_1_mass__lg_mstar_dot_1_max'] == pytest.approx(
            0.5205, abs=0.0001)

        phase_flags = ['ML', 'HeCoreBurning', 'He-WD']
        res = extract_mesa.extract_parameters(data,
                                              parameters,
                                              phase_flags=phase_flags)
        res = {k: v for k, v in zip(parameters + phase_flags, res)}

        assert res['ML'] is True
        assert res['HeCoreBurning'] is True
        assert res['He-WD'] is False
Пример #8
0
def test_dewi_tauris2000(data):
    data, _, profiles = fileio.read_compressed_track(
        base_path / 'test_data/M1.080_M0.502_P192.67_Z0.01129.h5',
        return_profiles=True)

    stable, ce_age = common_envelope.is_stable(data,
                                               criterion='Mdot',
                                               value=-2)
    data = data[data['age'] <= ce_age]

    profile = profiles['profile_1_mdot-2.0']

    af, M1_final = common_envelope.dewi_tauris2000(data, profile, a_th=0)

    assert af == pytest.approx(4.8597844860, abs=0.00001)
    assert M1_final == pytest.approx(0.38321120, abs=0.00001)

    af, M1_final = common_envelope.dewi_tauris2000(data, profile, a_th=1.0)

    assert af == pytest.approx(9.17843738836, abs=0.00001)
    assert M1_final == pytest.approx(0.39115816046997015, abs=0.00001)
Пример #9
0
    def test_extract_parameters_ml(self, base_path):
        """
        Test that the ML phases are correctly returned.

        n_ml_phases = 0:
            result = [<val>, <val>]

        n_ml_phases = 1:
            result = [<val>, [<val>]]

        n_ml_phases = 2:
            result = [<val>, [<val>, <val>]]
        """
        parameters = ['period_days__init', 'period_days__ML']

        data, _ = fileio.read_compressed_track(
            base_path / 'test_data/M2.341_M1.782_P8.01_Z0.01412.h5')

        result = extract_mesa.extract_parameters(data,
                                                 parameters=parameters,
                                                 phase_flags=[],
                                                 n_ml_phases=0)
        assert len(result) == 2
        assert type(result[1]) != list

        result = extract_mesa.extract_parameters(data,
                                                 parameters=parameters,
                                                 phase_flags=[],
                                                 n_ml_phases=1)
        assert len(result) == 2
        assert type(result[1]) == list
        assert len(result[1]) == 1

        result = extract_mesa.extract_parameters(data,
                                                 parameters=parameters,
                                                 phase_flags=[],
                                                 n_ml_phases=2)
        assert len(result) == 2
        assert type(result[1]) == list
        assert len(result[1]) == 2
Пример #10
0
    def test_ml_phase(self, base_path):

        # -- 1 Mass loss phase consisting of a long wind ml phase and a short RLOF phase --
        data, _ = fileio.read_compressed_track(base_path / 'test_data/M0.814_M0.512_P260.18_Z0.h5',
                                               return_profiles=False)

        # test returned ages
        a1, a2 = evolution_phases.ML(data, mltype='rlof', return_age=True)
        assert a1 == pytest.approx(12316067393.354174, abs=0.001)
        assert a2 == pytest.approx(12316911998.086807, abs=0.001)

        a1, a2 = evolution_phases.ML(data, mltype='wind', return_age=True)
        assert a1 == pytest.approx(12283352829.773027, abs=0.001)
        assert a2 == pytest.approx(12316994026.181108, abs=0.001)

        a1, a2 = evolution_phases.ML(data, mltype='total', return_age=True)
        assert a1 == pytest.approx(12283352829.773027, abs=0.001)
        assert a2 == pytest.approx(12316994026.181108, abs=0.001)

        # check that ML returns same start and end as MLstart and MLend
        a1_ml, a2_ml = evolution_phases.ML(data, mltype='rlof', return_age=True)
        a1_start = evolution_phases.MLstart(data, mltype='rlof', return_age=True)
        a2_end = evolution_phases.MLend(data, mltype='rlof', return_age=True)
        assert a1_ml == a1_start
        assert a2_ml == a2_end

        s_ml = evolution_phases.ML(data, mltype='rlof', return_age=False)
        s_start = evolution_phases.MLstart(data, mltype='rlof', return_age=False)
        s_end = evolution_phases.MLend(data, mltype='rlof', return_age=False)
        assert data['model_number'][s_ml][0] == data['model_number'][s_start][0]
        assert data['model_number'][s_ml][-1] == data['model_number'][s_end][0]

        # -- 4 Mass loss phases: first with both rlof and wind, the other 3 only wind --
        data, _ = fileio.read_compressed_track(base_path / 'test_data/M1.276_M1.140_P333.11_Z0.h5',
                                               return_profiles=False)

        # test returned ages
        ages = evolution_phases.ML(data, mltype='rlof', return_age=True, return_multiple=True)
        assert len(ages) == 1
        a1, a2 = ages[0]
        assert a1 == pytest.approx(3461120558.9109983, abs=0.001)
        assert a2 == pytest.approx(3462394022.0863924, abs=0.001)

        ages = evolution_phases.ML(data, mltype='wind', return_age=True, return_multiple=True)
        assert len(ages) == 4
        a1, a2 = ages[0]
        assert a1 == pytest.approx(3440285863.557928, abs=0.001)
        assert a2 == pytest.approx(3462498981.825389, abs=0.001)

        ages = evolution_phases.ML(data, mltype='total', return_age=True, return_multiple=True)
        assert len(ages) == 4
        a1, a2 = ages[1]
        assert a1 == pytest.approx(3462515931.0189767, abs=0.001)
        assert a2 == pytest.approx(3463059499.121973, abs=0.001)
        a1, a2 = ages[2]
        assert a1 == pytest.approx(3572455931.1686773, abs=0.001)
        assert a2 == pytest.approx(3576048979.7216263, abs=0.001)
        a1, a2 = ages[3]
        assert a1 == pytest.approx(3576114881.085102, abs=0.001)
        assert a2 == pytest.approx(3576115123.911062, abs=0.001)


        # -- 2 Mass loss phases both with wind and rlof mass loss --
        data, _ = fileio.read_compressed_track(base_path / 'test_data/M2.341_M1.782_P8.01_Z0.01412.h5',
                                               return_profiles=False)

        # RLOF
        ages = evolution_phases.ML(data, mltype='rlof', return_age=True, return_multiple=True)
        assert len(ages) == 2
        a1, a2 = ages[0]
        assert a1 == pytest.approx(607563161.616631, abs=0.001)
        assert a2 == pytest.approx(617932607.0240884, abs=0.001)
        a1, a2 = ages[1]
        assert a1 == pytest.approx(970323465.489477, abs=0.001)
        assert a2 == pytest.approx(975582471.8171717, abs=0.001)

        # Wind
        ages = evolution_phases.ML(data, mltype='wind', return_age=True, return_multiple=True)
        assert len(ages) == 2
        a1, a2 = ages[0]
        assert a1 == pytest.approx(612221727.4877452, abs=0.001)
        assert a2 == pytest.approx(619258765.4160738, abs=0.001)
        a1, a2 = ages[1]
        assert a1 == pytest.approx(971574716.1957985, abs=0.001)
        assert a2 == pytest.approx(976109951.0074742, abs=0.001)

        # Total
        ages = evolution_phases.ML(data, mltype='total', return_age=True, return_multiple=True)
        assert len(ages) == 2
        a1, a2 = ages[0]
        assert a1 == pytest.approx(607563161.616631, abs=0.001)
        assert a2 == pytest.approx(619258765.4160738, abs=0.001)
        a1, a2 = ages[1]
        assert a1 == pytest.approx(970323465.489477, abs=0.001)
        assert a2 == pytest.approx(976109951.0074742, abs=0.001)
Пример #11
0
    def test_get_all_phases(self, base_path):
        phase_names = ['init', 'final', 'MS', 'MSstart', 'MSend', 'RGB', 'RGBstart', 'RGBend', 'MLstart', 'MLend',
                       'ML', 'CE', 'CEstart', 'CEend', 'HeIgnition', 'HeCoreBurning', 'HeShellBurning']

        # test checking if all parameters are available.
        data, _ = fileio.read_compressed_track(base_path / 'test_data/M0.789_M0.304_P20.58_Z0.h5', return_profiles=False)
        data = data[['age', 'period_days']]

        with pytest.raises(ValueError):
             phases = evolution_phases.get_all_phases(['MS'], data)

        # stable model without He ignition and struggles at the end
        # age of the last 1470 time steps doesn't change!
        data, _ = fileio.read_compressed_track(base_path / 'test_data/M0.789_M0.304_P20.58_Z0.h5', return_profiles=False)
        phases = evolution_phases.get_all_phases(phase_names, data)

        assert data['model_number'][phases['init']][0] == 3
        assert data['model_number'][phases['final']][0] == 30000
        assert data['model_number'][phases['MS']][0] == 3
        assert data['model_number'][phases['MS']][-1] == 114
        assert data['model_number'][phases['MSstart']][0] == 3
        assert data['model_number'][phases['MSend']][0] == 114
        assert data['model_number'][phases['RGB']][0] == 114
        assert data['model_number'][phases['RGB']][-1] == 948
        assert data['model_number'][phases['RGBstart']][0] == 114
        assert data['model_number'][phases['RGBend']][0] == 948
        assert data['model_number'][phases['MLstart']][0] == 936
        assert data['model_number'][phases['MLend']][0] == 30000
        assert data['model_number'][phases['ML']][0] == 936
        assert data['model_number'][phases['ML']][-1] == 30000
        assert phases['HeIgnition'] is None

        # stable model without He ignition
        data, _ = fileio.read_compressed_track(base_path / 'test_data/M0.814_M0.512_P260.18_Z0.h5', return_profiles=False)
        phases = evolution_phases.get_all_phases(phase_names, data)

        assert data['model_number'][phases['RGB']][0] == 111
        assert data['model_number'][phases['RGB']][-1] == 6570
        assert data['model_number'][phases['RGBstart']][0] == 111
        assert data['model_number'][phases['RGBend']][0] == 6570
        assert data['model_number'][phases['ML']][0] == 6006
        assert data['model_number'][phases['ML']][-1] == 7098
        assert phases['HeIgnition'] is None
        assert phases['HeCoreBurning'] is None
        assert phases['HeShellBurning'] is None

        # stable model with degenerate He ignition but issues in the He burning phase, and a double ML phase
        data, _ = fileio.read_compressed_track(base_path / 'test_data/M1.125_M0.973_P428.86_Z0.h5', return_profiles=False)
        phases = evolution_phases.get_all_phases(phase_names, data)

        assert data['model_number'][phases['ML']][0] == 8970
        assert data['model_number'][phases['ML']][-1] == 14406
        assert data['model_number'][phases['HeIgnition']][0] == 19947
        assert phases['HeCoreBurning'] is None
        assert phases['HeShellBurning'] is None
        assert phases['CE'] is None
        assert phases['CEstart'] is None
        assert phases['CEend'] is None

        # CE model
        data, _ = fileio.read_compressed_track(base_path / 'test_data/M1.205_M0.413_P505.12_Z0.h5', return_profiles=False)
        data = data[data['model_number'] <= 12111]
        data['CE_phase'][-1] = 1
        data['CE_phase'][-2] = 1
        phases = evolution_phases.get_all_phases(phase_names, data)

        assert data['model_number'][phases['ML']][0] == 11295
        assert data['model_number'][phases['ML']][-1] == 12111
        assert data['model_number'][phases['CE']][0] == 12108
        assert data['model_number'][phases['CE']][1] == 12111
        assert data['model_number'][phases['CEstart']][0] == 12108
        assert data['model_number'][phases['CEend']][0] == 12111
        assert phases['HeIgnition'] is None
        assert phases['HeCoreBurning'] is None
        assert phases['HeShellBurning'] is None

        # HB star with core and shell He burning
        data, _ = fileio.read_compressed_track(base_path / 'test_data/M1.276_M1.140_P333.11_Z0.h5', return_profiles=False)
        phases = evolution_phases.get_all_phases(phase_names, data)

        assert data['model_number'][phases['ML']][0] == 8823
        assert data['model_number'][phases['ML']][-1] == 11892
        assert data['model_number'][phases['HeIgnition']][0] == 11709
        assert data['model_number'][phases['HeCoreBurning']][0] == 12492
        assert data['model_number'][phases['HeCoreBurning']][-1] == 12594
        assert data['model_number'][phases['HeShellBurning']][0] == 12597
        assert data['model_number'][phases['HeShellBurning']][-1] == 14268

        # sdB star with core and shell He burning
        data, _ = fileio.read_compressed_track(base_path / 'test_data/M1.269_M1.229_P133.46_Z0.00320.h5',
                                            return_profiles=False)
        phases = evolution_phases.get_all_phases(['sdA', 'sdB', 'sdO'], data)

        assert phases['sdA'] is None
        assert data['model_number'][phases['sdB']][0] == 22608
        assert data['model_number'][phases['sdB']][-1] == 22689
        assert phases['sdO'] is None

        a1, a2 = evolution_phases.HeCoreBurning(data, return_age=True)

        assert a1 == pytest.approx(3232213210.6798477, abs=0.001)
        assert a2 == pytest.approx(3316814816.4952917, abs=0.001)
Пример #12
0
def extract_mesa(file_list,
                 stability_criterion='J_div_Jdot_div_P',
                 stability_limit=10,
                 n_ml_phases=0,
                 ce_formalism='iben_tutukov1984',
                 ce_parameters={'al': 1},
                 ce_profile_name=None,
                 parameters=[],
                 phase_flags=[],
                 extra_info_parameters=[],
                 add_setup_pars_to_result=True,
                 verbose=False,
                 flatten_output=False,
                 **kwargs):

    parameters, column_names = _process_parameters(parameters)

    extra_info_parameters, extra_names = _process_parameters(
        extra_info_parameters)

    columns = ['path', 'stability', 'n_ML_phases'
               ] + extra_names + column_names + phase_flags
    if add_setup_pars_to_result:
        columns += [
            'stability_criterion', 'stability_limit', 'ce_profile_name',
            'ce_formalism', 'ce_parameters'
        ]
    columns += ['error_flags']
    results = []

    # check if the same extraction parameters are used for all models, or if specific parameters are already
    # provided in the files list
    file_list = process_file_list(file_list,
                                  stability_criterion=stability_criterion,
                                  stability_limit=stability_limit,
                                  ce_formalism=ce_formalism,
                                  ce_parameters=ce_parameters,
                                  ce_profile_name=ce_profile_name,
                                  verbose=verbose)

    for i, model in file_list.iterrows():

        if verbose:
            print(i, model['path'])

        # 1: Get the data
        try:
            data, extra_info, profiles = fileio.read_compressed_track(
                model['path'], return_profiles=True)
        except Exception as e:
            if verbose:
                print(e)
            continue

        # 2: check for stability and cut data at start of CE
        stable, ce_age = common_envelope.is_stable(
            data,
            criterion=model['stability_criterion'],
            value=model['stability_limit'])
        stability = 'stable'

        if not stable:
            # if the model is not stable, cut of the evolution at the start of the CE as anything after than
            # is non physical anyway.
            data = data[data['age'] <= ce_age]

            if ce_profile_name is not None:
                try:
                    profiles = profiles[model['ce_profile_name']]
                except Exception:
                    # todo: deal correctly with the missing profile!
                    print('CE: profile missing')
            data = common_envelope.apply_ce(data,
                                            profiles=profiles,
                                            ce_formalism=model['ce_formalism'],
                                            **model['ce_parameters'])

            # check if CE is ejected or if the system is a merger or a contact binary
            s = np.where((data['star_2_radius'] >= 0.99 * data['rl_2'])
                         & (data['star_1_radius'] >= 0.99 * data['rl_1']))

            if data['binary_separation'][-1] <= 0:
                stability = 'merger'
                print('CE: Merged')
            elif len(data['model_number'][s]) > 0:
                stability = 'contact'
                print('CE: Contact')
            else:
                stability = 'CE'

        # 3: extract some standard parameters: Path, stability and nr of ML phases.
        pars = [model['path'].split('/')[-1]]
        pars += [stability, count_ml_phases(data)]

        # 4: add the extra info to the output
        for p in extra_info_parameters:
            pars.append(extra_info[p])

        # 5: extract the requested parameters & 6: add the requested phase flags
        extracted_pars = extract_parameters(data,
                                            parameters,
                                            phase_flags,
                                            n_ml_phases=n_ml_phases)
        pars += extracted_pars

        # 7: Add the extraction setup parameters if requested
        if add_setup_pars_to_result:
            setup_pars = [
                model['stability_criterion'], model['stability_limit'],
                model['ce_profile_name'], model['ce_formalism'],
                model['ce_parameters']
            ]
            pars += setup_pars

        # 8: todo: check for some possible errors and flag them
        error_flags = evolution_errors.check_error_flags(
            data, extra_info['termination_code'])
        pars.append(error_flags)

        results.append(pars)

    results = pd.DataFrame(results, columns=columns)

    if flatten_output:
        # go over all columns. If a column contains a list instead of a value flatten that column
        results = _flatten_dataframe(results, n_ml_phases)

    return results