def calc_factor_in_front_of_density_for_fm_perp(
            self, hkl, space_group_symop: SpaceGroupSymopL, cell: Cell,
            atom_site_susceptibility: AtomSiteSusceptibilityL, h_loc,
            chi_iso_ferro: float = 0., chi_iso_antiferro: float = 0.,
            flag_two_channel: bool = False):
        """Calculate factor in front of density for FM_perp.

        Arguments
        ---------
            - hkl
            - space_group_symop
            - ...
        """
        v_hkl_2d_i, v_ferro, v_antiferro = \
            self.calc_factor_in_front_of_density_for_fm(
                hkl, space_group_symop, cell, atom_site_susceptibility, h_loc,
                chi_iso_ferro=chi_iso_ferro,
                chi_iso_antiferro=chi_iso_antiferro,
                flag_two_channel=flag_two_channel)

        k_hkl_1, k_hkl_2, k_hkl_3 = cell.calc_k_loc(*hkl)
        na = numpy.newaxis
        v_hkl_perp_2d_i = calc_moment_perp(
            (k_hkl_1[:, na], k_hkl_2[:, na], k_hkl_3[:, na]), v_hkl_2d_i)
        v_perp_ferro = calc_moment_perp(
            (k_hkl_1[:, na], k_hkl_2[:, na], k_hkl_3[:, na]), v_ferro)
        v_perp_antiferro = calc_moment_perp(
            (k_hkl_1[:, na], k_hkl_2[:, na], k_hkl_3[:, na]), v_antiferro)
        return v_hkl_perp_2d_i, v_perp_ferro, v_perp_antiferro
Exemple #2
0
    def temp_func(l_par):
        for name, parameter in zip(l_name, l_par):
            if name[0][0] == "atom_site_susceptibility":
                atom_site_susceptibility.set_variable_by_name(name, parameter)
            elif name[0][0] == "mem_parameters":
                mem_parameters.set_variable_by_name(name, parameter)

        chi_iso_f = mem_parameters.chi_ferro
        chi_iso_af = mem_parameters.chi_antiferro

        atom_site_susceptibility.apply_chi_iso_constraint(cell)
        atom_site_susceptibility.apply_moment_iso_constraint(cell)
        atom_site_susceptibility.apply_space_group_constraint(
            atom_site, space_group)

        l_chi_sq = []
        l_der_chi_sq, l_der_chi_sq_f, l_der_chi_sq_a = [], [], []

        # FIXME: add flag for orbital magnetic moment
        for diffrn, f_nucl, fr_e, fr_s, e_up, h_loc, k_hkl, phase_3d, \
            chi_perp_ferro, chi_perp_aferro in \
            zip(l_diffrn, l_f_nucl, l_fr_e, l_fr_s, l_e_up, l_h_loc, l_k_hkl,
                l_phase_3d, l_chi_perp_ferro, l_chi_perp_antiferro):

            moment_2d, moment_ferro, moment_antiferro = \
                density_point.calc_moment_2d(
                    space_group_symop, cell, atom_site_susceptibility, h_loc,
                    chi_iso_ferro=1., chi_iso_antiferro=1.,
                    flag_two_channel=flag_two_channel)

            f_m = calc_fm_by_density(mult_i, den_i, np, volume, moment_2d,
                                     phase_3d)
            f_m_perp = calc_moment_perp(k_hkl, f_m)

            # # correction on orbital moment
            # diffrn_refln = diffrn.diffrn_refln
            # setup = diffrn.setup
            # field = setup.field
            # ind_h = diffrn_refln.numpy_index_h
            # ind_k = diffrn_refln.numpy_index_k
            # ind_l = diffrn_refln.numpy_index_l
            # chi_m = crystal.calc_susceptibility_moment_tensor(
            #     ind_h, ind_k, ind_l, flag_only_orbital=True)
            # sft_ij = chi_m[:9]
            # sftm_ij = chi_m[9:]

            # fm_orb_perp_loc = calc_fm_perp_loc(e_up, field, k_hkl, sft_ij,
            #                                    sftm_ij)

            # add ferro and anti_ferro

            f_m_perp_sum = (f_m_perp[0] + chi_iso_f * chi_perp_ferro[0] +
                            chi_iso_af * chi_perp_aferro[0],
                            f_m_perp[1] + chi_iso_f * chi_perp_ferro[1] +
                            chi_iso_af * chi_perp_aferro[1],
                            f_m_perp[2] + chi_iso_f * chi_perp_ferro[2] +
                            chi_iso_af * chi_perp_aferro[2])

            fr_m, delta_fr_m = diffrn.calc_fr(cell,
                                              f_nucl,
                                              f_m_perp_sum,
                                              delta_f_m_perp=f_m_perp)
            delta_fr_m_f = delta_fr_m
            delta_fr_m_a = delta_fr_m

            diffrn.diffrn_refln.numpy_fr_calc = fr_m

            chi_sq, der_chi_sq = calc_chi_sq(fr_e, fr_s, fr_m, delta_fr_m)
            der_chi_sq_f = calc_chi_sq(fr_e, fr_s, fr_m, delta_fr_m_f)[1]
            der_chi_sq_a = calc_chi_sq(fr_e, fr_s, fr_m, delta_fr_m_a)[1]
            l_chi_sq.append(chi_sq)
            l_der_chi_sq.append(der_chi_sq)
            l_der_chi_sq_f.append(der_chi_sq_f)
            l_der_chi_sq_a.append(der_chi_sq_a)
        return sum(l_chi_sq)
Exemple #3
0
def refine_susceptibility(crystal: Crystal,
                          l_diffrn: List[Diffrn],
                          density_point: DensityPointL,
                          mem_parameters: MEMParameters,
                          disp: bool = True,
                          d_info: dict = None) -> (float, float):
    """
    Refinement of susceptibility.

    Parameters
    ----------
    crystal : Crystal
        DESCRIPTION.
    l_diffrn : TYPE
        DESCRIPTION.
    density_point : DensityPointL
        DESCRIPTION.
    chi_iso_ferro : float, optional
        DESCRIPTION. The default is 0..
    chi_iso_antiferro : float, optional
        DESCRIPTION. The default is 0..
    flag_ferro : bool, optional
        DESCRIPTION. The default is True.
    flag_antiferro : bool, optional
        DESCRIPTION. The default is True.
    disp : bool, optional
        DESCRIPTION. The default is True.

    Returns
    -------
    float
        Chi_iso_ferro.
    float
        Chi_iso_antiferro.

    """
    flag_info = d_info is not None

    if flag_info:
        d_info_keys = d_info.keys()
        if "stop" not in d_info_keys:
            d_info["stop"] = False
        if "print" not in d_info_keys:
            d_info["print"] = ""

    crystal.apply_constraints()

    flag_two_channel = mem_parameters.method == "2channel"

    cell = crystal.cell
    space_group = crystal.space_group
    atom_site = crystal.atom_site
    space_group_symop = space_group.full_space_group_symop
    atom_site_susceptibility = crystal.atom_site_susceptibility
    # l_magnetic_labes = atom_site_susceptibility.label

    volume = density_point.volume_unit_cell
    np = density_point.number_unit_cell

    den_i = density_point.numpy_density
    den_ferro_i = density_point.numpy_density_ferro
    den_antiferro_i = density_point.numpy_density_antiferro
    mult_i = density_point.numpy_multiplicity

    l_f_nucl, l_fr_e, l_fr_s, l_e_up, l_h_loc = [], [], [], [], []
    l_k_hkl, l_phase_3d = [], []
    l_chi_perp_ferro, l_chi_perp_antiferro = [], []
    total_peaks = 0
    for diffrn in l_diffrn:
        diffrn_orient_matrix = diffrn.diffrn_orient_matrix
        u_matrix = diffrn_orient_matrix.u
        e_up = calc_e_up_loc(0., 0., 0., u_matrix)

        setup = diffrn.setup
        field = float(setup.field)
        h_loc = (field * e_up[0], field * e_up[1], field * e_up[2])
        diffrn_refln = diffrn.diffrn_refln
        index_h = numpy.array(diffrn_refln.index_h, dtype=int)
        index_k = numpy.array(diffrn_refln.index_k, dtype=int)
        index_l = numpy.array(diffrn_refln.index_l, dtype=int)
        total_peaks += index_h.size
        hkl = (index_h, index_k, index_l)
        fr_e = numpy.array(diffrn_refln.fr, dtype=float)
        fr_s = numpy.array(diffrn_refln.fr_sigma, dtype=float)
        f_nucl = crystal.calc_f_nucl(*hkl)
        k_hkl = cell.calc_k_loc(*hkl)
        phase_3d = density_point.calc_phase_3d(hkl, space_group_symop)

        moment_2d, chi_2d_ferro, chi_2d_antiferro = \
            density_point.calc_moment_2d(
                space_group_symop, cell, atom_site_susceptibility, h_loc,
                chi_iso_ferro=1., chi_iso_antiferro=1.,
                flag_two_channel=flag_two_channel)

        chi_ferro = calc_fm_by_density(mult_i, den_ferro_i, np, volume,
                                       chi_2d_ferro, phase_3d)
        chi_perp_ferro = calc_moment_perp(k_hkl, chi_ferro)

        chi_aferro = calc_fm_by_density(mult_i, den_antiferro_i, np, volume,
                                        chi_2d_antiferro, phase_3d)
        chi_perp_aferro = calc_moment_perp(k_hkl, chi_aferro)

        l_f_nucl.append(f_nucl)
        l_fr_e.append(fr_e)
        l_fr_s.append(fr_s)
        l_e_up.append(e_up)
        l_h_loc.append(h_loc)
        l_k_hkl.append(k_hkl)
        l_phase_3d.append(phase_3d)
        l_chi_perp_ferro.append(chi_perp_ferro)
        l_chi_perp_antiferro.append(chi_perp_aferro)

    l_name_1 = atom_site_susceptibility.get_variable_names()
    l_par_1_0 = [
        atom_site_susceptibility.get_variable_by_name(name)
        for name in l_name_1
    ]

    l_name_2 = mem_parameters.get_variable_names()
    l_par_2_0 = [
        mem_parameters.get_variable_by_name(name) for name in l_name_2
    ]
    l_name = l_name_1 + l_name_2
    l_par_0 = l_par_1_0 + l_par_2_0

    def temp_func(l_par):
        for name, parameter in zip(l_name, l_par):
            if name[0][0] == "atom_site_susceptibility":
                atom_site_susceptibility.set_variable_by_name(name, parameter)
            elif name[0][0] == "mem_parameters":
                mem_parameters.set_variable_by_name(name, parameter)

        chi_iso_f = mem_parameters.chi_ferro
        chi_iso_af = mem_parameters.chi_antiferro

        atom_site_susceptibility.apply_chi_iso_constraint(cell)
        atom_site_susceptibility.apply_moment_iso_constraint(cell)
        atom_site_susceptibility.apply_space_group_constraint(
            atom_site, space_group)

        l_chi_sq = []
        l_der_chi_sq, l_der_chi_sq_f, l_der_chi_sq_a = [], [], []

        # FIXME: add flag for orbital magnetic moment
        for diffrn, f_nucl, fr_e, fr_s, e_up, h_loc, k_hkl, phase_3d, \
            chi_perp_ferro, chi_perp_aferro in \
            zip(l_diffrn, l_f_nucl, l_fr_e, l_fr_s, l_e_up, l_h_loc, l_k_hkl,
                l_phase_3d, l_chi_perp_ferro, l_chi_perp_antiferro):

            moment_2d, moment_ferro, moment_antiferro = \
                density_point.calc_moment_2d(
                    space_group_symop, cell, atom_site_susceptibility, h_loc,
                    chi_iso_ferro=1., chi_iso_antiferro=1.,
                    flag_two_channel=flag_two_channel)

            f_m = calc_fm_by_density(mult_i, den_i, np, volume, moment_2d,
                                     phase_3d)
            f_m_perp = calc_moment_perp(k_hkl, f_m)

            # # correction on orbital moment
            # diffrn_refln = diffrn.diffrn_refln
            # setup = diffrn.setup
            # field = setup.field
            # ind_h = diffrn_refln.numpy_index_h
            # ind_k = diffrn_refln.numpy_index_k
            # ind_l = diffrn_refln.numpy_index_l
            # chi_m = crystal.calc_susceptibility_moment_tensor(
            #     ind_h, ind_k, ind_l, flag_only_orbital=True)
            # sft_ij = chi_m[:9]
            # sftm_ij = chi_m[9:]

            # fm_orb_perp_loc = calc_fm_perp_loc(e_up, field, k_hkl, sft_ij,
            #                                    sftm_ij)

            # add ferro and anti_ferro

            f_m_perp_sum = (f_m_perp[0] + chi_iso_f * chi_perp_ferro[0] +
                            chi_iso_af * chi_perp_aferro[0],
                            f_m_perp[1] + chi_iso_f * chi_perp_ferro[1] +
                            chi_iso_af * chi_perp_aferro[1],
                            f_m_perp[2] + chi_iso_f * chi_perp_ferro[2] +
                            chi_iso_af * chi_perp_aferro[2])

            fr_m, delta_fr_m = diffrn.calc_fr(cell,
                                              f_nucl,
                                              f_m_perp_sum,
                                              delta_f_m_perp=f_m_perp)
            delta_fr_m_f = delta_fr_m
            delta_fr_m_a = delta_fr_m

            diffrn.diffrn_refln.numpy_fr_calc = fr_m

            chi_sq, der_chi_sq = calc_chi_sq(fr_e, fr_s, fr_m, delta_fr_m)
            der_chi_sq_f = calc_chi_sq(fr_e, fr_s, fr_m, delta_fr_m_f)[1]
            der_chi_sq_a = calc_chi_sq(fr_e, fr_s, fr_m, delta_fr_m_a)[1]
            l_chi_sq.append(chi_sq)
            l_der_chi_sq.append(der_chi_sq)
            l_der_chi_sq_f.append(der_chi_sq_f)
            l_der_chi_sq_a.append(der_chi_sq_a)
        return sum(l_chi_sq)

    chi_sq = temp_func(l_par_0)
    print(f"Chi_sq before optimization {chi_sq/total_peaks:.5f}.           ",
          end="\r")
    if flag_info:
        d_info["print"] = \
            f"Chi_sq/n before optimization {chi_sq/total_peaks:.5f}."

    res = scipy.optimize.minimize(
        temp_func,
        l_par_0,
        method="BFGS",
        callback=lambda x: func_temp(x, param_name=l_name, d_info=d_info),
        options={"eps": 0.001})
    l_param = res.x
    chi_sq_new = res.fun

    hess_inv = res["hess_inv"]
    sigma = (abs(numpy.diag(hess_inv)))**0.5

    print(f"Chi_sq after optimization {chi_sq_new/total_peaks:.5f}.          ",
          end="\r")
    if flag_info:
        d_info["print"] = \
            f"Chi_sq/n after optimization {chi_sq_new/total_peaks:.5f}."

    for name, parameter, sig in zip(l_name, l_param, sigma):
        name_sig = name[:-1] + ((f"{name[-1][0]:}_sigma", name[-1][1]), )
        if name[0][0] == "atom_site_susceptibility":
            atom_site_susceptibility.set_variable_by_name(name, parameter)
            atom_site_susceptibility.set_variable_by_name(name_sig, sig)
        elif name[0][0] == "mem_parameters":
            mem_parameters.set_variable_by_name(name, parameter)
            mem_parameters.set_variable_by_name(name_sig, sig)

    for diffrn in l_diffrn:
        diffrn.diffrn_refln.numpy_to_items()
        chi_sq, points = diffrn.diffrn_refln.calc_chi_sq_points()
        refine_ls = RefineLs(goodness_of_fit_all=chi_sq / points,
                             number_reflns=points)
        diffrn.add_items([refine_ls])
Exemple #4
0
    def calc_fr(self):
        """Calculate Flip Ratios for diffraction experiments."""
        crystal = self.crystals()[0]  # FIXME:
        l_diffrn = self.experiments()  # FIXME:
        density_point = self.density_point
        mem_parameters = self.mem_parameters
        chi_iso_ferro = mem_parameters.chi_ferro
        chi_iso_antiferro = mem_parameters.chi_antiferro

        flag_two_channel = mem_parameters.method == "2channel"

        cell = crystal.cell
        space_group = crystal.space_group
        space_group_symop = space_group.full_space_group_symop
        atom_site_susceptibility = crystal.atom_site_susceptibility

        # FIXME: temporary solution of calculation rbs_i if it's not defined
        density_point.calc_rbs_i(space_group_symop,
                                 points_a=mem_parameters.points_a,
                                 points_b=mem_parameters.points_b,
                                 points_c=mem_parameters.points_c)

        total_peaks = 0

        den_i = numpy.array(density_point.density, dtype=float)
        den_ferro_i = numpy.array(density_point.density_ferro, dtype=float)
        den_antiferro_i = numpy.array(density_point.density_antiferro,
                                      dtype=float)
        mult_i = numpy.array(density_point.multiplicity, dtype=int)

        volume = cell.volume
        n_points = mult_i.sum()

        for diffrn in l_diffrn:
            diffrn_orient_matrix = diffrn.diffrn_orient_matrix
            e_up = diffrn_orient_matrix.calc_e_up()
            setup = diffrn.setup
            field = float(setup.field)
            h_loc = (field * e_up[0], field * e_up[1], field * e_up[2])
            diffrn_refln = diffrn.diffrn_refln
            index_h = numpy.array(diffrn_refln.index_h, dtype=int)
            index_k = numpy.array(diffrn_refln.index_k, dtype=int)
            index_l = numpy.array(diffrn_refln.index_l, dtype=int)
            total_peaks += index_h.size
            hkl = (index_h, index_k, index_l)

            f_nucl = crystal.calc_f_nucl(*hkl)
            k_hkl = cell.calc_k_loc(*hkl)
            phase_3d = density_point.calc_phase_3d(hkl, space_group_symop)

            moment_2d, chi_2d_ferro, chi_2d_antiferro = \
                density_point.calc_moment_2d(
                    space_group_symop, cell, atom_site_susceptibility, h_loc,
                    chi_iso_ferro=1., chi_iso_antiferro=1.,
                    flag_two_channel=flag_two_channel)

            chi_ferro = calc_fm_by_density(mult_i, den_ferro_i, n_points,
                                           volume, chi_2d_ferro, phase_3d)
            chi_perp_ferro = calc_moment_perp(k_hkl, chi_ferro)

            chi_aferro = calc_fm_by_density(mult_i, den_antiferro_i, n_points,
                                            volume, chi_2d_antiferro, phase_3d)
            chi_perp_aferro = calc_moment_perp(k_hkl, chi_aferro)

            f_m = calc_fm_by_density(mult_i, den_i, n_points, volume,
                                     moment_2d, phase_3d)
            f_m_perp = calc_moment_perp(k_hkl, f_m)

            f_m_perp_sum = (f_m_perp[0] + chi_iso_ferro * chi_perp_ferro[0] +
                            chi_iso_antiferro * chi_perp_aferro[0],
                            f_m_perp[1] + chi_iso_ferro * chi_perp_ferro[1] +
                            chi_iso_antiferro * chi_perp_aferro[1],
                            f_m_perp[2] + chi_iso_ferro * chi_perp_ferro[2] +
                            chi_iso_antiferro * chi_perp_aferro[2])

            fr_m, delta_fr_m = diffrn.calc_fr(cell,
                                              f_nucl,
                                              f_m_perp_sum,
                                              delta_f_m_perp=f_m_perp)
            diffrn.diffrn_refln.numpy_fr_calc = fr_m
        for diffrn in l_diffrn:
            diffrn.diffrn_refln.numpy_to_items()
            chi_sq, points = diffrn.diffrn_refln.calc_chi_sq_points()
            refine_ls = RefineLs(goodness_of_fit_all=chi_sq / points,
                                 number_reflns=points)
            diffrn.add_items([refine_ls])