Example #1
0
def test_DCplot():
    """
    DCplot should return an axes object when a DiffSystem is passed
    """
    Xr = [[0, .4], [.6, 1]]
    X = np.linspace(0, 1, 101)
    DC = np.linspace(1, 10, 101) * 1e-14
    diffsys = DiffSystem(Xr=Xr, X=X, DC=DC)
    ax = DCplot(diffsys, label='test')

    assert isinstance(ax, Axes)
Example #2
0
def test_SFplot():
    """
    SFplot should return an axes object when a DiffProfile and time is passed
    """
    diffsys = DiffSystem(Xr=[0, 1], X=[0, 1], DC=[1e-14, 1e-13])
    dis = mesh(0, 1000, 201)
    profile_init = step(dis, 500, diffsys)
    time = 200 * 3600
    profile = sphSim(profile_init, diffsys, time)
    ax = SFplot(profile, time, Xlim=[0, 1], label='test')

    assert isinstance(ax, Axes)
Example #3
0
def test_system():
    """
    DiffSystem constructor
    """
    # Construct with X, DC
    Xr = [[0, .4], [.6, 1]]
    X = np.linspace(0, 1, 101)
    DC = np.linspace(1, 10, 101) * 1e-14
    diffsys = DiffSystem(Xr=Xr, X=X, DC=DC)

    assert diffsys.Xr.shape == (diffsys.Np, 2)
    assert isinstance(diffsys.name, str)
    assert len(diffsys.Dfunc) == diffsys.Np
    for i in range(diffsys.Np):
        assert len(diffsys.Dfunc[i][0]) == len(diffsys.Dfunc[i][1])

    # Construct with Dfunc
    diffsys1 = DiffSystem(Xr=Xr, Dfunc=diffsys.Dfunc)

    assert diffsys1.Xr.shape == (diffsys1.Np, 2)
    assert len(diffsys1.Dfunc) == diffsys1.Np
Example #4
0
def test_automesh():
    """
    automesh should return a meshed array whose length is within its range.
    """
    diffsys = DiffSystem(Xr=[0, 1], X=[0, 1], DC=[1e-14, 1e-13])
    dis = mesh(0, 1000, 201)
    profile_init = step(dis, 500, diffsys)
    time = 200 * 3600
    profile = sphSim(profile_init, diffsys, time)
    dism = automesh(profile, diffsys, n=[300, 400])

    assert len(dism) >= 300 and len(dism) <= 400
Example #5
0
def test_dispfunc():
    """
    disfunc and profilefunc should give functions to copy profile data.
    """
    diffsys = DiffSystem(Xr=[0, 1], X=[0, 1], DC=[1e-14, 1e-13])
    dis = mesh(0, 1000, 201)
    profile_init = step(dis, 500, diffsys)
    time = 200 * 3600
    profile = sphSim(profile_init, diffsys, time)

    fX = profilefunc(profile)
    fdis = disfunc(profile.dis, profile.X)

    assert np.all(abs(splev(dis, fX) - profile.X) < 0.01)
    assert np.all(abs(splev(profile.X, fdis) - dis) < 0.1)
def test_sphsim():
    """
    Single-phase system simulation.
    Offset of the simulated matano plane should be very small.
    """
    diffsys = DiffSystem(Xr=[0, 1], X=[0, 1], DC=[1e-14, 1e-14])
    dis = mesh(0, 1000, 201)
    profile_init = step(dis, 500, diffsys)
    time = 200 * 3600
    profile_final = sphSim(profile_init, diffsys, time)

    mpi = matanocalc(profile_init, [0, 1])
    mpf = matanocalc(profile_final, [0, 1])

    assert isinstance(profile_final, DiffProfile)
    assert len(profile_final.If) == diffsys.Np + 1
    assert abs(mpi - mpf) < 1
def test_mphsim():
    """
    Multiple-phase system simulation.
    Offset of the simulated matano plane should be very small.
    """
    Xr = [[0, .4], [.6, 1]]
    X = np.linspace(0, 1, 101)
    DC = np.linspace(1, 2, 101) * 1e-14
    diffsys = DiffSystem(Xr=Xr, X=X, DC=DC)
    dis = mesh(0, 1000, 201)
    profile_init = step(dis, 500, diffsys)
    time = 200 * 3600
    profile_final = mphSim(profile_init, diffsys, time)

    mpi = matanocalc(profile_init, [0, 1])
    mpf = matanocalc(profile_final, [0, 1])

    assert isinstance(profile_final, DiffProfile)
    assert len(profile_final.If) == diffsys.Np + 1
    assert abs(mpi - mpf) < 1
Example #8
0
def DCbias(diffsys, X, deltaD, r=0.3, efunc=None):
    """
    This function creates bias for a diffusion coefficients profile

    Parameters
    ----------
    diffsys : DiffSystem
        Original diffusion coefficients.
    X : float
        Concentration location which has largest bias.
    deltaD : float
        Scale of the bias. D *= 10**deltaD is the maximum of bias.
    r : float, optional
        Bias at X will create smaller bias in range of (X-r, X+r)
    efunc : function, optional
        Function to create bias on diffusion coefficients.
        Default = pydiffusion.utils.efunc
        efunc(X, Xf, r)
        efunc should return 1 as the maximum when X == Xf,
        and return 0 when abs(X-Xf) == r.

    Returns
    -------
    fDbias : DiffSystem
        Diffusion coefficients with bias.

    """
    Xr, Np, fD = diffsys.Xr, diffsys.Np, diffsys.Dfunc
    efunc = efunc_default if efunc is None else efunc
    fDbias = []
    for i in range(Np):
        if X >= Xr[i, 0] and X <= Xr[i, 1]:
            Xf = np.linspace(Xr[i, 0], Xr[i, 1], 30)
            Df = np.exp(splev(Xf, fD[i]))
            eid = np.where((Xf >= X - r) & (Xf <= X + r))[0]
            for j in eid:
                Df[j] *= 10**(deltaD * efunc(X, Xf[j], r))
            fDbias += [splrep(Xf, np.log(Df))]
        else:
            fDbias += [fD[i]]
    return DiffSystem(Xr, fDbias)
Example #9
0
def FSA(profile_exp,
        profile_sm,
        diffsys,
        time,
        Xlim=[],
        n=[400, 500],
        w=None,
        f=None,
        alpha=0.3,
        name=''):
    """
    Forward Simulation Analysis
    Extract diffusion coefficients based on a diffusion profile.
    Please do not close any plot window during the FSA process.

    This is the final step of FSA.

    Parameters
    ----------
    profile_exp : DiffProfile
        Experimental diffusion profile, used for comparison with simulation
        results.
    profile_sm : DiffProfile
        Diffusion profile after data smooth on experimental profile.
    diffsys : DiffSystem
        Diffusion coefficients
    time : float
        Diffusion time in seconds
    Xlim : list (float), optional
        Passed to 'pydiffusion.Dtools.SF', 'pydiffusion.utils.step'.
        Indicates the left and right concentration limits for calculation.
        Default value = [profile.X[0], profile.X[-1]].
    n : list. optional
        Passed to 'pydiffusion.utils.automesh'.
        Meshing number range, default = [400, 500].
    w : list, optional
        Weights of each phase to calculate error.
        Passed to 'pydiffusion.utils.error_profile'.
    f : function of Meshing
        Keyword argument of automesh()
    alpha : float
        Keyword argument of automesh()
    name : str, optional
        Name the output DiffProfile

    Returns
    -------
    profile_sim : DiffProfile
        Simulated diffusion profile after FSA.
    diffsys_sim : DiffSystem
        Calculated diffusion efficients by FSA.

    Examples
    --------
    After datasmooth() and Dmodel(), FSA can be performed to calculate accurate diffusion coefficients:

    >>> ds = datasmooth(exp)
    >>> dsys = Dmodel(ds, time)
    >>> fsa = FSA(exp, ds, dsys, time)

    """
    # Create step profile on meshed grids
    dism = automesh(profile=profile_sm, diffsys=diffsys, n=n, f=f, alpha=alpha)
    matano = matanocalc(profile_sm, Xlim)
    if Xlim == [] and profile_sm.X[-1] < profile_sm.X[0]:
        profile_init = step(dism, matano, diffsys,
                            [diffsys.Xr[-1, 1], diffsys.Xr[0, 0]])
    else:
        profile_init = step(dism, matano, diffsys, Xlim)

    # Determine the stop criteria of forward simulations
    error_sm = error_profile(profile_sm, profile_exp)
    ipt = input(
        'Default error = %.6f\nInput the stop criteria of error: [%.6f]\n' %
        (error_sm, error_sm * 2))
    error_stop = error_sm * 2 if ipt == '' else float(ipt)

    # If there is no Xspl info in diffsys, use Phase Mode
    # else: ask if use Phase or Point Mode
    if diffsys.Xspl is not None:
        ipt = input(
            'Use Phase Mode? [n]\n(The shape of diffusivity curve does not change)\n'
        )
        pp = False if 'y' in ipt or 'Y' in ipt else True
    else:
        pp = False

    if name == '':
        name = profile_exp.name + '_FSA'

    # Diffusion coefficients used for forward simulations
    diffsys_sim = DiffSystem(diffsys.Xr,
                             diffsys.Dfunc,
                             Xspl=diffsys.Xspl,
                             name=name)

    # Plot FSA status
    fig = plt.figure('FSA', figsize=(16, 6))
    ax1, ax2 = fig.add_subplot(121), fig.add_subplot(122)
    profileplot(profile_exp,
                ax1,
                ls='none',
                marker='o',
                c='b',
                fillstyle='none')
    profileplot(profile_sm, ax1, ls='-', c='g', lw=1)
    SFplot(profile_sm, time, Xlim, ax2, ls='none', c='b', marker='.')
    DCplot(diffsys_sim, ax2, ls='-', c='r', lw=2)
    plt.draw()
    plt.tight_layout()
    plt.pause(0.1)

    n_sim = 0
    while True:

        # Simulation
        n_sim += 1
        profile_sim = mphSim(profile_init, diffsys_sim, time, name=name)
        error_sim = error_profile(profile_sim, profile_exp, w)
        print('Simulation %i, error = %f(%f)' % (n_sim, error_sim, error_stop))

        # Plot simulation results
        ax1.cla()
        ax2.cla()
        profileplot(profile_exp,
                    ax1,
                    ls='none',
                    marker='o',
                    c='b',
                    fillstyle='none')
        profileplot(profile_sm, ax1, ls='-', c='g', lw=1)
        profileplot(profile_sim, ax1, ls='-', c='r', lw=2)
        SFplot(profile_sm, time, Xlim, ax2, ls='none', c='b', marker='.')
        DCplot(diffsys_sim, ax2, ls='-', c='r', lw=2)
        plt.draw()
        plt.tight_layout()

        # DC adjust
        Dfunc_adjust = [0] * diffsys_sim.Np

        # If error > stop criteria, continue simulation by auto DC adjustment
        if error_sim > error_stop:
            for ph in range(diffsys_sim.Np):
                try:
                    Dfunc_adjust[ph] = Dadjust(profile_sm, profile_sim,
                                               diffsys_sim, ph, pp)
                except (ValueError, TypeError) as error:
                    ita_finish()
                    raise error
            diffsys_sim.Dfunc = Dfunc_adjust

        # If error < stop criteria or simulate too many times
        if error_sim <= error_stop or n_sim > 9:

            ita_start()

            # Ask if exit
            ipt = ask_input('Satisfied with FSA? [n]')
            if 'y' in ipt or 'Y' in ipt:
                ita_finish()
                break

            # If use Point Mode
            if diffsys_sim.Xspl is not None:
                ipt = ask_input('Use Point Mode (y) or Phase Mode (n)? [y]')
                pp = False if 'n' in ipt or 'N' in ipt else True
                if pp:
                    for ph in range(diffsys_sim.Np):
                        try:
                            Dfunc_adjust[ph] = Dadjust(profile_sm, profile_sim,
                                                       diffsys_sim, ph, pp)
                        except (ValueError, TypeError) as error:
                            ita_finish()
                            raise error
                    diffsys_sim.Dfunc = Dfunc_adjust

                    DCplot(diffsys_sim, ax2, ls='-', c='m', lw=2)
                    plt.draw()
                    plt.pause(0.1)
                    ita_finish()
                    continue

            # Phase Mode, ask if use manual input for each phase
            pp = False
            ipt = input('Phase Mode\nManually input for each phase? [n]')
            manual = True if 'y' in ipt or 'Y' in ipt else False
            for ph in range(diffsys_sim.Np):
                if manual:
                    ipt = input(
                        'Input deltaD for phase # %i:\n(DC = DC * 10^deltaD, default deltaD = auto)\n'
                        % (ph + 1))
                    deltaD = float(ipt) if ipt != '' else None
                else:
                    deltaD = None
                try:
                    Dfunc_adjust[ph] = Dadjust(profile_sm, profile_sim,
                                               diffsys_sim, ph, pp, deltaD)
                except (ValueError, TypeError) as error:
                    ita_finish()
                    raise error

            # Apply the adjustment to diffsys_sim
            diffsys_sim.Dfunc = Dfunc_adjust

            DCplot(diffsys_sim, ax2, ls='-', c='m', lw=2)
            plt.draw()
            plt.pause(0.1)
            ita_finish()

    return profile_sim, diffsys_sim
Example #10
0
def Dmodel(profile, time, Xspl=None, Xlim=[], output=True, name=''):
    """
    Given the diffusion profile and diffusion time, modeling the diffusion
    coefficients for each phase. Please do not close any plot window during
    the modeling process.

    Dmodel() is the second step of the forward simulation analysis (FSA).

    Parameters
    ----------
    profile : DiffProfile
        Diffusion profile. Multiple phase profile must be after datasmooth to
        identify phase boundaries.
    time : float
        Diffusion time in seconds.
    Xspl : list, optional
        If Xspl is given, Dmodel will be done automatically.
    Xlim : list, optional
        Left and Right limit of diffusion coefficients. Xlim is also passed to
        SF function to calculate diffusion coefficients initially.
    output : bool, optional
        Plot Dmodel result or not. Can be False only if Xspl is given.
    name : str, optional
        Name of the output DiffSystem

    Examples
    --------
    After datasmooth(), a initial diffusion coefficients will be established before
    FSA():

    >>> ds = datasmooth(exp)
    >>> dsys = Dmodel(ds, time)

    """
    if not isinstance(Xlim, list):
        raise TypeError('Xlim must be a list')
    if len(Xlim) != 2 and Xlim != []:
        raise ValueError(
            'Xlim must be an empty list or a list with length = 2')

    dis, X = profile.dis, profile.X

    # If input Xlim doesn't follow trend of X, correct it
    if Xlim != [] and (X[-1] - X[0]) * (Xlim[1] - Xlim[0]) < 0:
        Xlim = Xlim[::-1]

    # Initial set-up of Xr (phase boundaries)
    Xlim = [X[0], X[-1]] if Xlim == [] else Xlim
    DC = SF(profile, time, Xlim)
    Xr = np.array(Xlim, dtype=float)
    for i in range(len(dis) - 1):
        if dis[i] == dis[i + 1]:
            Xr = np.insert(Xr, -1, [X[i], X[i + 1]])
    Np = len(Xr) // 2
    Xr.sort()
    Xr = Xr.reshape(Np, 2)
    fD = [0] * Np

    ita_start()

    # Choose Spline or UnivariateSpline
    if Xspl is None or output:
        ax = plt.figure().gca()
        ax.semilogy(X, DC, 'b.')
        ax.set_title('Sauer-Freise result')
        ax.set_xlabel('Mole fraction')
        ax.set_ylabel('Diffusion Coefficients ' + '$(m^2/s)$')
        plt.tight_layout()

    ipt = ask_input(
        'Use Spline (y) or UnivariateSpline (n) to model diffusion coefficients? [y]\n'
    )
    choice = False if 'N' in ipt or 'n' in ipt else True

    # Xspl provided, no need for manually picking Xspl
    if Xspl is not None:
        if len(Xspl) != Np:
            raise ValueError('Xspl must has a length of phase number')

        for i in range(Np):
            if Xr[i, 1] > Xr[i, 0]:
                pid = np.where((X >= Xr[i, 0]) & (X <= Xr[i, 1]))[0]
            else:
                pid = np.where((X <= Xr[i, 0]) & (X >= Xr[i, 1]))[0]

            # Spline
            if choice:
                try:
                    Dp = Dpcalc(X, DC, Xspl[i])
                    fD[i] = Dfunc_spl(Xspl[i], Dp)
                except (ValueError, TypeError) as error:
                    ita_finish()
                    raise error

            # UnivariateSpline
            else:
                try:
                    fD[i] = Dfunc_uspl(X, DC, Xspl[i], Xr[i])
                except (ValueError, TypeError) as error:
                    ita_finish()
                    raise error

        print('DC modeling finished, Xspl info:')
        print(Xspl)

        if output:
            ax.cla()
            ax.set_title('DC Modeling Result')
            ax.semilogy(X, DC, 'b.')
            for i in range(Np):
                Xf = np.linspace(Xr[i, 0], Xr[i, 1], 30)
                ax.semilogy(Xf, np.exp(splev(Xf, fD[i])), 'r-')
            ax.set_xlabel('Mole fraction')
            ax.set_ylabel('Diffusion Coefficients ' + '$(m^2/s)$')
            plt.tight_layout()
            plt.pause(0.1)
            plt.show()

        ita_finish()

        return DiffSystem(Xr, Dfunc=fD, Xspl=Xspl)

    Xspl = [0] * Np if choice else None

    for i in range(Np):
        if Xr[i, 1] > Xr[i, 0]:
            pid = np.where((X >= Xr[i, 0]) & (X <= Xr[i, 1]))[0]
        else:
            pid = np.where((X <= Xr[i, 0]) & (X >= Xr[i, 1]))[0]

        # Spline
        if choice:
            while True:
                DC_real = [
                    k for k in DC[pid] if not np.isnan(k) and not np.isinf(k)
                ]
                DCmean = np.mean(DC_real)
                for k in pid:
                    if np.isnan(DC[k]) or np.isinf(
                            DC[k]) or abs(np.log10(DC[k] / DCmean)) > 5:
                        DC[k] = DCmean
                ax.cla()
                ax.semilogy(X[pid], DC[pid], 'b.')
                ax.set_xlabel('Mole fraction')
                ax.set_ylabel('Diffusion Coefficients ' + '$(m^2/s)$')
                ax.set_title('Phase %i' % (i + 1))
                plt.draw()
                msg = '# of spline points: 1 (constant), 2 (linear), >2 (spline)\n'
                ipt = ask_input(msg + 'input # of spline points\n')
                ax.set_title('Phase %i: Select %i points of Spline' %
                             (i + 1, int(ipt)))
                plt.pause(0.1)
                Xp = np.array(plt.ginput(int(ipt)))[:, 0]
                try:
                    Dp = Dpcalc(X, DC, Xp)
                    fD[i] = Dfunc_spl(Xp, Dp)
                except (ValueError, TypeError) as error:
                    ita_finish()
                    raise error
                Xspl[i] = list(Xp)
                Xf = np.linspace(Xr[i, 0], Xr[i, 1], 30)
                ax.semilogy(Xf, np.exp(splev(Xf, fD[i])), 'r-', lw=2)
                plt.draw()
                ipt = ask_input('Continue to next phase? [y]')
                redo = False if 'N' in ipt or 'n' in ipt else True
                if redo:
                    break

        # UnivariateSpline
        else:
            while True:
                ax.cla()
                ax.semilogy(X[pid], DC[pid], 'b.')
                ax.set_xlabel('Mole fraction')
                ax.set_ylabel('Diffusion Coefficients ' + '$(m^2/s)$')
                #ax.set_title('Phase %i' % (i+1))
                ax.set_title(
                    'Phase %i: Select 2 boundaries for UnivariateSpline' %
                    (i + 1))
                plt.draw()
                plt.pause(0.1)
                Xp = np.array(plt.ginput(2))[:, 0]
                #ipt = ask_input('input 2 boundaries for UnivariateSpline\n')
                #Xp = np.array([float(x) for x in ipt.split()])
                try:
                    fD[i] = Dfunc_uspl(X, DC, Xp, Xr[i])
                except (ValueError, TypeError) as error:
                    ita_finish()
                    raise error
                Xf = np.linspace(Xr[i, 0], Xr[i, 1], 30)
                ax.semilogy(Xf, np.exp(splev(Xf, fD[i])), 'r-', lw=2)
                plt.draw()
                ipt = ask_input('Continue to next phase? [y]')
                redo = False if 'N' in ipt or 'n' in ipt else True
                if redo:
                    break

    ita_finish()

    print('DC modeling finished, Xspl info:')
    print(Xspl)

    ax.cla()
    ax.set_title('DC Modeling Result')
    ax.semilogy(X, DC, 'b.')
    for i in range(Np):
        Xf = np.linspace(Xr[i, 0], Xr[i, 1], 30)
        ax.semilogy(Xf, np.exp(splev(Xf, fD[i])), 'r-')
    ax.set_xlabel('Mole fraction')
    ax.set_ylabel('Diffusion Coefficients ' + '$(m^2/s)$')
    plt.tight_layout()
    plt.pause(0.1)
    plt.show()

    if name == '':
        name = profile.name + '_%.1fh_Dmodeled' % (time / 3600)

    return DiffSystem(Xr, Dfunc=fD, Xspl=Xspl, name=name)
Example #11
0
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from pydiffusion.core import DiffSystem
from pydiffusion.utils import step, mesh
from pydiffusion.simulation import mphSim
from pydiffusion.plot import profileplot, DCplot
from pydiffusion.io import read_csv, save_csv

# Create diffusion system with constant DC
diffsys = DiffSystem(Xr=[0, 1], X=[0, 1], DC=[1e-14, 1e-14], name='Constant D')

# Create initial step profile
dis = mesh(0, 1000, 501)
profile_init = step(dis, 500, diffsys, name='Intitial step profile')

fig = plt.figure(figsize=(16, 6))
ax1, ax2 = fig.add_subplot(121), fig.add_subplot(122)
ax1.set_title('Diffusion Coefficients', fontsize=15)
ax2.set_title('Initial Step Profile', fontsize=15)
DCplot(diffsys, ax1)
profileplot(profile_init, ax2)

# Diffusion simulation using the setups
time = 200 * 3600
profile_final = mphSim(profile_init, diffsys, time)

ax = profileplot(profile_init, ls='--')
profileplot(profile_final, ax, c='r')

# Read diffusion coefficients data of Ni-Mo system
Example #12
0
def read_csv(filename, Xlim=None, name=''):
    """
    Read diffusion data from csv file.

    Parameters
    ----------
    filename : str
        csv file path.
    Xlim : list (length of 2), optional
        A list to determine the two ends solubilities.
    name : str, optional
        Name the output DiffProfile and DiffSystem

    Returns
    -------
    profile : DiffProfile
        output DiffProfile object.
    diffsys : DiffSystem
        output DiffSystem object.

    Examples
    --------
    Both profile and diffusivity data:

    >>> profile, dsys = read_csv('data.csv')

    Profile data only:

    >>> profile, _ = read_csv('data.csv')

    """
    data = pd.read_csv(filename)
    if 'X' not in data.columns:
        raise ValueError('No column X in csv file')
    X = np.array(data['X'])

    # Auto rename
    if name == '':
        if '/' in filename:
            r = filename.rfind('/')
        elif '\\' in filename:
            r = filename.rfind('\\')
        else:
            r = -1
        if filename.endswith('.csv'):
            name = filename[r + 1:-4]
        else:
            name = filename[r + 1:]

    if 'dis' in data.columns:
        dis = np.array(data['dis'])
        If = []
        XIf = []
        for i in range(len(dis) - 1):
            if dis[i] == dis[i + 1]:
                If += [dis[i]]
                XIf += [X[i], X[i + 1]]
        profile = DiffProfile(dis, X, If, name=name)
        if Xlim is None:
            XIf = np.array([X[0]] + XIf + [X[-1]])
        else:
            XIf = np.array([Xlim[0]] + XIf + [Xlim[-1]])
        Xr = XIf.reshape((len(XIf) // 2, 2))
    if 'DC' in data.columns:
        DC = np.array(data['DC'])
    else:
        X = DC = None
    if Xr is not None:
        diffsys = DiffSystem(Xr, X=X, DC=DC, name=name)
    return profile, diffsys