Beispiel #1
0
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')
Beispiel #2
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)
Beispiel #3
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')
Beispiel #4
0
 def moles(self, species):
     "Number of moles of species or elements."
     species = v.Species(species)
     is_pure_element = (len(species.constituents.keys()) == 1 and
                        list(species.constituents.keys())[0] == species.name)
     result = S.Zero
     normalization = S.Zero
     if is_pure_element:
         element = list(species.constituents.keys())[0]
         for idx, sublattice in enumerate(self.constituents):
             active = set(sublattice).intersection(self.components)
             result += self.site_ratios[idx] * \
                 sum(int(spec.number_of_atoms > 0) * spec.constituents.get(element, 0) * v.SiteFraction(self.phase_name, idx, spec)
                     for spec in active)
             normalization += self.site_ratios[idx] * \
                 sum(spec.number_of_atoms * v.SiteFraction(self.phase_name, idx, spec)
                     for spec in active)
     else:
         for idx, sublattice in enumerate(self.constituents):
             active = set(sublattice).intersection({species})
             if len(active) == 0:
                 continue
             result += self.site_ratios[idx] * sum(v.SiteFraction(self.phase_name, idx, spec) for spec in active)
             normalization += self.site_ratios[idx] * \
                 sum(int(spec.number_of_atoms > 0) * v.SiteFraction(self.phase_name, idx, spec)
                     for spec in active)
     return result / normalization
Beispiel #5
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
Beispiel #6
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')
Beispiel #7
0
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')
Beispiel #8
0
def test_magnetic_endmember_mixing_energy_is_zero():
    """The mixing energy for an endmember with a magnetic contribution should be zero."""
    m = Model(CRFE_DBF, ['CR', 'FE', 'VA'], 'BCC_A2')
    statevars = {
        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, 'GM_MIX', 0.0)
Beispiel #9
0
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')
Beispiel #10
0
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')
Beispiel #11
0
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')
Beispiel #12
0
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')
Beispiel #13
0
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')
Beispiel #14
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)
Beispiel #15
0
def test_endmember_mixing_energy_is_zero():
    """The mixing energy for an endmember in a multi-sublattice model should be zero."""
    m = Model(CUMG_DBF, ['CU', 'MG', 'VA'], 'CU2MG')
    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', 0.0)
Beispiel #16
0
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_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))
Beispiel #18
0
def test_binary_magnetic_reimported():
    "Export and re-import a TDB before the calculation."
    dbf_imported = Database.from_string(DBF.to_string(fmt='tdb'), fmt='tdb')
    check_energy(Model(dbf_imported, ['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')
Beispiel #19
0
def test_order_disorder_mixing_energy_is_nan():
    """The endmember-referenced mixing energy is undefined and the energy should be NaN."""
    m = Model(ALFE_DBF, ['AL', 'FE', 'VA'], 'B2_BCC')
    statevars = {
        v.T: 300,
        v.SiteFraction('B2_BCC', 0, 'AL'): 1,
        v.SiteFraction('B2_BCC', 0, 'FE'): 0,
        v.SiteFraction('B2_BCC', 1, 'AL'): 0,
        v.SiteFraction('B2_BCC', 1, 'FE'): 1,
        v.SiteFraction('B2_BCC', 2, 'VA'): 1
    }
    check_output(m, statevars, 'GM_MIX', np.nan)
Beispiel #20
0
def build_sitefractions(phase_name, sublattice_configurations,
                        sublattice_occupancies):
    """Convert nested lists of sublattice configurations and occupancies to a list
    of dictionaries. The dictionaries map SiteFraction symbols to occupancy
    values. Note that zero occupancy site fractions will need to be added
    separately since the total degrees of freedom aren't known in this function.

    Parameters
    ----------
    phase_name : str
        Name of the phase
    sublattice_configurations : [[str]]
        sublattice configuration
    sublattice_occupancies : [[float]]
        occupancy of each sublattice

    Returns
    -------
    [[float]]
        a list of site fractions over sublattices

    """
    result = []
    for config, occ in zip(sublattice_configurations, sublattice_occupancies):
        sitefracs = {}
        config = [[c] if not isinstance(c, (list, tuple)) else c
                  for c in config]
        occ = [[o] if not isinstance(o, (list, tuple)) else o for o in occ]
        if len(config) != len(occ):
            raise ValueError(
                'Sublattice configuration length differs from occupancies')
        for sublattice_idx in range(len(config)):
            if isinstance(config[sublattice_idx],
                          (list, tuple)) != isinstance(occ[sublattice_idx],
                                                       (list, tuple)):
                raise ValueError(
                    'Sublattice configuration type differs from occupancies')
            if not isinstance(config[sublattice_idx], (list, tuple)):
                # This sublattice is fully occupied by one component
                sitefracs[v.SiteFraction(
                    phase_name, sublattice_idx,
                    config[sublattice_idx])] = occ[sublattice_idx]
            else:
                # This sublattice is occupied by multiple elements
                if len(config[sublattice_idx]) != len(occ[sublattice_idx]):
                    raise ValueError(
                        'Length mismatch in sublattice configuration')
                for comp, val in zip(config[sublattice_idx],
                                     occ[sublattice_idx]):
                    sitefracs[v.SiteFraction(phase_name, sublattice_idx,
                                             comp)] = val
        result.append(sitefracs)
    return result
Beispiel #21
0
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')
Beispiel #22
0
def test_degenerate_zero_ordering():
    "Degenerate sublattice configuration has zero ordering energy."
    mod = Model(DBF, ['CR', 'NI'], 'L12_FCC')
    sub_dict = {
        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
    }
    #print({x: mod.models[x].subs(sub_dict) for x in mod.models})
    desired = mod.models['ord'].xreplace(sub_dict).evalf()
    assert abs(desired - 0) < 1e-5, "%r != %r" % (desired, 0)
Beispiel #23
0
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)
Beispiel #24
0
def _translate_endmember_to_array(endmember, variables):
    site_fractions = sorted(variables, key=str)
    frac_array = np.zeros(len(site_fractions))
    for idx, component in enumerate(endmember):
        frac_array[site_fractions.index(
            v.SiteFraction(site_fractions[0].phase_name, idx, component))] = 1
    return frac_array
Beispiel #25
0
def _map_internal_dof(input_database, components, phase_name, points):
    """
    Map matrix of internal degrees of freedom to global compositions.
    """
    # Map the internal degrees of freedom to global coordinates
    # Normalize site ratios by the sum of site ratios times a factor
    # related to the site fraction of vacancies
    phase_obj = input_database.phases[phase_name]
    site_ratio_normalization = np.zeros(points.shape[:-1])
    phase_compositions = np.empty(points.shape[:-1] + (len(components), ))
    variables, sublattice_dof = generate_dof(phase_obj, components)
    for idx, sublattice in enumerate(phase_obj.constituents):
        vacancy_column = np.ones(points.shape[:-1])
        if 'VA' in set(sublattice):
            var_idx = variables.index(v.SiteFraction(phase_obj.name, idx,
                                                     'VA'))
            vacancy_column -= points[..., :, var_idx]
        site_ratio_normalization += phase_obj.sublattices[idx] * vacancy_column

    for col, comp in enumerate(components):
        avector = [
            float(vxx.species == comp) *
            phase_obj.sublattices[vxx.sublattice_index] for vxx in variables
        ]
        phase_compositions[..., :,
                           col] = np.divide(np.dot(points[..., :, :], avector),
                                            site_ratio_normalization)
    return phase_compositions
Beispiel #26
0
 def ideal_mixing_energy(self, dbe):
     #pylint: disable=W0613
     """
     Returns the ideal mixing energy in symbolic form.
     """
     phase = dbe.phases[self.phase_name]
     # Normalize site ratios
     site_ratio_normalization = self._site_ratio_normalization(phase)
     site_ratios = phase.sublattices
     site_ratios = [c / site_ratio_normalization for c in site_ratios]
     ideal_mixing_term = S.Zero
     for subl_index, sublattice in enumerate(phase.constituents):
         active_comps = set(sublattice).intersection(self.components)
         if len(active_comps) == 1:
             continue  # no mixing if only one species in sublattice
         ratio = site_ratios[subl_index]
         for comp in active_comps:
             sitefrac = \
                 v.SiteFraction(phase.name, subl_index, comp)
             # We lose some precision here, but this makes the limit behave nicely
             # We're okay until fractions of about 1e-12 (platform-dependent)
             mixing_term = Piecewise((sitefrac * log(sitefrac),
                                      sitefrac > MIN_SITE_FRACTION / 10.),
                                     (0, True))
             ideal_mixing_term += (mixing_term * ratio)
     ideal_mixing_term *= (v.R * v.T)
     return ideal_mixing_term
Beispiel #27
0
 def __init__(self, dbf, comps, phase, solution=None, kmax=None):
     self.components = set([x.upper() for x in comps])
     if 'VA' in self.components:
         raise ValueError('Vacancies are unsupported in TestModel')
     self.models = dict()
     variables = [
         v.SiteFraction(phase.upper(), 0, x)
         for x in sorted(self.components)
     ]
     if solution is None:
         solution = np.random.dirichlet(
             np.ones_like(variables, dtype=np.int))
     self.solution = dict(list(zip(variables, solution)))
     kmax = kmax if kmax is not None else 2
     scale_factor = 1e4 * len(self.components)
     ampl_scale = 1e3 * np.ones(kmax, dtype=np.float)
     freq_scale = 10 * np.ones(kmax, dtype=np.float)
     polys = Add(*[
         ampl_scale[i] * sin(freq_scale[i] * Add(*[
             Add(*[(varname - sol)**(j + 1)
                   for varname, sol in self.solution.items()])
             for j in range(kmax)
         ]))**2 for i in range(kmax)
     ])
     self.models['test'] = scale_factor * Add(
         *[(varname - sol)**2
           for varname, sol in self.solution.items()]) + polys
Beispiel #28
0
    def mole_fraction(species_name, phase_name, constituent_array,
                      site_ratios):
        """
        Return an abstract syntax tree of the mole fraction of the
        given species as a function of its constituent site fractions.

        Note that this will treat vacancies the same as any other component,
        i.e., this will not give the correct _overall_ composition for
        sublattices containing vacancies with other components by normalizing
        by a factor of 1 - y_{VA}. This is because we use this routine in the
        order-disorder model to calculate the disordered site fractions from
        the ordered site fractions, so we need _all_ site fractions, including
        VA, to sum to unity.
        """

        # Normalize site ratios
        site_ratio_normalization = 0
        numerator = S.Zero
        for idx, sublattice in enumerate(constituent_array):
            # sublattices with only vacancies don't count
            if len(sublattice) == 1 and sublattice[0] == 'VA':
                continue
            if species_name in list(sublattice):
                site_ratio_normalization += site_ratios[idx]
                numerator += site_ratios[idx] * \
                    v.SiteFraction(phase_name, idx, species_name)

        if site_ratio_normalization == 0 and species_name == 'VA':
            return 1

        if site_ratio_normalization == 0:
            raise ValueError('Couldn\'t find ' + species_name + ' in ' + \
                str(constituent_array))

        return numerator / site_ratio_normalization
Beispiel #29
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
Beispiel #30
0
    def degree_of_ordering(self):
        result = S.Zero
        site_ratio_normalization = S.Zero
        # Calculate normalization factor
        for idx, sublattice in enumerate(self.constituents):
            active = set(sublattice).intersection(self.components)
            subl_content = sum(int(spec.number_of_atoms > 0) * v.SiteFraction(self.phase_name, idx, spec) for spec in active)
            site_ratio_normalization += self.site_ratios[idx] * subl_content

        site_ratios = [c/site_ratio_normalization for c in self.site_ratios]
        for comp in self.components:
            comp_result = S.Zero
            for idx, sublattice in enumerate(self.constituents):
                active = set(sublattice).intersection(set(self.components))
                if comp in active:
                    comp_result += site_ratios[idx] * Abs(v.SiteFraction(self.phase_name, idx, comp) - self.moles(comp)) / self.moles(comp)
            result += comp_result
        return result / sum(int(spec.number_of_atoms > 0) for spec in self.components)