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

Added F99 model #30

Merged
merged 31 commits into from
Jul 15, 2020
Merged

Added F99 model #30

merged 31 commits into from
Jul 15, 2020

Conversation

icweaver
Copy link
Member

@icweaver icweaver commented Jul 7, 2020

  • Add support for Measurements
  • Generalize for F04

Contributing to #10

@icweaver icweaver changed the title F99 Adding F99 model Jul 7, 2020
@icweaver icweaver changed the title Adding F99 model [WIP] Adding F99 model Jul 7, 2020
@icweaver icweaver changed the title [WIP] Adding F99 model [WIP]: Adding F99 model Jul 7, 2020
@icweaver icweaver mentioned this pull request Jul 7, 2020
10 tasks
@icweaver icweaver changed the title [WIP]: Adding F99 model [WIP]: added F99 model Jul 7, 2020
@codecov
Copy link

codecov bot commented Jul 7, 2020

Codecov Report

Merging #30 into master will increase coverage by 0.09%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #30      +/-   ##
==========================================
+ Coverage   99.35%   99.45%   +0.09%     
==========================================
  Files           4        4              
  Lines         155      182      +27     
==========================================
+ Hits          154      181      +27     
  Misses          1        1              
Impacted Files Coverage Δ
src/DustExtinction.jl 100.00% <ø> (ø)
src/color_laws.jl 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update ad510f3...2101f98. Read the comment docs.

@giordano
Copy link
Member

giordano commented Jul 7, 2020

Everything looks to be working alright except for Measurements handling. I think this might be related to the package (Dierckx.jl) I am using for interpolation?

I'm not at the computer right now, but if I remember correctly Dierckx.jl is based on an external C library, right? If so, yeah, Measurements.jl can't propagate the uncertainty through ccalls, but you can use the @uncertain macro: https://juliaphysics.github.io/Measurements.jl/stable/examples/#@uncertain-Macro-1

src/color_laws.jl Show resolved Hide resolved
src/color_laws.jl Outdated Show resolved Hide resolved
Project.toml Show resolved Hide resolved
test/color_laws.jl Outdated Show resolved Hide resolved
@icweaver
Copy link
Member Author

icweaver commented Jul 7, 2020

Everything looks to be working alright except for Measurements handling. I think this might be related to the package (Dierckx.jl) I am using for interpolation?

I'm not at the computer right now, but if I remember correctly Dierckx.jl is based on an external C library, right? If so, yeah, Measurements.jl can't propagate the uncertainty through ccalls, but you can use the @uncertain macro: https://juliaphysics.github.io/Measurements.jl/stable/examples/#@uncertain-Macro-1

This is so cool! @uncertain is working like a charm for single wavelengths. For example, I can do this:

>>> @uncertain F99()(wave_unc[1])
0.08548387096774193 ± 0.0

but I think I am having trouble broadcasting this when I try:

>>> @uncertain F99().([wave_unc[1], wave_unc[2]])
ERROR: MethodError: no method matching measurement(::Tuple{Array{Measurement{Float64},1}})

for example.

@giordano
Copy link
Member

giordano commented Jul 7, 2020

but I think I am having trouble broadcasting this when I try:

See #30 (comment) 😉

@icweaver
Copy link
Member Author

icweaver commented Jul 7, 2020

but I think I am having trouble broadcasting this when I try:

See #30 (comment) 😉

hahaha, was just about to respond. Thanks! It's like you read my mind

src/color_laws.jl Outdated Show resolved Hide resolved
Copy link
Member

@mileslucas mileslucas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution- I've got some comments about the internals, but the documentation and testing looks good at first glance.

First, I think if we can make the interpolation work using Interpolations.jl instead of Dierckx.jl we'd be better off because as a pure-julia library we avoid issues like you saw with Measurements.jl as well as auto-differentiation. However, currently Interpolations only manages gridded interpolation up to Linear degree and requires an equally-spaced grid for BSplines up to Cubic. I have no issues including this now but I think we will want to note that it is not AD friendly.

Second, keep an eye out for moving calculations earlier. This can be achieved by the use of const variables as well as putting more calculations into the F99 struct. What I mean by this is anything that can be fully specified using Rv only (such as opt_axebv_y can be added as a field to the struct- e.g. F99(Rv) = F99(Rv, f99_opt_coeff(rv)) where that function calls what you've written out. This way, even something as innocuous as F99().(wavelengths) saves by doing that calculation once instead of every iterated method call.

Also, in general, using static data structures like Tuple is better for static data, although I know not all of this code follows that. It would be useful to check performance using Vector vs Tuple vs SVector from StaticArrays for the internals some day.

Comment on lines 248 to 253
# x value above which FM90 parametrization used
x_cutval_uv = 10000.0 / 2700.0

# required UV points for spline interpolation
x_splineval_uv = 10000.0 ./ [2700.0, 2600.0]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if these are constants, I think we should move them outside the function definition and declare as constants like so

const x_cutval_uv = aa_to_invum(2700)
const x_splineval_uv = aa_to_invum.((2700, 2600))

additionally by manually writing out a Tuple, we avoid allocating an array each method call.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 244 to 245
optnir_axav_x::Vector{<:Real},
optnir_axav_y::Vector{<:Real},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general we want to use abstract types for function dispatch, such as AbstractVector{<:Real} here. However, you don't really need to type any of these variables because they're constrained by their behavior already in the code- the most generic program actually has no types!

I would remove all the type specializations here, and you can callback @code_warntype _curve_F99_method(x, Rv, ...) from the REPL to see if you have type-stability, which is what matters.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# FM90 model and values
fm90_model = FM90(c1=c1, c2=c2, c3=c3, c4=c4, x0=x0, gamma=gamma)
# evaluate model and get results in A(x)/A(V)
axav_fm90 = fm90_model.(10000.0 ./ xuv) / Rv .+ 1.0 # Expects xuv in Å
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: using the @. macro makes this line simpler and avoids bugs like the missing ./ before Rv

Suggested change
axav_fm90 = fm90_model.(10000.0 ./ xuv) / Rv .+ 1.0 # Expects xuv in Å
axav_fm90 = @. fm90_model(aa_to_invum(xuv)) / Rv + 1 # Expects xuv in Å

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/color_laws.jl Show resolved Hide resolved
Comment on lines 337 to 338
optnir_axav_x = 10000.0 ./
[26500.0, 12200.0, 6000.0, 5470.0, 4670.0, 4110.0]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to others- make const if possible and use tuples to avoid allocations

const optnir_axav_x = aa_to_invum.((26500, 12200, 6000, 5470, 4670, 4110))

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0.701 + 1.0016 * Rv,
1.208 + 1.0032 * Rv - 0.00033 * (Rv^2),
]
nir_axebv_y = [0.265, 0.829] * Rv / 3.1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you'll want to make use of broadcasting here-

nir_axebv_y = @. (0.264, 0.829) * Rv / 3.1

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@icweaver
Copy link
Member Author

icweaver commented Jul 8, 2020

Thanks so much for these comments, @mileslucas! I was trying to strike a balance between doing a 1-1 translation from the original astropy code and making things more Julian. Your suggestions have helped answer a lot of "best practices" questions I've had when starting with this language and I'll start implementing them ASAP

@icweaver
Copy link
Member Author

icweaver commented Jul 9, 2020

Sorry, not sure why this latest commit failed on some platforms while working on others. The local tests I ran before committing all passed.

@icweaver
Copy link
Member Author

icweaver commented Jul 9, 2020

Sorry, not sure why this latest commit failed on some platforms while working on others. The local tests I ran before committing all passed.

Ahh, didn't realize evalpoly is only for 1.4

https://docs.julialang.org/en/v1/base/math/#Base.Math.evalpoly

That's a bummer. Being able to broadcast was super useful for re-writing this

opt_axebv_y = (
    -0.426 + 1.0044 * Rv,
    -0.050 + 1.0016 * Rv,
     0.701 + 1.0016 * Rv,
     1.208 + 1.0032 * Rv - 0.00033 * (Rv^2),
)

as

opt_axebv_y = evalpoly.(Rv, opt_axebv_y_params)

and just pack all those constants into a nested Tuple outside the main function. Is there a way to broadcast with @evalpoly or should I just drop this? I thought maybe a comprehension like this

(@evalpoly Rv param... for param in opt_axebv_y_params)

might work, but I am pretty sure I am butchering the syntax here.

end

# terms depending on Rv
c2 = @evalpoly (1. / Rv) f99_Rv_params...
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cannot work with this macro, you need to list the elements of the vector one by one. That's why the function was introduced

Copy link
Member Author

@icweaver icweaver Jul 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, just saw your comment! Yep, just realized that when I looked at Travis. Oh well =\

That's neat though that you can do exactly that in v1.4

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alrighty, everything should be switched over now. I've never had to think about things like backwards compatibility before, so this has been an extremely useful lesson for me, thanks!

@icweaver
Copy link
Member Author

Ah, I see now it's failing because you can't splat a Tuple into @evalpoly in Julia v1.0.5

@siddharthlal25
Copy link
Member

According to the discussion here, it looks like Interpolations.jl does not have support for cubic B-splines (which is used by the python implementation), while this package does.

I was just going through Interpolations.jl and found this, is this what you were looking for?

@icweaver
Copy link
Member Author

icweaver commented Jul 10, 2020

According to the discussion here, it looks like Interpolations.jl does not have support for cubic B-splines (which is used by the python implementation), while this package does.

I was just going through Interpolations.jl and found this, is this what you were looking for?

Right, so my understanding was that the issue was with the next part down, which I believe @mileslucas mentions here, re: cubic splines on a non-uniform grid?

I added using Interpolations.jl to my general TODO for #10. It would be awesome if we could use it in the future! Although, it looks like it is not being actively maintained right now =\

Found an open issue here!

@icweaver
Copy link
Member Author

icweaver commented Jul 10, 2020

Following up on the spline issue, there is this package that could be useful!

  • Pros: It's written in pure Julia (which should make it play nice with AD?) and can do cubic splines on an irregular grid
  • Cons?: Those cubic splines are actually Akima splines, so our results will differ from the astropy implementation of the dust models

I have no experience using Akima splines, but it looks like it may actually perform better than traditional cubic B-splines.

I guess it comes down to: should DustExtinction.jl exactly reproduce its Python cousin's results, or should it use the "latest and greatest" technology? tbh, I can see arguments for both.

Copy link
Member

@mileslucas mileslucas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Things are looking pretty good, keep an eye out for re-ordering the computations like I mentioned in the previous review.

Comment on lines 15 to 30
# x value above which FM90 parametrization used
const f99_x_cutval_uv = aa_to_invum(2700)

# required UV points for spline interpolation
const f99_x_splineval_uv = aa_to_invum.((2700, 2600))

# spline points
const f99_optnir_axav_x = aa_to_invum.((26500, 12200, 6000, 5470, 4670, 4110))
const f99_nir_axebv_y_params = @. (0.265, 0.829) / 3.1

# c1-c2 correlation terms
const f99_c3 = 3.23
const f99_c4 = 0.41
const f99_x0 = 4.596
const f99_gamma = 0.99

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these would fit in better closer to the F99 definition- you'll see things are generally clustered by law already

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure 804fb33

@icweaver icweaver requested a review from mileslucas July 14, 2020 15:58
@icweaver
Copy link
Member Author

It looks like the CI sporadically fails when installing Julia, but otherwise I think everything should be addressed now for another review. Thanks!

Copy link
Member

@mileslucas mileslucas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking good! Thanks again for the contribution. The only changes left are completely internal and I'm not too concerned. Unless anybody else has concerns I'll merge this later tonight and do a new release.

Comment on lines 270 to 273
# using cubic spline anchored in UV, optical, and IR

# optical/NIR points in input x

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not really following the comments here

Copy link
Member Author

@icweaver icweaver Jul 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, whoops! That's from some leftover Python styling before I switched to thinking in terms of "kernels". Thanks for catching that, should be fixed now! (5a6b6fd)

@mileslucas
Copy link
Member

Actually, if you want to go ahead and edit Project.toml and bump the version to 0.8.0 we'll be prepped for a release.

@icweaver
Copy link
Member Author

icweaver commented Jul 14, 2020

This is looking good! Thanks again for the contribution. The only changes left are completely internal and I'm not too concerned. Unless anybody else has concerns I'll merge this later tonight and do a new release.

Awesome, thanks! I opened up a separate PR for F04 (#31) and F19 (#32) as well. I tried to keep in mind everything y'all have taught me =]

@giordano giordano changed the title [WIP]: added F99 model Added F99 model Jul 14, 2020
@mileslucas mileslucas merged commit c30f719 into JuliaAstro:master Jul 15, 2020
@icweaver icweaver deleted the F99 branch July 15, 2020 13:17
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

Successfully merging this pull request may close these issues.

4 participants