Beispiel #1
0
 def test_to_dict_gaussian(self):
     width = 2.0
     kernel = PyGaussianKernel(width)
     dict_repr = kernel.to_dict()
     self.assertAlmostEqual(width, dict_repr["std_dev"])
     self.assertAlmostEqual(5 * width, dict_repr["upper_limit"])
     self.assertAlmostEqual(-5 * width, dict_repr["lower_limit"])
def main():
    #prefix = "data/almgsi_chgl_random_seed_strain_noise2/chgl"
    prefix = "data/almgsi_chgl_3D_surface_1nm_64_strain_consistent/chgl"
    dx = 10.0  # Discretisation in angstrom
    dim = 3
    L = 64
    num_gl_fields = 3
    M = 0.1
    alpha = 5.0
    dt = 1.0
    gl_damping = M

    coeff, terms = get_polyterms(FNAME)

    poly = PyPolynomial(4)

    with open(FNAME, 'r') as infile:
        info = json.load(infile)

    kernel = PyGaussianKernel(info["kernel"]["std_dev"])
    regressor = PyKernelRegressor(info["kernel_regressor"]["xmin"],
                                  info["kernel_regressor"]["xmax"])
    regressor.set_kernel(kernel)
    regressor.set_coeff(info["kernel_regressor"]["coeff"])
    grad_coeff = info["gradient_coeff"]

    for item in info["terms"]:
        c = item["coeff"]
        powers = item["powers"]
        poly.add_term(c, PyPolynomialTerm(powers))
        print(c, powers)

    alpha = grad_coeff[0] / dx**2
    b1 = grad_coeff[1] / dx**2
    b2 = grad_coeff[2] / dx**2
    gradient_coeff = [[b2, b1, b2], [b1, b2, b2], [b2, b2, b1]]
    print(gradient_coeff)

    chgl = PyCHGLRealSpace(dim, L, prefix, num_gl_fields, M, alpha, dt,
                           gl_damping, gradient_coeff)

    landau = PyTwoPhaseLandau()
    landau.set_polynomial(poly)
    landau.set_kernel_regressor(regressor)
    landau.set_discontinuity(info["discontinuity_conc"],
                             info["discontinuity_jump"])

    chgl.set_free_energy(landau)
    #chgl.from_npy_array(precipitates_square(L))
    chgl.use_adaptive_stepping(1E-10, 1, 0.05)
    chgl.build3D()
    add_strain(chgl)
    chgl.from_file(prefix + "00000053000.grid")

    chgl.run(500000, 5000, start=53000)
    chgl.save_free_energy_map(prefix + "_free_energy_map.grid")
Beispiel #3
0
    def test_gaussian_from_dict(self):
        width = 2.0
        kernel = PyGaussianKernel(width)
        dict_repr = kernel.to_dict()

        x0 = -0.34
        k0 = kernel.evaluate(x0)
        kernel.from_dict(dict_repr)
        self.assertAlmostEqual(k0, kernel.evaluate(x0))
Beispiel #4
0
    def test_fit_kernel(self):

        width = 0.5
        kernel = PyGaussianKernel(width)
        x = np.linspace(0.0, 10.0, 500, endpoint=True)
        y = x**2
        num_kernels = 60
        regressor = fit_kernel(x=x,
                               y=y,
                               num_kernels=num_kernels,
                               kernel=kernel)
        y_fit = regressor.evaluate(x)
        self.assertTrue(np.allclose(y, y_fit, atol=1E-4))
Beispiel #5
0
    def test_to_dict(self):

        width = 2.0
        kernel = PyGaussianKernel(width)
        regressor = PyKernelRegressor(0.0, 1.0)
        coeff = np.linspace(0.0, 10.0, 100)
        regressor.set_coeff(coeff)
        regressor.set_kernel(kernel)

        dict_repr = regressor.to_dict()
        self.assertAlmostEqual(0.0, dict_repr["xmin"])
        self.assertAlmostEqual(1.0, dict_repr["xmax"])
        self.assertEqual("gaussian", dict_repr["kernel_name"])
        self.assertTrue(np.allclose(coeff, dict_repr["coeff"]))
    def test_chglrealspace3D(self):
        chgl = self.get_chgl3D()
        chgl.build3D()

        # Initialize a regression kernel and a regressor
        kernel = PyGaussianKernel(2.0)
        regressor = PyKernelRegressor(0.0, 1.0)

        # Initialize a two phase landau polynomial
        landau = PyTwoPhaseLandau()

        # Transfer the kernel and the regressor
        regressor.set_kernel(kernel)
        landau.set_kernel_regressor(regressor)

        # Initialize 4D polynomial (concentration, shape1, shape2, shape3)
        poly = PyPolynomial(4)
        landau.set_polynomial(poly)
        chgl.set_free_energy(landau)

        chgl.run(5, 1000)
Beispiel #7
0
    def test_gaussian_kernel(self):

        width = 2.0
        kernel = PyGaussianKernel(width)

        # Confirm that the integral is 1
        w = np.linspace(-10 * width, 10 * width, 20000).tolist()

        values = [kernel.evaluate(x) for x in w]
        integral = np.trapz(values, dx=w[1] - w[0])
        self.assertAlmostEqual(integral, 1.0, places=4)

        # Check some values
        expected = np.exp(-0.5) * 0.5 / np.sqrt(2 * np.pi)
        self.assertAlmostEqual(kernel.evaluate(width), expected)
        self.assertAlmostEqual(kernel.evaluate(-width), expected)

        # Check derivatives
        self.assertAlmostEqual(kernel.deriv(0.0), 0.0)
        self.assertAlmostEqual(kernel.deriv(width), -expected / width)
Beispiel #8
0
    def test_from_dict(self):
        width = 2.0
        kernel = PyGaussianKernel(width)
        regressor = PyKernelRegressor(0.0, 1.0)
        coeff = np.linspace(0.0, 10.0, 100)
        regressor.set_coeff(coeff)
        regressor.set_kernel(kernel)

        # Evaluate at points
        x_values = [0.0, 2.0, -2.0, 5.0]
        y_values_orig = regressor.evaluate(x_values)

        dict_repr = regressor.to_dict()

        regressor.from_dict(dict_repr)
        y_values_new = regressor.evaluate(x_values)
        self.assertTrue(np.allclose(y_values_orig, y_values_new))

        # Verify that exception is raised if a wrong kernel is passed
        dict_repr["kernel_name"] = "quadratic"
        with self.assertRaises(ValueError):
            regressor.from_dict(dict_repr)
Beispiel #9
0
    def test_run(self):
        chgl = self.get_chgl()
        chgl.print_polynomial()
        chgl.random_initialization([0.0, 0.0, 0.0], [1.0, 1.0, 1.0])
        with self.assertRaises(RuntimeError):
            chgl.run(5, 1000)

        # We set a free energy form
        landau = PyTwoPhaseLandau()

        # This polynomial has the wrong size
        # make sure that an exception is raised
        poly = PyPolynomial(2)
        regressor = PyKernelRegressor(0.0, 1.0)
        kernel = PyGaussianKernel(2.0)

        # Case 1: Fail because no kernel is set
        with self.assertRaises(ValueError):
            chgl.set_free_energy(landau)

        # Case 2: Fail because no polynomial is set
        regressor.set_kernel(kernel)
        landau.set_kernel_regressor(regressor)
        with self.assertRaises(ValueError):
            chgl.set_free_energy(landau)

        poly = PyPolynomial(3)
        landau.set_polynomial(poly)
        chgl.set_free_energy(landau)

        try:
            chgl.run(5, 1000)
        except RuntimeError as exc:
            # The only way run should raise a runtime error at this stage is
            # if FFTW is not installed
            self.assertTrue("CHGL requires FFTW!" in str(exc))
    def fit(self,
            conc,
            free_energy,
            weights={},
            init_shape_coeff=None,
            kernel_width=0.2,
            num_kernels=30,
            show=True,
            width=0.1,
            smear_width=0,
            shape="auto",
            lamb=None):
        """Fit the free energy functional.

        :param numpy.ndarray conc2. Concentrations in the second phase
        :param numpy.ndarray F2: Free energy in the second phase
        :param dict weights: Dictionary with penalty weights associated
            with the shape order parameter deviating from the desired
            behaviour. The following weights are available
            eq_phase1: A cost term equal to sum(n_eq**2) for concentrations
                less than self.c2 is added to the fitting cost function
            eq_phase2: A cost term equal to (n_eq(c_min) - 1.0)**2 where
                c_min is the concentration where F2 takes its minimum value.
                The effect of this is to penalize solutions that has a shape
                order paremter very different from one.
        """
        if init_shape_coeff is not None:
            if len(init_shape_coeff) != 2:
                raise ValueError("init_shape_coeff have to be None or "
                                 "of a list of length 2")

        if (width is None):
            peak = np.argmax(free_energy)
            conc_max = conc[peak]
            width = self.c2 - conc_max
        indx_min = np.argmin(np.abs(conc - self.c2 + width))
        indx_max = np.argmin(np.abs(conc - self.c2 - width))

        F_fit = free_energy[indx_min:indx_max]
        conc_fit = conc[indx_min:indx_max]
        minimum = np.argmin(np.abs(conc - self.c2))
        free_energy -= free_energy[minimum]

        if shape == "auto":
            shape = 27 * (free_energy[indx_min] - free_energy[minimum])
            assert shape > 0.0

        # Update the coefficients
        A = self._get_slope_parameter(-shape, shape, conc[indx_min])
        self.conc_coeff2[0] = A
        self.conc_coeff2[1] = -A * self.c2
        self.coeff_shape[0] = -shape
        self.coeff_shape[2] = shape

        # Subtract of the reminder that needs to be fitted with
        # Kernel regression
        reminder = free_energy - self.evaluate(conc)

        from matplotlib import pyplot as plt
        plt.plot(conc, reminder)
        plt.plot(conc, self.evaluate(conc))
        plt.plot(conc, free_energy)
        plt.show()

        # Smear the reminder in the critical area
        if smear_width > 0:
            smear_data = reminder[indx_min - smear_width:indx_min +
                                  smear_width]
            deriv1 = reminder[indx_min-smear_width] - \
                reminder[indx_min-smear_width-1]
            deriv2 = reminder[indx_min+smear_width+1] - \
                reminder[indx_min+smear_width]

            matrix = np.zeros((4, 4))
            rhs = np.zeros(4)
            imax = smear_width
            imin = -smear_width

            for i in range(4):
                # Continuity at beginning
                matrix[0, i] = imin**(3 - i)

                # Continuity at end
                matrix[1, i] = imax**(3 - i)

                # Smooth at beginning
                if i < 3:
                    matrix[2, i] = (3 - i) * imin**(3 - i - 1)
                    matrix[3, i] = (3 - i) * imax**(3 - i - 1)
            rhs[0] = reminder[indx_min - smear_width]
            rhs[1] = reminder[indx_min + smear_width]
            rhs[2] = deriv1
            rhs[3] = deriv2
            coeff = np.linalg.solve(matrix, rhs)
            x = np.linspace(imin, imax, 2 * smear_width)
            reminder[indx_min-smear_width:indx_min+smear_width] = \
                sum(coeff[i]*x**(3-i) for i in range(4))

        self.kernel = PyGaussianKernel(kernel_width)

        # Remove discontinuity
        diff = np.abs(reminder - np.roll(reminder, 1))
        disc_indx = np.argmax(diff[1:])
        self.discontinuity_jump = reminder[disc_indx] - reminder[disc_indx + 1]
        self.discontinuity_conc = conc[disc_indx]
        reminder[disc_indx + 1:] += self.discontinuity_jump

        self.phase_one_regressor = fit_kernel(x=conc,
                                              y=reminder,
                                              num_kernels=num_kernels,
                                              kernel=self.kernel,
                                              lamb=lamb,
                                              extrapolate='linear',
                                              extrap_range=0.5)

        if show:
            from matplotlib import pyplot as plt
            fig = plt.figure()
            ax = fig.add_subplot(1, 2, 1)
            n_eq = np.array(self.equil_shape_order(conc))
            ax.plot(conc, free_energy, label="Free")
            ax.plot(conc, self.evaluate(conc), label="Evaluated")
            ax.plot(conc,
                    self.phase_one_regressor.evaluate(conc),
                    label="regressor")
            ax.axvline(conc[indx_min], ls="--", color="gray")
            ax.axvline(conc[indx_max], ls="--", color="gray")
            ax.legend()
            ax2 = fig.add_subplot(1, 2, 2)
            ax2.plot(conc, n_eq)

            plt.show()
class TwoPhasePolynomialRegressor(TwoPhaseLandauPolynomialBase):
    def __init__(self,
                 c1=0.0,
                 c2=1.0,
                 num_dir=3,
                 init_guess=None,
                 conc_order1=2,
                 conc_order2=2):
        TwoPhaseLandauPolynomialBase.__init__(self,
                                              c1=c1,
                                              c2=c2,
                                              num_dir=num_dir,
                                              init_guess=init_guess,
                                              conc_order1=conc_order1,
                                              conc_order2=conc_order2)
        self._kernel = None
        self._phase_one_regressor = None
        self.discontinuity_conc = 0.0
        self.discontinuity_jump = 0.0

    @property
    def phase_one_regressor(self):
        if self._phase_one_regressor is None:
            raise RuntimeError(
                "It appears like no regressor was set. Call the fit function!")
        return self._phase_one_regressor

    @phase_one_regressor.setter
    def phase_one_regressor(self, new_obj):
        self._phase_one_regressor = new_obj

    @property
    def kernel(self):
        if self._kernel is None:
            raise RuntimeError("No kernel has been set!")
        return self._kernel

    @kernel.setter
    def kernel(self, new_obj):
        self._kernel = new_obj

    def _eval_phase1(self, conc):
        """Evaluate regressor in phase 1."""
        if self._phase_one_regressor is None:
            return 0.0
        return self._phase_one_regressor.evaluate(conc)

    def _deriv_phase1(self, conc):
        return self.phase_one_regressor.deriv(conc)

    @array_func
    def eval_at_equil(self, conc):
        """Evaluate the free energy at equillibrium order.

        :param float conc: Concentration
        """

        return TwoPhaseLandauPolynomialBase.eval_at_equil(self, conc) - \
            self.discontinuity_jump*heaviside(conc - self.discontinuity_conc)

    @array_func
    def evaluate(self, conc, shape=None):
        """
        Evaluate the free energy polynomial

        :param float conc: Concentration
        :param shape list: List with the shape order parameters.
            If None, the shape order parameters are set to their
            equillibrium
        """
        if shape is None:
            return self.eval_at_equil(conc)
        return TwoPhaseLandauPolynomialBase.evaluate(self, conc, shape=shape) - \
              self.discontinuity_jump*heaviside(conc - self.discontinuity_conc)

    def fit(self,
            conc,
            free_energy,
            weights={},
            init_shape_coeff=None,
            kernel_width=0.2,
            num_kernels=30,
            show=True,
            width=0.1,
            smear_width=0,
            shape="auto",
            lamb=None):
        """Fit the free energy functional.

        :param numpy.ndarray conc2. Concentrations in the second phase
        :param numpy.ndarray F2: Free energy in the second phase
        :param dict weights: Dictionary with penalty weights associated
            with the shape order parameter deviating from the desired
            behaviour. The following weights are available
            eq_phase1: A cost term equal to sum(n_eq**2) for concentrations
                less than self.c2 is added to the fitting cost function
            eq_phase2: A cost term equal to (n_eq(c_min) - 1.0)**2 where
                c_min is the concentration where F2 takes its minimum value.
                The effect of this is to penalize solutions that has a shape
                order paremter very different from one.
        """
        if init_shape_coeff is not None:
            if len(init_shape_coeff) != 2:
                raise ValueError("init_shape_coeff have to be None or "
                                 "of a list of length 2")

        if (width is None):
            peak = np.argmax(free_energy)
            conc_max = conc[peak]
            width = self.c2 - conc_max
        indx_min = np.argmin(np.abs(conc - self.c2 + width))
        indx_max = np.argmin(np.abs(conc - self.c2 - width))

        F_fit = free_energy[indx_min:indx_max]
        conc_fit = conc[indx_min:indx_max]
        minimum = np.argmin(np.abs(conc - self.c2))
        free_energy -= free_energy[minimum]

        if shape == "auto":
            shape = 27 * (free_energy[indx_min] - free_energy[minimum])
            assert shape > 0.0

        # Update the coefficients
        A = self._get_slope_parameter(-shape, shape, conc[indx_min])
        self.conc_coeff2[0] = A
        self.conc_coeff2[1] = -A * self.c2
        self.coeff_shape[0] = -shape
        self.coeff_shape[2] = shape

        # Subtract of the reminder that needs to be fitted with
        # Kernel regression
        reminder = free_energy - self.evaluate(conc)

        from matplotlib import pyplot as plt
        plt.plot(conc, reminder)
        plt.plot(conc, self.evaluate(conc))
        plt.plot(conc, free_energy)
        plt.show()

        # Smear the reminder in the critical area
        if smear_width > 0:
            smear_data = reminder[indx_min - smear_width:indx_min +
                                  smear_width]
            deriv1 = reminder[indx_min-smear_width] - \
                reminder[indx_min-smear_width-1]
            deriv2 = reminder[indx_min+smear_width+1] - \
                reminder[indx_min+smear_width]

            matrix = np.zeros((4, 4))
            rhs = np.zeros(4)
            imax = smear_width
            imin = -smear_width

            for i in range(4):
                # Continuity at beginning
                matrix[0, i] = imin**(3 - i)

                # Continuity at end
                matrix[1, i] = imax**(3 - i)

                # Smooth at beginning
                if i < 3:
                    matrix[2, i] = (3 - i) * imin**(3 - i - 1)
                    matrix[3, i] = (3 - i) * imax**(3 - i - 1)
            rhs[0] = reminder[indx_min - smear_width]
            rhs[1] = reminder[indx_min + smear_width]
            rhs[2] = deriv1
            rhs[3] = deriv2
            coeff = np.linalg.solve(matrix, rhs)
            x = np.linspace(imin, imax, 2 * smear_width)
            reminder[indx_min-smear_width:indx_min+smear_width] = \
                sum(coeff[i]*x**(3-i) for i in range(4))

        self.kernel = PyGaussianKernel(kernel_width)

        # Remove discontinuity
        diff = np.abs(reminder - np.roll(reminder, 1))
        disc_indx = np.argmax(diff[1:])
        self.discontinuity_jump = reminder[disc_indx] - reminder[disc_indx + 1]
        self.discontinuity_conc = conc[disc_indx]
        reminder[disc_indx + 1:] += self.discontinuity_jump

        self.phase_one_regressor = fit_kernel(x=conc,
                                              y=reminder,
                                              num_kernels=num_kernels,
                                              kernel=self.kernel,
                                              lamb=lamb,
                                              extrapolate='linear',
                                              extrap_range=0.5)

        if show:
            from matplotlib import pyplot as plt
            fig = plt.figure()
            ax = fig.add_subplot(1, 2, 1)
            n_eq = np.array(self.equil_shape_order(conc))
            ax.plot(conc, free_energy, label="Free")
            ax.plot(conc, self.evaluate(conc), label="Evaluated")
            ax.plot(conc,
                    self.phase_one_regressor.evaluate(conc),
                    label="regressor")
            ax.axvline(conc[indx_min], ls="--", color="gray")
            ax.axvline(conc[indx_max], ls="--", color="gray")
            ax.legend()
            ax2 = fig.add_subplot(1, 2, 2)
            ax2.plot(conc, n_eq)

            plt.show()

    def to_dict(self):
        data = TwoPhaseLandauPolynomialBase.to_dict(self)

        data["discontinuity_jump"] = self.discontinuity_jump
        data["discontinuity_conc"] = self.discontinuity_conc

        # Store the kernel regressor
        try:
            data["kernel_regressor"] = self.phase_one_regressor.to_dict()
            data["kernel"] = self.kernel.to_dict()
        except RuntimeError:
            pass
        return data