Esempio n. 1
0
    def optimize_rotation(self, ellipsoid, e_matrix, init_rot):
        """Optimize a rotation."""
        self._check_ellipsoid(ellipsoid)
        axes, angles = unwrap_euler_angles(init_rot)
        orig_strain = to_full_tensor(self.eigenstrain.copy())
        aspect = np.array(ellipsoid["aspect"])

        self.eshelby = StrainEnergy.get_eshelby(aspect, self.poisson)
        opt_args = {
            "ellipsoid": ellipsoid,
            "elast_matrix": e_matrix,
            "strain_energy_obj": self,
            "orig_strain": orig_strain,
            "rot_axes": axes
        }
        opts = {"eps": 1.0}
        res = minimize(cost_minimize_strain_energy,
                       angles,
                       args=(opt_args, ),
                       options=opts)
        rot_seq = combine_axes_and_angles(axes, res["x"])
        optimal_orientation = {
            "energy": res["fun"],
            "rot_sequence": rot_seq,
            "rot_matrix": rot_matrix(rot_seq)
        }

        # Reset the eigenstrain back
        self.eigenstrain = to_voigt(orig_strain)
        return optimal_orientation
Esempio n. 2
0
    def plot(self, scale_factor, elast_matrix, rot_seq=None, latex=False):
        """Create a plot of the energy as different aspect ratios."""
        from matplotlib import pyplot as plt
        a_over_c = np.logspace(0, 3, 100)
        b_over_c = [1, 2, 5, 10, 50, 100]

        orig_strain = self.eigenstrain.copy()

        if rot_seq is not None:
            strain = to_full_tensor(orig_strain)
            rot_mat = rot_matrix(rot_seq)
            strain = rotate_tensor(strain, rot_mat)
            self.eigenstrain = to_voigt(strain)

        fig = plt.figure()
        ax = fig.add_subplot(1, 1, 1)
        for b in b_over_c:
            W = []
            a_plot = []
            for a in a_over_c:
                if a < b:
                    continue
                aspect = [a, b, 1.0]
                self.eshelby = StrainEnergy.get_eshelby(aspect, self.poisson)
                E = self.strain_energy(scale_factor, elast_matrix) * 1000.0
                W.append(E)
                a_plot.append(a)
            ax.plot(a_plot, W, label="{}".format(int(b)))

        # Separation line
        b_sep = np.logspace(0, 3, 100)
        W = []
        for b in b_sep:
            aspect = [b, b, 1.0]
            self.eshelby = StrainEnergy.get_eshelby(aspect, self.poisson)
            E = self.strain_energy(scale_factor, elast_matrix) * 1000.0
            W.append(E)

        ax.plot(b_sep, W, "--", color="grey")
        ax.legend(frameon=False, loc="best")
        if latex:
            xlab = "\$a/c\$"
            ylab = "Strain energy (meV/\$\SI{}{\\angstrom^3}\$)"
        else:
            xlab = "$a/c$"
            ylab = "Strain enregy (meV/A^3)"
        ax.set_xlabel(xlab)
        ax.set_ylabel(ylab)
        ax.spines["right"].set_visible(False)
        ax.spines["top"].set_visible(False)
        ax.set_xscale("log")
        self.eigenstrain = orig_strain
        return fig
Esempio n. 3
0
    def explore_orientations(self,
                             voxels,
                             theta_ax="y",
                             phi_ax="z",
                             step=5,
                             theta_min=0,
                             theta_max=180,
                             phi_min=0,
                             phi_max=360,
                             fname=None):
        """Explore orientation dependency of the strain energy.
        
        :param np.ndarray voxels: Voxel representation of the geometry
        :param str theta_ax: Rotation axis for theta angle
        :param str phi_ax: Rotation axis for phi angle
        :param int step: Angle change in degress
        :param int theta_min: Start angle for theta
        :param int theta_max: End angle for theta
        :param int phi_min: Start angle for phi
        :param int phi_max: End angle for phi
        :param fname str: Filename for storing the output result
        """
        th = list(range(theta_min, theta_max, step))
        ph = list(range(phi_min, phi_max, step))

        misfit_orig = self.misfit_strain.copy()
        orig_C = self.C.copy()
        result = []
        now = time.time()
        status_interval = 30
        for ang in product(th, ph):
            if time.time() - now > status_interval:
                print("Theta: {}, Phi: {}".format(ang[0], ang[1]))
                now = time.time()
            seq = [(theta_ax, -ang[0]), (phi_ax, -ang[1])]
            matrix = rot_matrix(seq)

            # Rotate the strain tensor
            self.misfit_strain = rotate_tensor(misfit_orig, matrix)
            self.C = rotate_rank4_tensor(orig_C.copy(), matrix)
            energy = self.strain_energy_voxels(voxels)
            result.append([ang[0], ang[1], energy])

        if fname is None:
            fname = "khacaturyan_orientaions{}.csv".format(timestamp)

        np.savetxt(fname,
                   np.array(result),
                   delimiter=",",
                   header="Theta ({}) deg, Phi ({}) deg, Energy (eV)".format(
                       theta_ax, phi_ax))
        print("Results of orientation exploration written to {}".format(fname))
Esempio n. 4
0
def cost_minimize_strain_energy(euler, args):
    """Cost function used to minimize."""

    ellipsoid = args["ellipsoid"]
    scale_factor = ellipsoid["scale_factor"]
    e_matrix = args["elast_matrix"]
    orig_strain = args["orig_strain"]
    obj = args["strain_energy_obj"]
    rot_axes = args["rot_axes"]

    rot_seq = combine_axes_and_angles(rot_axes, euler)
    matrix = rot_matrix(rot_seq)
    tensor = rotate_tensor(orig_strain, matrix)
    tensor = to_voigt(tensor)
    obj.eigenstrain = tensor
    return obj.strain_energy(scale_factor, e_matrix)
Esempio n. 5
0
    def show_ellipsoid(self, ellipsoid, rot_seq):
        """Show the ellipsoid at given orientation."""
        from matplotlib import pyplot as plt
        matrix = rot_matrix(rot_seq)
        coefs = np.array(ellipsoid["aspect"])

        # Spherical angles
        u = np.linspace(0, 2.0 * np.pi, 100)
        v = np.linspace(0, np.pi, 100)
        rx, ry, rz = coefs
        x = rx * np.outer(np.cos(u), np.sin(v))
        y = ry * np.outer(np.sin(u), np.sin(v))
        z = rz * np.outer(np.ones_like(u), np.cos(v))

        N_pos = x.shape[0] * x.shape[1]
        # Pack x, y, z into a numpy matrix
        all_coords = np.zeros((3, N_pos))
        all_coords[0, :] = np.ravel(x)
        all_coords[1, :] = np.ravel(y)
        all_coords[2, :] = np.ravel(z)

        # Rotate all. Use the transpose of the rotation matrix because
        # the rotation matrix is intended to be used for rotating the
        # coordinate system, keeping the ellipsoid fixed
        # so the inverse rotation is required when rotating the ellipsoid
        all_coords = matrix.T.dot(all_coords)
        x = np.reshape(all_coords[0, :], x.shape)
        y = np.reshape(all_coords[1, :], y.shape)
        z = np.reshape(all_coords[2, :], z.shape)

        # Adjustment of the axes, so that they all have the same span:
        fig = plt.figure()
        ax = fig.add_subplot(111, projection='3d')
        ax.plot_surface(x, y, z, rstride=4, cstride=4, color="grey")

        max_radius = max(rx, ry, rz)
        for axis in 'xyz':
            getattr(ax, 'set_{}lim'.format(axis))((-max_radius, max_radius))
        return fig
Esempio n. 6
0
    def explore_orientations(self,
                             ellipsoid,
                             C_matrix,
                             step=10,
                             fname="",
                             theta_ax="y",
                             phi_ax="z"):
        """Explore the strain energy as a function of ellipse orientation.
        
        :param dict ellipsoid: Dictionary with information of the ellipsoid
            The format should be {"aspect": [1.0, 1.0, 1.0], "C_prec": ..., 
            "scale_factor": 1.0}
            C_prec is the elastic tensor of the precipitate material.
            If not given, scale_factor has to be given, and the elastic
            tensor of the precipitate material is taken as this factor
            multiplied by the elastic tensor of the matrix material
        :param numpy.ndarray C_matrix: Elastic tensor of the matrix material
        :param float step: Angle step size in degree
        :param str fname: If given the result of the exploration is 
            stored in a csv file with this filename
        :param str theta_ax: The first rotation is performed
            around this axis
        :param str phi_ax: The second rotation is performed around this
            axis (in the new coordinate system after the first rotation
            is performed)
        """
        from itertools import product
        #self._check_ellipsoid(ellipsoid)
        scale_factor = ellipsoid.get("scale_factor", None)
        C_prec = ellipsoid.get("C_prec", None)

        if C_prec is None:
            C_prec = scale_factor * C_matrix

        # Convert the tensors to their isotropic representation
        C_matrix = self.make_isotropic(C_matrix)
        C_prec = self.make_isotropic(C_prec)

        aspect = np.array(ellipsoid["aspect"])
        self.eshelby = StrainEnergy.get_eshelby(aspect, self.poisson)
        result = []
        misfit_orig = to_full_tensor(self.misfit)
        theta = np.arange(0.0, np.pi, step * np.pi / 180.0)
        phi = np.arange(0.0, 2.0 * np.pi, step * np.pi / 180.0)
        theta = np.append(theta, [np.pi])
        phi = np.append(phi, [2.0 * np.pi])

        C_matrix_orig = C_matrix.copy()
        C_prec_orig = C_prec.copy()
        for ang in product(theta, phi):
            th = ang[0]
            p = ang[1]
            theta_deg = th * 180 / np.pi
            phi_deg = p * 180 / np.pi
            seq = [(theta_ax, -theta_deg), (phi_ax, -phi_deg)]
            matrix = rot_matrix(seq)
            #matrix = rot_matrix_spherical_coordinates(p, th)

            # Rotate the strain tensor
            strain = rotate_tensor(misfit_orig, matrix)
            self.misfit = to_mandel(strain)

            # Rotate the elastic tensor of the matrix material
            C_matrix = rotate_rank4_mandel(C_matrix_orig, matrix)

            # Rotate the elastic tensor of the precipitate material
            C_prec = rotate_rank4_mandel(C_prec_orig, matrix)
            if abs(p) < 1E-3 and (abs(th - np.pi / 4.0) < 1E-3
                                  or abs(th - 3.0 * np.pi / 4.0) < 1E-3):
                print(self.eshelby.aslist())

            energy = self.strain_energy(C_matrix=C_matrix, C_prec=C_prec)
            res = {"energy": energy, "theta": th, "phi": p}
            a = matrix.T.dot([1.0, 0.0, 0.0])
            b = matrix.T.dot([0.0, 1.0, 0.0])
            c = matrix.T.dot([0.0, 0.0, 1.0])
            res["half_axes"] = {"a": a, "b": b, "c": c}
            res["misfit"] = self.misfit
            result.append(res)

        if fname != "":
            self.save_orientation_result(result, fname)

        # Sort the result from low energy to high energy
        energies = [res["energy"] for res in result]
        sorted_indx = np.argsort(energies)
        result = [result[indx] for indx in sorted_indx]

        # Reset the strain
        self.misfit = to_mandel(misfit_orig)
        return result