Replies: 4 comments 3 replies
-
I like the design a lot, thanks! The only thing I'm not sure about is having the the internal |
Beta Was this translation helpful? Give feedback.
-
Dear Maurizio, The MHFT instrument team is looking into an option with a reflecting HWP. The reflection on the HWP may induce a time variation of the detector-boresight quaternion, synchronous with the HWP rotation, if the HWP is tilted with respect to its rotation axis. Other long-term effects, such as thermo-elastic deformations, may induce a slow evolution of the detector-boresight quaternion. With your new proposal, these effects can be included using a time variable detector-boresight quaternion. The only issue, is that in case of an HWP synchronous effect, the sampling of the pointing must be as fast as the sampling of the detectors. Alessandro Novelli and Silvia Micheli have simulated the HWP synchronous variation with a workaround, that is currently quite slow to run. To my knowledge, this effect is already included in falcons. I understand that you are proposing something in this sentence:
but I am not sure if this can be used to the systematics I have in mind. |
Beta Was this translation helpful? Give feedback.
-
I think the proposal will work effectively to simulate several pointing systematics, especially for the pointing disturbance due to vibrations. If I comment on the HWP wedge effect, I simulated the systematics by Falcons 3 years ago, and way was just I generate true pointing and wrong pointing i.e. with constant offset due to a wedge, and then rotate the wrong pointing with HWP rotation rate around true pointing as rotation axis. Every calculation scheme was done in 19Hz. However, if I think about implementation again now, I will buy @ziotom78 's aproach because it is more coherent. |
Beta Was this translation helpful? Give feedback.
-
PR #319 is a tentative implementation of the ideas in this discussion. |
Beta Was this translation helpful? Give feedback.
-
I am starting a discussion to decide how to rework the code used to compute the pointing information and the angle of the HWP. First, I'll present the structure of the current code, and then I will present a few ideas to improve the performance.
Basic principles
The code computes the final pointing of each detector according to the transformations explained in the chapter Scanning Strategy of the User's Manual. Each rotation is encoded using a quaternion, and there are several of them:
One quaternion to convert from the reference frame of a detector to the reference frame of the boresight of the instrument (LFT, MFT, HFT); this quaternion at the moment is considered to be constant in time.
One quaternion to convert from the reference frame of the boresight of the instrument to the reference frame of the spacecraft (sometimes called “spin reference frame”, because the z axis is aligned with the spin axis). This quaternion is constant in time as well.
One quaternion to convert from the reference frame of the spacecraft to Ecliptic coordinates. This quaternion does of course depend on time, as it encodes the constant precession of the spin axis around the Sun-Earth axis and the revolution of the Earth around the Sun.
The code multiplies the quaternions to get the overall transformation from the reference frame of a detector to Ecliptic coordinates; these quaternions are sampled with a customizable sample rate, which is usually chosen to be a fraction of 1 Hz because the typical angular speeds are slower than that.
How the code works now
The full quaternions are combined generated by
Simulation.set_scanning_strategy
. These are sampled at a lower frequency than the scientific TOD—typically ~1 min—and are saved in the fieldSimulation.spin2ecliptic_quats
, which is a(N_q, 4)
matrix, whereN_q
is the number of quaternions. As the quaternions are related to the spacecraft, one array is enough for a full focal-plane simulation. These quaternions encode the details of the precession of the spin axis around the Sun-Earth axis and model the revolution of the Earth (and thus of the L₂ point where LiteBIRD will stay) around the Sun.The real juice is in
get_pointings
, which works on a singleObservation
. It takes three quaternions:Observation
object (this is the only field read by the function from this object);Simulation.set_scanning_strategy
, see above).The function calls
get_det2ecl_quaternions
, which employsducc0
to compute all the quaternions at the nominal sampling frequency of the TOD. There is just one buffer with shape(N, 4)
that gets allocated at the beginning, and then when looping over the detectors it keeps overwriting it every time.Once the fully sampled quaternions have been computed, the function
all_compute_pointing_and_orientation
converts them into actual pointings, i.e., θ, φ, and ψ. These pointings are saved byget_pointings
intoObservation
.The method
Simulation.compute_pointings
iterates over a set ofObservations
to callget_pointings
for each of them. The purpose of this function is to save the pointings within eachObservation
object, but it also returns them to the caller. (This is a reference to the pointings in theObservation
objects, so no actual copies of the arrays are made.)Pointings are used in four modules:
scan_map.py
;dipole.py
;The binning map-maker;
The destriper.
What we want from the code
The actual API has served us well, but it has one significant limitation: all the pointings are stored in memory, and this takes more space than the scientific signal itself! (We need just one floating-point for each scientific sample but 4 floating-point numbers for the pointings: θ, φ, ψ, and the HWP angle α, which however is the same for all the detectors.) Moreover, there are a few other limitations:
The HWP angles are added to the orientation angles. However, we would like to keep them separate, because this is needed to correctly perform 4π beam convolution.
We want to simulate time-dependent effects, in particular:
A proposal for a new API
The idea we want to discuss here is a new API which can help to save memory. Since all the code that uses pointings so far requires to access pointing information for one detector at a time, the idea is to add a method that returns the pointings for just one detector, instead of keeping the pointings of all the detectors in one huge matrix.
In the following code snippets, I will always include typing hints to make the code clearer. I'll assume that the following
import
s are valid:How to handle time-dependent effects?
At the moment, there are three families of quaternions:
To ease the burden to interpolate time-dependent quaternions, the code implements the class
Spin2EclipticQuaternions
that keeps an array of quaternions, each associated with a time, and can interpolate them at any arbitrary sampling frequency. Of course, this class is used only with the quaternions in point 3.We should make
Spin2EclipticQuaternions
more general by renaming it toTimeDependentQuaternions
and add the ability to multiply twoTimeDependentQuaternions
instances, returning a newTimeDependentQuaternions
. In this way we could make the quaternions in point 1. and 2. above time-dependent and combine the three families as easy as we are doing now. This would enable us to simulate a quite large amount of time-dependent optical systematics caused either by mechanical or thermal fluctuations.It is conceptually easy to implement the multiplication of two
TimeDependentQuaternions
objects, but special care must be applied to times: the code must ensure that both quaternions are sampled at the same frequency!How to handle systematics caused by the HWP?
We already have a
HWP
class, from whichIdealHWP
is derived. We should change the API so that the class has a virtual method namedapply_hwp_to_pointings
with the following signature:An ideal HWP would just use
hwp_angle
, storing the value2πνt
into it (withν
being the angular speed of the HWP), and ignore the presence ofbore2ecl_quaternions
. However, in a derived class there might be the simulation of some systematic effects that introduces some noise in the pointings; in the latter case, the code is free to modifyquaternions
by multiplying each of them by a new quaternion on the left.Note that we do not want to use
TimeDependentQuaternions
here, as that class is optimized for low-sampling quaternions, while a HWP spins quickly! Instead,apply_hwp_to_pointings
gets the fully sampled quaternions.How to properly query pointings for one detector
The amount of information needed to be carried over in the code is larger if we want to recompute all the pointings whenever we need them. (The current status is that the full pointing information is stored in the
(N, 3)
pointing matrix containing θ, φ, and ψ, and nothing else is needed.) We must always be able to know (1) if there are time-dependent effect to be applied to the detector/boresight orientation, (2) if there are non-idealities in the HWP, (3) which coordinate system are we using.The cleanest way to do this is to keep all of these information in a new class, which we might call
PointingProvider
. This class should keep an instance of aHWP
class (or any derived class), an instance ofTimeDependentQuaternions
that enables to convert from the reference frame of the boresight to the reference frame of the Ecliptic/Galactic coordinate system, and the specification of the coordinate system itself.A copy of
PointingProvider
could be stored in eachObservation
object, as havingpointings
immediately available there has proved to be useful so far. (The fact that NumPy are reference-counted grants that the amount of memory used by the code won't explode.)The class should implement the following methods:
The problem with this design is that
PointingProvider.get_pointings()
requires to allocate a NumPy array with shape(N, 4)
for theN
quaternions at 19 Hz. A possible optimization could be to cache this array, as it is very likely that multiple calls toget_pointings
will need the same number of samples (it will be typically iterated over several detectors). Here is a possible implementation:How
PointingProvider
should be used by callersAssuming that each object
Observation
have a member variable calledpointing_provider
of typePointingProvider
, one could get the pointings using the following syntax:Of course, we could build a tiny method that wraps this call inside the
Observation
class:In this way, the previous snipped would become
Beta Was this translation helpful? Give feedback.
All reactions