Skip to content

Separability of parts of bifs #22

@RossBoylan

Description

@RossBoylan

This is closely related to #15.

Narrow question

@kyoung21b many bump-related items are created only after discovering basis="fourier". Should bumps actually be tied to the basis? The bump info is not saved with the basis object. But it's written as if other bases might use other bump types, or perhaps be unable to use bumps at all.

Broader issue

Also mostlly @kyoung21b. To what extent can we separate concerns into separate spheres? For example, it appears that some of the logic and parameters depend on the likelihood x prior distribution type. There are parameters defined on bifs that seem only to be relevant for some of those, e.g., Rician.

Example 1

The idea is that instead of

        myShape = init_image.shape
        if self.imdim == 1:
            self.kdist = self.bas.kdist1D(*myShape)
            self.k_image = self.bas.tx1(self.init_image) # Get k-space image
        elif self.imdim == 2:
            self.kdist = self.bas.kdist2D(*myShape)
            self.k_image = self.bas.tx2(self.init_image) # Get k-space image
        elif self.imdim == 3:
            self.kdist = self.bas.kdist3D(*myShape)
            self.k_image = self.bas.txn(self.init_image) # Get k-space image

(I've used Python's '*' operator to simplify the existing code) you'd have something like

    self.k_image = self.basis.k_image(self)

where self.basis is some kind of basis object, self is an argument so basis.k_image() can get needed info from the bifs object, and k_image() returns an appropriate k-space image while setting kdist in self.basis.

There is an argument in favor of passing the needed components explicitly to basis.k_image() rather than having it extract them from the bifs object. The advantage of the formulation I gave is that it works better if different classes of basis objects need different info. That's all somewhat theoretical since our mainline only has one possible basis.

Example 2

            if self.prior == "Gaussian" and self.likelihood == "Gaussian":
                self.bifsk_image = self.bifs_map_gauss_gauss(self.prior_mean,self.prior_std2,self.mod_image,self.ksd2)
            elif self.prior == "Gaussian" and self.likelihood == "Rician":
                conj = self.bifs_map_gauss_gauss(self.prior_mean,self.prior_std2,self.mod_image,self.ksd2)
                besind = np.zeros(self.init_image.shape,dtype=int)
                besind[np.where(conj > self.bessel_approx_lims[1])] = 1
                besind[np.where(conj > self.bessel_approx_lims[2])] = 2
                besind[np.where(conj > self.bessel_approx_lims[3])] = 3
                self.bsa = self.bessel_approx_array[besind,:]
                self.bifsk_image = self.bifs_map_gauss_rice(self.prior_mean,self.prior_std,self.mod_image,self.likelihood_scale)
            else:

becomes

   self.bifsk_image = self.likelihood.bifs_map(self)

where self.likelihood is an object, not a string, with a class that depended on the type of prior and likelihood. The rician version would have all the bessel function machinery and Rician-specific parameters tucked away inside of it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    designconcerning the intended behavior of the application

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions