-
Notifications
You must be signed in to change notification settings - Fork 77
Lambda enhancements #520
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
Lambda enhancements #520
Conversation
…to lambda_enhancements
…AGB, EAGB, and HG
…or CHeB, EAGB, HG, TPAGB
|
I need to fix a bug related to the mass and metallicity bins... Should be using M = [1.0, 2.0, ...] instead of M = [1.5, 2.5, ...] |
…ins; reduce number of log calculations
Good job. Just one thing: where you have parameters to functions (e.g. double TPAGB::CalculateLambdaNanjing(double mass, double metallicity) and others), our convention is (see COMPAS doc, ~p53): (a) class member variable names begin with m_, and are typically followed by an uppercase alpha character (though that (the uppercase character) is sometimes relaxed if it makes sense - e.g. m_dM rather than m_DM) The rationale for (a)-(e) is consistency; the rationale for (a), (b), and (c) in particular is that readers of the code at some later stage can tell easily where a variable came from - whether it was calculated locally, passed in as a parameter, or whether it is a class member variable. Typically we don't modify parameters that were passed in to functions - although there are a (very) few places in the code where we do for pragmatic reasons (performance mostly). If a function modifies either class member variables or parameters it should be documented in the descriptive text before the function declaration. If parameters are not modified by the function they should be declared const, and similarly if the function does not modify class member variables it should be declared const.
Yes, but maybe necessary. Could you use std::numeric_limits::max() instead of the arbitrary 1000000.0?
I've only looked at the changes to the code through github - I haven't looked at the entire code in context -
So, are we planning to make both the old and new lambdas available into the future? Or do we just want them available now for testing new vs old? Do we want to release a version on the code that allows users to choose, or do we just want to leave the old code in for a while so we can test? If we want to release the code and allow users to choose between old and new lambdas, then we'll need a new program option. If we just want to leave both there for a while as we test, maybe just have a switch in the code that requires a code change - no |
|
Hi @jeffriley. Thanks for the detailed feedback! The requested changes related to variable names and type seem to be straightforward and I will fix them on Thursday.
My reasoning is that in my changes, CalculateLambdaNanjing(...) no longer directly outputs a star's lambda, but has switched roles to become a lookup table for Xu & Li (2010) fitting parameters. And of course, this table has discrete mass and metallicity values since Xu & Li (2010) ran a discrete grid of stellar models. The new functions I have added, CalculateMassInterpolatedLambdaNanjing() and CalculateMassInterpolatedLambdaNanjing(const double metallicity), output lambda for continuous mass/metallicity by calling CalculateLambdaNanjing() at the discrete masses/metallicities and interpolating over them. So I thought that it would be odd and perhaps unsafe to allow CalculateLambdaNanjing() to take continuous mass or metallicity values.
I think Ilya's suggestion has been to make a new program option for users to choose between old and new lambdas. I guess the purpose of this is so that the results of the old and new lambdas can be compared even with future versions of COMPAS. |
…ng masses in constants
… mass indices for CHeB
… mass indices for EAGB
… masses and metallicities for rest of stellar types and fix compilation errors
… values and remove some unneeded caps on radius
…pending on options
|
I have checked that the default code behaviour (not switching on any of the newly introduced lambda options) reproduces the detailed system plot (Fig 15 of methods paper). I also find identical output from 1000 binaries evolved using this new version and evolved using the existing version (v2.26.02). |
ilyamandel
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@themikelau : thank you very much for this PR!
It seems you updated the default pythonSubmit.py, but I think we have now changed to using runSubmit.py -- can you please update that instead?
Did you update the documentation to include the new code options?
A couple of comments on the code, though I'll defer to @jeffriley :
- I find CalculateLambdaNanjing() and EvaluateLambdaNanjing() slightly confusing; maybe rename the old CalculateLambdaNanjing into CalculateLambdaNanjingStarTrack, and the new EvaluateLamdaNanjing into CalculateLambdaNanjing?
- You often use multiple return statements inside complicated nested if/else loops. I think the usual COMPAS convention adopted by Jeff -- which I agree makes it easier to read the code -- is to assign the result to a variable and only return at the end of the function.
- (Perhaps for the future?) Instead of treating mass and metallicity interpolation separately, I might have opted for a single utility to interpolate on a 2-d grid (or not, if beyond the grid or if the interpolation along a given dimension is off). This might make for fewer special cases / functions. E.g., if I want the value at point {x,y} that falls within the grid, so that x_1<x<x_2 and y_1<y<y_2, and interpolation is on along both axes, then f(x,y)= dx dy f(x_1,y_1) + dx (1-dy) f(x_1,y_2) + (1-dx) dy f(x_2,y_1) + (1-dx) (1-dy) f(x_2,y_2), where dx=(x-x_1)/(x_2-x_1) and dy = (y-y_1)/(y_2-y_1).
Indeed. It's ok to do a sanity check or two at the very start of a function and, based on those sanity checks, return immediately if we shouldn't even execute the function, but after that, it's much easier for a future reader of the code to read and understand what's happening if they can assume there is one entry point (some languages allow multiple entry points for functions...) and one exit point for the function. So, as @ilyamandel says, the convention we use in COMPAS is to assign the return value to a variable, and return that at the end - and use if/else to execute only those parts of the function that are required rather than return early. I'll repeat my mantra here. We should always code with future readers/maintainers of the code in mind. The compiler really doesn't care what our code looks like - it's very adept at parsing code however we format it. Code is typically written once, and read many times - if by being a little more verbose, formatting the code so it's easy on the eyes (even adding parentheses that aren't strictly necessary just for clarity for the reader), sometimes even repeating a little bit of code instead of trying to be tricky or get everything done in the fewest lines of code possible, we can make it easier to read and maintain (especially for people working on the code long after we've moved on), then that's what we should do. Compilers these days are almost always optimising compilers, so even though you might think a little bit of verbosity, or less trickiness, might make the code run slower, it probably won't - the compiler's going to optimise your code anyway... |
…aNanjingStartrack
|
Thanks @ilyamandel and @jeffriley for your wisdom.
Just to be safe I will run another test to check that the output with default options is same as in dev after these changes. |
|
Ok, I have just checked that the output of 1000 binaries is identical with that produced with v2.26.03. Happy for this to be merged. |
This pull request is to fix the issue of discontinuous Nanjing lambda's (Issue #418).
m_Mass0, (ZAMS mass corresponding to rejuvenated star?) rather than the true birth mass. Note that this is opposite to Startrack's implementation.In terms of code, here's a summary of what has been done to achieve the above.
CalculateLambdaNanjingfunctions in CHeB.cpp, EAGB.cpp, TPAGB.cpp, and HG.cpp to take mass and metallicity as inputs to facilitate interpolation, e.g.double CHeB::CalculateLambdaNanjing(double mass, double metallicity) {...}.double BaseStar::CalculateMassInterpolatedLambdaNanjing(const double metallicity)that performs mass interpolation for given metallicity. This function accesses the star'sm_Mass0, callsCalculateLambdaNanjingfor its adjacent mass bins, then linearly interpolate between the two values.double BaseStar::CalculateMassAndZInterpolatedLambdaNanjing()that performs metallicity interpolation. This function accesses the star's metallicity, callsCalculateMassInterpolatedLambdaNanjingfor its adjacent metallicity bins, then linearly interpolate between the two logged metallicities.min(Rmax, m_Radius)instead ofm_Radius, whereRmaxis different for each mass.CalculateLambdaNanjing:What could be improved
double Rmax = 1000000.0;is ugly?CalculateLambdaNanjingtake in discrete mass and metallicity values, sinceCalculateMassAndZInterpolatedLambdaNanjingandCalculateMassInterpolatedLambdaNanjingare doing all the interpolation anyway? E.g. Having something likeswitch (mass) { case '1.0': [...] case '2.0': [...]instead ofif mass < 1.5 [...] elseif mass < 2.5 [...]?Overall, this is all very rudimentary I would appreciate feedback from code experts. Once the code is polished up, I will update this branch with the latest updates from dev (there are currently conflicts) and update the changelog.