コード例 #1
0
    def setup(self):

        self.plot_potential_space = numpy.linspace(
            0, self.thickness + self.offset,
            10 * self.precision * (self.thickness + self.offset) + 1)

        self.k_space = numpy.linspace(
            0, self.q_max / 2.0,
            int(self.q_precision * self.q_max * 1000) + 1)

        self.start_end = (0, numpy.argmax(self.k_space > self.cutoff))
        self.k_interpolation_range = self.k_space[self.start_end[0]:self.start_end[1]]

        if self.ideal_potential is None:
            self.ideal_potential = load_potential(self.file)

        self.ideal_potential = shift_potential(self.ideal_potential, self.offset)


        self.reflcalc = ReflectionCalculation(
            self.ideal_potential, 0, self.thickness + self.offset, 0.1)

        self.reflectivity = self.reflcalc.refl(2 * self.k_space)

        if self.start == 'exact':
            self.start = self.reflectivity[self.start_end[0]:self.start_end[1]]

        if self.start is None:
            self.start = 0

        self.start = array(self.start)

        self.real = shake(self.reflectivity.real, self.start_end, self.noise, self.start.real)
        self.imag = shake(self.reflectivity.imag, self.start_end, self.noise, self.start.imag)
コード例 #2
0
    def run(self, constrain):

        self.setup()

        rec = PotentialReconstruction(
            self.thickness + self.offset, self.precision,
            cutoff=self.pot_cutoff)
        reflcalc = ReflectionCalculation(
            None, 0, self.thickness + self.offset, 0.1)

        # plot the exact potential/refl/ for comparison
        self._plot_exact()

        # split the fourier transform up into two parts
        # f1 has the changing input
        # f2 has the non-changing input
        # since f2 contains much more data in general, we can save a lot of computation by
        # caching f2 and just
        # computing f1 each time.

        f1_index = slice(None, self.start_end[1]+1)
        f2_index = slice(self.start_end[1]+1, None)
        # self.real, self.imag contain the reflection coefficient
        f1 = FourierTransform(self.k_space[f1_index],
                              self.real[f1_index], self.imag[f1_index])
        f2 = FourierTransform(self.k_space[f2_index],
                              self.real[f2_index], self.imag[f2_index])

        if self.use_only_real_part:
            f1.method = f1.cosine_transform
            f2.method = f2.cosine_transform

        transform = UpdateableFourierTransform(f1, f2)


        # TODO: change the class name
        # Reconstruct the reflection using the fourier transform at  k =
        # k_interpolation_range (the low k range)
        # rec is used to reconstruct the potential
        # reflcalc is used to calculate the reflection coefficient
        # the constrain function constrains the potential
        interpolation = ReflectivityAmplitudeInterpolation(
            transform, self.k_interpolation_range, rec, reflcalc, constrain)

        interpolation.set_hook(self._plot_hook)
        if self.diagnostic_session:
            interpolation.set_hook(self._diagnostic_hook)

        solution = interpolation.interpolate(self.iterations, tolerance=self.tolerance)

        if self.plot_potential:
            self._potential_axes.legend()
        if self.plot_phase:
            self._phase_axes.legend()
        if self.plot_reflectivity:
            self._reflectivity_axes.legend()
        if self.show_plot:
            pylab.show()

        return solution
コード例 #3
0
plot_potential = True
plot_phase = False
plot_reflectivity = False

plot_potential_space = numpy.linspace(offset/2, end, 1000)

def shake(var, start_end):
    #var[start_end[0]:start_end[1]] = numpy.random.uniform(-1, 1, start_end[1]-start_end[0])
    var[start_end[0]:start_end[1]] = 0
    #var[start_end[0]:start_end[1]] *= numpy.random.normal(1.0, 0.05, start_end[1] - start_end[0])
    #var *= numpy.random.normal(loc=1.0, scale=noise, size=len(var))
    return var


potential = scipy.interpolate.interp1d(exact_potential[0]-offset/2, exact_potential[1], fill_value=(0, 0), bounds_error=False)
reflcalc = ReflectionCalculation(potential, 0, end, 0.1)
exact_refl = reflcalc.refl(exact_phase[0])
exact_phase[1] = exact_refl.real
exact_phase[2] = -exact_refl.imag
exact_potential[0] -= offset/2
offset = 0
cont_extact_potential = potential

k_space = exact_phase[0] / 2
start_end = (0, numpy.argmax(k_space > cutoff))

Refl = (array(exact_phase[1]), array(exact_phase[2]))
real = shake(exact_phase[1], start_end)
imag = shake(exact_phase[2], start_end)

eps = 1.0 / precision
コード例 #4
0
class TestRun(object):
    """
    This class is used for some numerical simulations of given potentials.
    This sets-up the required classes to do a reflectivity amplitude interpolation.

    On top of that, it has some nice plotting features, to see how the
    potential/reflection amplitzde/reflectivity is evolving for each iteration.

    The algorithm can be adjusted by changing the attributes defined in __init__.
    """

    def __init__(self, file_or_potential):

        # Starting value for the iteration. 'exact' is possible.
        # This will start the iteration at the exact reflectivity amplitude.
        # None/0 will start with a reflectivity amplitude being 0 below the
        # critical edge, see self.cutoff
        self.start = [0]

        # Sets R(k) = self.start for k < cutoff
        # 0.01 is approximately the critical edge for Si
        self.cutoff = 0.01

        # adds gaussian noise to R(q)
        self.noise = 5e-2

        # Max number of iteration till abortion
        self.iterations = 30

        # Algorithm terminates after R(k) is changing less than the given tolerance
        self.tolerance = 1e-8

        # Shifts the potential to the right, usefull when dealing with potential
        # having a rough surface
        self.offset = 20  # -500

        # Film thickness
        self.thickness = 520

        # int, 1/precision is the discretization step
        self.precision = 1

        # This will set values close to the boundary to 0
        self.pot_cutoff = 2

        # simulated R(k) up to k = q_max / 2
        self.q_max = 0.5
        # Simulation precision. Higher values simulates R(k) more densely.
        self.q_precision = 1

        # For the algorithm, use only the real part of R(k)?
        # TODO: also only use the imaginary part?
        self.use_only_real_part = False

        # Plot the potential?
        self.plot_potential = True
        # Plot the reflectivity amplitude?
        self.plot_phase = False
        # Plot the phase as: arg(r)
        self.plot_phase_angle = False
        # Plot the reflectivity?
        self.plot_reflectivity = False
        # Plot not every iteration, but every n-th
        self.plot_every_nth = 10
        # Plot anything at all
        self.show_plot = True
        # Store the results into this given path. If None, do not save to file.
        # Will only store every n-th iteration
        self.store_path = None

        self.ideal_potential = None
        self.file = None
        # Load potential from a file or accept a given potential function
        if isinstance(file_or_potential, str):
            self.file = file_or_potential
        else:
            self.ideal_potential = file_or_potential

        # if set to true, the script will gather diagnostic information
        # and store it into _diagnostics, which can be accessed via
        # self.diagnosis()
        self.diagnostic_session = False

        # Diagnosis object, stores some useful information
        self._diagnosis = {
            'iteration': [],
            'last_iteration': 0
        }

    def setup(self):

        self.plot_potential_space = numpy.linspace(
            0, self.thickness + self.offset,
            10 * self.precision * (self.thickness + self.offset) + 1)

        self.k_space = numpy.linspace(
            0, self.q_max / 2.0,
            int(self.q_precision * self.q_max * 1000) + 1)

        self.start_end = (0, numpy.argmax(self.k_space > self.cutoff))
        self.k_interpolation_range = self.k_space[self.start_end[0]:self.start_end[1]]

        if self.ideal_potential is None:
            self.ideal_potential = load_potential(self.file)

        self.ideal_potential = shift_potential(self.ideal_potential, self.offset)


        self.reflcalc = ReflectionCalculation(
            self.ideal_potential, 0, self.thickness + self.offset, 0.1)

        self.reflectivity = self.reflcalc.refl(2 * self.k_space)

        if self.start == 'exact':
            self.start = self.reflectivity[self.start_end[0]:self.start_end[1]]

        if self.start is None:
            self.start = 0

        self.start = array(self.start)

        self.real = shake(self.reflectivity.real, self.start_end, self.noise, self.start.real)
        self.imag = shake(self.reflectivity.imag, self.start_end, self.noise, self.start.imag)

    def _plot_exact(self):

        rec = PotentialReconstruction(self.thickness + self.offset, self.precision,
                                      cutoff=self.pot_cutoff)

        transform = FourierTransform(self.k_space, self.reflectivity.real,
                                     self.reflectivity.imag)
        potential = rec.reconstruct(transform)

        num_plots = int(self.plot_potential) + int(self.plot_phase) + int(self.plot_reflectivity)
        plot_k = 0
        if self.plot_potential:
            plot_k += 1
            self._potential_axes = pylab.subplot(num_plots, 1, plot_k)

            # cosine transform doesnt use imaginary part of the reflectivity amplitude
            # transform.method = transform.cosine_transform

            self.reference_potential = potential

            self.store_data(zip(self.plot_potential_space, self.ideal_potential(
                self.plot_potential_space)),'pot_exact', 'potential')

            self.store_data(zip(self.plot_potential_space, potential(
                self.plot_potential_space)), 'pot_ideal', 'potential')

            ax = self._potential_axes
            ax.plot(self.plot_potential_space,
                    self.ideal_potential(self.plot_potential_space),
                    label='Reconstructed SLD (exact)')
            ax.plot(self.plot_potential_space, potential(self.plot_potential_space), '-',
                    color='black', label='Exact SLD')
            ax.set_ylim(-1e-6, 1e-5)

        if self.plot_phase:
            plot_k += 1
            self._phase_axes = pylab.subplot(num_plots, 1, plot_k)

            ax = self._phase_axes
            if self.plot_phase_angle:
                ax.plot(self.k_space, numpy.angle(self.reflectivity),
                        label="Exact phase")
            else:
                ax.plot(self.k_space, (self.reflectivity.real * self.k_space ** 2),
                        label="Exact reflectivity (real)")

            self.store_data(zip(self.k_space, self.reflectivity.real, self.reflectivity.imag,
                                self.reflectivity.real * self.k_space ** 2,
                                self.reflectivity.imag * self.k_space ** 2),
                            'phase_exact', 'phase')

        if self.plot_reflectivity:
            plot_k += 1
            self._reflectivity_axes = pylab.subplot(num_plots, 1, plot_k)

            refl_ideal = self.reflcalc.refl(2 * self.k_space)

            self.store_data(zip(2 * self.k_space, abs(self.reflectivity) ** 2), 'refl_exact',
                            'reflectivity')
            self.store_data(zip(2 * self.k_space, abs(refl_ideal) ** 2), 'refl_ideal',
                            'reflectivity')

            ax = self._reflectivity_axes
            ax.plot(2 * self.k_space,
                    self.reflectivity.real ** 2 + self.reflectivity.imag ** 2,
                    label='Exact reflectivity (w/o noise)')
            ax.plot(2 * self.k_space, self.real ** 2 + self.imag ** 2, '+',
                    label='Exact reflectivity (w noise)')
            ax.plot(2 * self.k_space, refl_ideal.real ** 2 + refl_ideal.imag ** 2,
                    label='Ideal Reflectivity')

            ax.set_yscale('log')

    def diagnosis(self):
        return self._diagnosis

    def _diagnostic_hook(self, interpolator):
        assert isinstance(interpolator, ReflectivityAmplitudeInterpolation)

        refl = interpolator.reflectivity
        exact = (self.reflectivity[self.start_end[0]:self.start_end[1]])
        # total relative error in percentage
        relative_error = 1.0 / len(refl) * sum(abs((refl - exact) / exact * 100))

        self._diagnosis['iteration'].append((interpolator.iteration, interpolator.diff, relative_error))
        self._diagnosis['last_iteration'] = interpolator.iteration

    def _plot_hook(self, interpolator):
        iteration = interpolator.iteration
        potential = interpolator.potential
        interpolated_reflectivity = interpolator.reflectivity.real
        is_last = interpolator.is_last_iteration

        if iteration % self.plot_every_nth == 0 or is_last is True or iteration == 1:

            if self.plot_potential:
                ax = self._potential_axes

                x_space = self.plot_potential_space
                pot = potential(x_space)

                self.store_data(zip(x_space, pot), 'pot_it_{}'.format(iteration), 'potential')
                ax.plot(x_space, pot, '--', label=f"Iteration {iteration}")

            if self.plot_phase:
                ax = self._phase_axes

                k_subspace = self.k_space[0:self.start_end[1]]
                refl = interpolator.reflectivity

                self.store_data(
                    zip(k_subspace, refl.real, refl.imag, refl.real * k_subspace ** 2,
                        refl.imag * k_subspace ** 2),
                    'phase_it_{}'.format(iteration), 'phase')

                if self.plot_phase_angle:
                    # refl = interpolator.reflcalc.refl(2 * self.k_space)
                    qmax = 1.0
                    refl = interpolator.reflcalc.refl(
                        2 * numpy.linspace(0, qmax / 2,
                                           int(self.q_precision * qmax * 1000) + 1))
                    ax.plot(
                        numpy.linspace(0, qmax / 2, int(self.q_precision * qmax * 1000) + 1),
                        numpy.angle(refl),
                        label=f"Iteration {iteration}")
                else:
                    # That's just the real part of the reflectivity amplitude
                    ax.plot(k_subspace, interpolated_reflectivity * k_subspace ** 2, '.',
                            label=f"Iteration {iteration}")

            if self.plot_reflectivity:
                ax = self._reflectivity_axes

                R = interpolator.reflcalc.refl(2 * self.k_space)
                self.store_data(zip(2 * self.k_space, abs(R) ** 2),
                                'refl_it_{}'.format(iteration), 'reflectivity')
                ax.plot(2 * self.k_space, R.real ** 2 + R.imag ** 2, '--',
                        label=f"Iteration {iteration}")

            # relative error
            exact = (self.reflectivity[self.start_end[0]:self.start_end[1]])
            ampl_err = abs((interpolator.reflectivity - exact)/exact)
            err_percent = numpy.mean(ampl_err) * 100
            print(f"{iteration:3d} diff: {interpolator.diff:.4f} rel. err: {err_percent:.2f}%")
            ## print the real relative error
            #print(interpolator.reflectivity.real - exact.real) / exact.real)

    def store_data(self, X, filename, header=[]):
        if self.store_path is None:
            return

        if header == 'potential':
            header = ["x [Ang]", "SLD [1/Ang^2]"]
        elif header == 'phase':
            header = ["k [1/Ang]", "Re R [1]", "Im R [1]", "k^2 * Re R [1/Ang^2]",
                      "k^2 * Im R [1/Ang^2]"]
        elif header == 'reflectivity':
            header = ["q [1/Ang]", "|R|^2 [1]"]

        if len(header) > 0:
            header = "\t".join(header)

        numpy.savetxt(self.store_path + filename + ".dat", X, header=header, delimiter="\t")

    def run(self, constrain):

        self.setup()

        rec = PotentialReconstruction(
            self.thickness + self.offset, self.precision,
            cutoff=self.pot_cutoff)
        reflcalc = ReflectionCalculation(
            None, 0, self.thickness + self.offset, 0.1)

        # plot the exact potential/refl/ for comparison
        self._plot_exact()

        # split the fourier transform up into two parts
        # f1 has the changing input
        # f2 has the non-changing input
        # since f2 contains much more data in general, we can save a lot of computation by
        # caching f2 and just
        # computing f1 each time.

        f1_index = slice(None, self.start_end[1]+1)
        f2_index = slice(self.start_end[1]+1, None)
        # self.real, self.imag contain the reflection coefficient
        f1 = FourierTransform(self.k_space[f1_index],
                              self.real[f1_index], self.imag[f1_index])
        f2 = FourierTransform(self.k_space[f2_index],
                              self.real[f2_index], self.imag[f2_index])

        if self.use_only_real_part:
            f1.method = f1.cosine_transform
            f2.method = f2.cosine_transform

        transform = UpdateableFourierTransform(f1, f2)


        # TODO: change the class name
        # Reconstruct the reflection using the fourier transform at  k =
        # k_interpolation_range (the low k range)
        # rec is used to reconstruct the potential
        # reflcalc is used to calculate the reflection coefficient
        # the constrain function constrains the potential
        interpolation = ReflectivityAmplitudeInterpolation(
            transform, self.k_interpolation_range, rec, reflcalc, constrain)

        interpolation.set_hook(self._plot_hook)
        if self.diagnostic_session:
            interpolation.set_hook(self._diagnostic_hook)

        solution = interpolation.interpolate(self.iterations, tolerance=self.tolerance)

        if self.plot_potential:
            self._potential_axes.legend()
        if self.plot_phase:
            self._phase_axes.legend()
        if self.plot_reflectivity:
            self._reflectivity_axes.legend()
        if self.show_plot:
            pylab.show()

        return solution
コード例 #5
0
q_max = 1.0

x_space = linspace(0, thickness + shift, 10 * (thickness + shift) + 1)
for q_max in [0.5, 1.0, 5.0]:
    q_extrapolation = q_max + 0.1
    k_space = linspace(0, q_max / 2, int(1000 * q_max) + 1)
    k_extrapolation_space = linspace(q_max / 2, q_extrapolation,
                                     (q_extrapolation - q_max) * 1000 + 1)

    potential = load_potential("profile.dat")
    potential = shift_potential(potential, shift)

    reconstruction = PotentialReconstruction(shift + thickness,
                                             precision,
                                             cutoff=cutoff)
    reflection_calc = ReflectionCalculation(lambda x: 0, 0, shift + thickness)

    reflection_calc.set_potential(potential)

    refl = reflection_calc.refl(2 * k_space)
    refl_extrapolation = reflection_calc.refl(2 * k_extrapolation_space)
    #refl_extrapolation = (refl_extrapolation * exp(-1j * angle(refl_extrapolation))).real

    transform_left = FourierTransform(k_space, refl.real, refl.imag)
    transform_extrapolation = FourierTransform(k_extrapolation_space,
                                               refl_extrapolation.real,
                                               refl_extrapolation.imag)

    transform = UpdateableFourierTransform(transform_extrapolation,
                                           transform_left)
コード例 #6
0
if plot_reflectivity:
    pylab.plot(2 * k_space, real ** 2 + imag ** 2)
    pylab.yscale('log')
    legends.append('Exact Reflectivity (with noise)')

# The actual logic
for iter in range(0, iterations + 1):

    transform = FourierTransform(k_space, real, imag, offset)
    transform.method = transform.cosine_transform

    rec = PotentialReconstruction(end, precision, pot_cutoff)

    potential, _ = rec.reconstruct(transform, shift=offset/2)
    potential = constrain(potential, rec._xspace)
    reflcalc = ReflectionCalculation(potential, offset, end, 0.1)

    # Use the new reflection coefficient for small k-values and re-do the inversion ...
    R = reflcalc.refl(2 * k_space[start_end[0]:start_end[1]])
    R = array(map(lambda x: x.real, R))

    exact_real = array((Refl[0])[start_end[0]:start_end[1]])

    #R = numpy.random.uniform(-1, 1, start_end[1]-start_end[0]+1)
    # relative error
    print((R - exact_real)/exact_real*100)

    if numpy.max(abs(real[start_end[0]:start_end[1]] - R)) < 1e-8:
        break

    real[start_end[0]:start_end[1]] = R
コード例 #7
0
ファイル: test.py プロジェクト: reflectometry/DirectInversion
pylab.plot(support, V(support))
pylab.plot(support, V2(support))
#pylab.plot(support, V2(support).imag)
pylab.show()

F3 = GeneralFourierTransform(support, V2)
pylab.plot(w_space[len(w_space) / 2:],
           abs(array([1 / w * F.fourier(w) for w in w_space if w > 0]))**2)
pylab.plot(w_space[len(w_space) / 2:],
           abs(array([1 / w * F3.fourier(w) for w in w_space if w > 0]))**2)
pylab.yscale('log')
#pylab.ylim(-1, 5)
pylab.show()

reflcalc = ReflectionCalculation(None, -250, 300, 0.05)


def scale(f):
    return lambda x: f(x) * 1e-6


reflcalc.set_potential(scale(V))

reflcalc.plot_refl(numpy.linspace(0, 2, 1000))
reflcalc.set_potential(scale(V2))
#reflcalc.plot_potential()
#pylab.show()
reflcalc.plot_refl(numpy.linspace(0, 2, 1000))
pylab.show()
コード例 #8
0
# total film thickness
end = 50

k_space = exact_phase[0] / 2

real = exact_phase[1]
imag = exact_phase[2]

pylab.plot(exact_potential[0], exact_potential[1])
pylab.show()

potential = scipy.interpolate.interp1d(exact_potential[0],
                                       exact_potential[1],
                                       fill_value=(0, 0),
                                       bounds_error=False)
reflcalc = ReflectionCalculation(potential, 0, end, 0.01)

#reflcalc.plot_potential()
#pylab.show()
refl = reflcalc.refl(2 * k_space)

pylab.plot(k_space, refl.real**2 + refl.imag**2)
pylab.plot(k_space, (exact_phase[1]**2 + exact_phase[2]**2) * 10)

pylab.yscale('log')
pylab.show()

pylab.plot(k_space, refl.real * k_space**2)
pylab.plot(k_space, real * k_space**2)

pylab.legend(['calculated real', 'loaded'])