Closed mjo22 closed 7 months ago
I'll finish some PRs first, but I'd be interested in generalizing pose to have a handful of back end encodings
Awesome. Note we already have a QuaternionPose
, EulerPose
, and MatrixPose
, but I think it would be more powerful to just have one class called Pose
and to pass a Rotation
operator to it, which could be these different representations.
With the new factors I've been thinking a lot of how to really achieve modularity in
cryojax
.The most notable additions are the
FourierOperator
andRealOperator
classes. With this, I've started to expand on a paradigm that I already had loose implementations of:cryojax.simulator
models should take functions as input.For example, consider the new, refactored,
CTFOptics
class. This used to be a function which computed the CTF when called. Now, it is more so what I would call an optics model. When it is called, it operates on the image somehow. This involves applying the CTF function---the newCTF
class, a subclass of aFourierOperator
---and also calling the envelope function, also aFourierOperator
.Note two cool aspects of this.
1) This allows us to interchangeably use phenomenological and physical models, both of which are very common in cryo-EM. In one case, an envelope function could be a gaussian, parameterized by a phenomenological beta factor. In another case, we could create an envelope function that is a gaussian whose parameters model chromatic aberration. Further, this even allows us to interchangeably use analytical and empirical models! There is an operator called
Empirical
, which basically just stores a buffer. 2) These functions---namely theseFourierOperator
andRealOperator
classes---can be composed before ever being called with multiplication*
and addition+
operators, using magic methods__mul__
and__add__
. This makes for some cool behavior. For example, see thecryojax.inference.distributions.FourierIndependentGaussian.__init__
.Overall, continuing on this paradigm I think a) should give users a ton of control when scripting and b) continue to make it so us developers need not have way too many subclasses! Expanding on a), note that
FourierOperator
andRealOperator
are public API! A user should be able to subclass these and pass their own models intocryojax
, without needing to make a PR. Expanding on b), note that there is no need to have two differentCTFOptics
subclasses for the different envelopes. The user chooses which envelope model to pass, and even whether or not to pass one at all.For anyone interested in learning more about and expanding on this paradigm (@geoffwoollard? @ehthiede ?), here is one refactor that should be done:
Pose
object for each kind of rotation---euler, quaternion, and matrix. However, aPose
is a rotation and translation.Pose
object. ThisPose
should somehow have aRotation
object, which can beEuler
,Quaternion
, orMatrix
.Rotation
can adhere to similar principles as theFourierOperator
class. It can use the__matmul__
magic method to compose rotations of different types.Then, similar to the
CTFOptics
class, the user will similarly be passing an operator to thePose
class, rather than choosing aPose
class with particular parameters!For more examples of how I use
FourierOperator
s, seeGaussianDetector.variance
andGaussianIce.variance
Exposure.dose
andExposure.radiation
(a new attempt to give theExposure
model a vision, eventually giving functionality for something like here: https://elifesciences.org/articles/6980)