def test_thermochemical_error_with_multiple_T_X_points(datasets_db):
    """Multiple temperature and composition datapoints in a dataset for a mixing phase should be successful."""
    datasets_db.insert(CU_MG_SM_MIX_T_X_FCC_A1)

    dbf = Database(CU_MG_TDB)
    error = calculate_thermochemical_error(dbf, ['CU', 'MG', 'VA'], list(dbf.phases.keys()), datasets_db)
    assert np.isclose(float(error), -31830.303030303032, atol=0.01)
def test_thermochemical_error_with_multiple_X_points(datasets_db):
    """Multiple composition datapoints in a dataset for a mixing phase should be successful."""
    datasets_db.insert(CU_MG_CPM_MIX_X_HCP_A3)

    dbf = Database(CU_MG_TDB)
    error = calculate_thermochemical_error(dbf, ['CU','MG','VA'], list(dbf.phases.keys()), datasets_db)
    assert np.isclose(float(error), -520.0, atol=0.01)
def test_thermochemical_error_with_multiple_T_points(datasets_db):
    """Multiple temperature datapoints in a dataset for a stoichiometric comnpound should be successful."""
    datasets_db.insert(CU_MG_HM_MIX_T_CUMG2)

    dbf = Database(CU_MG_TDB)
    error = calculate_thermochemical_error(dbf, ['CU','MG','VA'], list(dbf.phases.keys()), datasets_db)
    assert np.isclose(float(error), -3672.727272727273, atol=0.01)
Beispiel #4
0
def test_thermochemical_error_for_mixing_entropy_error_is_excess_only(
        datasets_db):
    """Tests that error in mixing entropy data is excess only (the ideal part is removed)."""
    # If this fails, make sure the ideal mixing contribution is removed.
    phase_models = {
        "components": ["AL", "B"],
        "phases": {
            "LIQUID": {
                "sublattice_model": [["AL", "B"]],
                "sublattice_site_ratios": [1]
            },
            "FCC_A1": {
                "sublattice_model": [["AL", "B"]],
                "sublattice_site_ratios": [1]
            }
        }
    }

    dataset_excess_mixing = {
        "components": ["AL", "B"],
        "phases": ["FCC_A1"],
        "solver": {
            "sublattice_site_ratios": [1],
            "sublattice_occupancies": [[[0.5, 0.5]]],
            "sublattice_configurations": [[["AL", "B"]]],
            "mode": "manual"
        },
        "conditions": {
            "P": 101325,
            "T": 298.15
        },
        "output": "SM_MIX",
        "values": [[[10]]],
        "excluded_model_contributions": ["idmix"]
    }
    datasets_db.insert(dataset_excess_mixing)

    dbf = generate_parameters(phase_models, datasets_db, 'SGTE91', 'linear')
    assert dbf.elements == {'AL', 'B'}
    assert set(dbf.phases.keys()) == {'LIQUID', 'FCC_A1'}
    assert len(dbf._parameters.search(where('parameter_type') == 'L')) == 1
    phases = list(dbf.phases.keys())
    comps = list(dbf.elements)

    # the error should be exactly 0 because we are only fitting to one point
    # the dataset is excess only
    zero_error_prob = scipy.stats.norm(loc=0, scale=0.2).logpdf(
        0.0)  # SM weight = 0.2
    # Explicitly pass parameters={} to not try fitting anything
    thermochemical_data = get_thermochemical_data(dbf,
                                                  comps,
                                                  phases,
                                                  datasets_db,
                                                  symbols_to_fit=[])
    error = calculate_thermochemical_error(dbf, comps, thermochemical_data)
    assert np.isclose(error, zero_error_prob, atol=1e-6)
Beispiel #5
0
def lnprob(
    params,
    comps=None,
    dbf=None,
    phases=None,
    datasets=None,
    symbols_to_fit=None,
    phase_models=None,
    scheduler=None,
    callables=None,
    thermochemical_callables=None,
):
    """
    Returns the error from multiphase fitting as a log probability.
    """
    starttime = time.time()
    parameters = {
        param_name: param
        for param_name, param in zip(symbols_to_fit, params)
    }
    try:
        multi_phase_error = calculate_zpf_error(dbf,
                                                comps,
                                                phases,
                                                datasets,
                                                phase_models,
                                                parameters=parameters,
                                                callables=callables)
    except (ValueError, LinAlgError) as e:
        multi_phase_error = [np.inf]
    multi_phase_error = [
        np.inf if np.isnan(x) else x**2 for x in multi_phase_error
    ]
    multi_phase_error = -np.sum(multi_phase_error)
    single_phase_error = calculate_thermochemical_error(
        dbf,
        comps,
        phases,
        datasets,
        parameters,
        phase_models=phase_models,
        callables=thermochemical_callables)
    actvity_error = calculate_activity_error(dbf,
                                             comps,
                                             phases,
                                             datasets,
                                             parameters=parameters,
                                             phase_models=phase_models,
                                             callables=callables)
    total_error = multi_phase_error + single_phase_error + actvity_error
    logging.debug(
        'Single phase error: {:0.2f}. Multi phase error: {:0.2f}. Activity Error: {:0.2f}. Total error: {:0.2f}'
        .format(single_phase_error, multi_phase_error, actvity_error,
                total_error))
    logging.debug('lnprob time: {}'.format(time.time() - starttime))
    return np.array(total_error, dtype=np.float64)
Beispiel #6
0
def test_datasets_convert_thermochemical_string_values_producing_correct_value(
        datasets_db):
    """Strings where floats are expected should give correct answers for thermochemical datasets"""
    datasets_db.insert(
        clean_dataset(CU_MG_DATASET_THERMOCHEMICAL_STRING_VALUES))

    dbf = Database(CU_MG_TDB)
    error = calculate_thermochemical_error(dbf, ['CU', 'MG', 'VA'],
                                           list(dbf.phases.keys()),
                                           datasets_db)
    assert np.isclose(float(error), -3672.727272727273, atol=0.01)
Beispiel #7
0
def test_thermochemical_error_with_multiple_T_X_points(datasets_db):
    """Multiple temperature and composition datapoints in a dataset for a mixing phase should be successful."""
    datasets_db.insert(CU_MG_SM_MIX_T_X_FCC_A1)

    dbf = Database(CU_MG_TDB)
    phases = list(dbf.phases.keys())
    comps = ['CU', 'MG', 'VA']
    thermochemical_data = get_thermochemical_data(dbf, comps, phases,
                                                  datasets_db)
    error = calculate_thermochemical_error(dbf, comps, thermochemical_data)
    assert np.isclose(float(error), -3282497.2380024833, rtol=1e-6)
Beispiel #8
0
def test_thermochemical_error_with_multiple_T_points(datasets_db):
    """Multiple temperature datapoints in a dataset for a stoichiometric comnpound should be successful."""
    datasets_db.insert(CU_MG_HM_MIX_T_CUMG2)

    dbf = Database(CU_MG_TDB)
    phases = list(dbf.phases.keys())
    comps = ['CU', 'MG', 'VA']
    thermochemical_data = get_thermochemical_data(dbf, comps, phases,
                                                  datasets_db)
    error = calculate_thermochemical_error(dbf, comps, thermochemical_data)
    assert np.isclose(error, -14.287293263253728, rtol=1e-6)
def test_mixing_energies_are_fit(datasets_db):
    """Tests that given mixing energy data, the excess parameter is fit."""
    phase_models = {
        "components": ["AL", "B"],
        "phases": {
            "LIQUID": {
                "sublattice_model": [["AL", "B"]],
                "sublattice_site_ratios": [1]
            },
            "FCC_A1": {
                "sublattice_model": [["AL", "B"]],
                "sublattice_site_ratios": [1]
            }
        }
    }

    dataset_excess_mixing = {
        "components": ["AL", "B"],
        "phases": ["FCC_A1"],
        "solver": {
            "sublattice_site_ratios": [1],
            "sublattice_occupancies": [[[0.5, 0.5]]],
            "sublattice_configurations": [[["AL", "B"]]],
            "mode": "manual"
        },
        "conditions": {
            "P": 101325,
            "T": 298.15
        },
        "output": "HM_MIX",
        "values": [[[-10000]]]
    }
    datasets_db.insert(dataset_excess_mixing)

    dbf = generate_parameters(phase_models, datasets_db, 'SGTE91', 'linear')

    assert dbf.elements == {'AL', 'B'}
    assert set(dbf.phases.keys()) == {'LIQUID', 'FCC_A1'}
    assert len(dbf._parameters.search(where('parameter_type') == 'L')) == 1
    assert dbf.symbols['VV0000'] == -40000

    # check that read/write is ok
    read_dbf = dbf.from_string(dbf.to_string(fmt='tdb'), fmt='tdb')
    assert read_dbf.elements == {'AL', 'B'}
    assert set(read_dbf.phases.keys()) == {'LIQUID', 'FCC_A1'}
    assert len(
        read_dbf._parameters.search(where('parameter_type') == 'L')) == 1

    # the error should be exactly 0 because we are only fitting to one point
    from espei.error_functions import calculate_thermochemical_error
    assert calculate_thermochemical_error(read_dbf, sorted(dbf.elements),
                                          sorted(dbf.phases.keys()),
                                          datasets_db) == 0
Beispiel #10
0
def test_thermochemical_error_with_multiple_X_points(datasets_db):
    """Multiple composition datapoints in a dataset for a mixing phase should be successful."""
    datasets_db.insert(CU_MG_CPM_MIX_X_HCP_A3)

    dbf = Database(CU_MG_TDB)
    phases = list(dbf.phases.keys())
    comps = ['CU', 'MG', 'VA']
    thermochemical_data = get_thermochemical_data(dbf, comps, phases,
                                                  datasets_db)
    error = calculate_thermochemical_error(dbf, comps, thermochemical_data)

    assert np.isclose(error, -4061.119001241541, rtol=1e-6)
Beispiel #11
0
def test_thermochemical_error_for_mixing_entropy_error_is_excess_only(
        datasets_db):
    """Tests that error in mixing entropy data is excess only (the ideal part is removed)."""
    # If this fails, make sure the ideal mixing contribution is removed.
    phase_models = {
        "components": ["AL", "B"],
        "phases": {
            "LIQUID": {
                "sublattice_model": [["AL", "B"]],
                "sublattice_site_ratios": [1]
            },
            "FCC_A1": {
                "sublattice_model": [["AL", "B"]],
                "sublattice_site_ratios": [1]
            }
        }
    }

    dataset_excess_mixing = {
        "components": ["AL", "B"],
        "phases": ["FCC_A1"],
        "solver": {
            "sublattice_site_ratios": [1],
            "sublattice_occupancies": [[[0.5, 0.5]]],
            "sublattice_configurations": [[["AL", "B"]]],
            "mode": "manual"
        },
        "conditions": {
            "P": 101325,
            "T": 298.15
        },
        "output": "SM_MIX",
        "values": [[[10]]]
    }
    datasets_db.insert(dataset_excess_mixing)

    dbf = generate_parameters(phase_models, datasets_db, 'SGTE91', 'linear')
    assert dbf.elements == {'AL', 'B'}
    assert set(dbf.phases.keys()) == {'LIQUID', 'FCC_A1'}
    assert len(dbf._parameters.search(where('parameter_type') == 'L')) == 1

    # the error should be exactly 0 because we are only fitting to one point
    # the dataset is excess only
    from espei.error_functions import calculate_thermochemical_error
    assert calculate_thermochemical_error(dbf, sorted(dbf.elements),
                                          sorted(dbf.phases.keys()),
                                          datasets_db) == 0
Beispiel #12
0
    def predict(params, **ctx):
        """
        Calculate lnprob = lnlike + lnprior
        """
        logging.debug('Parameters - {}'.format(params))

        # lnprior
        prior_rvs = ctx['prior_rvs']
        lnprior_multivariate = [rv.logpdf(theta) for rv, theta in zip(prior_rvs, params)]
        logging.debug('Priors: {}'.format(lnprior_multivariate))
        lnprior = np.sum(lnprior_multivariate)
        if np.isneginf(lnprior):
            # It doesn't matter what the likelihood is. We can skip calculating it to save time.
            logging.log(TRACE, 'Proposal - lnprior: {:0.4f}, lnlike: {}, lnprob: {:0.4f}'.format(lnprior, np.nan, lnprior))
            return lnprior

        # lnlike
        parameters = {param_name: param for param_name, param in zip(ctx['symbols_to_fit'], params)}
        zpf_kwargs = ctx.get('zpf_kwargs')
        activity_kwargs = ctx.get('activity_kwargs')
        thermochemical_kwargs = ctx.get('thermochemical_kwargs')
        starttime = time.time()
        if zpf_kwargs is not None:
            try:
                multi_phase_error = calculate_zpf_error(parameters=parameters, **zpf_kwargs)
            except (ValueError, np.linalg.LinAlgError) as e:
                raise e
                print(e)
                multi_phase_error = -np.inf
        else:
            multi_phase_error = 0
        if activity_kwargs is not None and False:
            actvity_error = calculate_activity_error(parameters=parameters, **activity_kwargs)
        else:
            actvity_error = 0
        if thermochemical_kwargs is not None:
            single_phase_error = calculate_thermochemical_error(parameters=parameters, **thermochemical_kwargs)
        else:
            single_phase_error = 0
        total_error = multi_phase_error + single_phase_error + actvity_error
        logging.log(TRACE, 'Likelihood - {:0.2f}s - Thermochemical: {:0.3f}. ZPF: {:0.3f}. Activity: {:0.3f}. Total: {:0.3f}.'.format(time.time() - starttime, single_phase_error, multi_phase_error, actvity_error, total_error))
        lnlike = np.array(total_error, dtype=np.float64)

        lnprob = lnprior + lnlike
        logging.log(TRACE, 'Proposal - lnprior: {:0.4f}, lnlike: {:0.4f}, lnprob: {:0.4f}'.format(lnprior, lnlike, lnprob))
        return lnprob
Beispiel #13
0
 def predict(params, ctx):
     parameters = {
         param_name: param
         for param_name, param in zip(ctx['symbols_to_fit'], params)
     }
     zpf_kwargs = ctx.get('zpf_kwargs')
     activity_kwargs = ctx.get('activity_kwargs')
     thermochemical_kwargs = ctx.get('thermochemical_kwargs')
     starttime = time.time()
     if zpf_kwargs is not None:
         try:
             multi_phase_error = calculate_zpf_error(parameters=parameters,
                                                     **zpf_kwargs)
         except (ValueError, np.linalg.LinAlgError) as e:
             raise e
             print(e)
             multi_phase_error = -np.inf
     else:
         multi_phase_error = 0
     if activity_kwargs is not None:
         actvity_error = calculate_activity_error(parameters=parameters,
                                                  **activity_kwargs)
     else:
         actvity_error = 0
     if thermochemical_kwargs is not None:
         single_phase_error = calculate_thermochemical_error(
             parameters=parameters, **thermochemical_kwargs)
     else:
         single_phase_error = 0
     total_error = multi_phase_error + single_phase_error + actvity_error
     logging.log(
         TRACE,
         'Likelihood - {:0.2f}s - Thermochemical: {:0.3f}. ZPF: {:0.3f}. Activity: {:0.3f}. Total: {:0.3f}.'
         .format(time.time() - starttime, single_phase_error,
                 multi_phase_error, actvity_error, total_error))
     error = np.array(total_error, dtype=np.float64)
     return error
Beispiel #14
0
def test_mixing_energies_are_fit(datasets_db):
    """Tests that given mixing energy data, the excess parameter is fit."""
    phase_models = {
        "components": ["AL", "B"],
        "phases": {
            "LIQUID": {
                "sublattice_model": [["AL", "B"]],
                "sublattice_site_ratios": [1]
            },
            "FCC_A1": {
                "sublattice_model": [["AL", "B"]],
                "sublattice_site_ratios": [1]
            }
        }
    }

    dataset_excess_mixing = {
        "components": ["AL", "B"],
        "phases": ["FCC_A1"],
        "solver": {
            "sublattice_site_ratios": [1],
            "sublattice_occupancies": [[[0.5, 0.5]]],
            "sublattice_configurations": [[["AL", "B"]]],
            "mode": "manual"
        },
        "conditions": {
            "P": 101325,
            "T": 298.15
        },
        "output": "HM_MIX",
        "values": [[[-10000]]]
    }
    datasets_db.insert(dataset_excess_mixing)

    dbf = generate_parameters(phase_models, datasets_db, 'SGTE91', 'linear')

    assert dbf.elements == {'AL', 'B'}
    assert set(dbf.phases.keys()) == {'LIQUID', 'FCC_A1'}
    assert len(dbf._parameters.search(where('parameter_type') == 'L')) == 1
    assert dbf.symbols['VV0000'] == -40000

    # check that read/write is ok
    read_dbf = dbf.from_string(dbf.to_string(fmt='tdb'), fmt='tdb')
    assert read_dbf.elements == {'AL', 'B'}
    assert set(read_dbf.phases.keys()) == {'LIQUID', 'FCC_A1'}
    assert len(
        read_dbf._parameters.search(where('parameter_type') == 'L')) == 1

    from espei.error_functions import calculate_thermochemical_error, get_thermochemical_data
    # the error should be exactly 0 because we are only fitting to one point
    zero_error_prob = scipy.stats.norm(loc=0, scale=500.0).logpdf(
        0.0)  # HM weight = 500
    # Explicitly pass parameters={} to not try fitting anything
    thermochemical_data = get_thermochemical_data(dbf,
                                                  sorted(read_dbf.elements),
                                                  list(read_dbf.phases.keys()),
                                                  datasets_db,
                                                  symbols_to_fit=[])
    error = calculate_thermochemical_error(dbf, sorted(read_dbf.elements),
                                           thermochemical_data)
    assert np.isclose(error, zero_error_prob, atol=1e-6)