def test_export_import(): "Equivalence of Model using re-imported database." test_model = Model( Database.from_string(ALNIPT_DBF.to_string(fmt='tdb'), fmt='tdb'), ['PT', 'NI', 'VA'], 'FCC_L12') ref_model = Model(ALNIPT_DBF, ['NI', 'PT', 'VA'], 'FCC_L12') assert test_model == ref_model
def test_export_import(): "Equivalence of Model using re-imported database." test_model = Model( Database.from_string(ALCRNI_DBF.to_string(fmt='tdb'), fmt='tdb'), ['CR', 'NI'], 'L12_FCC') ref_model = Model(ALCRNI_DBF, ['CR', 'NI'], 'L12_FCC') assert test_model == ref_model
def test_instantiate_models_only_returns_desired_phases(): """instantiate_models should only return phases passed""" comps = ['AL', 'NI', 'VA'] phases = ['FCC_A1', 'LIQUID'] # models are overspecified w.r.t. phases too_many_phases = ['FCC_A1', 'LIQUID', 'AL3NI1'] too_many_models = { phase: Model(ALNIPT_DBF, comps, phase) for phase in too_many_phases } inst_mods = instantiate_models(ALNIPT_DBF, comps, phases, model=too_many_models) assert len(inst_mods) == len(phases) # models are underspecified w.r.t. phases too_few_phases = ['FCC_A1'] too_few_models = { phase: Model(ALNIPT_DBF, comps, phase) for phase in too_few_phases } inst_mods = instantiate_models(ALNIPT_DBF, comps, phases, model=too_few_models) assert len(inst_mods) == len(phases)
def test_reference_energy_of_unary_twostate_einstein_magnetic_is_zero(): """The referenced energy for the pure elements in a unary Model with twostate and Einstein contributions referenced to that phase is zero.""" m = Model(FEMN_DBF, ['FE', 'VA'], 'LIQUID') statevars = {v.T: 298.15, v.SiteFraction('LIQUID', 0, 'FE'): 1, v.SiteFraction('LIQUID', 1, 'VA'): 1} refstates = [ReferenceState(v.Species('FE'), 'LIQUID')] m.shift_reference_state(refstates, FEMN_DBF) check_output(m, statevars, 'GMR', 0.0)
def test_shift_reference_state_model_contribs_take_effect(): """Shift reference state with contrib_mods set adds contributions to the pure elements.""" TDB = """ ELEMENT A GRAPHITE 12.011 1054.0 5.7423 ! ELEMENT B BCC_A2 55.847 4489.0 27.2797 ! TYPE_DEFINITION % SEQ * ! PHASE TEST % 1 1 ! CONSTITUENT TEST : A,B: ! """ dbf = Database(TDB) comps = ['A', 'B'] phase = 'TEST' m = Model(dbf, comps, phase) refstates = [ReferenceState('A', phase), ReferenceState('B', phase)] m.shift_reference_state(refstates, dbf) statevars = { v.T: 298.15, v.P: 101325, v.SiteFraction(phase, 0, 'A'): 0.5, v.SiteFraction(phase, 0, 'B'): 0.5, } # ideal mixing should be present for GMR idmix_val = 2*0.5*np.log(0.5)*v.R*298.15 check_output(m, statevars, 'GMR', idmix_val) # shifting the reference state, adding an excess contribution # should see that addition in the output m.shift_reference_state(refstates, dbf, contrib_mods={'xsmix': S(1000.0)}) # each pure element contribution is has xsmix changed from 0 to 1 # At x=0.5, the reference xsmix energy is added to by 0.5*1000.0, which is # then subtracted out of the GM energy check_output(m, statevars, 'GMR', idmix_val-1000.0)
def test_non_zero_reference_mixing_enthalpy_for_va_interaction(): """The referenced mixing enthalpy for a Model with a VA interaction parameter is non-zero.""" m = Model(VA_INTERACTION_DBF, ['AL', 'VA'], 'FCC_A1') refstates = [ReferenceState('AL', 'FCC_A1')] m.shift_reference_state(refstates, VA_INTERACTION_DBF) statevars_pure = { v.T: 300, v.SiteFraction('FCC_A1', 0, 'AL'): 1, v.SiteFraction('FCC_A1', 0, 'VA'): 0, v.SiteFraction('FCC_A1', 1, 'VA'): 1 } check_output(m, statevars_pure, 'GMR', 0.0) statevars_mix = { v.T: 300, v.SiteFraction('FCC_A1', 0, 'AL'): 0.5, v.SiteFraction('FCC_A1', 0, 'VA'): 0.5, v.SiteFraction('FCC_A1', 1, 'VA'): 1 } # 4000.0 * 0.5=2000 +500 # (Y0VA doesn't contribute), but the VA endmember does (not referenced) check_output(m, statevars_mix, 'HMR', 2500.0) statevars_mix = { v.T: 300, v.SiteFraction('FCC_A1', 0, 'AL'): 0.5, v.SiteFraction('FCC_A1', 0, 'VA'): 0.5, v.SiteFraction('FCC_A1', 1, 'VA'): 1 } # 4000.0 * 0.5 (Y0VA doesn't contribute) check_output(m, statevars_mix, 'HM_MIX', 2000.0)
def test_constituents_not_in_model(): """Test that parameters with constituent arrays not matching the phase model are filtered out correctly""" dbf = Database(TDB_PARAMETER_FILTERS_TEST) modA = Model(dbf, ['A', 'B'], 'ALPHA') modB = Model(dbf, ['B', 'C'], 'BETA') assert v.SiteFraction('ALPHA', 0, 'B') not in modA.ast.free_symbols assert v.SiteFraction('BETA', 1, 'D') not in modB.ast.free_symbols assert v.SiteFraction('BETA', 2, 'C') not in modB.ast.free_symbols
def test_reference_energy_for_different_phase(): """The referenced energy a different phase should be correct.""" m = Model(ALFE_DBF, ['AL', 'FE', 'VA'], 'AL2FE') # formation reference states refstates = [ReferenceState('AL', 'FCC_A1'), ReferenceState('FE', 'BCC_A2')] m.shift_reference_state(refstates, ALFE_DBF) statevars = {v.T: 300, v.SiteFraction('AL2FE', 0, 'AL'): 1, v.SiteFraction('AL2FE', 1, 'FE'): 1} check_output(m, statevars, 'GMR', -28732.525) # Checked in Thermo-Calc
def test_negative_site_fraction(): "Raise exception on negative site fraction." check_energy(Model(DBF, ['CR', 'NI'], 'LIQUID'), \ {v.T: 300, v.SiteFraction('LIQUID', 0, 'CR'): -0.3, v.SiteFraction('LIQUID', 0, 'NI'): -2}, \ 5.52773e3, mode='sympy') check_energy(Model(DBF, ['CR', 'NI'], 'LIQUID'), \ {v.T: 300, v.SiteFraction('LIQUID', 0, 'CR'): -0.3, v.SiteFraction('LIQUID', 0, 'NI'): -2}, \ 5.52773e3, mode='numpy')
def test_case_sensitivity(): "Case sensitivity of component and phase names." check_energy(Model(DBF, ['Cr', 'nI'], 'Liquid'), \ {v.T: 300, v.SiteFraction('LIQUID', 0, 'CR'): 1e-12, v.SiteFraction('liquid', 0, 'ni'): 1}, \ 5.52773e3, mode='sympy') check_energy(Model(DBF, ['Cr', 'nI'], 'Liquid'), \ {v.T: 300, v.SiteFraction('LIQUID', 0, 'CR'): 1e-12, v.SiteFraction('liquid', 0, 'ni'): 1}, \ 5.52773e3, mode='numpy')
def test_binary_dilute(): "Dilute binary solution phase." check_energy(Model(DBF, ['CR', 'NI'], 'LIQUID'), \ {v.T: 300, v.SiteFraction('LIQUID', 0, 'CR'): 1e-12, v.SiteFraction('LIQUID', 0, 'NI'): 1.0-1e-12}, \ 5.52773e3, mode='sympy') check_energy(Model(DBF, ['CR', 'NI'], 'LIQUID'), \ {v.T: 300, v.SiteFraction('LIQUID', 0, 'CR'): 1e-12, v.SiteFraction('LIQUID', 0, 'NI'): 1.0-1e-12}, \ 5.52773e3, mode='numpy')
def test_zero_site_fraction(): "Energy of a binary solution phase where one site fraction is zero." check_energy(Model(DBF, ['CR', 'NI'], 'LIQUID'), \ {v.T: 300, v.SiteFraction('LIQUID', 0, 'CR'): 0, v.SiteFraction('LIQUID', 0, 'NI'): 1}, \ 5.52773e3, mode='sympy') check_energy(Model(DBF, ['CR', 'NI'], 'LIQUID'), \ {v.T: 300, v.SiteFraction('LIQUID', 0, 'CR'): 0, v.SiteFraction('LIQUID', 0, 'NI'): 1}, \ 5.52773e3, mode='numpy')
def test_model_eq(): "Model equality comparison." test_model = Model(ALCRNI_DBF, ['AL', 'CR'], 'L12_FCC') assert test_model == test_model assert test_model == Model(ALCRNI_DBF, ['AL', 'CR'], 'L12_FCC') assert not (test_model == Model(ALCRNI_DBF, ['NI', 'CR'], 'L12_FCC')) # literals which don't have __dict__ assert not (test_model == 42) assert not (test_model == None) assert not (42 == test_model) assert not (None == test_model)
def test_model_ne(): "Model inequality comparison." test_model = Model(ALCRNI_DBF, ['AL', 'CR'], 'L12_FCC') assert not (test_model != test_model) assert not (test_model != Model(ALCRNI_DBF, ['AL', 'CR'], 'L12_FCC')) assert test_model != Model(ALCRNI_DBF, ['NI', 'CR'], 'L12_FCC') # literals which don't have __dict__ assert test_model != 42 assert test_model != None assert 42 != test_model assert None != test_model
def test_reference_energy_of_unary_twostate_einstein_magnetic_is_zero(): """The referenced energy for the pure elements in a unary Model with twostate and Einstein contributions referenced to that phase is zero.""" m = Model(FEMN_DBF, ['FE', 'VA'], 'LIQUID') statevars = { v.T: 298.15, v.SiteFraction('LIQUID', 0, 'FE'): 1, v.SiteFraction('LIQUID', 1, 'VA'): 1 } refstates = [ReferenceState(v.Species('FE'), 'LIQUID')] m.shift_reference_state(refstates, FEMN_DBF) check_output(m, statevars, 'GMR', 0.0)
def test_ternary_rkm_solution(): "Solution phase with ternary interaction parameters." check_energy(Model(DBF, ['AL', 'CR', 'NI'], 'LIQUID'), \ {v.T: 1500, v.SiteFraction('LIQUID', 0, 'AL'): 0.44, v.SiteFraction('LIQUID', 0, 'CR'): 0.20, v.SiteFraction('LIQUID', 0, 'NI'): 0.36}, \ -1.16529e5, mode='sympy') check_energy(Model(DBF, ['AL', 'CR', 'NI'], 'LIQUID'), \ {v.T: 1500, v.SiteFraction('LIQUID', 0, 'AL'): 0.44, v.SiteFraction('LIQUID', 0, 'CR'): 0.20, v.SiteFraction('LIQUID', 0, 'NI'): 0.36}, \ -1.16529e5, mode='numpy')
def test_get_data_quantities_AL_NI_VA_interaction(): """Test that an interaction with a VA produces the correct data quantities We just have a template database that has the phase defined. We then hot patch the Model object to have the GM from the fixed model we printed out and the data we printed out. The hot patch is needed because this is formation enthalpy data and the model needs to have the lower order terms in composition. One possible issue is that the new GM in the fixed model does not have any individual contributions, so it cannot be used to test excluded model contributions. The only excluded model contributions in this data are idmix, but the property we are testing is HM_FORM, so the feature transform of the idmix property should be zero. """ # Hack the namespace to make the copy-pasted Gibbs energy function work from sympy import log, Piecewise T = v.T data = [{'components': ['AL', 'NI', 'VA'], 'phases': ['BCC_B2'], 'solver': {'mode': 'manual', 'sublattice_occupancies': [[1.0, [0.5, 0.5], 1.0], [1.0, [0.75, 0.25], 1.0]], 'sublattice_site_ratios': [0.5, 0.5, 1.0], 'sublattice_configurations': (('AL', ('NI', 'VA'), 'VA'), ('AL', ('NI', 'VA'), 'VA')), 'comment': 'BCC_B2 sublattice configuration (2SL)'}, 'conditions': {'P': 101325.0, 'T': np.array([300.])}, 'reference_state': 'SGTE91', 'output': 'HM_FORM', 'values': np.array([[[-40316.61077, -56361.58554]]]), 'reference': 'C. Jiang 2009 (constrained SQS)', 'excluded_model_contributions': ['idmix']}, {'components': ['AL', 'NI', 'VA'], 'phases': ['BCC_B2'], 'solver': {'mode': 'manual', 'sublattice_occupancies': [[1.0, [0.5, 0.5], 1.0], [1.0, [0.75, 0.25], 1.0]], 'sublattice_site_ratios': [0.5, 0.5, 1.0], 'sublattice_configurations': (('AL', ('NI', 'VA'), 'VA'), ('AL', ('NI', 'VA'), 'VA')), 'comment': 'BCC_B2 sublattice configuration (2SL)'}, 'conditions': {'P': 101325.0, 'T': np.array([300.])}, 'reference_state': 'SGTE91', 'output': 'HM_FORM', 'values': np.array([[[-41921.43363, -57769.49473]]]), 'reference': 'C. Jiang 2009 (relaxed SQS)', 'excluded_model_contributions': ['idmix']}] NEW_GM = 8.3145*T*(0.5*Piecewise((v.SiteFraction("BCC_B2", 0, "AL")*log(v.SiteFraction("BCC_B2", 0, "AL")), v.SiteFraction("BCC_B2", 0, "AL") > 1.0e-16), (0, True))/(0.5*v.SiteFraction("BCC_B2", 0, "AL") + 0.5*v.SiteFraction("BCC_B2", 0, "NI") + 0.5*v.SiteFraction("BCC_B2", 1, "AL") + 0.5*v.SiteFraction("BCC_B2", 1, "NI")) + 0.5*Piecewise((v.SiteFraction("BCC_B2", 0, "NI")*log(v.SiteFraction("BCC_B2", 0, "NI")), v.SiteFraction("BCC_B2", 0, "NI") > 1.0e-16), (0, True))/(0.5*v.SiteFraction("BCC_B2", 0, "AL") + 0.5*v.SiteFraction("BCC_B2", 0, "NI") + 0.5*v.SiteFraction("BCC_B2", 1, "AL") + 0.5*v.SiteFraction("BCC_B2", 1, "NI")) + 0.5*Piecewise((v.SiteFraction("BCC_B2", 0, "VA")*log(v.SiteFraction("BCC_B2", 0, "VA")), v.SiteFraction("BCC_B2", 0, "VA") > 1.0e-16), (0, True))/(0.5*v.SiteFraction("BCC_B2", 0, "AL") + 0.5*v.SiteFraction("BCC_B2", 0, "NI") + 0.5*v.SiteFraction("BCC_B2", 1, "AL") + 0.5*v.SiteFraction("BCC_B2", 1, "NI")) + 0.5*Piecewise((v.SiteFraction("BCC_B2", 1, "AL")*log(v.SiteFraction("BCC_B2", 1, "AL")), v.SiteFraction("BCC_B2", 1, "AL") > 1.0e-16), (0, True))/(0.5*v.SiteFraction("BCC_B2", 0, "AL") + 0.5*v.SiteFraction("BCC_B2", 0, "NI") + 0.5*v.SiteFraction("BCC_B2", 1, "AL") + 0.5*v.SiteFraction("BCC_B2", 1, "NI")) + 0.5*Piecewise((v.SiteFraction("BCC_B2", 1, "NI")*log(v.SiteFraction("BCC_B2", 1, "NI")), v.SiteFraction("BCC_B2", 1, "NI") > 1.0e-16), (0, True))/(0.5*v.SiteFraction("BCC_B2", 0, "AL") + 0.5*v.SiteFraction("BCC_B2", 0, "NI") + 0.5*v.SiteFraction("BCC_B2", 1, "AL") + 0.5*v.SiteFraction("BCC_B2", 1, "NI")) + 0.5*Piecewise((v.SiteFraction("BCC_B2", 1, "VA")*log(v.SiteFraction("BCC_B2", 1, "VA")), v.SiteFraction("BCC_B2", 1, "VA") > 1.0e-16), (0, True))/(0.5*v.SiteFraction("BCC_B2", 0, "AL") + 0.5*v.SiteFraction("BCC_B2", 0, "NI") + 0.5*v.SiteFraction("BCC_B2", 1, "AL") + 0.5*v.SiteFraction("BCC_B2", 1, "NI")) + Piecewise((v.SiteFraction("BCC_B2", 2, "VA")*log(v.SiteFraction("BCC_B2", 2, "VA")), v.SiteFraction("BCC_B2", 2, "VA") > 1.0e-16), (0, True))/(0.5*v.SiteFraction("BCC_B2", 0, "AL") + 0.5*v.SiteFraction("BCC_B2", 0, "NI") + 0.5*v.SiteFraction("BCC_B2", 1, "AL") + 0.5*v.SiteFraction("BCC_B2", 1, "NI"))) + (45262.9*v.SiteFraction("BCC_B2", 0, "AL")*v.SiteFraction("BCC_B2", 0, "NI")*v.SiteFraction("BCC_B2", 1, "AL")*v.SiteFraction("BCC_B2", 2, "VA") + 45262.9*v.SiteFraction("BCC_B2", 0, "AL")*v.SiteFraction("BCC_B2", 1, "AL")*v.SiteFraction("BCC_B2", 1, "NI")*v.SiteFraction("BCC_B2", 2, "VA"))/(0.5*v.SiteFraction("BCC_B2", 0, "AL") + 0.5*v.SiteFraction("BCC_B2", 0, "NI") + 0.5*v.SiteFraction("BCC_B2", 1, "AL") + 0.5*v.SiteFraction("BCC_B2", 1, "NI")) + (1.0*v.SiteFraction("BCC_B2", 0, "AL")*v.SiteFraction("BCC_B2", 1, "AL")*v.SiteFraction("BCC_B2", 2, "VA")*Piecewise((10083 - 4.813*T, (T >= 298.15) & (T < 2900.0)), (0, True)) + v.SiteFraction("BCC_B2", 0, "AL")*v.SiteFraction("BCC_B2", 1, "NI")*v.SiteFraction("BCC_B2", 2, "VA")*(9.52839e-8*T**3 + 0.00123463*T**2 + 0.000871898*T*log(T) + 1.31471*T - 64435.3 + 23095.2/T) + v.SiteFraction("BCC_B2", 0, "AL")*v.SiteFraction("BCC_B2", 1, "VA")*v.SiteFraction("BCC_B2", 2, "VA")*(10.0*T + 16432.5) + v.SiteFraction("BCC_B2", 0, "NI")*v.SiteFraction("BCC_B2", 1, "AL")*v.SiteFraction("BCC_B2", 2, "VA")*(9.52839e-8*T**3 + 0.00123463*T**2 + 0.000871898*T*log(T) + 1.31471*T - 64435.3 + 23095.2/T) + 1.0*v.SiteFraction("BCC_B2", 0, "NI")*v.SiteFraction("BCC_B2", 1, "NI")*v.SiteFraction("BCC_B2", 2, "VA")*Piecewise((8715.084 - 3.556*T, (T >= 298.15) & (T < 3000.0)), (0, True)) + 32790.6*v.SiteFraction("BCC_B2", 0, "NI")*v.SiteFraction("BCC_B2", 1, "VA")*v.SiteFraction("BCC_B2", 2, "VA") + v.SiteFraction("BCC_B2", 0, "VA")*v.SiteFraction("BCC_B2", 1, "AL")*v.SiteFraction("BCC_B2", 2, "VA")*(10.0*T + 16432.5) + 32790.6*v.SiteFraction("BCC_B2", 0, "VA")*v.SiteFraction("BCC_B2", 1, "NI")*v.SiteFraction("BCC_B2", 2, "VA"))/(0.5*v.SiteFraction("BCC_B2", 0, "AL") + 0.5*v.SiteFraction("BCC_B2", 0, "NI") + 0.5*v.SiteFraction("BCC_B2", 1, "AL") + 0.5*v.SiteFraction("BCC_B2", 1, "NI")) dbf = Database("""$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $ Date: 2019-12-08 18:05 $ Components: AL, NI, VA $ Phases: BCC_B2 $ Generated by brandon (pycalphad 0.8.1.post1) $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ ELEMENT AL FCC_A1 26.982 4577.3 28.322 ! ELEMENT NI FCC_A1 58.69 4787.0 29.796 ! ELEMENT VA VACUUM 0.0 0.0 0.0 ! TYPE_DEFINITION % SEQ * ! DEFINE_SYSTEM_DEFAULT ELEMENT 2 ! DEFAULT_COMMAND DEFINE_SYSTEM_ELEMENT VA ! PHASE BCC_B2 % 3 0.5 0.5 1 ! CONSTITUENT BCC_B2 :AL,NI,VA:AL,NI,VA:VA: ! """) mod = Model(dbf, ['AL', 'NI', 'VA'], 'BCC_B2') dd = {ky: 0.0 for ky in mod.models.keys()} dd['GM'] = NEW_GM mod.models = dd print(mod.HM) config_tup = (('AL',), ('NI', 'VA'), ('VA',)) calculate_dict = get_prop_samples(data, config_tup) sample_condition_dicts = _get_sample_condition_dicts(calculate_dict, list(map(len, config_tup))) qty = get_data_quantities('HM_FORM', mod, [0], data, sample_condition_dicts) print(qty) assert np.all(np.isclose([-6254.7802775, -5126.1206475, -7458.3974225, -6358.04118875], qty))
def test_pure_numpy(): "Pure component end-members in numpy mode." check_energy(Model(DBF, ['AL'], 'LIQUID'), \ {v.T: 2000, v.SiteFraction('LIQUID', 0, 'AL'): 1}, \ -1.28565e5, mode='numpy') check_energy(Model(DBF, ['AL'], 'B2'), \ {v.T: 1400, v.SiteFraction('B2', 0, 'AL'): 1, v.SiteFraction('B2', 1, 'AL'): 1}, \ -6.57639e4, mode='numpy') check_energy(Model(DBF, ['AL'], 'L12_FCC'), \ {v.T: 800, v.SiteFraction('L12_FCC', 0, 'AL'): 1, v.SiteFraction('L12_FCC', 1, 'AL'): 1}, \ -3.01732e4, mode='numpy')
def test_complex_infinity_can_build_callables_successfully(): """Test that functions that containing complex infinity can be built with codegen.""" mod = Model(C_FE_DBF, ['C'], 'DIAMOND_A4') mod_vars = [v.N, v.P, v.T] + mod.site_fractions # Test builds functions only, since functions takes about 1 second to run. # Both lambda and llvm backends take a few seconds to build the derivatives # and are probably unnecessary to test. assert zoo in list(mod.GM.atoms()) build_functions(mod.GM, mod_vars, include_obj=True, include_grad=False, include_hess=False) int_cons = mod.get_internal_constraints() build_constraint_functions(mod_vars, int_cons)
def test_changing_model_ast_also_changes_mixing_energy(): """If a models contribution is modified, the mixing energy should update accordingly.""" m = Model(CUMG_DBF, ['CU', 'MG', 'VA'], 'CU2MG') m.models['mag'] = 1000 statevars = { v.T: 300, v.SiteFraction('CU2MG', 0, 'CU'): 1, v.SiteFraction('CU2MG', 0, 'MG'): 0, v.SiteFraction('CU2MG', 1, 'CU'): 0, v.SiteFraction('CU2MG', 1, 'MG'): 1, } check_output(m, statevars, 'GM_MIX', 1000) m.reference_model.models['mag'] = 1000 check_output(m, statevars, 'GM_MIX', 0)
def test_build_functions_options(): """The correct SymEngine backend can be chosen for build_functions""" mod = Model(ALNIPT_DBF, ['AL'], 'LIQUID') int_cons = mod.get_internal_constraints() backend = 'lambda' fs_lambda = build_functions(mod.GM, mod.GM.free_symbols, include_obj=True, func_options={'backend': backend}, include_grad=True, grad_options={'backend': backend}, include_hess=True, hess_options={'backend': backend}) assert isinstance(fs_lambda.func, LambdaDouble) assert isinstance(fs_lambda.grad, LambdaDouble) assert isinstance(fs_lambda.hess, LambdaDouble) cfs_lambda = build_constraint_functions(mod.GM.free_symbols, int_cons, func_options={'backend': backend}, jac_options={'backend': backend}, hess_options={'backend': backend}) assert isinstance(cfs_lambda.cons_func, LambdaDouble) assert isinstance(cfs_lambda.cons_jac, LambdaDouble) assert isinstance(cfs_lambda.cons_hess, LambdaDouble) backend = 'llvm' fs_llvm = build_functions(mod.GM, mod.GM.free_symbols, include_obj=True, func_options={'backend': backend}, include_grad=True, grad_options={'backend': backend}, include_hess=True, hess_options={'backend': backend}) print(fs_llvm.func) print(fs_lambda.func) assert isinstance(fs_llvm.func, LLVMDouble) assert isinstance(fs_llvm.grad, LLVMDouble) assert isinstance(fs_llvm.hess, LLVMDouble) cfs_llvm = build_constraint_functions(mod.GM.free_symbols, int_cons, func_options={'backend': backend}, jac_options={'backend': backend}, hess_options={'backend': backend}) assert isinstance(cfs_llvm.cons_func, LLVMDouble) assert isinstance(cfs_llvm.cons_jac, LLVMDouble) assert isinstance(cfs_llvm.cons_hess, LLVMDouble)
def _get_interaction_predicted_values(dbf, comps, phase_name, configuration, output): mod = Model(dbf, comps, phase_name) mod.models['idmix'] = 0 # TODO: better reference state handling endpoints = endmembers_from_interaction(configuration) first_endpoint = _translate_endmember_to_array(endpoints[0], mod.ast.atoms(v.SiteFraction)) second_endpoint = _translate_endmember_to_array(endpoints[1], mod.ast.atoms(v.SiteFraction)) grid = np.linspace(0, 1, num=100) point_matrix = grid[None].T * second_endpoint + (1 - grid)[None].T * first_endpoint # TODO: Real temperature support point_matrix = point_matrix[None, None] predicted_values = calculate( dbf, comps, [phase_name], output=output, T=298.15, P=101325, points=point_matrix, model=mod)[output].values.flatten() return grid, predicted_values
def test_magnetic_reference_energy_is_zero(): """The referenced energy binary magnetic Model is zero.""" m = Model(CRFE_DBF, ['CR', 'FE', 'VA'], 'BCC_A2') refstates = [ReferenceState('CR', 'BCC_A2'), ReferenceState('FE', 'BCC_A2')] m.shift_reference_state(refstates, CRFE_DBF) statevars_FE = {v.T: 300, v.SiteFraction('BCC_A2', 0, 'CR'): 0, v.SiteFraction('BCC_A2', 0, 'FE'): 1, v.SiteFraction('BCC_A2', 1, 'VA'): 1} check_output(m, statevars_FE, 'GMR', 0.0) statevars_CR = {v.T: 300, v.SiteFraction('BCC_A2', 0, 'CR'): 1, v.SiteFraction('BCC_A2', 0, 'FE'): 0, v.SiteFraction('BCC_A2', 1, 'VA'): 1} check_output(m, statevars_CR, 'GMR', 0.0)
def test_binary_magnetic_ordering(): "Two-component phase with IHJ magnetic model and ordering." # ordered case check_energy(Model(DBF, ['CR', 'NI'], 'L12_FCC'), \ {v.T: 300, v.SiteFraction('L12_FCC', 0, 'CR'): 4.86783e-2, v.SiteFraction('L12_FCC', 0, 'NI'): 9.51322e-1, v.SiteFraction('L12_FCC', 1, 'CR'): 9.33965e-1, v.SiteFraction('L12_FCC', 1, 'NI'): 6.60348e-2}, \ -9.23953e3, mode='sympy') check_energy(Model(DBF, ['CR', 'NI'], 'L12_FCC'), \ {v.T: 300, v.SiteFraction('L12_FCC', 0, 'CR'): 4.86783e-2, v.SiteFraction('L12_FCC', 0, 'NI'): 9.51322e-1, v.SiteFraction('L12_FCC', 1, 'CR'): 9.33965e-1, v.SiteFraction('L12_FCC', 1, 'NI'): 6.60348e-2}, \ -9.23953e3, mode='numpy')
def test_binary_magnetic(): "Two-component phase with IHJ magnetic model." # disordered case check_energy(Model(DBF, ['CR', 'NI'], 'L12_FCC'), \ {v.T: 500, v.SiteFraction('L12_FCC', 0, 'CR'): 0.33, v.SiteFraction('L12_FCC', 0, 'NI'): 0.67, v.SiteFraction('L12_FCC', 1, 'CR'): 0.33, v.SiteFraction('L12_FCC', 1, 'NI'): 0.67}, \ -1.68840e4, mode='sympy') check_energy(Model(DBF, ['CR', 'NI'], 'L12_FCC'), \ {v.T: 500, v.SiteFraction('L12_FCC', 0, 'CR'): 0.33, v.SiteFraction('L12_FCC', 0, 'NI'): 0.67, v.SiteFraction('L12_FCC', 1, 'CR'): 0.33, v.SiteFraction('L12_FCC', 1, 'NI'): 0.67}, \ -1.68840e4, mode='numpy')
def test_changing_model_ast_also_changes_mixing_energy(): """If a models contribution is modified, the mixing energy should update accordingly.""" m = Model(CUMG_DBF, ['CU', 'MG', 'VA'], 'CU2MG') m.models['mag'] = 1000 statevars = { v.T: 300, v.SiteFraction('CU2MG', 0, 'CU'): 1, v.SiteFraction('CU2MG', 0, 'MG'): 0, v.SiteFraction('CU2MG', 1, 'CU'): 0, v.SiteFraction('CU2MG', 1, 'MG'): 1, } check_output(m, statevars, 'GM_MIX', 1000) m.endmember_reference_model.models['mag'] = 1000 check_output(m, statevars, 'GM_MIX', 0)
def test_reference_energy_for_different_phase(): """The referenced energy a different phase should be correct.""" m = Model(ALFE_DBF, ['AL', 'FE', 'VA'], 'AL2FE') # formation reference states refstates = [ ReferenceState('AL', 'FCC_A1'), ReferenceState('FE', 'BCC_A2') ] m.shift_reference_state(refstates, ALFE_DBF) statevars = { v.T: 300, v.SiteFraction('AL2FE', 0, 'AL'): 1, v.SiteFraction('AL2FE', 1, 'FE'): 1 } check_output(m, statevars, 'GMR', -28732.525) # Checked in Thermo-Calc
def test_ternary_symmetric_param(): "Generate the other two ternary parameters if only the zeroth is specified." check_energy(Model(DBF, ['AL', 'CR', 'NI'], 'FCC_A1'), \ {v.T: 300, v.SiteFraction('FCC_A1', 0, 'AL'): 1.97135e-1, v.SiteFraction('FCC_A1', 0, 'CR'): 1.43243e-2, v.SiteFraction('FCC_A1', 0, 'NI'): 7.88541e-1}, -37433.794, mode='sympy')
def test_incompatible_model_instance_raises(): "Calculate raises when an incompatible Model instance built with a different phase is passed." comps = ['AL', 'CR', 'NI'] phase_name = 'L12_FCC' mod = Model(DBF, comps, 'LIQUID') # Model instance does not match the phase with pytest.raises(ValueError): calculate(DBF, comps, phase_name, T=1400.0, output='_fail_', model=mod)
def test_single_model_instance_raises(): "Calculate raises when a single Model instance is passed with multiple phases." comps = ['AL', 'CR', 'NI'] phase_name = 'L12_FCC' mod = Model(DBF, comps, 'L12_FCC') # Model instance does not match the phase with pytest.raises(ValueError): calculate(DBF, comps, ['LIQUID', 'L12_FCC'], T=1400.0, output='_fail_', model=mod)
def test_binary_xiong_twostate_einstein(): "Phase with Xiong magnetic, two-state and Einstein energy contributions." femn_dbf = Database(FEMN_TDB) mod = Model(femn_dbf, ['FE', 'MN', 'VA'], 'LIQUID') check_energy(mod, { v.T: 10, v.SiteFraction('LIQUID', 0, 'FE'): 1, v.SiteFraction('LIQUID', 0, 'MN'): 0, v.SiteFraction('LIQUID', 1, 'VA'): 1 }, 10158.591, mode='sympy') check_energy(mod, { v.T: 300, v.SiteFraction('LIQUID', 0, 'FE'): 0.3, v.SiteFraction('LIQUID', 0, 'MN'): 0.7, v.SiteFraction('LIQUID', 1, 'VA'): 1 }, 4200.8435, mode='sympy') check_energy(mod, { v.T: 1500, v.SiteFraction('LIQUID', 0, 'FE'): 0.8, v.SiteFraction('LIQUID', 0, 'MN'): 0.2, v.SiteFraction('LIQUID', 1, 'VA'): 1 }, -86332.217, mode='sympy')
def test_order_disorder_interstital_sublattice_validation(): # Check that substitutional/interstitial sublattices that break our # assumptions raise errors DBF_OrderDisorder_broken = Database(""" ELEMENT VA VACUUM 0.0000E+00 0.0000E+00 0.0000E+00 ! ELEMENT A DISORD 0.0000E+00 0.0000E+00 0.0000E+00 ! ELEMENT B DISORD 0.0000E+00 0.0000E+00 0.0000E+00 ! ELEMENT C DISORD 0.0000E+00 0.0000E+00 0.0000E+00 ! DEFINE_SYSTEM_DEFAULT ELEMENT 2 ! DEFAULT_COMMAND DEF_SYS_ELEMENT VA ! TYPE_DEFINITION % SEQ *! TYPE_DEFINITION ' GES A_P_D ORD_MORE_INSTL DIS_PART DISORD ,,,! TYPE_DEFINITION & GES A_P_D ORD_LESS_INSTL DIS_PART DISORD ,,,! TYPE_DEFINITION ) GES A_P_D ORD_SUBS_INSTL DIS_PART DISORD ,,,! PHASE DISORD % 2 1 3 ! CONSTITUENT DISORD : A,B,VA : VA : ! $ Has one more interstitial sublattice than disordered: PHASE ORD_MORE_INSTL %' 4 0.5 0.5 3 1 ! CONSTITUENT ORD_MORE_INSTL : A,B,VA : A,B,VA : VA : A : ! $ Has one less interstitial sublattice than disordered: PHASE ORD_LESS_INSTL %& 2 0.5 0.5 ! CONSTITUENT ORD_LESS_INSTL : A,B,VA : A,B,VA : ! $ The interstitial sublattice has the same species as the substitutional $ and cannot be distinguished: PHASE ORD_SUBS_INSTL %) 3 0.5 0.5 3 ! CONSTITUENT ORD_SUBS_INSTL : A,B,VA : A,B,VA : A,B,VA : ! """) # Case 1: Ordered phase has one more interstitial sublattice than disordered with pytest.raises(ValueError): Model(DBF_OrderDisorder_broken, ["A", "B", "VA"], "ORD_MORE_INSTL") # Case 2: Ordered phase has one more interstitial sublattice than disordered with pytest.raises(ValueError): Model(DBF_OrderDisorder_broken, ["A", "B", "VA"], "ORD_LESS_INSTL") # Case 3: The ordered phase has interstitial sublattice has the same species # as the substitutional and cannot be distinguished with pytest.raises(ValueError): Model(DBF_OrderDisorder_broken, ["A", "B", "VA"], "ORD_SUBS_INSTL")
def test_lnprob_calculates_single_phase_probability_for_success(datasets_db): """lnprob() succesfully calculates the probability from single phase data""" dbf = Database.from_string(CU_MG_TDB_FCC_ONLY, fmt='tdb') datasets_db.insert(CU_MG_HM_MIX_SINGLE_FCC_A1) comps = ['CU', 'MG', 'VA'] phases = ['FCC_A1'] param = 'VV0003' orig_val = -14.0865 eq_callables = build_callables(dbf, comps, phases, model=Model, parameters={param: orig_val}) pm = eq_callables.pop('model') eq_callables.pop('phase_records') mods_no_idmix = {} for phase_name in phases: mods_no_idmix[phase_name] = Model(dbf, comps, phase_name, parameters=[sympy.Symbol(param)]) mods_no_idmix[phase_name].models['idmix'] = 0 prop = 'HM_MIX' # from the dataset thermochemical_callables = {} from sympy import Symbol thermochemical_callables[prop] = build_callables(dbf, comps, phases, model=mods_no_idmix, output=prop, parameters={param: orig_val}, build_gradients=False) # pop off the callables not used in properties because we don't want them around (they should be None, anyways) thermochemical_callables[prop].pop('phase_records') # thermochemical_callables[prop].pop('model') res_orig = lnprob([orig_val], comps=comps, dbf=dbf, phases=phases, phase_models=pm, datasets=datasets_db, symbols_to_fit=[Symbol(param)], callables=eq_callables, thermochemical_callables=thermochemical_callables) assert np.isreal(res_orig) assert np.isclose(res_orig, -19859.38) res_10 = lnprob([10], comps=comps, dbf=dbf, phases=phases, phase_models=pm, datasets=datasets_db, symbols_to_fit=[Symbol(param)], callables=eq_callables, thermochemical_callables=thermochemical_callables) assert np.isreal(res_10) assert np.isclose(res_10, -20100.125) res_1e5 = lnprob([1e5], comps=comps, dbf=dbf, phases=phases, phase_models=pm, datasets=datasets_db, symbols_to_fit=[param], callables=eq_callables, thermochemical_callables=thermochemical_callables) assert np.isreal(res_1e5) assert np.isclose(res_1e5, -13520000.0)
def test_get_data_quantities_magnetic_energy(): data = [{"components": ["AL", "CR"], "phases": ["ALCR2"], "solver": {"mode": "manual", "sublattice_site_ratios": [1.0, 2.0], "sublattice_configurations": [["AL", "CR"]]}, "conditions": {"P": [101325], "T": [300]}, "excluded_model_contributions": ["idmix", "mag"], "output": "SM_FORM", "values": [[[5.59631999999999]]]}] config_tup = (('AL',), ('CR',)) calculate_dict = get_prop_samples(data, config_tup) sample_condition_dicts = _get_sample_condition_dicts(calculate_dict, list(map(len, config_tup))) # First test without any magnetic parameters dbf_nomag = Database(""" ELEMENT AL FCC_A1 26.982 4577.3 28.322 ! ELEMENT CR BCC_A2 51.996 4050.0 23.56 ! PHASE ALCR2 % 2 1.0 2.0 ! CONSTITUENT ALCR2 :AL,CR:AL,CR: ! """) mod_nomag = Model(dbf_nomag, ['AL', 'CR'], 'ALCR2') qty_nomag = get_data_quantities('SM_FORM', mod_nomag, [0], data, sample_condition_dicts) print(qty_nomag) assert np.all(np.isclose([16.78896], qty_nomag)) # Then with magnetic parameters, which are excluded model contributions dbf = Database(""" ELEMENT AL FCC_A1 2.6982E+01 4.5773E+03 2.8322E+01! ELEMENT CR BCC_A2 5.1996E+01 4.0500E+03 2.3560E+01! TYPE_DEFINITION & GES A_P_D ALCR2 MAGNETIC -1.0 4.00000E-01 ! PHASE ALCR2 %& 2 1 2 ! CONSTITUENT ALCR2 :AL,CR : AL,CR : ! PARAMETER TC(ALCR2,AL:AL;0) 298.15 -619; 6000 N REF0 ! PARAMETER BMAGN(ALCR2,AL:AL;0) 298.15 -.92; 6000 N REF0 ! PARAMETER TC(ALCR2,CR:AL;0) 298.15 -619; 6000 N REF0 ! PARAMETER BMAGN(ALCR2,CR:AL;0) 298.15 -.92; 6000 N REF0 ! PARAMETER TC(ALCR2,AL:CR;0) 298.15 -619; 6000 N REF0 ! PARAMETER BMAGN(ALCR2,AL:CR;0) 298.15 -.92; 6000 N REF0 ! PARAMETER TC(ALCR2,CR:CR;0) 298.15 -619; 6000 N REF0 ! PARAMETER BMAGN(ALCR2,CR:CR;0) 298.15 -.92; 6000 N REF0 ! PARAMETER TC(ALCR2,AL,CR:AL;0) 298.15 -485; 6000 N REF0 ! PARAMETER BMAGN(ALCR2,AL,CR:AL;0) 298.15 -.92; 6000 N REF0 ! PARAMETER TC(ALCR2,AL,CR:CR;0) 298.15 -485; 6000 N REF0 ! PARAMETER BMAGN(ALCR2,AL,CR:CR;0) 298.15 -.92; 6000 N REF0 ! """) mod = Model(dbf, ['AL', 'CR'], 'ALCR2') qty = get_data_quantities('SM_FORM', mod, [0], data, sample_condition_dicts) print(qty) assert np.all(np.isclose([16.78896], qty))
def test_ternary_ordered_magnetic(): "Ternary ordered solution phase with IHJ magnetic model." # ordered case check_energy(Model(DBF, ['AL', 'CR', 'NI'], 'L12_FCC'), \ {v.T: 300, v.SiteFraction('L12_FCC', 0, 'AL'): 5.42883e-8, v.SiteFraction('L12_FCC', 0, 'CR'): 2.07934e-6, v.SiteFraction('L12_FCC', 0, 'NI'): 9.99998e-1, v.SiteFraction('L12_FCC', 1, 'AL'): 7.49998e-1, v.SiteFraction('L12_FCC', 1, 'CR'): 2.50002e-1, v.SiteFraction('L12_FCC', 1, 'NI'): 4.55313e-10}, \ -40717.204, mode='sympy') check_energy(Model(DBF, ['AL', 'CR', 'NI'], 'L12_FCC'), \ {v.T: 300, v.SiteFraction('L12_FCC', 0, 'AL'): 5.42883e-8, v.SiteFraction('L12_FCC', 0, 'CR'): 2.07934e-6, v.SiteFraction('L12_FCC', 0, 'NI'): 9.99998e-1, v.SiteFraction('L12_FCC', 1, 'AL'): 7.49998e-1, v.SiteFraction('L12_FCC', 1, 'CR'): 2.50002e-1, v.SiteFraction('L12_FCC', 1, 'NI'): 4.55313e-10}, \ -40717.204, mode='numpy')
def test_non_zero_reference_mixing_enthalpy_for_va_interaction(): """The referenced mixing enthalpy for a Model with a VA interaction parameter is non-zero.""" m = Model(VA_INTERACTION_DBF, ['AL', 'VA'], 'FCC_A1') refstates = [ReferenceState('AL', 'FCC_A1')] m.shift_reference_state(refstates, VA_INTERACTION_DBF) statevars_pure = {v.T: 300, v.SiteFraction('FCC_A1', 0, 'AL'): 1, v.SiteFraction('FCC_A1', 0, 'VA'): 0, v.SiteFraction('FCC_A1', 1, 'VA'): 1} check_output(m, statevars_pure, 'GMR', 0.0) statevars_mix = {v.T: 300, v.SiteFraction('FCC_A1', 0, 'AL'): 0.5, v.SiteFraction('FCC_A1', 0, 'VA'): 0.5, v.SiteFraction('FCC_A1', 1, 'VA'): 1} # 4000.0 * 0.5=2000 +500 # (Y0VA doesn't contribute), but the VA endmember does (not referenced) check_output(m, statevars_mix, 'HMR', 2500.0) statevars_mix = {v.T: 300, v.SiteFraction('FCC_A1', 0, 'AL'): 0.5, v.SiteFraction('FCC_A1', 0, 'VA'): 0.5, v.SiteFraction('FCC_A1', 1, 'VA'): 1} # 4000.0 * 0.5 (Y0VA doesn't contribute) check_output(m, statevars_mix, 'HM_MIX', 2000.0)
def test_underspecified_refstate_raises(): """A Model cannot be shifted to a new reference state unless references for all pure elements are specified.""" m = Model(FEMN_DBF, ['FE', 'MN', 'VA'], 'LIQUID') refstates = [ReferenceState(v.Species('FE'), 'LIQUID')] m.shift_reference_state(refstates, FEMN_DBF)