Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polarisation conventions #40

Open
AlecThomson opened this issue Nov 20, 2024 · 5 comments
Open

Polarisation conventions #40

AlecThomson opened this issue Nov 20, 2024 · 5 comments

Comments

@AlecThomson
Copy link

AlecThomson commented Nov 20, 2024

Hey all,

I'm hoping to open a discussion on whether supporting some other polarisation conventions would be within scope for Hyperdrive. Personally, I'm keen to use it for ASKAP data, but having support for other pol. conventions would hopefully allow Hyperdrive's uptake for use on any (all?) instruments.

In particular, I would hope that the IAU convention could be supported. For linear polarisations this has X corresponding to the North-South axis, and Y the East-West. For Stokes this means:

$$\begin{align} XX = I + Q \\\ XY = U + iV \\\ YX = U - iV \\\ YY = I - Q \\\ \end{align}$$

or

$$\begin{align} I = (XX + YY)/2 \\\ Q = (XX - YY)/2 \\\ U = (XY + YX)/2 \\\ V = -i(XY - YX)/2 \\\ \end{align}$$

Being but a baby rustacean, it's not immediately clear to me the best way for this to be implemented. Nor if any kind of change would cause be a bunch of breaking changes downstream. I have some vague thoughts that set of Mueller-like matrices could be handy for defining conventions (see e.g. https://github.com/AlecThomson/FixMS).

Some extra thoughts if some kind of generalisation is within scope. ASKAP uses yet another Stokes convention, where:

$$\begin{align} I = (XX + YY) \\\ Q = (XX - YY) \\\ U = (XY + YX) \\\ V = -i(XY - YX) \\\ \end{align}$$

Although I'm in two minds about adding/supporting non-IAU conventions is ever a good idea...

There's also the circular convention (potential can of worms), where:

$$\begin{align} RR = I + V \\\ RL = Q + iU \\\ LR = Q - iU \\\ LL = I - V \\\ \end{align}$$

Although, I can certainly understand if supporting non-linear bases is completely out of scope.

I'm keen to hear what you all think, and happy to chat on anything as well :)

@d3v-null
Copy link
Collaborator

Hey Alec!
I'd love to help remove any blockers that are preventing other instruments from using hyperdrive.
Can you be a bit clearer about exactly what changes are needed?

Do you just want to be able to read files written out with other polarisations? If so can you provide samples?
Is it your sky model that needs to support these polarisations? Is it the beam?

These are the polarisations we currently support https://github.com/MWATelescope/mwa_hyperdrive/blob/main/src/context/mod.rs#L26

pub enum Polarisations {
    XX_XY_YX_YY,
    XX,
    YY,
    XX_YY,
    XX_YY_XY,
}

adding your polarisation options and compiling will give you errors that show you where in the code it's used.

@AlecThomson
Copy link
Author

AlecThomson commented Nov 20, 2024

Thanks @d3v-null! Ok, so I think perhaps other bases like circular could be added there (in the snippet you show).

But, I think the changes may need to occur in flux_density e.g.

impl FluxDensity {
/// Given two flux densities, calculate the spectral index that fits them.
/// Uses only Stokes I.
pub(super) fn calc_spec_index(&self, fd2: &Self) -> f64 {
(fd2.i / self.i).ln() / (fd2.freq / self.freq).ln()
}
/// Convert a `FluxDensity` into a [Jones] matrix representing instrumental
/// Stokes (i.e. XX, XY, YX, YY).
///
/// The IAU convention and TMS define X as North-South and Y as East-West.
/// However, hyperdrive (and many MWA definitions, softwares) use X as EW
/// and Y as NS. For this reason, this conversion looks like the opposite of
/// what is expected (equation 4.55). In other words, hyperdrive orders its
/// Jones matrices [XX XY YX YY], where X is East-West and Y is North-South.
pub(crate) fn to_inst_stokes(self) -> Jones<f64> {
Jones::from([
c64::new(self.i - self.q, 0.0),
c64::new(self.u, -self.v),
c64::new(self.u, self.v),
c64::new(self.i + self.q, 0.0),
])
}
}

Here is at least one place where the orientation of X and Y are assumed.

I wonder if an optional kwarg could be added here that defaults to "MWA" - in which case the current Jones is returned. There could be an enum of other supported conventions which could be accessed and provide the appropriate transform from sky to instrument Stokes.

Is there anywhere in the codebase where the inverse operation (i.e. instrumental to sky) is performed?

@AlecThomson
Copy link
Author

Would something like this be appropriate?

enum InstrumentalConvention {
    MWA,
    IAU,
    ASKAP,  
}

impl FluxDensity {
    ...
 
    /// Convert a `FluxDensity` into a [Jones] matrix representing instrumental
    /// Stokes (i.e. XX, XY, YX, YY).
    ///
    /// The IAU convention and TMS define X as North-South and Y as East-West.
    /// However, hyperdrive (and many MWA definitions, softwares) use X as EW
    /// and Y as NS. For this reason, this conversion looks like the opposite of
    /// what is expected (equation 4.55). In other words, hyperdrive orders its
    /// Jones matrices [XX XY YX YY], where X is East-West and Y is North-South.
    pub(crate) fn to_inst_stokes(self, convention: InstrumentalConvention) -> Jones<f64> {

        match convention {
            // MWA has:
            // XX = I - Q
            // XY = U - iV
            // YX = U + iV
            // YY = I + Q
            MWA => Jones::from([
                c64::new(self.i - self.q, 0.0),
                c64::new(self.u, -self.v),
                c64::new(self.u, self.v),
                c64::new(self.i + self.q, 0.0),
            ]),
            // IAU has:
            // XX = I + Q
            // XY = U + iV
            // YX = U - iV
            // YY = I - Q
            IAU => Jones::from([
                c64::new(self.i + self.q, 0.0),
                c64::new(self.u, self.v),
                c64::new(self.u, -self.v),
                c64::new(self.i - self.q, 0.0),
            ]),
            // ASKAP has:
            // XX = 0.5(I + Q)
            // XY = 0.5(U + iV)
            // YX = 0.5(U - iV)
            // YY = 0.5(I - Q)
            ASKAP => Jones::from([
                c64::new(0.5 * (self.i + self.q), 0.0),
                c64::new(0.5 * self.u, 0.5 * self.v),
                c64::new(0.5 * self.u, -0.5 * self.v),
                c64::new(0.5 * (self.i - self.q), 0.0),
            ]),
        }
    }
}

@AlecThomson
Copy link
Author

Maybe with a little thing like:

impl InstrumentalConvention {
    fn from_str(s: &str) -> Self {
        match s {
            "MWA" => Self::MWA,
            "IAU" => Self::IAU,
            "ASKAP" => Self::ASKAP,
            _ => panic!("Unknown instrumental convention: {}", s),
        }
    }
}

@d3v-null
Copy link
Collaborator

d3v-null commented Nov 20, 2024

Oh God, I had no idea there were this many different conventions in use.

Let's step back a bit and figure out what we're trying to do here, because what you're proposing is quite a big change.

Once they've been simulated, converting between the convention in use (MWA) and the desired convention (ASKAP) is pretty trivial.

XX_askap = 0.5 * YY_mwa etc.

so maybe converting when writing out would be easier?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants