-
Notifications
You must be signed in to change notification settings - Fork 70
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
IGRF calculation #504
Comments
Excited to see this. A few shallow comments after you ideas:
Bonus: until we implement the Holmes and Featherstone (2002) method, I think the functions for computing the Legendre polynomials should include a warning (maybe just in the docs) informing users to avoid using the function for higher orders. |
A couple comments:
|
Looks great! 👍 Just noticed a Python package on the NOAA website https://www.ngdc.noaa.gov/IAGA/vmod/pyIGRF.zip I think pack the coefficient will be very reasonable, which makes life easier without the internet. It is 40 kb, so it won't be an issue. |
Commenting on Mark W.'s thoughts re: IGRF vs SH generally "Should this implementation be specific to IGRF, or more general for an arbitrary magnetic field model?" -> It would greatly enable general use if the class was written more arbitrarily. I think as a first step though obviously IGRF functionality given the user base but the more that can be done to enable general use for arbitrary spherical harmonics in the future would be useful and let folks use different versions of SH models. It is worth noting that a fair amount of the tools in SHTools (like Mark pointed out) provide some of this base functionality already. |
Hi all, thank you for the great inputs! To answer some of them:
Yes, absolutely. And we have no intention of trying to replicate more than necessary. The niche we aim to cover is for evaluating SH models at arbitrary points (which SH tools can do but not as conveniently as we'd like) and doing inversions (synthesis but with non-gridded input data).
We're planning on adding IGRF calculation first and then generalizing this to gravity and magnetic spherical harmonics. But we'll do it in stages to avoid overengineering things (which we tend to do). I'm personally going to need this for research soon so there is a good chance that it will happen relatively quickly (famous last words). I don't think it's likely we'll implement really general spherical harmonics but only the gravity and magnetics specific part.
It's not really Python code. It's a wrapper around a fortran or C code that does all the actual calculation.
I like @MarkWieczorek's suggestion of duplicating the file somewhere we control and downloading with Pooch. I think I'd commit it to the repository instead of using Zenodo to avoid spamming their API any more than we already do.
Alright, I'll definitely have a look at that. I need to read the paper more carefully. The SHTools implementation is a huge help, thanks @MarkWieczorek! In #505 I'm calculating without it and can only go up to degree 600. That's plenty for what I want out of this right now but if it's not too hard to add I'll make the effort.
That does help, thanks. I wrote one for a class I'm teaching and I use Python's
Yes, definitely! It's a single calculation so I'll do it here for now but it would be great to have in Boule.
We were brainstorming this at the Fatiando call earlier today and came with this usage example for a class (which is our preferred option): # Start with this class
class IGRF():
def __init__(self, date, ellipsoid=boule.WGS84):
# Fetch and read the coeffs from the file
# Interpolate to the given date
# Define g and h, normalization, reference radius
def predict(coordinates, field="b"):
# Predict on the given geodetic coordinates
# Choose what to predict: V, bn, be, bu
def grid(coordinates, field="b", ...):
# Generate an xarray grid at the specified coordinates
# made with verde.grid_coordinates
# Usage
be, bn, bu = IGRF(datetime(1990, 3, 14)).predict((lon, lat, height), field="b")
grid = IGRF(datetime(1990, 3, 14)).grid(grid_coords, field="b")
# Plot an intensity grid
np.sqrt(grid.bu**2 + grid.be**2 + grid.bn**2).plot()
# Later, could be generalized to this (and then IGRF inherits from it)
class MagneticSphericalHarmonics():
def __init__(
self,
max_degree,
reference_radius,
normalization="schmidt",
damping=None, # Regularization for the inversion
ellipsoid=None, # None means spherical coordinates
g=None, h=None, # Can initialize the model with coefficients
)
# Usage for fitting
sh = MagneticSphericalHarmonics(max_degree=100, reference_radius=bl.WGS84.mean_radius)
coordinates = (longitude, latitude_sph, radius)
sh.fit(b_e=(coordinates, b_e_data, b_e_weights), b_n=(coordinates, b_n_data, b_n_weights))
sh.predict(..., field="b")
sh.grid(..., field="b") What do you all think? Is there anything we're missing? |
Thanks @leouieda for capturing all these ideas. To that draft, I'd just add that the def fit(self, be=None, bn=None, bu=None):
# Fit the sph coefficients with these data. At least one of the arguments
# should not be None. They would be in the form of `(coordinates, data, weights)`.
...
return self This design for the fit method was originally thought for the equivalent sources classes. |
Not sure if this is useful at this point, but I recently found myself going down the IGRF rabbit hole and found this repo with a decent overview of a lot of the current projects to to calculate the IGRF in the readme. Unfortunately there seems to be a lack of modern ways to efficiently compute the reference field over a grid-like structure, which this would hopefully solve. |
@ckohnke thanks for the link! I've seen several of those and many of them are wrappers of the same Fortran code from NOAA. But it's nice to see what's available. |
Description of the desired feature:
I'd like to implement calculation of the IGRF field. This would require the following components:
datetime
module.Since the model is only degree 13, we don't have to worry too much about the Legendre functions blowing up at larger orders. It would be nice to have the Holmes and Featherstone (2002) method implemented later but it's not required for this job.
Design-wise, I have a few questions:
igrf
function would be very straight forward: calculate the 3-components at the given time and location. The location can be a float or array. But this won't produce an xarray grid. A class could haveIGRF.predict
andIGRF.grid
like our equivalent-sources. But it won't have afit
since the model is already fit. In that case,IGRF
could be an instance of aSphericalHarmonics
class but I'm not sure I like that.bould.Ellipsoid
to be passed so it can do the conversions? Should it be optional (withellipsoid=None
assuming values in geocentric coordinates)? Or do we do everything in spherical and delegate the conversions entirely to Boule outside the IGRF function (this would require adding a vector rotation function toboule.Ellipsoid
)?I might break this down into multiple PRs adding different part as possibly private functions (Legendre and coefficient reading ones).
Are you willing to help implement and maintain this feature?
Yes!
The text was updated successfully, but these errors were encountered: