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

Classy transfer_model #63

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open

Conversation

jlashner
Copy link
Contributor

Hi Steven, here's my first shot at a classy transfer model. It's behavior is as follows:

  • If a 'class_obj' is specified in transfer params, it will attempt to use that class object instead of creating a new one. It will figure out on its own whether or not .compute() has been run by checking to see if the transfer function exists yet.
  • If no class_obj is specified, a new class object is created. It uses a few default parameters like omega_b, omega_cdm, and h based on the cosmo object, updated with any parameters passed via class_params.

With our modified class code, it is possible to obtain negative T(k), which will break this since you can't take ln(T). If this transfer is only used to calculate the power spectrum, then it should be fine to return ln(|T|), since P(k)~T(k)^2. However if other parts of your code use T(k) (not squared) then this might be a problem. I did a quick scan of hmf and couldn't really find T(k) being used outside of calculating P(k). Do you have an opinion on the best way to handle this? In any case, I added a flip_T transfer option which returns ln(|T|), but we should discuss if there is a better way to handle this.

@codecov
Copy link

codecov bot commented May 20, 2020

Codecov Report

Merging #63 into master will decrease coverage by 0.51%.
The diff coverage is 25.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #63      +/-   ##
==========================================
- Coverage   65.41%   64.89%   -0.52%     
==========================================
  Files          22       22              
  Lines        2495     2527      +32     
==========================================
+ Hits         1632     1640       +8     
- Misses        863      887      +24     
Impacted Files Coverage Δ
hmf/density_field/transfer_models.py 76.88% <25.00%> (-8.61%) ⬇️

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 ef35734...0962687. Read the comment docs.

Copy link
Collaborator

@steven-murray steven-murray left a comment

Choose a reason for hiding this comment

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

This all looks really great so far -- it's definitely got the right usage of things.

I suggest adding a test for the new class, to convince ourselves it's doing the right thing. Aim for 100% coverage of this class! I can help with that if you need me to as well.

import classy
except ImportError as e:
pass

_allfits = ["CAMB", "FromFile", "EH_BAO", "EH_NoBAO", "BBKS", "BondEfs"]
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can add "CLASS" to this list

super(CLASS, self).__init__(*args, **kwargs)
self.spline_fn = None

if self.params['class_obj'] is not None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you put a check whether the actual class is an instance of classy.Class?

trans = self.class_obj.get_transfer(output_format='camb')
if not trans:
self.class_obj.compute()
trans = self.class_obj.get_transfer(output_format='camb')
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not very familiar with Class, but I feel like there might be a more elegant way to do this. Is there no other way to check if compute has been called other than to get the transfer and check if it's not None? Ideally, you'd have:

if not self.class_obj.condition:
    self.class_obj.compute()

trans = self.class_obj.get_transfer(output_format='camb')

**class_object:**
Custom class object. If not set, a new Class object will be
created.
**flip_t:**
Copy link
Collaborator

Choose a reason for hiding this comment

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

The transfer function in hmf is only used to get the power spectrum (at this point). I think it's reasonable just to always take the absolute for now. It might be good to post an issue about this though, and we can think about returning the actual transfer function rather than the log. I chose the log because at the time I thought it must always be positive, and the log is easier to take a spline of.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, you'll need to remove flip_t from the docsring as well :-)

trans = self.class_obj.get_transfer(output_format='camb')

_k, _t = trans['k (h/Mpc)'], trans['-T_tot/k2']
if self.params['flip_T']:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Note point above about using absolute.

try:
import classy
except ImportError as e:
pass
Copy link
Collaborator

@steven-murray steven-murray May 21, 2020

Choose a reason for hiding this comment

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

Set HAVE_CLASS=False here if it fails, then raise an error in the class __init__ if it's false.

Also, add a line to the setup.cfg in the extras_require section to the effect of

class = 
    classy

_defaults = {"class_params": None, "class_obj": None,
"flip_T": False}

def __init__(self, *args, **kwargs):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Here's the place to raise an error if HAVE_CLASS=False

@steven-murray
Copy link
Collaborator

Also, before we merge, you should:

  1. Add your name to the contributors list (actually, it might already be there)
  2. Add your changes to the CHANGELOG.rst
  3. Install pre-commit and run pre-commit run -a in the top-level of the repo. I think the Linter is failing because of some black formatting issues. This will fix those automatically (most likely).

We'll also have to resolve conflicts with master, but let's do those things first.

@jlashner
Copy link
Contributor Author

Great! Implemented all of your suggestions and changed a few things:

  1. Added a test comparing CLASS and CAMB transfers with default params, making sure they are the same
  2. I removed the flip_T argument, and if T is negative I'm printing a warning and just returning the absolute value. We're a bit concerned if this will work properly when splined, so I think we still might want to implement an option where you don't have to take the log.
  3. Had some flake8 problems about \* characters in the docstring I copied from the other transfer functions. I'm not sure why it didn't like those in the CLASS transfer but is ok with them in the other transfer functions, but I just removed them.

Let me know if there's anything else, thanks!

@jlashner
Copy link
Contributor Author

So I think this is failing my test because class is not installed on the test server. Do you have any idea how to add that? I think it needs to be manually installed. Cobaya-install can also be used to install a suite of cosmological packages which might be easier.

I did run the tests locally and they passed.

Copy link
Collaborator

@steven-murray steven-murray left a comment

Choose a reason for hiding this comment

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

OK, this all looks good. To get tests working, you should do two things.

First, make sure the test doesn't run when CLASS is not installed. You can do this by using the pytest.importorskip function as the first thing inside the test function. This means people don't have to have CLASS installed to run the tests, and it will just print out that it got skipped (to remind them that there are more tests they might want to run).

Second, you'll have to edit .github/workflows/test_suite.yaml to add in installation of CLASSY. At around line 70 you should find an "Install" section. Add on the relevant commands to the end of that section (it seems like it's not going to just be pip install classy unfortunately). It's just bash running there, so you can do whatever you need to do (you could also create a new section under "Install" and call it "Install CLASSY").



class CLASS(FromFile):
"""
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add an r just before the quotes to be able to use the \*\* notation in the docstring (not that you have to do that).

**class_object:**
Custom class object. If not set, a new Class object will be
created.
**flip_t:**
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, you'll need to remove flip_t from the docsring as well :-)

@steven-murray
Copy link
Collaborator

Hi @jlashner, did you progress with this? Can I assist in any way?

@jlashner
Copy link
Contributor Author

Hi Steven, sorry for leaving this out for so long. So I stopped working on this because we were running into some consistency issues between our modified CLASS model and the cosmology that's used throughout hmf, which is an astropy cosmology model. It seems to me that in order to be consistent we'd have to make a new cosmology class that wraps our CLASS object and maps all of the used astropy methods to CLASS methods. Do you have any input on whether this is the right thing to do, and if there would be any lingering astropy cosmology dependence in HMF? Thanks!

Anyway, after we figured out that we'd need to put more work into hmf for it to be consistent I decided to move ahead with other parts of the project while we looked into some other options or determined whether the CLASS wrapper was worth implementing in HMF. It looks like the only thing thats left is some minor docstring comments that I can implement. I was also holding off because the CLASS installation is not all that straightforward and I'm not sure the best way to do it through github actions. If you want to take a shot at it that would be super helpful!

@steven-murray
Copy link
Collaborator

Hi @jlashner, thanks for the update!

How bad is the inconsistency? Is it a fundamental inconsistency between astropy and CLASS, or between your modification of CLASS only? Could we get away with using the code as-is for now, and making an issue that we'll want to someday update the CLASS wrapper?

The CLASS installation is indeed not straightforward. I think I can give it a go soon.

@steven-murray steven-murray changed the base branch from master to dev November 25, 2020 20:19
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.

2 participants