SHTOOLS icon indicating copy to clipboard operation
SHTOOLS copied to clipboard

SHExpandLSQ for complex values - combine separate coefficient arrays

Open robinchrist opened this issue 5 years ago • 3 comments

Hi,

I want to apply SHExpandLSQ to a complex valued array. I have understood that SHExpandLSQ only takes real input, so I'm doing separate fits on the real and imaginary parts.

However I assumed that I could just combine the returned coefficient arrays and get the same results when for expand, but this doesn't work:

hilm_real, chi2_real = pyshtools.expand.SHExpandLSQ(np.real(reim_data), inlat, inlon, sphorder)
hilm_imag, chi2_imag = pyshtools.expand.SHExpandLSQ(np.imag(reim_data), inlat, inlon, sphorder)

hlm_real = pyshtools.SHCoeffs.from_array(hilm_real)
reconstructedReal = hlm_real.expand(lat=inlat, lon=inlon)
deviation_real = np.real(reim_data) - reconstructedReal
print('deviation_real for real: min = ' + str(np.min(np.abs(deviation_real))) + ', max = ' + str(np.max(np.abs(deviation_real))) + ', mean = ' + str(np.mean(np.abs(deviation_real))) + ', chi = ' + str(np.sum(np.square(deviation_real))))

hlm_imag = pyshtools.SHCoeffs.from_array(hilm_imag)
reconstructedimag = hlm_imag.expand(lat=inlat, lon=inlon)
deviation_imag = np.imag(reim_data) - reconstructedimag
print('deviation_imag for imag: min = ' + str(np.min(np.abs(deviation_imag))) + ', max = ' + str(np.max(np.abs(deviation_imag))) + ', mean = ' + str(np.mean(np.abs(deviation_imag))) + ', chi = ' + str(np.sum(np.square(deviation_imag))))

hilm_complex = hilm_real + 1j*hilm_imag
hlm_complex = pyshtools.SHCoeffs.from_array(hilm_complex)
reconstructedComplex = hlm_complex.expand(lat=inlat, lon=inlon)
deviation_to_separate = reconstructedComplex - (reconstructedReal + 1j*reconstructedimag)
print('deviation_to_separate: min = ' + str(np.min(np.abs(deviation_to_separate))) + ', max = ' + str(np.max(np.abs(deviation_to_separate))) + ', mean = ' + str(np.mean(np.abs(deviation_to_separate))) + ', chi = ' + str(np.sum(np.square(deviation_to_separate))))

which gives

deviation_real for real: min = 1.8123470792164031e-07, max = 0.02399276818309759, mean = 0.0015879964062471847, chi = 0.13405475009741488
deviation_imag for imag: min = 1.4086760584397506e-08, max = 0.025954209358143007, mean = 0.001817595279754483, 
deviation_to_separate: min = 0.0, max = 0.2844782293230475, mean = 0.07088919414456854, chi = (2.6888420851680928+32.486839201184736j)

I expected that deviation_to_separate is zero (or at least very, very close to).

What is the right way to combine these two sets of coefficients into a single set of coefficients for the complex function?

robinchrist avatar Nov 19 '20 19:11 robinchrist

...nevermind, figured it out myself!

For future reference and everyone else wondering:

Direct addition of the raw coefficient arrays does not work, because converting the coefficient arrays from real to complex is a nontrivial step. You need to make use of the builtin capabilities of the SHCoeffs class:

hlm_complex = hlm_real.convert(kind='complex') + 1j*hlm_imag.convert(kind='complex')

Perhaps it would be useful to add a section about this in the documentation?

robinchrist avatar Nov 19 '20 19:11 robinchrist

I'm not quite sure where to document this. Do you have any ideas?

  • The best solution to this problem would be add a new fortran function that deals with complex data. I am all for someone contributing this! I rarely work with complex data, so this is not high on priority list.
  • A hacky solution would be to add a new python function that wraps the intermediate steps you used. It's not ideal, but at least it would work.

MarkWieczorek avatar Jan 21 '21 12:01 MarkWieczorek

For info, I've made some improvements to the least squares inversion routines: #463.

I didn't yet implement complex coefficients, but this should be easier to do now than before (the changes would go in the new function shlsq). I would welcome a PR on this as I don't have time to look into this now.

MarkWieczorek avatar Apr 08 '24 11:04 MarkWieczorek