diff --git a/py/experimentalfits.py b/py/experimentalfits.py index 28bf667f9eafa9b6527d07d1cee213b2c370dfb9..4b823dfeb222b1039c6bd9341c39ab93ab553925 100644 --- a/py/experimentalfits.py +++ b/py/experimentalfits.py @@ -2,12 +2,6 @@ import numpy as np import matplotlib.pyplot as plt import fits -# Set font size and stuff for images in the tex document -plt.rcParams.update({'font.size': 16, - 'lines.linewidth': 2, - 'lines.markersize': 10, - 'lines.markeredgewidth': 2}) - # Read the experiments height = 30e-9 Ex115 = fits.Experiment("../data/experiment/Sb2Te_asd_20W_115C.csv", height) @@ -58,6 +52,8 @@ def fit_J_115(): axes = jfit.plotJ() axes.set_xlim(-500,31800) axes.set_ylim(-0.001, 0.048) + axes.ticklabel_format(style="sci", scilimits=(0,0), useOffset=False, + axis="both") fig = axes.figure fig.tight_layout() return fig @@ -66,6 +62,8 @@ def fit_Nc_115(): jfit = Ex115.nucleationRateFit([1.7e3,9.7e3,20e3]).fit() jfit.info() axes = jfit.plotN() + axes.ticklabel_format(style="sci", scilimits=(0,0), useOffset=False, + axis="both") axes.figure.tight_layout() return axes.figure @@ -101,7 +99,7 @@ S = fits.SeriesOfMeasurements(np.array([115,120,125,130]) + 273.15, [Ex115,Ex120,Ex125,Ex130], 2) S.load() V = fits.ArrheniusFit(S).fit() -C = fits.SimpleCntFit(S, 296.4e6, 837, 9e-2).fit() +C = fits.SimpleCntFit(S, 296.4e6, 837, V.Ea, 9e-2).fit() def fit_cnt(): C.info() @@ -109,6 +107,7 @@ def fit_cnt(): axes.set_xlim(384.7,405.3) axes.set_ylim(-1e12,4e13) C.plot(axes) + axes.lines[0].set_marker("s") axes.legend() fig.tight_layout() return fig @@ -138,12 +137,12 @@ def fit_mobility(L=296.4e6, Tm=837): # Generate and save figures -#show_incubationtime().savefig("../img/exp_incubationtime.png") -#fit_v().savefig("../img/exp_v.png") -#fit_J_115().savefig("../img/exp_J_115.png") -#fit_Nc_115().savefig("../img/exp_Nc_115.png") -#comp_120().savefig("../img/exp_jmak_120.png") -#comp_125().savefig("../img/exp_jmak_125.png") -#fit_cnt().savefig("../img/exp_cnt.png") -#fit_arrhenius().savefig("../img/exp_v_arrhenius.png") -#fit_arrhenius_lin().savefig("../img/exp_v_arrhenius_lin.png") +show_incubationtime().savefig("../img/exp_incubationtime.png") +fit_v().savefig("../img/exp_v.png") +fit_J_115().savefig("../img/exp_J_115.png") +fit_Nc_115().savefig("../img/exp_Nc_115.png") +comp_120().savefig("../img/exp_jmak_120.png") +comp_125().savefig("../img/exp_jmak_125.png") +fit_cnt().savefig("../img/exp_cnt.png") +fit_arrhenius().savefig("../img/exp_v_arrhenius.png") +fit_arrhenius_lin().savefig("../img/exp_v_arrhenius_lin.png") diff --git a/py/fits/__init__.py b/py/fits/__init__.py index 5f51db4ba1e9588bf9deae6556b862e111f970ad..f7a0ed70d3b946448767bf3aa9989b2f08806198 100644 --- a/py/fits/__init__.py +++ b/py/fits/__init__.py @@ -2,6 +2,16 @@ Analysis of experiments on phase change materials. """ +# Change matplotlib settings +import matplotlib.pyplot as plt +from cycler import cycler +colors = ['blue','red','green','orange','purple'] +plt.rcParams.update({'font.size': 16, + 'lines.linewidth': 2, + 'lines.markersize': 5, + 'lines.markeredgewidth': 2, + 'axes.prop_cycle': cycler('color', colors)}) + # Import classes for single measurements and fits from .measurements import * from .measurements import __all__ @@ -20,4 +30,4 @@ from .comparisons import * from .comparisons import __all__ as __all3__ __all__.extend(__all3__) -del __all3__ \ No newline at end of file +del __all3__ diff --git a/py/fits/comparisons.py b/py/fits/comparisons.py index fc2666cdb66fdf8581bb549c04189507debd1ac2..2cc4580b7df7f91c03e2f80ad6f9daef302b55c6 100644 --- a/py/fits/comparisons.py +++ b/py/fits/comparisons.py @@ -21,7 +21,7 @@ class ExperimentComparison: """ Comparison of the crystallised fraction. """ if axes is None: fig, axes = plt.subplots(1,1) - axes.plot(self.E.times, self.E.cfract, linestyle="none", marker="x", + axes.plot(self.E.times, self.E.cfract, linestyle="none", marker="s", label="Experiment") axes.plot(self.S.times, self.S.cfract, label="Simulation") axes.set_xlabel("$t\\ [s]$") @@ -32,7 +32,7 @@ class ExperimentComparison: """ Comparison of the grain count. """ if axes is None: fig, axes = plt.subplots(1,1) - axes.plot(self.E.times, self.E.nuclei, linestyle="none", marker="x", + axes.plot(self.E.times, self.E.nuclei, linestyle="none", marker="s", label="Experiment") axes.plot(self.S.times, self.S.nuclei, label="Simulation") axes.set_xlabel("$t\\ [s]$") @@ -91,6 +91,7 @@ class ExperimentComparison: class TheoryComparison: def __init__(self, M, J, v): + """ A measurement M, used nucleation rate J and velocity v """ self.M = M self.J = J self.v = v diff --git a/py/fits/measurements.py b/py/fits/measurements.py index 31bbb97541551dad01ec5aac9984fe93956b2e51..6b1be89620f1e77215a2723fd5f5fb2fa3a1ae49 100644 --- a/py/fits/measurements.py +++ b/py/fits/measurements.py @@ -42,12 +42,12 @@ class Measurement: cfract - crystallized fraction [1] """ - def plot_fc(self, axes=None): + def plot_fc(self, axes=None, **kwargs): """ Plot the crystallised fraction over time. """ if axes is None: fig, axes = plt.subplots(1,1) - axes.plot(self.times, self.cfract, linestyle="none", marker="x", - label="data") + axes.plot(self.times, self.cfract, **dict({"linestyle":"none", + "marker":"s", "label":"data"}, **kwargs)) axes.set_xlabel("$t \\ [s]$") axes.set_ylabel("$f_c$") return axes @@ -56,7 +56,7 @@ class Measurement: """ Plot the counted nuclei over time. """ if axes is None: fig, axes = plt.subplots(1,1) - axes.plot(self.times, self.nuclei, linestyle="none", marker="x", + axes.plot(self.times, self.nuclei, linestyle="none", marker="s", label="data") axes.set_xlabel("$t \\ [s]$") axes.set_ylabel("$N$") @@ -66,7 +66,7 @@ class Measurement: """ Plot the size of the i-th nucleus over time. """ if axes is None: fig, axes = plt.subplots(1,1) - axes.plot(self.times, self.radii[i]*1e6, linestyle="none", marker="x", + axes.plot(self.times, self.radii[i]*1e6, linestyle="none", marker="s", label="$r_{{{}}}$".format(i)) axes.set_xlabel("$t \\ [s]$") axes.set_ylabel("$r \\ [\\mu m]$") @@ -264,10 +264,11 @@ class NucleationRateFit: # Assume poisson uncertainty uN2 = np.maximum(np.sqrt(N2), 1) axes.errorbar(self._ta, N2, uN2, linestyle=":", label="data") - y0, y1 = 0, 0 + xs, ys = [self.domainboundaries[0][0]], [0] for (tmin, tmax), (J,_) in zip(self.domainboundaries, self.Js): - y0, y1 = y1, y1+J*(tmax-tmin) - plt.plot([tmin,tmax], [y0, y1], label="integrated mean rate") + xs.append(tmax) + ys.append(ys[-1] + J*(tmax-tmin)) + plt.plot(xs, ys, label="integrated mean rate") axes.set_xlabel("$t \\ [s]$") axes.set_ylabel("$N_{corrected}$") return axes @@ -399,7 +400,7 @@ class JmakFit: xs, ys, _ = self.linearise() n, k = self.n, self.k c = np.log(k) - axes.plot(xs, ys, linestyle="none", marker="x", label="data") + axes.plot(xs, ys, linestyle="none", marker="s", label="data") axes.plot(xs, n*xs+c, label="fit") axes.set_xlabel('$\ln(t \\ [s])$') axes.set_ylabel('$\ln( - \ln( 1 - f_c ))$') diff --git a/py/fits/scripts.py b/py/fits/scripts.py index 219bbb510e6374a196c70b7a7d502499ded93c32..b6ebd776f8438a68336cac9288b997991e5d8a68 100644 --- a/py/fits/scripts.py +++ b/py/fits/scripts.py @@ -4,6 +4,8 @@ This file provides some general mathematical methods: weightedmean - Weighted mean value of values with uncertainties chisq_ndf - Chisquared per degree of freedom for given data, function and parameters + enlargedLinspace - A linspace (n evenly spaced values from a to b) enlarged + symetrically by a factor """ import numpy as np @@ -55,5 +57,5 @@ def enlargedLinspace(left,right,num=50,factor=1): a factor. Default factor is one, default amount of points is 50. """ - shift = (right-left)*factor + shift = (right-left)*(factor-1) return np.linspace(left-shift, right+shift, num) \ No newline at end of file diff --git a/py/fits/series.py b/py/fits/series.py index d3e8b3691c3c05e973c6239267a12fbc816b6d1f..9f58d9479f2cb214a2ec40b1d984b43ec7623ded 100644 --- a/py/fits/series.py +++ b/py/fits/series.py @@ -6,7 +6,7 @@ from several measurements at different temperatures. import numpy as np import matplotlib.pyplot as plt import scipy.optimize -from .scripts import linreg, chisq_ndf +from .scripts import linreg, chisq_ndf, enlargedLinspace # Some physial constants kB = 1.380649e-23 @@ -51,13 +51,13 @@ class SeriesOfMeasurements: """ return ArrheniusFit(self) - def simpleCntFit(self, L, Tm, IE): + def simpleCntFit(self, L, Tm, Ea, IE): """ Return an object to fit classical nucleation theory to the rates of this series, using given values for the latent heat L, the melting temperature Tm and an initial guess for the interfacial energy IE. """ - return SimpleCntFit(self, L, Tm, IE) + return SimpleCntFit(self, L, Tm, Ea, IE) def mobilityFit(self, dGv): """ @@ -81,7 +81,7 @@ class ArrheniusFit: """ Fit in the linearised problem. """ m, um, c, uc, _, _ = linreg(1/self.Ts, np.log(self.vs), self.uvs) self.vinf, self.uvinf = np.exp(c), np.exp(c)*uc - self.Ea, self.uEa = -m, um + self.Ea, self.uEa = -m*kB, um*kB return self def fit(self): @@ -89,29 +89,29 @@ class ArrheniusFit: self.linfit() fitfunc = lambda x,a,b: a*np.exp(-b/x) Ts, vs, uvs = self.Ts, self.vs, self.uvs - p0 = [self.vinf, self.Ea] + p0 = [self.vinf, self.Ea/kB] popt, pcov = scipy.optimize.curve_fit(fitfunc, Ts, vs, p0=p0, sigma=uvs, absolute_sigma=True) - self.vinf, self.Ea = popt[0], popt[1] - self.uvinf, self.uEa = np.sqrt(pcov[0,0]), np.sqrt(pcov[1,1]) + self.vinf, self.Ea = popt[0], popt[1]*kB + self.uvinf, self.uEa = np.sqrt(pcov[0,0]), np.sqrt(pcov[1,1])*kB return self def v(self,T): """ Velocity as a function of temperature according to the fit result. """ - return self.vinf * np.exp(-self.Ea/T) + return self.vinf * np.exp(-self.Ea/kB/T) def info(self): """ Print some information. """ - print("Fitting v = vinf*exp(-Ea/T)") + print("Fitting v = vinf*exp(-Ea/kB/T)") print("vinf = {} +- {}".format(self.vinf, self.uvinf)) print("Ea = {} +- {}".format(self.Ea, self.uEa)) - Ea, uEa = [x/eV*kB for x in [self.Ea, self.uEa]] - print(" = (",Ea,"+-",uEa,")eV/kB") + Ea, uEa = [x/eV for x in [self.Ea, self.uEa]] + print(" = (",Ea,"+-",uEa,")eV") print("chisq/ndf:", chisq_ndf(self.Ts, self.vs, self.uvs, (lambda x,a,b: a*np.exp(-b/x)), - [self.vinf, self.Ea])) + [self.vinf, self.Ea/kB])) return self def plot_lin(self, axes=None): @@ -119,7 +119,7 @@ class ArrheniusFit: if axes is None: fig, axes = plt.subplots(1,1) invTs = 1/self.Ts - m, c = -self.Ea, np.log(self.vinf) + m, c = -self.Ea/kB, np.log(self.vinf) axes.errorbar(invTs, np.log(self.vs), self.uvs/self.vs, linestyle="none", marker="_", label="data") axes.plot(invTs, m*invTs+c, label="fit") @@ -147,6 +147,10 @@ def bulkFreeEnergy(T,L,Tm): def criticalFreeEnergy(T,IE,L,Tm): return 16*np.pi*IE**3/(3*bulkFreeEnergy(T,L,Tm)**2) +def nucleationrate(T,a,IE,Ea,L,Tm): + return ( 1/(3*np.pi**2*a) * np.sqrt(kB*T*IE) * + np.exp(-(Ea + criticalFreeEnergy(T,IE,L,Tm))/kB/T) ) + class SimpleCntFit: """ A simple fit of classical nucleation theory onto the nucleation rates, @@ -154,52 +158,45 @@ class SimpleCntFit: the prefactor b and interfacial energy IE as fit parameters. """ - def __init__(self, series, L, Tm, IE): + def __init__(self, series, L, Tm, Ea, IE): """ Build an object of a given series of measurements, using given values - for the latent heat L, melting temperature Tm and an initial guess for - the interfacial energy IE. + for the latent heat L, melting temperature Tm, activation energy Ea + and an initial guess for the interfacial energy IE. """ self.Ts = series.Ts self.Js = series.Js self.uJs = series.uJs - self.L, self.Tm, self.IE = L, Tm, IE + self.L, self.Tm, self.Ea, self.IE = L, Tm, Ea, IE def fit(self): """ Perform the fit. """ Ts, Js, uJs = self.Ts, self.Js, self.uJs - # Functions for nucleation rate from CNT - J = lambda T,b,IE,L,Tm: (b*bulkFreeEnergy(T,L,Tm)**2/(8*np.pi) * - 1/np.sqrt(IE**3*kB*T) * - np.exp(-criticalFreeEnergy(T,IE,L,Tm)/kB/T)) # Fitfunction with L and Tm from literature - fitfunc = lambda T,b,IE: J(T,b,IE,self.L,self.Tm) - # Guess for IE is literature value, choose initial prefactor to fit some + fitfunc = lambda T,a,IE: nucleationrate(T,a,IE,self.Ea,self.L,self.Tm) + # Guess for IE is a given value, choose initial prefactor to fit some # arbitary point. Do the fit. - b0 = Js[len(Js)//2]/fitfunc(Ts[len(Js)//2],1,self.IE) + a0 = fitfunc(Ts[len(Js)//2],1,self.IE) / Js[len(Js)//2] popt, pcov = scipy.optimize.curve_fit(fitfunc, Ts, Js, maxfev=60000, - p0=[b0,self.IE], sigma=uJs) - self.b, self.IE = popt - self.ub, self.uIE = np.sqrt(pcov[0,0]), np.sqrt(pcov[1,1]) -# self.b, self.IE = b0, self.IE -# self.ub, self.uIE = 1, 1 + p0=[a0,self.IE], sigma=uJs) + self.a, self.IE = popt + self.ua, self.uIE = np.sqrt(pcov[0,0]), np.sqrt(pcov[1,1]) +# self.a, self.IE = a0, self.IE +# self.ua, self.uIE = 1, 1 return self def J(self,T): """ Nucleation rate as a temperature dependent function from this fit. """ - b, IE, L, Tm = self.b, self.IE, self.L, self.Tm - return (b*bulkFreeEnergy(T,L,Tm)**2/(8*np.pi) * - 1/np.sqrt(IE**3*kB*T) * - np.exp(-criticalFreeEnergy(T,IE,L,Tm)/kB/T)) + return nucleationrate(T,self.a,self.IE,self.Ea,self.L,self.Tm) def info(self): """ Print some information. """ - print("Fitting J = b*dGv**2/(8*pi)/sqrt(IE**3*kB*T) * exp(-dGc/kB/T)") + print("Fitting J = 1/(3*pi^2*a) * sqrt(kB*T*IE) * exp(-(Ea + dGc)/kB/T)") print(" dGc = 16*pi*IE^3/(3*dGv)") print(" dGv = L*(Tm-T)/Tm*2*T/(Tm+T)") - print("b: ",self.b,"+-",self.ub) + print("a: ",self.a,"+-",self.ua) print("IE:",self.IE,"+-",self.uIE) return self @@ -212,7 +209,7 @@ class SimpleCntFit: else: plotrange = axes.get_xlim() axes.plot(Ts, Js, linestyle="none", marker=".", label="mean rates") - pxs = np.linspace(plotrange[0], plotrange[1], 200) + pxs = enlargedLinspace(plotrange[0], plotrange[1], 200, 1.05) axes.plot(pxs, self.J(pxs), label="fit") axes.set_xlabel("$T \\ [K]$") axes.set_ylabel("$J \\ [1/m^3/s]$") diff --git a/py/simulationresults.py b/py/simulationresults.py index d7a113773fc26ed637c37300f1998e02bb3b9328..abc767f7d71ecb3a13c045cf866728d4984852af 100644 --- a/py/simulationresults.py +++ b/py/simulationresults.py @@ -3,17 +3,9 @@ Comparing the experimental data to the simulations with parameters from them. """ import numpy as np -import matplotlib import matplotlib.pyplot as plt import fits -# Set font size and stuff for images in the tex document -matplotlib.style.use("classic") -plt.rcParams.update({'font.size': 16, - 'lines.linewidth': 2, - 'lines.markersize': 10, - 'lines.markeredgewidth': 2}) - # Read the experimental data height = 30e-9 Ex115 = fits.Experiment("../data/experiment/Sb2Te_asd_20W_115C.csv", height) @@ -27,6 +19,12 @@ S120 = fits.Simulation("../data/sb2te_120.csv") S125 = fits.Simulation("../data/sb2te_125.csv") S130 = fits.Simulation("../data/sb2te_130.csv") +# Read the simulations with constant nucleation rate +S115s = fits.Simulation("../data/sb2te_simple_115.csv") +S120s = fits.Simulation("../data/sb2te_simple_120.csv") +S125s = fits.Simulation("../data/sb2te_simple_125.csv") +S130s = fits.Simulation("../data/sb2te_simple_130.csv") + # Time offsets coming from nucleation rates starting with zero S115.timeoffset(1.7e3) @@ -35,6 +33,10 @@ C15 = fits.ExperimentComparison(Ex115, S115) C20 = fits.ExperimentComparison(Ex120, S120) C25 = fits.ExperimentComparison(Ex125, S125) C30 = fits.ExperimentComparison(Ex130, S130) +C15s = fits.ExperimentComparison(Ex115, S115s) +C20s = fits.ExperimentComparison(Ex120, S120s) +C25s = fits.ExperimentComparison(Ex125, S125s) +C30s = fits.ExperimentComparison(Ex130, S130s) # Nucleation rate fits #C15.compare_J([1.2e3,10e3,19e3,28e3]) @@ -42,23 +44,30 @@ C30 = fits.ExperimentComparison(Ex130, S130) #C25.compare_J([2000,3500]) #C30.compare_J([250,1100,1900]) -def analyse_115(): - axes1 = C15.plot_fc() +def _analyse(C): + axes1 = C.plot_fc() + axes1.ticklabel_format(style="sci", scilimits=(0,0), useOffset=False, + axis="both") axes1.legend() axes1.figure.tight_layout() - axes2 = C15.plot_N() + axes2 = C.plot_N() + axes2.ticklabel_format(style="sci", scilimits=(0,0), useOffset=False, + axis="both") axes2.legend() axes2.figure.tight_layout() return axes1.figure, axes2.figure +def analyse_115(): + return _analyse(C15) + def analyse_125(): - axes1 = C25.plot_fc() - axes1.legend() - axes1.figure.tight_layout() - axes2 = C25.plot_N() - axes2.legend() - axes2.figure.tight_layout() - return axes1.figure, axes2.figure + return _analyse(C25) + +def analyse_115_s(): + return _analyse(C15s) + +def analyse_125_s(): + return _analyse(C25s) def comp_jmak_115(): jb = Ex115.jmakBuild(2) @@ -70,6 +79,8 @@ def comp_jmak_115(): axes.lines[2].set_marker("") axes.lines[2].set_linestyle("solid") axes.lines[2].set_label("Simulation") + axes.ticklabel_format(style="sci", scilimits=(0,0), useOffset=False, + axis="both") axes.legend() axes.figure.tight_layout() return axes.figure @@ -84,13 +95,17 @@ def comp_jmak_125(): axes.lines[2].set_marker("") axes.lines[2].set_linestyle("solid") axes.lines[2].set_label("Simulation") + axes.ticklabel_format(style="sci", scilimits=(0,0), useOffset=False, + axis="both") axes.legend() axes.figure.tight_layout() return axes.figure # Generate and save images -#for figs, T in zip([analyse_115(), analyse_125()], [115, 125]): -# figs[0].savefig("../img/simres_sb2te_{}_fc.png".format(T)) -# figs[1].savefig("../img/simres_sb2te_{}_N.png".format(T)) -#comp_jmak_115().savefig("../img/simres_sb2te_jmak_115.png") -#comp_jmak_125().savefig("../img/simres_sb2te_jmak_125.png") +for figs, name in zip([analyse_115(), analyse_125(), analyse_115_s(), + analyse_125_s()], + ["115", "125", "115_s", "125_s"]): + figs[0].savefig("../img/simres_sb2te_{}_fc.png".format(name)) + figs[1].savefig("../img/simres_sb2te_{}_N.png".format(name)) +comp_jmak_115().savefig("../img/simres_sb2te_jmak_115.png") +comp_jmak_125().savefig("../img/simres_sb2te_jmak_125.png") diff --git a/py/test_analysis.py b/py/test_analysis.py index 26b63bfe0206272fcee0de2bf9dc91c8759c4259..5468c3a20ff38e4aa71504e909d5d2a554b3557d 100644 --- a/py/test_analysis.py +++ b/py/test_analysis.py @@ -6,12 +6,6 @@ import numpy as np import matplotlib.pyplot as plt import fits -# Set font size and stuff for images in the tex document -plt.rcParams.update({'font.size': 16, - 'lines.linewidth': 2, - 'lines.markersize': 10, - 'lines.markeredgewidth': 2}) - # Read all done simulations, give the nucleation rate that was put in Comparisons = [] setrates = np.array([8e13,6e14,4e15]) * 4000**2 * 6.28e-8**3 @@ -40,6 +34,7 @@ def test_nucleationratefit_bias(): def show_nucleationrate_test(): print("Set:", Comparisons[2].J) axes1 = Comparisons[2].fit().plot_Nc() + axes1.lines[0].set_color("tab:blue") axes1.lines[1].set_label("fit") axes1.legend() axes1.figure.tight_layout() @@ -57,6 +52,6 @@ def show_nucleationrate_test(): # Generate and save images -#fig1, fig2 = show_nucleationrate_test() -#fig1.savefig("../img/simtest_J_1.png") -#fig2.savefig("../img/simtest_J_2.png") +fig1, fig2 = show_nucleationrate_test() +fig1.savefig("../img/simtest_J_1.png") +fig2.savefig("../img/simtest_J_2.png") diff --git a/tex/SimpleThesis.cls b/tex/SimpleThesis.cls index 66352172da7772bd1a6d4b2cda4302e72311d126..ed14818962352a68861b5af420ffedfe1425029a 100755 --- a/tex/SimpleThesis.cls +++ b/tex/SimpleThesis.cls @@ -48,6 +48,12 @@ ]{geometry} \KOMAoptions{twoside=semi,BCOR=10mm} +% Penalize some unwanted behaviour +\widowpenalty=8000 % No page break after first line of paragraph +\clubpenalty=8000 % No page breakes before last line of paragraph +\binoppenalty=7000 % No line break after binary math operators +\relpenalty=5000 % No line break after math relations + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Provide the options master and bachelor to define thesis type. diff --git a/tex/experimentaldata.tex b/tex/experimentaldata.tex index 8fd7787807c636d689813953e610c32fe52535d1..2a39a2d8dbb2ac3d92c452c7d4e1c7d5214e3e00 100644 --- a/tex/experimentaldata.tex +++ b/tex/experimentaldata.tex @@ -97,6 +97,25 @@ experiments as well. In most of these tests, the result of the analysis was approximately one sigma away from the value used in the simulation. + \begin{figure}[tbp] + \begin{subfigure}{.49\linewidth} + \includegraphics[width=\linewidth]{../img/simtest_J_1.png} + \end{subfigure} + \hfill + \begin{subfigure}{.49\linewidth} + \includegraphics[width=\linewidth]{../img/simtest_J_2.png} + \end{subfigure} + \caption{Comparison of the nucleation rate that was set in the simulation + ($\SI[per-mode=reciprocal]{2.378}{\per\s}$), + the number of grains in the simulation + and the mean rate obtained from the presented fit on this data + ($\SI[per-mode=reciprocal]{2.256\pm0.092}{\per\s}$ on the left and + $\SI[per-mode=reciprocal]{2.324\pm0.095}{\per\s}$ on the right). + Both images use the same parameters, but a different seed for random + number generation.} + \label{fig:expfit_J_test} + \end{figure} + For the available data on \sbte{} however, the assumption of a constant nucleation rate does not seem to hold. This can be seen in the data shown in figure~\ref{fig:expfit_J} and will also @@ -140,25 +159,6 @@ experiments as well. % \end{tabular} % \end{center} - \begin{figure}[tbp] - \begin{subfigure}{.49\linewidth} - \includegraphics[width=\linewidth]{../img/simtest_J_1.png} - \end{subfigure} - \hfill - \begin{subfigure}{.49\linewidth} - \includegraphics[width=\linewidth]{../img/simtest_J_2.png} - \end{subfigure} - \caption{Comparison of the nucleation rate that was set in the simulation - ($\SI[per-mode=reciprocal]{2.378}{\per\s}$), - the number of grains in the simulation - and the mean rate obtained from the presented fit on this data - ($\SI[per-mode=reciprocal]{2.256\pm0.092}{\per\s}$ on the left and - $\SI[per-mode=reciprocal]{2.324\pm0.095}{\per\s}$ on the right). - Both images use the same parameters, but a different seed for random - number generation.} - \label{fig:expfit_J_test} - \end{figure} - \begin{figure}[tbp] \begin{subfigure}{.49\linewidth} \includegraphics[width=\linewidth]{../img/exp_J_115.png} @@ -266,7 +266,8 @@ experiments as well. was fitted to this values. For $\dGv$, the introduced model was used together with values from other experiments~\citep{expdata,sb2teStructure} - that are listed in the next chapter. %TODO ref + that are listed in section~\ref{sec:sbteresults} together with all other + used parameters. For $\eta$, an Arrhenius behaviour was assumed with the same activation energy as obtained from the fit onto the velocities, which is motivated by the discussion in section~\ref{sec:arrheniusviscosity}. diff --git a/tex/introduction.tex b/tex/introduction.tex index 5022b7e601064bebdfcc80ed6fbdff91f8ec8c3a..6ad03f71d8e906c001de73bc874a557a522e202e 100644 --- a/tex/introduction.tex +++ b/tex/introduction.tex @@ -1,16 +1,15 @@ \chapter{Introduction} -\section{Motivation} - %TODO rewrite - +\section{Motivation} Phase change materials are a class of substances that can exist in two distinct phases. The properties of the phases can largely differ. - This includes several electrical and optical properties. %TODO One famous group of ... - In chalcogenide phase change materials for example both the - real and the imaginary part of the dielectric function change - about two orders of magnitude~\citep{Usecases}. + This includes several electrical and optical properties. + One established group of phase change material are the chalcogenide phase + change materials. + For them, both the real and the imaginary part of the dielectric function + can change about two orders of magnitude~\citep{Usecases}. Other changes include the refractive index ($\Delta n > 1$)~\citep{PCMsInOptics} and the electrical resistivity~\citep{phaseChangeRam}. @@ -41,7 +40,7 @@ Combining this technology with phase change materials enables to alter these properties post-production. - Most popular examples are semiconductor chalcogenides, + The most popular examples are the mentioned semiconductor chalcogenides, led by \GSTxxx{2}{2}{5} and other compositions of germanium, antimon and tellur. They undergo a crystalline - amorphous transition and have diff --git a/tex/simulationmodel.tex b/tex/simulationmodel.tex index 7d5f7ef98dde1256cce4f035b58d6823778514b4..173fabba28e417397b81a009b1ddcd1cc2a5f95a 100644 --- a/tex/simulationmodel.tex +++ b/tex/simulationmodel.tex @@ -180,7 +180,6 @@ and simple simulations to test the limits of the calculated behaviour. would be to port the code to another language that offers higher performance and better usability itself. -%TODO other title? \section{Numerical Limits} In numerical simulations of a phase field model, there is a conflict of three interests. One the one hand, for $\zeta \rightarrow 0$ the phase field model @@ -217,15 +216,17 @@ and simple simulations to test the limits of the calculated behaviour. \includegraphics[width=\columnwidth]{../img/tau_shape.png} \caption{Visualization of the relaxation process for an interface wider than the equilibrium shape. In the legend are time values in - units of $\tau$.} + units of $\tau$. The relaxation process is visible.} \end{subfigure} \hfill \begin{subfigure}{.49\columnwidth} \includegraphics[width=\columnwidth]{../img/tau_time.png} \caption{The integrated difference between the field and the theoretical - equilibrium shape as a function of time for different values of $\tau$.} + equilibrium shape as a function of time for different values of $\tau$. + The relaxation is approximately exponential with a slope dependent + on $\tau$.} \end{subfigure} - \caption{} + \caption{Tests regarding the relaxation of the interface shape.} \label{fig:tau_demo} \end{figure} diff --git a/tex/simulationresults.tex b/tex/simulationresults.tex index bd0fe736f1837697b2cff04a684c483f4aad4ace..97e213f2269a5f0115799172e9ba3b3e0c7e49e0 100644 --- a/tex/simulationresults.tex +++ b/tex/simulationresults.tex @@ -12,6 +12,7 @@ % This cryptic stuff in the section title is necessary as the % hyperref package does not want math mode in links \section{\texorpdfstring{\sbte}{Sb2Te}} + \label{sec:sbteresults} Two simulations for \sbte{} were implemeted using both physical and numerical values for $r_c$. For the velocity, an Arrhenius model is used together with the parameters @@ -30,7 +31,7 @@ $L$ & $\SI{47.2}{\J\per\g} \times \SI{6.28}{\g\per\cm\tothe{3}} = \SI{296.4e6}{\J\per\m\tothe{3}}$ & \citep{expdata}, \citep{sb2teStructure} \\ $T_m$ & $\SI{838}{\K}$ & \citep{expdata} \\ $v_\infty$ & $\SI{1.9 e15}{\m\per\s}$ & fit on $v$ (\citep{expdata}) \\ - $E_a$ & $\SI{1.82}{\eV}$ & fit (\citep{expdata}) fit on $v$\\ + $E_a$ & $\SI{1.82}{\eV}$ & fit on $v$ (\citep{expdata})\\ $\lambda^3 \eta_\infty \left(\frac{3 V_m}{4 \pi}\right)^{(2/3)}$ & $\SI{1.2 e99}{\J\m\squared\s}$ & fit on $N$(\citep{expdata}) \\ $\gamma$ & $\SI{7.29 e-2}{\J\per\m\squared}$ & fit on $N$ (\citep{expdata}) \\ \end{tabular} @@ -75,6 +76,11 @@ The results of this method are compared to the experiment in figures~\ref{fig:sbte_res_115} and~\ref{fig:sbte_res_125} and show better consistence. + Furthermore, the simulation describes the data better than the JMAK model + does, which can be seen in figure~\ref{fig:cmp_sim_jmak}. + While only small deviations can be seen for some temperatures, + the advantage becomes obvious whenever the nucleation rate varies strongly + over time. This is first of all a confirmation of the phase field model. As it is however not possible to extrapolate the behaviour for different temperatures and samples from these results, @@ -139,8 +145,10 @@ For $\SI{115}{\celsius}$, there are barly differences visible. For $\SI{125}{\celsius}$ however, where some unusual behaviour in the grain count appears, the simulation describes the data significantly better.} + \label{fig:cmp_sim_jmak} \end{figure} + \clearpage \section{AIST} For AIST, two simulation models models were implemented during this thesis. The first uses only physical reasonable parameters. @@ -162,7 +170,7 @@ The volume per atom was estimated from the latent heat per volume and the one per atom $L \cdot V_m = \SI{173 \pm 3}{\meV}$~\citep{AistExperiments}. The nucleation rate was obtained from classical nucleation theory. - + All parameters are listed in the following table: \begin{center} \begin{tabular}{c|c|c} Parameter & Value & Reference \\ @@ -213,6 +221,7 @@ The prefactor in the Arrhenius model for the viscosity is called $\eta_0$ here to distinguish it from the parameter in the MYEGA model. The nucleation rate is calculated as $J = J_\infty \exp(\frac{-E_J}{k_B T})$. + Concluding, the used parameters are: \begin{center} \begin{tabular}{c|c|c} Parameter & Value & Reference \\ diff --git a/tex/theory.tex b/tex/theory.tex index 1c3d81ad4492bf34c0e739e15d9f20071b10afe7..21abae841f2b4cba6f0f43f9f3be2d867f43537a 100644 --- a/tex/theory.tex +++ b/tex/theory.tex @@ -171,6 +171,14 @@ the phase field model. For the velocity of this process, there are different models that have been used for different materials and temperature ranges. + Most experiments are performed on a limited temperature range and use + a single model to describe the results. + The used models differ however for the different temperature ranges + and lead to contradictory results for the intermediate ranges. + Some authors who analyse data over the full temperature range introduce + a glass transition temperature $T_{glass}$ and use different models + above and below this temperature~\citep{crystalGrowthInPcm}. + \subsubsection{Arrhenius Model} Many processes that require an activation energy $E_a$ are proportional to a Boltzmann factor $\exp(\frac{- E_a}{k_B T})$, @@ -259,8 +267,8 @@ the phase field model. GeTe~\citep{geteExperimentsNew} in the simplified second one. \subsection{Viscosity} - %TODO different models are used below and above a glass transition - % temperature + For the viscosity, the same arguments apply as for the velocity regarding + the glass transition temperature. \subsubsection{Arrhenius Model} \label{sec:arrheniusviscosity} @@ -386,7 +394,7 @@ the phase field model. Originally, the theory was derived from a probabilistic point of view: The crystallized fraction of the material equals to the probability for an - arbitrary point to be crystallized. %TODO more to this way + arbitrary point to be crystallized. An alternative way directly integrates the crystallized fraction. The volume at time $t$ of a grain that appeared (with negligible size) at time $\tau$ @@ -896,11 +904,12 @@ the phase field model. evolution is relatively independend from it. \section{Numerical Methods} - %TODO The phase field model describes continuous fields or even approximates non continuous fields with smooth functions. For computational calculations however, the field has to be represented by a finite number of discrete values. + There is a wide range of techniques used for this, out of which only the used + ones will be presented here. \subsection{Finite Differences} The simulation is implemented using a finite difference diff --git a/tex/thesis.tex b/tex/thesis.tex index 80388ef616d7dfb2f632cfbf98b1f0b0ff9f63af..44ea66e1e0e2dfcda099886ad192b4e6b4ee2174 100755 --- a/tex/thesis.tex +++ b/tex/thesis.tex @@ -20,7 +20,7 @@ \newcommand{\dGv}{\Delta \! G_{\!V}} % bulk free energy \newcommand{\intdV}{\int_V d^3 \! x \,} % volume integral \newcommand{\NaN}{\texttt{NaN}} % NaN in fancy font -\newcommand{\sbte}{$\text{Sb}_{\text{2}}\text{Te}$} % <- Sb2Te and GST +\newcommand{\sbte}{$\text{Sb}_{\text{2}}\text{Te}$} % <- Sb2Te and GST (next line) \newcommand{\GSTxxx}[3]{$\text{Ge}_{\text{#1}}\text{Sb}_{\text{#2}}\text{Te}_{\text{#3}}$} \begin{document} @@ -28,27 +28,22 @@ \frontmatter \maketitle -\includepdf[]{staturory_declaration_in_lieu_of_an_oath} \cleardoublepage - \tableofcontents \mainmatter \input{introduction} - \input{theory} - \input{simulationmodel} - \input{experimentaldata} - \input{simulationresults} - \input{finalstuff} \appendix \bibliography{sources} +\cleardoublepage +\includepdf[]{staturory_declaration_in_lieu_of_an_oath} \end{document}