예제 #1
0
    def calculate(self, structure, **kwargs):
        """Calculate the descriptor for the given ASE structure.

        Parameters:

        structure: `ase.Atoms` object
            Atomic structure.

        """

        atoms = scale_structure(
            structure,
            scaling_type=self.atoms_scaling,
            atoms_scaling_cutoffs=self.atoms_scaling_cutoffs)

        # Source
        src = condor.Source(**self.param_source)

        # Detector
        det = condor.Detector(**self.param_detector)

        # Atoms
        atomic_numbers = map(lambda el: el.number, atoms)
        atomic_numbers = [
            atomic_number + 2 for atomic_number in atomic_numbers
        ]

        # convert Angstrom to m (CONDOR uses meters)
        atomic_positions = map(
            lambda pos: [pos.x * 1E-10, pos.y * 1E-10, pos.z * 1E-10], atoms)

        intensity_rgb = []
        rs_rgb = []
        ph_rgb = []
        real_space = None
        phases = None

        for [_, rot_matrices] in iteritems(self.rot_matrices):
            # loop over channels
            intensity_channel = []
            rs_channel = []
            ph_channel = []
            for rot_matrix in rot_matrices:
                # loop over the rotation matrices in a given channel
                # and sum the intensities in the same channel
                quaternion = condor.utils.rotation.quat_from_rotmx(rot_matrix)
                rotation_values = np.array([quaternion])
                rotation_formalism = 'quaternion'
                rotation_mode = 'intrinsic'

                par = condor.ParticleAtoms(
                    atomic_numbers=atomic_numbers,
                    atomic_positions=atomic_positions,
                    rotation_values=rotation_values,
                    rotation_formalism=rotation_formalism,
                    rotation_mode=rotation_mode)

                s = 'particle_atoms'
                condor_exp = condor.Experiment(src, {s: par}, det)
                res = condor_exp.propagate()

                # retrieve results
                real_space = np.fft.fftshift(
                    np.fft.ifftn(
                        np.fft.fftshift(
                            res["entry_1"]["data_1"]["data_fourier"])))
                intensity = res["entry_1"]["data_1"]["data"]
                fourier_space = res["entry_1"]["data_1"]["data_fourier"]
                phases = np.angle(fourier_space) % (2 * np.pi)

                if self.use_mask:
                    # set to zero values outside a ring-like mask
                    xc = (self.n_px - 1.0) / 2.0
                    yc = (self.n_py - 1.0) / 2.0
                    n = self.n_px
                    a, b = xc, yc
                    x, y = np.ogrid[-a:n - a, -b:n - b]

                    mask_int = x * x + y * y <= self.mask_r_min * self.mask_r_min
                    mask_ext = x * x + y * y >= self.mask_r_max * self.mask_r_max

                    for i in range(self.n_px):
                        for j in range(self.n_py):
                            if mask_int[i, j]:
                                intensity[i, j] = 0.0
                            if mask_ext[i, j]:
                                intensity[i, j] = 0.0

                intensity_channel.append(intensity)
                rs_channel.append(real_space.real)
                ph_channel.append(phases)

            # first sum the angles within the channel, then normalize
            intensity_channel = np.asarray(intensity_channel).sum(axis=0)
            rs_channel = np.asarray(rs_channel).sum(axis=0)
            ph_channel = np.asarray(ph_channel).sum(axis=0)

            # append normalized data from different channels
            # and divide by the angles per channel
            intensity_rgb.append(intensity_channel)
            rs_rgb.append(rs_channel)
            ph_rgb.append(ph_channel)

        intensity_rgb = np.asarray(intensity_rgb)
        intensity_rgb = (intensity_rgb - intensity_rgb.min()) / (
            intensity_rgb.max() - intensity_rgb.min())

        rs8 = (((real_space.real - real_space.real.min()) /
                (real_space.real.max() - real_space.real.min())) *
               255.0).astype(np.uint8)
        ph8 = (((phases - phases.min()) / (phases.max() - phases.min())) *
               255.0).astype(np.uint8)

        # reshape to have nb of color channels last
        intensity_rgb = intensity_rgb.reshape(intensity_rgb.shape[1],
                                              intensity_rgb.shape[2],
                                              intensity_rgb.shape[0])

        # add results in ASE structure info
        descriptor_data = dict(descriptor_name=self.name,
                               descriptor_info=str(self),
                               diffraction_2d_intensity=intensity_rgb,
                               diffraction_2d_real_space=rs8,
                               diffraction_2d_phase=ph8)

        structure.info['descriptor'] = descriptor_data

        return structure
예제 #2
0
파일: example.py 프로젝트: qsadhu/condor
 Z = numpy.concatenate((Z1.ravel(), Z2.ravel()))
 Y = numpy.concatenate((Y1.ravel(), Y2.ravel()))
 X = numpy.concatenate((X1.ravel(), X2.ravel()))
 proj = numpy.zeros(shape=(N_long, N_long))
 dx = long_diameter / (N_long - 1)
 for (x, y, z) in zip(X.ravel(), Y.ravel(), Z.ravel()):
     proj[int(round(y / dx)), int(round(x / dx))] += 1
 if plotting:
     pypl.imsave(out_dir + "/%s_proj.png" % (s), proj)
 atomic_positions = numpy.array(
     [[x, y, z] for x, y, z in zip(X.ravel(), Y.ravel(), Z.ravel())])
 atomic_numbers = numpy.ones(int(atomic_positions.size / 3),
                             dtype=numpy.int16)
 par = condor.ParticleAtoms(atomic_positions=atomic_positions,
                            atomic_numbers=atomic_numbers,
                            rotation_values=rotation_values,
                            rotation_formalism=rotation_formalism,
                            rotation_mode=rotation_mode)
 s = "particle_atoms"
 E = condor.Experiment(src, {s: par}, det)
 res = E.propagate()
 if plotting:
     real_space = numpy.fft.fftshift(
         numpy.fft.ifftn(
             numpy.fft.fftshift(
                 res["entry_1"]["data_1"]["data_fourier"])))
     fourier_space = res["entry_1"]["data_1"]["data_fourier"]
     vmin = numpy.log10(res["entry_1"]["data_1"]["data"].max() / 10000.)
     pypl.imsave(out_dir + "/%s_%2.2f.png" % (s, angle_d),
                 numpy.log10(res["entry_1"]["data_1"]["data"]),
                 vmin=vmin)
예제 #3
0
logger = logging.getLogger("condor")
#logger.setLevel("DEBUG")
logger.setLevel("WARNING")
#logger.setLevel("INFO")

N = 1
rotation_formalism="random"
rotation_values = None

# Source
src = condor.Source(wavelength=1E-10, pulse_energy=1E-3, focus_diameter=1001E-9)
# Detector
det = condor.Detector(distance=0.2, pixel_size=800E-6, nx=250, ny=250)
# Map
#print("Simulating map")
par = condor.ParticleAtoms(pdb_filename="%s/../../DNA.pdb" % this_dir,
                           rotation_formalism=rotation_formalism, rotation_values=rotation_values)
s = "particle_atoms"
E = condor.Experiment(src, {s : par}, det)

W = condor.utils.cxiwriter.CXIWriter("./condor.cxi")
for i in range(N):
    t = time.time()
    res = E.propagate()
    #print(time.time()-t)
    if plotting:
        real_space = numpy.fft.fftshift(numpy.fft.ifftn(res["entry_1"]["data_1"]["data_fourier"]))
        pypl.imsave(this_dir + "/%i.png" % (i), numpy.log10(res["entry_1"]["data_1"]["data"]))
        pypl.imsave(this_dir + "/%i_rs.png" % (i), abs(real_space))
    W.write(res)
W.close()
예제 #4
0
do_plot = False

if do_plot:
    import matplotlib
    matplotlib.use('TkAgg')
    from matplotlib import pyplot
    from matplotlib.colors import LogNorm

src = condor.Source(wavelength=0.1E-10, pulse_energy=1E-3, focus_diameter=1E-6)
ds = 16
det = condor.Detector(distance=2., pixel_size=110E-6*ds, nx=1024/ds+1, ny=1024/ds+1, solid_angle_correction=False)

psphere = {"particle_sphere": condor.ParticleSphere(diameter=1E-9, material_type="water")}
pmap = {"particle_map": condor.ParticleMap(diameter=1E-9, material_type="water", geometry="icosahedron")}
patoms = {"particle_atoms": condor.ParticleAtoms(pdb_filename="%s/../../DNA.pdb" % this_dir)}
          
particles = [psphere, pmap, patoms]

if do_plot:
    fig, (axs1, axs2) = pyplot.subplots(2, len(particles), figsize=(3*len(particles), 3*2))

for i,par in enumerate(particles): 

    E = condor.Experiment(src, par, det)
    res = E.propagate()
    data = res["entry_1"]["data_1"]["data"]
    if do_plot:
        axs1[i].set_title("2D: " + par.keys()[0])
        lims = (data.min(), data.max())
        axs1[i].imshow(data, norm=LogNorm(lims[0], lims[1]), cmap="gnuplot")
예제 #5
0
def test_compare_atoms_with_map(tolerance=0.1):
    """
    Compare the output of two diffraction patterns, one simulated with descrete atoms (spsim) and the other one from a 3D refractive index map on a regular grid.
    """
    src = condor.Source(wavelength=0.1E-9,
                        pulse_energy=1E-3,
                        focus_diameter=1E-6)
    det = condor.Detector(distance=0.5,
                          pixel_size=750E-6,
                          nx=100,
                          ny=100,
                          cx=45,
                          cy=59)
    angle_d = 72.
    angle = angle_d / 360. * 2 * numpy.pi
    rotation_axis = numpy.array([0.43, 0.643, 0.])
    rotation_axis = rotation_axis / condor.utils.linalg.length(rotation_axis)
    quaternion = condor.utils.rotation.quat(angle, rotation_axis[0],
                                            rotation_axis[1], rotation_axis[2])
    rotation_values = numpy.array([quaternion])
    rotation_formalism = "quaternion"
    rotation_mode = "extrinsic"
    short_diameter = 25E-9 * 12 / 100.
    long_diameter = 2 * short_diameter
    N_long = 20
    N_short = int(round(short_diameter / long_diameter * N_long))
    dx = long_diameter / (N_long - 1)
    massdensity = condor.utils.material.get_atomic_mass(
        "H") * scipy.constants.value("atomic mass constant") / dx**3
    # Map
    map3d = numpy.zeros(shape=(N_long, N_long, N_long))
    map3d[:N_short, :, :N_short] = 1.
    map3d[N_short:N_short + N_short, :N_short, :N_short] = 1.
    par = condor.ParticleMap(diameter=long_diameter,
                             material_type="custom",
                             massdensity=massdensity,
                             atomic_composition={"H": 1.},
                             geometry="custom",
                             map3d=map3d,
                             dx=dx,
                             rotation_values=rotation_values,
                             rotation_formalism=rotation_formalism,
                             rotation_mode=rotation_mode)
    s = "particle_map_custom"
    E = condor.Experiment(src, {s: par}, det)
    res = E.propagate()
    F_map = res["entry_1"]["data_1"]["data_fourier"]
    # Atoms
    Z1, Y1, X1 = numpy.meshgrid(numpy.linspace(0, short_diameter, N_short),
                                numpy.linspace(0, long_diameter, N_long),
                                numpy.linspace(0, short_diameter, N_short),
                                indexing="ij")
    Z2, Y2, X2 = numpy.meshgrid(numpy.linspace(0, short_diameter, N_short) +
                                long_diameter / 2.,
                                numpy.linspace(0, short_diameter, N_short),
                                numpy.linspace(0, short_diameter, N_short),
                                indexing="ij")
    Z = numpy.concatenate((Z1.ravel(), Z2.ravel()))
    Y = numpy.concatenate((Y1.ravel(), Y2.ravel()))
    X = numpy.concatenate((X1.ravel(), X2.ravel()))
    atomic_positions = numpy.array(
        [[x, y, z] for x, y, z in zip(X.ravel(), Y.ravel(), Z.ravel())])
    atomic_numbers = numpy.ones(atomic_positions.size // 3, dtype=numpy.int16)
    par = condor.ParticleAtoms(atomic_positions=atomic_positions,
                               atomic_numbers=atomic_numbers,
                               rotation_values=rotation_values,
                               rotation_formalism=rotation_formalism,
                               rotation_mode=rotation_mode)
    s = "particle_atoms"
    E = condor.Experiment(src, {s: par}, det)
    res = E.propagate()
    F_atoms = res["entry_1"]["data_1"]["data_fourier"]
    # Compare
    I_atoms = abs(F_atoms)**2
    I_map = abs(F_map)**2
    diff = I_atoms - I_map
    err = abs(diff).sum() / ((I_atoms.sum() + I_map.sum()) / 2.)
    if SAVE_OUTPUT:
        import matplotlib.pyplot as pypl
        pypl.imsave("./Iatoms_mol.png", abs(I_atoms))
        pypl.imsave("./Iatoms_map.png", abs(I_map))
    assert err < tolerance
예제 #6
0
#logger.setLevel("INFO")

N = 1
rotation_formalism = "random"
rotation_values = None

# Source
src = condor.Source(wavelength=1E-10,
                    pulse_energy=1E-3,
                    focus_diameter=1001E-9)
# Detector
det = condor.Detector(distance=0.2, pixel_size=800E-6, nx=250, ny=250)
# Map
#print("Simulating map")
par = condor.ParticleAtoms(pdb_id="1AKI",
                           rotation_formalism=rotation_formalism,
                           rotation_values=rotation_values)
s = "particle_atoms"
E = condor.Experiment(src, {s: par}, det)

W = condor.utils.cxiwriter.CXIWriter("./condor.cxi")
for i in range(N):
    t = time.time()
    res = E.propagate()
    #print(time.time()-t)
    if plotting:
        real_space = numpy.fft.fftshift(
            numpy.fft.ifftn(res["entry_1"]["data_1"]["data_fourier"]))
        pypl.imsave(this_dir + "/%i.png" % (i),
                    numpy.log10(res["entry_1"]["data_1"]["data"]))
        pypl.imsave(this_dir + "/%i_rs.png" % (i), abs(real_space))
예제 #7
0
                numpy.log10(res["entry_1"]["data_1"]["data"]))
    pypl.imsave(this_dir + "/simple_test_%s_rs.png" % s, abs(real_space))

# Icosahedron
#print("Simulating map")
par = condor.ParticleMap(diameter=1E-9,
                         material_type="water",
                         geometry="icosahedron")
s = "particle_map_icosahedron"
E = condor.Experiment(src, {s: par}, det)
res = E.propagate()
if plotting:
    real_space = numpy.fft.fftshift(
        numpy.fft.ifftn(res["entry_1"]["data_1"]["data_fourier"]))
    pypl.imsave(this_dir + "/simple_test_%s.png" % s,
                numpy.log10(res["entry_1"]["data_1"]["data"]))
    pypl.imsave(this_dir + "/simple_test_%s_rs.png" % s, abs(real_space))

# Atoms
#print("Simulating atoms")
par = condor.ParticleAtoms(pdb_filename="../../DNA.pdb")
s = "particle_atoms"
E = condor.Experiment(src, {s: par}, det)
res = E.propagate()
if plotting:
    real_space = numpy.fft.fftshift(
        numpy.fft.ifftn(res["entry_1"]["data_1"]["data_fourier"]))
    pypl.imsave(this_dir + "/simple_test_%s.png" % s,
                numpy.log10(res["entry_1"]["data_1"]["data"]))
    pypl.imsave(this_dir + "/simple_test_%s_rs.png" % s, abs(real_space))
예제 #8
0
    def calculate(self,
                  structure,
                  min_nb_atoms=20,
                  plot_3d=False,
                  plot_slices=False,
                  plot_slices_sph_coords=False,
                  save_diff_intensity=True,
                  **kwargs):
        """Calculate the descriptor for the given ASE structure.

        Parameters:

        structure: `ase.Atoms` object
            Atomic structure.

        min_nb_atoms: int, optional (default=20)
            If the structure contains less than ``min_nb_atoms``, the descriptor is not calculated and an array with
            zeros is return as descriptor. This is because the descriptor is expected to be no longer meaningful for
            such a small amount of atoms present in the chosen structure.

        """

        if len(structure) > min_nb_atoms - 1:

            atoms = scale_structure(
                structure,
                scaling_type=self.atoms_scaling,
                atoms_scaling_cutoffs=self.atoms_scaling_cutoffs,
                extrinsic_scale_factor=self.extrinsic_scale_factor)

            # Source
            src = condor.Source(**self.param_source)

            # Detector
            # solid_angle_correction are meaningless for 3d diffraction
            det = condor.Detector(solid_angle_correction=False,
                                  **self.param_detector)

            # Atoms
            atomic_numbers = map(lambda el: el.number, atoms)
            atomic_numbers = [
                atomic_number + 5 for atomic_number in atomic_numbers
            ]
            # atomic_numbers = [82 for atomic_number in atomic_numbers]

            # convert Angstrom to m (CONDOR uses meters)
            atomic_positions = map(
                lambda pos: [pos.x * 1E-10, pos.y * 1E-10, pos.z * 1E-10],
                atoms)

            par = condor.ParticleAtoms(atomic_numbers=atomic_numbers,
                                       atomic_positions=atomic_positions)

            s = "particle_atoms"
            condor_exp = condor.Experiment(src, {s: par}, det)
            res = condor_exp.propagate3d()

            # retrieve some physical quantities that might be useful for users
            intensity = res["entry_1"]["data_1"]["data"]
            fourier_space = res["entry_1"]["data_1"]["data_fourier"]
            phases = np.angle(fourier_space) % (2 * np.pi)

            # 3D diffraction calculation
            real_space = np.fft.fftshift(
                np.fft.ifftn(
                    np.fft.fftshift(res["entry_1"]["data_1"]["data_fourier"])))
            window = get_window(self.window, self.n_px)
            tot_density = window * real_space.real
            center_of_mass = ndimage.measurements.center_of_mass(tot_density)
            logger.debug("Tot density data dimensions: {}".format(
                tot_density.shape))
            logger.debug(
                "Center of mass of total density: {}".format(center_of_mass))

            # take the fourier transform of structure in real_space
            fft_coeff = fftpack.fftn(tot_density,
                                     shape=(self.nx_fft, self.ny_fft,
                                            self.nz_fft))

            # now shift the quadrants around so that low spatial frequencies are in
            # the center of the 2D fourier transformed image.
            fft_coeff_shifted = fftpack.fftshift(fft_coeff)

            # calculate a 3D power spectrum
            power_spect = np.abs(fft_coeff_shifted)**2

            if self.use_mask:
                xc = (self.nx_fft - 1.0) / 2.0
                yc = (self.ny_fft - 1.0) / 2.0
                zc = (self.nz_fft - 1.0) / 2.0

                # spherical mask
                a, b, c = xc, yc, zc
                x, y, z = np.ogrid[-a:self.nx_fft - a, -b:self.ny_fft - b,
                                   -c:self.nz_fft - c]

                mask_int = x * x + y * y + z * z <= self.mask_r_min * self.mask_r_min
                mask_out = x * x + y * y + z * z >= self.mask_r_max * self.mask_r_max

                for i in range(self.nx_fft):
                    for j in range(self.ny_fft):
                        for k in range(self.nz_fft):
                            if mask_int[i, j, k]:
                                power_spect[i, j, k] = 0.0
                            if mask_out[i, j, k]:
                                power_spect[i, j, k] = 0.0

            # cut the spectrum and keep only the relevant part for crystal-structure recognition of
            # hexagonal closed packed (spacegroup=194)
            # simple cubic (spacegroup=221)
            # face centered cubic (spacegroup=225)
            # diamond (spacegroup=227)
            # body centered cubic (spacegroup=229)
            # this interval (20:108) might need to be varied if other classes are added
            power_spect_cut = power_spect[20:108, 20:108, 20:108]
            # zoom by two times using spline interpolation
            power_spect = ndimage.zoom(power_spect_cut, (2, 2, 2))

            if save_diff_intensity:
                np.save(
                    '/home/ziletti/Documents/calc_nomadml/rot_inv_3d/power_spect.npy',
                    power_spect)

            # power_spect.shape = 176, 176, 176
            if plot_3d:
                plot_3d_volume(power_spect)

            vox = np.copy(power_spect)
            logger.debug("nan in data: {}".format(
                np.count_nonzero(~np.isnan(vox))))

            # optimized
            # these specifications are valid for a power_spect = power_spect[20:108, 20:108, 20:108]
            # and a magnification of 2
            xyz_indices_r = get_slice_volume_indices(
                vox,
                min_r=32.0,
                dr=1.0,
                max_r=83.,
                phi_bins=self.phi_bins,
                theta_bins=self.theta_bins)

            # slow - only for benchmarking the fast implementation below (shells_to_sph, interp_theta_phi_surfaces)
            # (vox_by_slices, theta_phi_by_slices) = _slice_3d_volume_slow(vox)

            # convert 3d shells
            (vox_by_slices, theta_phi_by_slices) = get_shells_from_indices(
                xyz_indices_r, vox)
            if plot_slices:
                plot_concentric_shells(
                    vox_by_slices,
                    base_folder=self.configs['io']['main_folder'],
                    idx_slices=None,
                    create_animation=False)

            image_by_slices = interp_theta_phi_surfaces(
                theta_phi_by_slices,
                theta_bins=self.theta_bins_fine,
                phi_bins=self.phi_bins_fine)

            if plot_slices_sph_coords:
                plot_concentric_shells_spherical_coords(
                    image_by_slices,
                    base_folder=self.configs['io']['main_folder'],
                    idx_slices=None)

            coeffs_list = []
            nl_list = []
            ls_list = []

            for idx_slice in range(image_by_slices.shape[0]):
                logger.debug("img #{} max: {}".format(
                    idx_slice, image_by_slices[idx_slice].max()))

                # set to zero the spherical harmonics coefficients above self.sph_l_cutoff
                coeffs = SHExpandDH(image_by_slices[idx_slice], sampling=2)
                coeffs_filtered = coeffs.copy()
                coeffs_filtered[:, self.sph_l_cutoff:, :] = 0.
                coeffs = coeffs_filtered.copy()

                nl = coeffs.shape[0]
                ls = np.arange(nl)
                coeffs_list.append(coeffs)
                nl_list.append(nl)
                ls_list.append(ls)

            coeffs = np.asarray(coeffs_list).reshape(image_by_slices.shape[0],
                                                     coeffs.shape[0],
                                                     coeffs.shape[1],
                                                     coeffs.shape[2])

            sh_coeffs_list = []

            for idx_slice in range(coeffs.shape[0]):
                sh_coeffs = SHCoeffs.from_array(coeffs[idx_slice])
                sh_coeffs_list.append(sh_coeffs)

            sh_spectrum_list = []
            for sh_coeff in sh_coeffs_list:
                sh_spectrum = sh_coeff.spectrum(convention='l2norm')
                sh_spectrum_list.append(sh_spectrum)

            sh_spectra = np.asarray(sh_spectrum_list).reshape(
                coeffs.shape[0], -1)

            # cut the spherical harmonics expansion to sph_l_cutoff order
            logger.debug(
                'Spherical harmonics spectra maximum before normalization: {}'.
                format(sh_spectra.max()))
            sh_spectra = sh_spectra[:, :self.sph_l_cutoff]
            sh_spectra = (sh_spectra - sh_spectra.min()) / (sh_spectra.max() -
                                                            sh_spectra.min())

            # add results in ASE structure info
            descriptor_data = dict(descriptor_name=self.name,
                                   descriptor_info=str(self),
                                   diffraction_3d_sh_spectrum=sh_spectra)

        else:
            # return array with zeros for structures with less than min_nb_atoms
            sh_spectra = np.zeros((52, int(self.sph_l_cutoff)))
            descriptor_data = dict(descriptor_name=self.name,
                                   descriptor_info=str(self),
                                   diffraction_3d_sh_spectrum=sh_spectra)

        structure.info['descriptor'] = descriptor_data

        return structure
예제 #9
0
    (1e6 * focus_diameter / 2.)**2))  # [J]

# Sample
pdb_id = '1FFK'
sample_size = 18e-9

# Simulation
src = condor.Source(wavelength=wavelength,
                    pulse_energy=pulse_energy,
                    focus_diameter=focus_diameter)
det = condor.Detector(distance=detector_distance,
                      pixel_size=pixelsize,
                      nx=nx,
                      ny=ny,
                      noise="poisson")
par = condor.ParticleAtoms(pdb_id=pdb_id, rotation_formalism="random")
E = condor.Experiment(source=src,
                      particles={"particle_atoms": par},
                      detector=det)

# Run multiple times and Save to file
N = 100
W = condor.utils.cxiwriter.CXIWriter(
    "../data/single_protein_diffraction_patterns.h5")
for i in range(N):
    o = E.propagate()
    W.write(o)
W.close()

# Save interpolated 3D diffraction volume
# =======================================