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

Dictionary used in the convert #310

Open
LeoVergaraS opened this issue Jul 11, 2024 · 6 comments
Open

Dictionary used in the convert #310

LeoVergaraS opened this issue Jul 11, 2024 · 6 comments

Comments

@LeoVergaraS
Copy link

Description

Hello, I would like to know why .imag and .real are used within the dictionary that convert uses when converting from correlations to Stokes visibilities. The visibilities should be complex numbers, but with this approach, real numbers are obtained.

What I Did

I did the following, is it correct?

"I": {
        ("XX", "YY"): lambda xx, yy: (xx + yy)/2,
        ("LL", "RR"): lambda ll, rr: (ll + rr) /2,
    },
    "Q": {
        ("XX", "YY"): lambda xx, yy: (xx - yy)/2,
        ("RL", "LR"): lambda rl, lr: (rl + lr)/2,
    },
    "U": {
        ("XY", "YX"): lambda xy, yx: (xy + yx)/2,
        ("RL", "LR"): lambda rl, lr: (lr - rl) * 1j /2,
    },
    "V": {
        ("XY", "YX"): lambda xy, yx: (yx - xy) * 1j/2,
        ("LL", "RR"): lambda ll, rr: (rr - ll)/2,
    },
@sjperkins
Copy link
Member

sjperkins commented Jul 12, 2024

It's been a while since I looked at this:

stokes_conv = {
"RR": {("I", "V"): lambda i, v: i + v + 0j},
"RL": {("Q", "U"): lambda q, u: q + u * 1j},
"LR": {("Q", "U"): lambda q, u: q - u * 1j},
"LL": {("I", "V"): lambda i, v: i - v + 0j},
"XX": {("I", "Q"): lambda i, q: i + q + 0j},
"XY": {("U", "V"): lambda u, v: u + v * 1j},
"YX": {("U", "V"): lambda u, v: u - v * 1j},
"YY": {("I", "Q"): lambda i, q: i - q + 0j},
"I": {
("XX", "YY"): lambda xx, yy: (xx + yy).real / 2,
("RR", "LL"): lambda rr, ll: (rr + ll).real / 2,
},
"Q": {
("XX", "YY"): lambda xx, yy: (xx - yy).real / 2,
("RL", "LR"): lambda rl, lr: (rl + lr).real / 2,
},
"U": {
("XY", "YX"): lambda xy, yx: (xy + yx).real / 2,
("RL", "LR"): lambda rl, lr: (rl - lr).imag / 2,
},
"V": {
("XY", "YX"): lambda xy, yx: (xy - yx).imag / 2,
("RR", "LL"): lambda rr, ll: (rr - ll).real / 2,
},
}

but it's likely because the RR, LL, XX, YY correlations have a zeroed imaginary component with respect to the stokes components.

     "RR": {("I", "V"): lambda i, v: i + v + 0j}, 
     "LL": {("I", "V"): lambda i, v: i - v + 0j}, 
     "XX": {("I", "Q"): lambda i, q: i + q + 0j}, 
     "YY": {("I", "Q"): lambda i, q: i - q + 0j}, 

I now wonder if this is a dangerous assumption to make in terms of real data. @landmanbester @o-smirnov, what do you think?

@bennahugo
Copy link
Collaborator

The conversions by @LeoVergaraS are correct. The conversions in this implementation (for I,Q,U,V) are presumably only used once visibilities have been gridded and fourier transformed Complex->Real - otherwise they would not make sense. Mind you stokes products only make sense in image space, not visibility space.

@o-smirnov
Copy link
Contributor

What context is the conversion being done in? "Physical" IQUV is always real so the resulting XX/YY/RR/LL will be real-only. When going from observed coherencies to Stokes, the imaginary part is usually discarded (it is zero by construction assuming perfect visibilities), so the above is correct. In practice, the resulting "imaginary" Stokes will be non-zero due to noise and calibration errors. I could just about conceive of a use case where one wants to retain the imaginaries for diagnostic purposes, but rather cross that bridge when we come to it...

@landmanbester
Copy link
Collaborator

We definitely don't expect the Stokes coherencies to be real valued, only the Stokes images are real after gridding+FFT. It looks like this function is meant for visibilities though so I think the implementation is incorrect.

Mind you stokes products only make sense in image space, not visibility space.

Why do you say this? In my mind Stokes coherencies are just what you get if you apply the vCZ theorem to Stokes images. Of course the conversions are more complicated when taking gains into account but that doesn't mean Stokes coherencies don't make sense.

In practice, the resulting "imaginary" Stokes will be non-zero due to noise and calibration errors. I could just about conceive of a use case where one wants to retain the imaginaries for diagnostic purposes, but rather cross that bridge when we come to it...

If the visibilities are assumed to be Hermitian the imaginary parts of the corresponding images have to cancel by construction. Dirty images will of course have an imaginary component if we only grid half the uv-plane (the usual case)

@miguelcarcamov
Copy link

Hi, @LeoVergaraS is my undergraduate student and we had this question for a long time. The code in africanus did not make sense to me since the convert function and its dictionary is meant to convert visibilities with shape (row, chan, corr) to visibilities with shape (row, chan, stokes).

There is a confusion in the thread. The context of the conversion is in visibility space and not image space where stokes values are real valued.

@sjperkins
Copy link
Member

One solution to the above might be to add entries forIc, Qc, Vc and Uc to the table below, that don't discard the imaginary component. So Ic would mean I complex.

stokes_conv = {
"RR": {("I", "V"): lambda i, v: i + v + 0j},
"RL": {("Q", "U"): lambda q, u: q + u * 1j},
"LR": {("Q", "U"): lambda q, u: q - u * 1j},
"LL": {("I", "V"): lambda i, v: i - v + 0j},
"XX": {("I", "Q"): lambda i, q: i + q + 0j},
"XY": {("U", "V"): lambda u, v: u + v * 1j},
"YX": {("U", "V"): lambda u, v: u - v * 1j},
"YY": {("I", "Q"): lambda i, q: i - q + 0j},
"I": {
("XX", "YY"): lambda xx, yy: (xx + yy).real / 2,
("RR", "LL"): lambda rr, ll: (rr + ll).real / 2,
},
"Q": {
("XX", "YY"): lambda xx, yy: (xx - yy).real / 2,
("RL", "LR"): lambda rl, lr: (rl + lr).real / 2,
},
"U": {
("XY", "YX"): lambda xy, yx: (xy + yx).real / 2,
("RL", "LR"): lambda rl, lr: (rl - lr).imag / 2,
},
"V": {
("XY", "YX"): lambda xy, yx: (xy - yx).imag / 2,
("RR", "LL"): lambda rr, ll: (rr - ll).real / 2,
},
}

Other suggestions:

  • IComplex
  • ICplx

Would you consider submitting a PR?

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

6 participants