Пример #1
0
class ROIProcessingPlugin(ProcessingPlugin):
    data = Input()
    image = Input()
    roi = Output()
    region = Output()

    def __init__(self, ROI: ROI):
        super(ROIProcessingPlugin, self).__init__()
        self.ROI = ROI
        self._param = None  # type: Parameter

        self.name = f"ROI #{self.ROI.index}"

    def evaluate(self):
        # TODO -- don't need to do scene matching if we are not using ROI.getArrayRegion
        # Add ROI to same scene as image
        # (workflow serialization changes the obj refs, they need to be the same for ROI.getArrayRegion)
        image_scene = self.image.value.scene()
        image_scene.addItem(self.ROI)
        self.region.value = self.ROI.getArrayRegion(self.data.value,
                                                    self.image.value)
        self.roi.value = self.region.value.astype(np.bool)

    @property
    def parameter(self):
        if not self._param:
            self._param = self.ROI.parameter()
        return self._param
Пример #2
0
class ImageRemap(ProcessingPlugin):
    name = 'Remesh'

    data = Input(description='Detector image', type=np.ndarray)
    geometry = InOut(description='pyFAI Geometry', type=pyFAI.geometry.Geometry)
    alphai = Input(description='GISAXS angle of incedence', type=float)
    out_range = Input(description='Coordinates of output image', type=list, default=None)
    resolution = Input(description='Resolution of output image', type=list, default=None)
    coord_sys = Input(description='Choice of coordinate system for output image', 
        type=str, default='qp_qz')


    qImage = Output(description='Remapped image', type=np.ndarray)
    xcrd = Output(description='X-coordinates output image', type=np.ndarray)
    ycrd = Output(description='Y-coordinates output image', type=np.ndarray)
    #hints = [ ]

    def evaluate(self):
        I, x, y = hipies.remesh(self.Image.value, self.geometry.value, self.alphai.value,
                    out_range = self.out_range.value, res = self.resolution.value,
                    coord_sys = self.coord_sys.value)
        self.qImage.value = I
        dist = self.geometry.value._dist
        centerX = np.unravel_index(x.abs().argmin(), x.shape)[1]
        centerY = np.unravel_index(y.abs().argmin(), y.shape)[0]
        pixel = [self.geometry.value.get_pixel1(), self.geometry.value.get_pixel2()]
        center = [ centerX * pixel[0], centerY * pixel[1])
        geometry.value.setFit2D(self.geometry.value._dist, center[0], center[1])
Пример #3
0
class XIntegratePlugin(ProcessingPlugin):
    name = 'X Integrate'
    ai = Input(description='A PyFAI.AzimuthalIntegrator object',
               type=AzimuthalIntegrator)
    data = Input(description='2d array representing intensity for each pixel',
                 type=np.ndarray)
    mask = Input(description='Array (same size as image) with 1 for masked pixels, and 0 for valid pixels',
                 type=np.ndarray)
    dark = Input(description='Dark noise image',
                 type=np.ndarray)
    flat = Input(description='Flat field image',
                 type=np.ndarray)
    normalization_factor = Input(description='Value of a normalization monitor',
                                 type=float, default=1.)
    qx = Output(description='Q_x bin center positions',
                type=np.array)
    Ix = Output(description='Binned/pixel-split integrated intensity',
                type=np.array)

    hints = [PlotHint(qx, Ix)]

    def evaluate(self):
        if self.dark.value is None: self.dark.value = np.zeros_like(self.data.value)
        if self.flat.value is None: self.flat.value = np.ones_like(self.data.value)
        if self.mask.value is None: self.mask.value = np.zeros_like(self.data.value)
        self.Ix.value = np.sum((self.data.value - self.dark.value) * np.average(self.flat.value - self.dark.value) / (
                self.flat.value - self.dark.value) * np.logical_not(self.mask.value), axis=0)
        centerx = self.ai.value.getFit2D()['centerX']
        centerz = self.ai.value.getFit2D()['centerY']
        self.qx.value = self.ai.value.qFunction(np.array([centerz] * self.data.value.shape[1]),
                                                np.arange(0, self.data.value.shape[1])) / 10.
        self.qx.value[np.arange(0, self.data.value.shape[1]) < centerx] *= -1.
Пример #4
0
class CakeIntegratePlugin(ProcessingPlugin):
    ai = Input(description='A PyFAI.AzimuthalIntegrator object',
               type=AzimuthalIntegrator)
    data = Input(description='2d array representing intensity for each pixel',
                 type=np.ndarray)
    npt_rad = Input(description='Number of bins along q', default=1000)
    npt_azim = Input(description='Number of bins along chi', default=1000)
    polz_factor = Input(description='Polarization factor for correction',
                        type=float,
                        default=0)
    unit = Input(description='Output units for q',
                 type=[str, units.Unit],
                 default="q_A^-1")
    radial_range = Input(
        description=
        'The lower and upper range of the radial unit. If not provided, range is simply '
        '(data.min(), data.max()). Values outside the range are ignored.',
        type=tuple)
    azimuth_range = Input(
        description=
        'The lower and upper range of the azimuthal angle in degree. If not provided, '
        'range is simply (data.min(), data.max()). Values outside the range are ignored.',
        type=tuple)
    mask = Input(
        description=
        'Array (same size as image) with 1 for masked pixels, and 0 for valid pixels',
        type=np.ndarray)
    dark = Input(description='Dark noise image', type=np.ndarray)
    flat = Input(description='Flat field image', type=np.ndarray)
    method = Input(
        description=
        'Can be "numpy", "cython", "BBox" or "splitpixel", "lut", "csr", "nosplit_csr", '
        '"full_csr", "lut_ocl" and "csr_ocl" if you want to go on GPU. To Specify the device: '
        '"csr_ocl_1,2"',
        type=str,
        default='splitbbox')
    normalization_factor = Input(
        description='Value of a normalization monitor', type=float, default=1.)
    chi = Output(description='Chi bin center positions', type=np.array)
    cake = Output(description='Binned/pixel-split integrated intensity',
                  type=np.array)
    q = Output(description='Q bin center positions', type=np.array)

    def evaluate(self):
        self.cake.value, q, chi = self.ai.value.integrate2d(
            data=nonesafe_flipud(self.data.value),
            npt_rad=self.npt_rad.value,
            npt_azim=self.npt_azim.value,
            radial_range=self.radial_range.value,
            azimuth_range=self.azimuth_range.value,
            mask=nonesafe_flipud(self.mask.value),
            polarization_factor=self.polz_factor.value,
            dark=nonesafe_flipud(self.dark.value),
            flat=nonesafe_flipud(self.flat.value),
            method=self.method.value,
            unit=self.unit.value,
            normalization_factor=self.normalization_factor.value)

        self.chi.value = chi
        self.q.value = q
Пример #5
0
class LinecutPlugin(ProcessingPlugin):
    name = 'Linecut'
    coordinate = Input(description='Coordinate of the cut',
                       type=int,
                       default=0)
    parallelAxis = Input(description='Axis the cut is parallel to',
                         type=str,
                         default="x")
    data = Input(description='2d array representing intensity for each pixel',
                 type=np.ndarray)
    mask = Input(
        description=
        'Array (same size as image) with 1 for masked pixels, and 0 for valid pixels',
        type=np.ndarray)
    dark = Input(description='Dark noise image', type=np.ndarray)
    flat = Input(description='Flat field image', type=np.ndarray)
    normalization_factor = Input(
        description='Value of a normalization monitor', type=float, default=1.)
    px = Output(name='px', description='Bin center positions', type=np.array)
    I = Output(name='Intensity',
               description='Binned/pixel-split intensity',
               type=np.array)

    hints = [PlotHint(px, I)]

    def evaluate(self):
        x = self.parallelAxis.value == "x"
        lperp = self.data.value.shape[not x]  #booleans are ints
        if self.coordinate.value >= lperp:
            self.coordinate.value = lperp - 1
        if self.coordinate.value < 0:
            self.coordinate.value = 0
        if self.dark.value is None:
            self.dark.value = np.zeros_like(self.data.value)
        if self.flat.value is None:
            self.flat.value = np.ones_like(self.data.value)
        if self.mask.value is None:
            self.mask.value = np.zeros_like(self.data.value)
        h = ((self.data.value - self.dark.value) *
             np.average(self.flat.value - self.dark.value) /
             (self.flat.value - self.dark.value) *
             np.logical_not(self.mask.value))
        self.I.value = (h[lperp - 1 - self.coordinate.value]
                        if x else [b[self.coordinate.value] for b in h][::-1])
        self.px.value = range(self.data.value.shape[x])  #booleans are ints

    def getCategory() -> str:
        return "Cuts"
Пример #6
0
class RickerWave(ProcessingPlugin):

    # inputs
    data = Input(description='Calibrant frame image data', type=np.ndarray)
    mask = Input(
        description='Array with 1 for masked pixels, and 0 for valid pixels',
        type=np.ndarray)
    domain = Input(description='Search domain in pixels: [r_min, r_max]',
                   type=list)
    scale = Input(description='Approxmate intensity along the ring',
                  type=float,
                  default=1)
    width = Input(description='Approximate width of the AgB ring in pixels',
                  type=float,
                  default=5)

    # output
    center = Output(
        description='Approximated position of the direct beam center',
        type=np.ndarray)

    def evaluate(self):
        self.center.value, _ = cwt2d(self.data.value,
                                     domain=self.domain.value,
                                     scale=self.scale.value,
                                     width=self.width.value)
Пример #7
0
class fourierAutocorrelation(ProcessingPlugin):
    name = 'Fourier Autocorrelation'

    data = Input(description='Calibrant frame image data', type=np.ndarray)
    center = Output(
        description='Approximated position of the direct beam center')
    ai = InOut(
        description='Azimuthal integrator; center will be modified in place',
        type=AzimuthalIntegrator)

    def evaluate(self):
        mask = self.ai.value.detector.mask
        data = np.array(self.data.value)
        if isinstance(mask,
                      np.ndarray) and mask.shape == self.data.value.shape:
            data = data * (1 - mask)

        con = signal.fftconvolve(data, data) / np.sqrt(
            signal.fftconvolve(np.ones_like(self.data.value),
                               np.ones_like(self.data.value)))

        self.center.value = np.array(np.unravel_index(con.argmax(),
                                                      con.shape)) / 2.
        self.center.value[0] = len(data) - self.center.value[0]
        fit2dparams = self.ai.value.getFit2D()
        fit2dparams['centerX'] = self.center.value[1]
        fit2dparams['centerY'] = self.center.value[0]
        self.ai.value.setFit2D(**fit2dparams)
Пример #8
0
class chisquared(ProcessingPlugin):
    dataA = Input(description='Frame A image data', type=np.ndarray)
    dataB = Input(description='Frame B image data', type=np.ndarray)

    chisquared = Output(
        description='Chi-squared difference between consecutive frames')

    def evaluate(self):
        self.chisquared.value = (self.dataA.value - self.dataB.value)**2.
class ReadCropped(ProcessingPlugin):
    """
    Return uniformly distributed projection angles in radian.
    """
    paths = Input(description='List of paths', type=List[str])
    pxmin = Input(description='start x pixel', type=int)
    pxmax = Input(description='stop x pixel', type=int)
    pxstep = Input(description='step of x pixel', type=int)
    pzmin = Input(description='min z pixel', type=int)
    pzmax = Input(description='max z pixel', type=int)
    tomo = Output(description='3D array of tomograms (''projection'' first)')
    angles = Output(description='angle')

    def evaluate(self):
        frames = []
        for f in self.paths.value:
            frames.append(fabio.open(f).data[np.arange(self.pxmin.value, self.pxmax.value, self.pxstep.value),self.pzmin.value:self.pzmax.value])
        self.tomo.value = np.array(frames)
        self.angles.value = np.linspace(0,180, len(self.paths.value))
Пример #10
0
class QIntegratePlugin(ProcessingPlugin):
    integrator = Input(description="A PyFAI.AzimuthalIntegrator object", type=AzimuthalIntegrator)
    data = Input(description="2d array representing intensity for each pixel", type=np.ndarray)
    npt = Input(description="Number of bins along q")
    polz_factor = Input(description="Polarization factor for correction", type=float)
    unit = Input(description="Output units for q", type=[str, units.Unit], default="q_A^-1")
    radial_range = Input(
        description="The lower and upper range of the radial unit. If not provided, range is simply "
        "(data.min(), data.max()). Values outside the range are ignored.",
        type=tuple,
    )
    azimuth_range = Input(
        description="The lower and upper range of the azimuthal angle in degree. If not provided, "
        "range is simply (data.min(), data.max()). Values outside the range are ignored."
    )
    mask = Input(description="Array (same size as image) with 1 for masked pixels, and 0 for valid pixels", type=np.ndarray)
    dark = Input(description="Dark noise image", type=np.ndarray)
    flat = Input(description="Flat field image", type=np.ndarray)
    method = Input(
        description='Can be "numpy", "cython", "BBox" or "splitpixel", "lut", "csr", "nosplit_csr", '
        '"full_csr", "lut_ocl" and "csr_ocl" if you want to go on GPU. To Specify the device: '
        '"csr_ocl_1,2"',
        type=str,
    )
    normalization_factor = Input(description="Value of a normalization monitor", type=float)
    q = Output(description="Q bin center positions", type=np.array)
    I = Output(description="Binned/pixel-split integrated intensity", type=np.array)

    def evaluate(self):
        self.q.value, self.I.value = self.integrator.value().integrate1d(
            data=self.data.value,
            npt=self.npt.value,
            radial_range=self.radial_range.value,
            azimuth_range=self.azimuth_range.value,
            mask=self.mask.value,
            polarization_factor=self.polz_factor.value,
            dark=self.dark.value,
            flat=self.flat.value,
            method=self.method.value,
            unit=self.unit.value,
            normalization_factor=self.normalization_factor.value,
        )
Пример #11
0
class QconversionGISAXS(ProcessingPlugin):
    integrator = Input(description='A PyFAI.AzimuthalIntegrator object', type=AzimuthalIntegrator)
    data = Input(description='Frame image data', type=np.ndarray)

    qx = Output(description='qx array with dimension of data', type=np.ndarray)
    qz = Output(description='qz array with dimension of data', type=np.ndarray)

    def evaluate(self):
        self.qx, self.qz = self.qconverion()

    def qconverion(self):
        chi = self.integrator.chiArray()
        twotheta = self.integrator.twoThetaArray()
        # find alphai
        alphai = self.integrator.getvalue('Wavelength')

        # Doble check what is chi = 0
        qx = 2 * np.pi / self.integrator.getvalue('Wavelength') * np.sin(twotheta) * np.sin(chi)
        qz = 2 * np.pi / self.integrator.getvalue('Wavelength') * np.sin(twotheta) * np.cos(chi)

        return qx, qz
Пример #12
0
class ROIProcessingPlugin(ProcessingPlugin):
    data = Input()
    image = Input()
    roi = Output()
    region = Output()

    def __init__(self, ROI: ROI):
        super(ROIProcessingPlugin, self).__init__()
        self.ROI = ROI
        self._param = None  # type: Parameter

        self.name = f"ROI #{self.ROI.index}"

    def evaluate(self):
        self.region.value = self.ROI.getLabelArray(self.data.value, self.image.value)
        self.roi.value = self.region.value.astype(np.bool)

    @property
    def parameter(self):
        if not self._param:
            self._param = self.ROI.parameter()
        return self._param
Пример #13
0
class Angles(ProcessingPlugin):
    """
    Return uniformly distributed projection angles in radian.
    """
    nang = Input(description='Number of projections', type=int)
    ang1 = Input(description='First proj. angle in deg',
                 type=float,
                 default=0.)
    ang2 = Input(description='Last proj. angle in deg', type=int, default=180.)
    angles = Output(description='Projection angles', type='np.ndarray')

    def evaluate(self):
        self.angles.value = tomopy.angles(self.nang.value,
                                          ang1=self.ang1.value,
                                          ang2=self.ang2.value)
Пример #14
0
class SimulateCalibrant(ProcessingPlugin):
    name = 'Simulate Calibrant'
    ai = Input(description='Azimimuthal integrator', type=AzimuthalIntegrator)
    Imax = Input(description='Maximum intensity of rings',
                 type=float,
                 default=1)
    calibrant = Input(description='pyFAI calibrant object to simulate',
                      type=calibrant)
    data = Output(description='Simulated data for given calibrant',
                  type=np.ndarray)

    def evaluate(self):
        self.calibrant.value.set_wavelength(self.ai.value.get_wavelength())
        self.data.value = self.calibrant.value.fake_calibration_image(
            self.ai.value, Imax=self.Imax.value)
Пример #15
0
class InPaint(ProcessingPlugin):
    name = 'Inpaint (pyFAI)'

    data = InOut(description='2d array representing intensity for each pixel',
                 type=np.ndarray)
    mask = Input(
        description=
        'Array (same size as image) with 1 for masked pixels, and 0 for valid pixels',
        type=np.ndarray)
    inpaint = Output(description='2d array with masking pixels '
                     'reconstructed'
                     '',
                     type=np.ndarray)

    def evaluate(self):
        self.inpaint.value = reconstruct(self.data.value, self.mask.value)
Пример #16
0
class HorizontalCutPlugin(ProcessingPlugin):
    data = Input(description='Frame image data', type=np.ndarray)
    qx = Input(description='qx coordinate corresponding to data', type=np.ndarray)
    mask = Input(description='Frame image data', type=np.ndarray, default=None)

    # Make qx range a single parameter, type = tuple
    qxminimum = Input(description='qx minimum limit', type=int)
    qxmaximum = Input(description='qx maximum limit', type=int)

    horizontalcut = Output(description='mask (1 is masked) with dimension of data', type=np.ndarray)

    def evaluate(self):
        if self.mask.value is not None:
            self.horizontalcut.value = np.logical_or(self.mask.value, self.qx < self.qxminimum.value,
                                                     self.qx > self.qxmaximum.value)
        else:
            self.horizontalcut.value = np.logical_or(self.qx < self.qxminimum.value, self.qx > self.qxmaximum.value)
Пример #17
0
class FindCenter(ProcessingPlugin):
    """
    Find rotation axis location.

    The function exploits systematic artifacts in reconstructed images
    due to shifts in the rotation center. It uses image entropy
    as the error metric and ''Nelder-Mead'' routine (of the scipy
    optimization module) as the optimizer :cite:`Donath:06`.
    """

    tomo = Input(description="3D tomographic data", type=np.ndarray)
    theta = Input(description="Projection angles in radian", type=np.ndarray)
    ind = Input(
        description="Index of the slice to be used for reconstruction",
        default=None,
        type=int)
    init = Input(
        description="Initial guess for the center", default=None, type=float)
    tol = Input(
        description="Desired sub-pixel accuracy", default=0.5, type=float)
    mask = Input(
        description="If True, apply a circular mask", default=True, type=bool)
    ratio = Input(
        description=
        "The ratio of the radius of the circular mask to the edge of the reconstructed image",
        default=1.,
        type=float)
    sinogram_order = Input(
        type=bool,
        default=False,
        description=
        "Determins whether data is a stack of sinograms (True, y-axis first axis) or a stack of radiographs (False, theta first axis)."
    )

    center = Output(description="Rotation axis location", type=float)

    def evaluate(self):
        self.center.value = tomopy.find_center(
            self.tomo.value,
            self.theta.value,
            ind=self.ind.value,
            init=self.init.value,
            tol=self.tol.value,
            mask=self.mask.value,
            ratio=self.ratio.value,
            sinogram_order=self.sinogram_order.value)
Пример #18
0
class AzimuthalCutPlugin(ProcessingPlugin):
    data = Input(description='Frame image data', type=np.ndarray)

    center = Input(
        description=
        'Array (same size as image) with 1 for masked pixels, and 0 for valid pixels',
        type=np.ndarray)

    detector = Input(
        description='PyFAI detector instance; the geometry of the detector'
        's inactive area will be masked.',
        type=Detector)
    polygon = Input(description='Polygon shape to mask (interior is masked)')
    mask = Output(description='Mask array (1 is masked).', type=np.ndarray)

    def evaluate(self):
        raise NotImplementedError
Пример #19
0
class ThresholdMaskPlugin(ProcessingPlugin):
    data = Input(description="Frame image data", type=np.ndarray)
    minimum = Input(description="Threshold floor", type=int)
    maximum = Input(description="Threshold ceiling", type=int)
    neighborhood = Input(
        description="Neighborhood size in pixels for morphological opening. Only clusters of this size"
        " that fail the threshold are masked",
        type=int,
    )
    mask = Output(description="Thresholded mask (1 is masked)", type=np.ndarray)

    def evaluate(self):
        self.mask.value = np.logical_or(self.data.value < self.minimum.value, self.data.value > self.maximum.value)

        y, x = np.ogrid[
            -self.neighborhood.value : self.neighborhood.value + 1, -self.neighborhood.value : self.neighborhood.value + 1
        ]
        kernel = x ** 2 + y ** 2 <= self.neighborhood.value ** 2

        morphology.binary_opening(self.mask.value, kernel, output=self.mask.value)  # write-back to mask
Пример #20
0
class FindCenterPc(ProcessingPlugin):
    """
    Find rotation axis location.

    The function exploits systematic artifacts in reconstructed images
    due to shifts in the rotation center. It uses image entropy
    as the error metric and ''Nelder-Mead'' routine (of the scipy
    optimization module) as the optimizer :cite:`Donath:06`.
    """

    proj1 = Input(description="2D projection data", type=np.ndarray)
    proj2 = Input(description="2D projection data", type=np.ndarray)
    tol = Input(description="Subpixel accuracy", type=float, default=0.5)

    center = Output(description="Rotation axis location", type=float)

    def evaluate(self):
        self.center.value = tomopy.find_center_pc(self.proj1.value,
                                                  self.proj2.value,
                                                  tol=self.tol.value)
Пример #21
0
class VerticalCutPlugin(ProcessingPlugin):
    data = Input(description='Frame image data', type=np.ndarray)
    qz = Input(description='qz coordinate corresponding to data', type=np.ndarray)

    mask = Input(description='Frame image data', type=np.ndarray, default=None)

    # Make qz range a single parameter, type = tuple
    qzminimum = Input(description='qz minimum limit', type=int)
    qzmaximum = Input(description='qz maximum limit', type=int)

    cut = Output(description='mask (1 is masked) with dimension of data', type=np.ndarray)

    hints = [VerticalROI(qzminimum, qzmaximum)]

    def evaluate(self):
        if self.mask.value is not None:
            self.cut.value = np.logical_or(self.mask.value, self.qz < self.qzminimum.value,
                                           self.qz > self.qzmaximum.value)
        else:
            self.cut.value = np.logical_or(self.qz.value < self.qzminimum.value,
                                           self.qz.value > self.qzmaximum.value)
Пример #22
0
class FindCenterVo(ProcessingPlugin):
    """
    Find rotation axis location using Nghia Vo's method. :cite:`Vo:14`.
    """

    tomo = Input(description="3D tomographic data", type=np.ndarray)
    ind = Input(
        description="Index of the slice to be used for reconstruction",
        type=int,
        default=None)
    smin = Input(description="Coarse search radius", type=int, default=-50)
    smax = Input(description="Coarse search radius", type=int, default=50)
    srad = Input(description="Fine search radius", type=float, default=6)
    step = Input(description="Step of fine searching", type=float, default=0.5)
    ratio = Input(
        description=
        "he ratio between the FOV of the camera and the size of object. It's used to generate the mask",
        type=float,
        default=0.5)
    drop = Input(
        description="Drop lines around vertical center of the mask",
        type=int,
        default=20)

    center = Output(description="Rotation axis location", type=float)

    def evaluate(self):
        self.center.value = tomopy.find_center_vo(
            self.tomo.value,
            ind=self.ind.value,
            smin=self.smin.value,
            smax=self.smax.value,
            srad=self.srad.value,
            step=self.step.value,
            ratio=self.ratio.value,
            drop=self.drop.value)
Пример #23
0
class Recon(ProcessingPlugin):
    """
    Reconstruct object from projection data.
    """
    tomo = Input(description="Input array", type=np.ndarray)
    angles = Input(description="Projection angles in radians",
                   type=List[float])
    center = Input(description="Location of rotation axis",
                   type=int,
                   default=None)

    sinogram_order = Input(
        description="Determines whether data is a stack of sinograms",
        type=bool,
        default=False)

    algorithm = Input(description="[art, bart, fbp, gridrec, etc.]",
                      type=str,
                      default='gridrec')
    init_recon = Input(description="Initial guess of the reconstruction",
                       type=np.ndarray,
                       default=None)
    ncore = Input(description="Number of CPU cores", type=int, default=None)
    nchunk = Input(description="Chunk size for each core",
                   type=int,
                   default=None)

    num_gridx = Input(
        description="Number of pixels along X in Reconstructed data",
        type=int,
        default=None)
    num_gridy = Input(
        description="Number of pixels along y in Reconstructed data",
        type=int,
        default=None)
    filter_name = Input(
        description="Name of the filter for analytic reconstruction",
        type=str,
        default='none')
    filter_par = Input(description="Filter parameters",
                       type=np.ndarray,
                       default=None)

    num_iter = Input(description="Number of algorithm iterations",
                     type=int,
                     default=None)

    num_block = Input(
        description="Number of data blocks for intermediate updating",
        type=int,
        default=None)

    ind_block = Input(description="Order of projections to be used",
                      type=np.ndarray,
                      default=None)

    reg_par = Input(description="Regularization parameter for smoothing",
                    type=float,
                    default=None)

    recon = Output(description="Reconstructed 3D array", type=np.ndarray)

    def evaluate(self):
        if self.algorithm.value == 'gridrec':
            kwargs = {
                'num_gridx': self.num_gridx.value,
                'num_gridy': self.num_gridy.value,
                'filter_name': self.filter_name.value,
                'filter_par': self.filter_par.value,
            }
        else:  # TODO: Not sure which are applicable to other algorithms yet
            kwargs = {
                'num_iter': self.num_iter.value,
                'num_block': self.num_block.value,
                'ind_block': self.ind_block.value,
                'reg_par': self.reg_par.value
            }

        # remove unset kwargs
        kwargs = {k: v for k, v in kwargs.items() if v is not None}

        self.recon.value = tomopy.recon(
            self.tomo.value,
            self.angles.value,
            center=self.center.value,
            sinogram_order=self.sinogram_order.value,
            algorithm=self.algorithm.value,
            init_recon=self.init_recon.value,
            ncore=self.ncore.value,
            nchunk=self.nchunk.value,
            **kwargs)
Пример #24
0
class QBackgroundFit(ProcessingPlugin):
    name = 'Q Background Fit'

    q = InOut(description='Q bin center positions', type=np.array)
    Iq = InOut(description='Q spectra bin intensities', type=np.array)
    # model = Input(description='Fittable model class in the style of Astropy', type=Enum)
    domainmin = Input(description='Min bound on the domain of the input data',
                      type=float)
    domainmax = Input(description='Max bound on the domain of the input data',
                      type=float)
    degree = Input(name='Polynomial Degree',
                   description='Polynomial degree number',
                   type=int,
                   min=1,
                   default=4)
    # fitter = Input(description='Fitting algorithm', default=fitting.LevMarLSQFitter(), type=Enum, limits={'Linear LSQ':fitting.LinearLSQFitter(), 'Levenberg-Marquardt LSQ':fitting.LevMarLSQFitter(), 'SLSQP LSQ':fitting.SLSQPLSQFitter(), 'Simplex LSQ':fitting.SimplexLSQFitter()})
    domainfilter = Input(
        description=
        'Domain limits where peaks will be fitted; auto-populated by ')

    backgroundmodel = Output(
        description=
        'A new model with the fitted parameters; behaves as parameterized function',
        type=Fittable1DModel)
    backgroundprofile = Output(
        description='The fitted profile from the evaluation of the '
        'resulting model over the input range.')
    rawIq = Output(description='The spectra data before subtraction.')

    hints = [
        PlotHint(q, Iq),
        PlotHint(q, backgroundprofile),
        PlotHint(q, rawIq)
    ]

    modelvars = {}

    def __init__(self):
        super(QBackgroundFit, self).__init__()
        self.peakranges = []

    @property
    def parameter(self):
        self._workflow.attach(self.find_peak_ranges)  # order may be bad...
        return super(QBackgroundFit, self).parameter

    def find_peak_ranges(self):
        from xicam.SAXS.processing.astropyfit import \
            AstropyQSpectraFit  # must be a late import to avoid being picked up first by plugin manager
        thisindex = self._workflow.processes.index(self)
        self.peakranges = [
            (process.domainmin.value, process.domainmax.value)
            for process in self._workflow.processes[thisindex + 1:]
            if isinstance(process, AstropyQSpectraFit)
        ]

    def detach(self):
        self._workflow.detach(self.find_peak_ranges)

    def evaluate(self):
        model = models.Polynomial1D(degree=self.degree.value)

        norange = self.domainmin.value == self.domainmax.value
        if self.domainmin.value is None and self.q.value is not None or norange:  # truncate the q and I arrays with limits
            self.domainmin.value = self.q.value.min()
        if self.domainmax.value is None and self.q.value is not None or norange:  # truncate the q and I arrays with limits
            self.domainmax.value = self.q.value.max()

        filter = np.logical_and(self.domainmin.value <= self.q.value,
                                self.q.value <= self.domainmax.value)
        for peakrange in self.peakranges:
            print('applying peak range:', peakrange)
            filter &= np.logical_or(peakrange[0] >= self.q.value,
                                    self.q.value >= peakrange[1])

        q = self.q.value[filter]
        Iq = self.Iq.value[filter]
        self.backgroundmodel.value = fitting.LinearLSQFitter()(model, q, Iq)
        self.backgroundprofile.value = self.backgroundmodel.value(self.q.value)
        self.rawIq.value = self.Iq.value.copy()
        self.Iq.value = self.Iq.value - self.backgroundprofile.value

    def getCategory() -> str:
        return "Fits"
Пример #25
0
class AstropyQSpectraFit(ProcessingPlugin):
    name = 'Q Fit (Astropy)'

    q = InOut(description='Q bin center positions',
              type=np.array)
    Iq = InOut(description='Q spectra bin intensities', type=np.array)
    model = Input(description='Fittable model class in the style of Astropy', type=Enum)
    domainmin = Input(description='Min bound on the domain of the input data', type=float)
    domainmax = Input(description='Max bound on the domain of the input data', type=float)
    fitter = Input(description='Fitting algorithm', default=fitting.LevMarLSQFitter(), type=Enum,
                   limits={'Linear LSQ': fitting.LinearLSQFitter(),
                           'Levenberg-Marquardt LSQ': fitting.LevMarLSQFitter(), 'SLSQP LSQ': fitting.SLSQPLSQFitter(),
                           'Simplex LSQ': fitting.SimplexLSQFitter()})

    fittedmodel = Output(description='A new model with the fitted parameters; behaves as parameterized function',
                         type=Fittable1DModel)
    fittedprofile = Output(
        description='The fitted profile from the evaluation of the resulting model over the input range.')

    hints = [PlotHint(q, Iq), PlotHint(q, fittedprofile)]

    modelvars = {}

    def __init__(self):
        super(AstropyQSpectraFit, self).__init__()
        self.model.limits = {plugin.name: plugin.plugin_object for plugin in
                             pluginmanager.getPluginsOfCategory('Fittable1DModelPlugin')}
        self.model.value = list(self.model.limits.values())[0]

    @property
    def parameter(self):

        # clear cache in
        for input in self.modelvars:
            del self.__dict__[input]
        varcache = self.modelvars.copy()
        self.modelvars = {}
        self._inputs = None
        self._inverted_vars = None
        if hasattr(self, '_inverted_vars'): del self._inverted_vars

        for name in self.model.value.param_names:
            param = getattr(self.model.value, name)
            # TODO: CHECK NAMESPACE
            if name in varcache:
                input = varcache[name]
            else:
                input = InOut(name=name, default=param.default, limits=param.bounds, type=float, fixed=False,
                              fixable=True)
            setattr(self, name, input)
            self.modelvars[name] = input
        parameter = super(AstropyQSpectraFit, self).parameter
        parameter.child('model').sigValueChanged.connect(self.reset_parameter)
        return parameter

    def reset_parameter(self):
        # cache old parameter
        oldparam = self._param

        # empty it
        for child in oldparam.children():
            child.remove()

        # reset attribute so new parameter is generated
        self._param = None

        # add new children to old parameter
        for child in self.parameter.children():  # type: Parameter
            oldparam.addChild(child)

        # set old parameter to attribute
        self._param = oldparam

    def evaluate(self):
        if self.model.value is None or self.model.value == '----': return
        norange = self.domainmin.value == self.domainmax.value
        if self.domainmin.value is None and self.q.value is not None or norange:  # truncate the q and I arrays with limits
            self.domainmin.value = self.q.value.min()
        if self.domainmax.value is None and self.q.value is not None or norange:  # truncate the q and I arrays with limits
            self.domainmax.value = self.q.value.max()
        for name, input in self.modelvars.items():  # propogate user-defined values to the model
            getattr(self.model.value, name).value = input.value
            getattr(self.model.value, name).fixed = input.fixed
        filter = np.logical_and(self.domainmin.value <= self.q.value, self.q.value <= self.domainmax.value)
        q = self.q.value[filter]
        Iq = self.Iq.value[filter]
        self.fittedmodel.value = self.fitter.value(self.model.value, q, Iq)
        self.fittedprofile.value = self.fittedmodel.value(self.q.value)

    def getCategory() -> str:
        return "Fits"