-
Notifications
You must be signed in to change notification settings - Fork 69
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
Implementing the Shikauchi+ (2024) core mass prescription for main sequence stars #1292
Implementing the Shikauchi+ (2024) core mass prescription for main sequence stars #1292
Conversation
Some things I wanted to ask:
|
@brcekadam I'll review in detail a bit later, but for now:
Mostly. This is why we use Compiling and running this code:
gives:
With every manipulation we lose precision (or maybe accuracy...) - digits roll off the end of the number. And, as it happens, because of the way C/C++ stores floating-point numbers (IEEE standard), not all real values can be represented exactly.
However, there are some exceptions throughout the code (should all be commented). The main reason for not using
I'll take a look at that when I review later |
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.
Thank you for the very nice work, @brcekadam !
Some of the requests below may overlap with @jeffriley 's.
For now, I am just reviewing the class with most of the changes, MainSequence.cpp.
m_HeliumAbundanceCore -- does this hold a meaningful value only if the Shikauchi prescription is used? If so, perhaps reflect that in the name so another developer doesn't misuse it?
I recommend defining the 10.0 Msun threshold in constants.h -- this way, if someone changes it, they'll automatically consistently change it everywhere it's used.
Around line 350:
if ((p_HeliumAbundanceCore == 1.0 - m_Metallicity) && (m_TotalMassLossRate == -m_Mdot))
You probably want utils.Compare() >= 0.0 on the first test; perhaps add a comment that, once you get to the hook, the He abundance fraction will be fixed to 1-metallicity and the core is not evolving-- otherwise, not clear why the luminosity being computed from Eq. (A5) when this function is called, say, half-way through the hook can be used as the luminosity at the start of the hook.
For the second one, utils.Compare == 0.0 ?
(see also line 538)
--
CalculateCoreMassMandel()
There's a function called TAMSCoreMass(); use that instead of cloning, so you just need a one-liner:
return std::max(m_MainSequenceCoreMass, CalculateTauOnPhase() * TAMSCoreMass() );
double totalMass = m_Mass;
double centralHeliumFraction = m_HeliumAbundanceCore;
double mixingCoreMass = m_MainSequenceCoreMass;
double lnMixingCoreMass = std::log(mixingCoreMass);
double heliumFractionOut = m_HeliumAbundanceCoreOut;
Other than the line which computes a log (which you obviously don't want to call more than once), I really don't see the point of renaming variables -- just makes the code longer and harder to read... (and even the ln you only use once, so no point in defining a new variable)
Line 815:
// Eq (A4)
double beta = 1.0 - FMIX_COEFFICIENTS[1] * totalMass / (FMIX_COEFFICIENTS[2] * fmix) * std::exp(-totalMass / FMIX_COEFFICIENTS[2]);
Eq. (A4) refers to M_ZAMS; why does this use m_Mass?
Line 831:
I don't understand what you are doing with the ODE solver. You aren't actually changing the value of \dot{Y} -- your right-hand-side of dxdt[0] is constant -- so why evolve it if it's a constant? If you do want to evolve it, luminosity and mass are changing as functions of time, too -- e.g., the mass is not mixingCoreMass, its exp(x[1]) -- but do you need to take small internal step sizes here since we are just doing difference equations elsewhere with the step size p_Dt? Except, perhaps, fast case A MT -- but then, the right-hand-side shouldn't be constant, either...
You don't need to muck with time units -- Q_CNO cannot be LSOL/MSOL (it should be energy per mass, contrary to what constants.h claims), so just define it in units of LSOL * Myr / MSOL, and then you can keep timesteps in their code units.
Oh, and don't take log10(luminosity) just to take PPOW(10.0,logL) a moment later -- it's unnecessary computational cost. :)
Line 855:
I don't understand what you are integrating. As far as I can tell, the right hand side is a constant:
dxdt[0] = (heliumFractionOut - m_InitialHeliumAbundance) / (mixingCoreMass - m_InitialMainSequenceCoreMass) * (deltaCoreMass / currentTimestepInYrs);
If dx/dt = k, where k is a constant, there is no need to integrate numerically :-) -- the solution is x(t) = x(0) + k t.
It's also possible I missed something -- adding comments would definitely help to clarify what you are doing in places like this, especially if there are no published equations to refer to.
[I won't comment further on rejuvenation because I couldn't quite follow what you were doing here; can I suggest that you write up some notes on the equations you are trying to solve in latex and attach them to this PR as a PDF? You'll reuse them later for your paper...]
Line 929 & 932: another example of unnecessary variable declaration
mixingCoreMass = std::get<0>(ShikauchiSolution);
m_MainSequenceCoreMass = mixingCoreMass; // Update the core mass
Around lines 927--935: the if and else if clearly don't cover all of the cases, and I am a bit worried that we are doing nothing when neither set of conditions are satisfied...
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.
@reinhold-willcox 's comment today about implementing wind mass accretion is one of the reasons why
m_TotalMassLossRate == -m_Mdot
in MainSequence::CalculateLuminosityShikauchi()
is a dangerous way to check whether mass transfer is ongoing: the mass may be changing because the star is accreting winds, even in the absence of mass transfer...
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.
MainSequence::CalculateLuminosityShikauchi()
if ((p_HeliumAbundanceCore == 1.0 - m_Metallicity)
I think it would be safer to do if(utils::Compare(p_Age, 0.99 * tMS) >= 0)
I don't quite understand why MainSequence::CalculateMainSequenceCoreMassShikauchi() returns the new central He fraction and core mass, but updates m_HeliumAbundanceCoreOut directly. That seems inconsistent. Why not just update all of the variables directly (and make the function return void)?
In the same function, you don't really need an ODE solver for Eq. (7) in your notes, especially since you are treating Eq. (5) as exact.
Same function: if a star accretes a significant amount of mass and go from M_c<M_c,0 to M_c>M_c0 in one time step, the derivative term should be used for all the mass accreted up to M_c,0 but not beyond. (See Slack discussion and @ryosuke-hirai 's comment on this.)
void MainSequence::UpdateMainSequenceCoreMass()
ShikauchiSolution = CalculateMainSequenceCoreMassShikauchi(p_Dt);
mixingCoreMass = std::get<0>(ShikauchiSolution);
centralHeliumFraction = std::get<1>(ShikauchiSolution);
m_HeliumAbundanceCore = std::min(centralHeliumFraction, 1.0 - m_Metallicity); // Update the core helium abundance
m_MainSequenceCoreMass = mixingCoreMass; // Update the core mass
As mentioned previously, just use the stored values instead of passing them around. Also, CalculateMainSequenceCoreMassShikauchi() should internally cap the central helium fraction to 1.0-m_Metallicity.
p_TotalMassLossRate != m_TotalMassLossRate
That's a very non-intuitive comparison. :)
… other fixes and code cleanup
Thank you so much for your comments, @jeffriley and @ilyamandel! I have now fixed most things, but here are some comment and answers to your questions:
I have restructured the conditions in
I have defined the threshold for Shikauchi prescription in constants.h and changed it to 15 Msun for now. Regarding the I've changed what is being integrated in the ODE solver. I was indeed integrating a constant term, which works okay for small mass loss (e.g. through winds). But for thermal timescale mass loss, we definitely need to take time steps smaller than the COMPAS time step to fully resolve the core mass evolution. This comparison I am also attaching a PDF document describing the rejuvenation procedure. |
@brcekadam I'm working on this - I will do my best to have it done before the end of this week. There are some changes I'd like to see, and I'll probably push those myself (it'd take me longer to describe them than actually make the changes). The initialisation of the constants bothers me a bit - I'm trying to decide the best place for that. I might suggest moving them to BaseStar and only do the initialisation if the option is enabled - but I'm not convinced I'm comfortable with that either. The problem is that because they are in MS_gt_07 they rely on the SHIKAUCHI threshold always being above 0.07 MSun - which I'm sure it always will be, but me (and you) being sure is not the same as it being that way in the code... Make sense? So, let me think about that and I'll get this done in the next day or two... |
@jeffriley -- I'd be OK with a big fat comment warning or an assert statement that SHIKAUCHI_LOWER_MASS_LIMIT must be above 0.7 Msun. ;-) |
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.
Very nice, @brcekadam ! One very minor request, one query, and one idea to consider. I am listing this as an approval, so you don't need to wait for another review from me. But, of course, I'd be interested in hearing your thoughts -- and please do wait for Jeff's comments.
- the comment on line 761 of MainSequence.cpp is missing one of the function arguments:
- void CalculateMainSequenceCoreMassShikauchi(const double p_Dt)
- I didn't know you could declare variables to have type auto in C++ (e.g., around lines 776-780 of MainSequence.cpp). Cool, thanks for teaching me! For my education, in this context, what's the benefit of doing that rather than declaring them to be double? [This might be a question for both you and @jeffriley :) ]
On the p_TotalMassLossRate issue:
Actually, I think the clean/safe thing to do is to call the function twice. :-)
Once for RLOF, but only taking into account the RLOF mass loss/gain; then again for winds, only taking into account the winds mass loss (or gain, if we ever implement it). Of course, only the second one would ever get called in SSE...
That might end up being the solution, but I'm not yet convinced it is the best one. I'm struggling with functions that rely on the star being a MS_gt_07 star not being in that class (they're in the MS class). I get why @brcekadam has done it the way he has, I'm just not sure it's the best way. But fear not, I will be pragmatic...
We use @brcekadam uses it here to type the return value of nested functions. There is no real reason to use EDIT: actually, I might take that back :-) I think EDIT: Ah, yes - the nested functions are lambda functions. They could probably be rewritten as properly typed and named nested functions, but lambda functions are ok here. So, I take it back :-) |
Thanks @ilyamandel! They are indeed lambda functions. Alpha, Beta, and Delta are functions of the core mass, total mass, and central helium fraction, so I thought this would be a clean way of defining them as nested functions. They are not needed anywhere else outside Regarding the |
I have some changes that I can't push at the moment due to a github outage - I'll push them as soon as I can. Here are my comemnst (associated with the changes I will push): What does Wrt I removed the class variable Can we do the same with I feel like we could do it if we move this clause in
into In
Would that work? If we can remove the class variable
I am not completely happy with the initialisations done in |
@brcekadam @ilyamandel I just pushed my changes |
@brcekadam -- yup, I see your point. And you can't expect to be able to access variables like m_MassLossRateInRLOF or functions like IsRLOF() because you don't necessarily have a binary star. OK, maybe this is the best we can do, though it feels like it may prove difficult to maintain in the future... |
Thank you, @jeffriley! You're right, I'll change the name to I actually wasn't familiar with static variables! I was doing a bit of testing and if I understand it correctly, Regarding the initialisation... I'll keep this in mind when starting evolution at different stellar types is implemented. I'll have to change a few things anyway, since we don't necessarily know what the core mass at TAMS is without fully evolving the star through the MS. Maybe I could do a fit of the data that's shown in the first plot (core mass at TAMS vs. initial mass), so that we know what the core mass at TAMS is for a given initial mass, and then that core mass value will be initialised post-MS. I'll be happy to work on this in the future. One thing I was also thinking about it is how the initialisation in |
Ah, yes - my mistake. In c++, a static local variable belongs to the class, not an instance of the class - so the behaviour you are seeing is expected (all instances of a class share the same static local variable) (I had forgotten that - I have always thought the implementation is not right - I think it makes more sense for the static local variable to belong to the instance, not the class, but apparently the c++ standard developers don't agree with me...). We can get around it though :-) In the code below I declare a static local variable that is actually a map, where the key is the instance id and the value is the value we want to store (in the code below, just an integer). Accessing the map variable using the instance id (
EDIT: the code above produces the following output
end edit (Aside: the way static local variables are implemented in c++ does open up the possibility that constituents of a binary star could actually share data - that could be interesting (even just to share signals/messages)).
Unless @ilyamandel or @veome22 changed this (and I confess I don't remember), CH stars don't spin down - or at least they don't change stellar type if they do. EDIT:
Clones could affect that, but still shouldn't impose too much overhead - we can keep an eye on that. |
Hmmm. Actually... I suspect the map in the code above might be used for every star/binary in the run... That could impose a bit more overhead than I thought... Maybe going back to using a class variable is better. We could test performance I suppose, but I think a class variable is safer. Bummer... |
I have just pushed the final changes! I renamed the |
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.
All good - thanks @brcekadam !
I can't find anywhere in the code where we distinguish between CHE_MODE::PESSIMISTIC and CHE_MODE::OPTIMISTIC. We clearly should, but you are right, we seem to ignore this setting! That's a bug, right, @jeffriley? |
Yes, it would seem it is a bug... I'm sure that functionality was once in
the code...
…On Fri, 17 Jan 2025, 5:24 pm Ilya Mandel, ***@***.***> wrote:
Unless @ilyamandel <https://github.com/ilyamandel> or @veome22
<https://github.com/veome22> changed this (and I confess I don't
remember), CH stars don't spin down - or at least they don't change stellar
type if they do.
I can't find anywhere in the code where we distinguish between
CHE_MODE::PESSIMISTIC and CHE_MODE::OPTIMISTIC. We clearly should, but you
are write, we seem to ignore this setting! That's a bug, right, @jeffriley
<https://github.com/jeffriley>?
—
Reply to this email directly, view it on GitHub
<#1292 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AGM5XNSGHZCXDA5PLZ3PMU32LCOY3AVCNFSM6AAAAABST6UFESVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDKOJXGUZDGNJQGQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
@jeffriley : I created a new issue, #1323 . |
This PR addresses the underestimation of convective core masses for mass-losing main sequence (MS) stars in COMPAS by implementing the Shikauchi et al. (2024) prescription (https://arxiv.org/abs/2409.00460). This is my first major PR and also my first C++ project, so I will greatly appreciate any feedback. I am happy to discuss and make changes as needed! This PR adds the following functionality:
--main-sequence-core-mass-prescription
, which has the following modes:SHIKAUCHI
(uses the new implementation),MANDEL
(replaces the--retain-core-mass-during-caseA-mass-transfer
option),NONE
(no treatment for MS core mass).m_MainSequenceCoreMass
variable (replacingm_MinimumCoreMass
), and it is currently not part of the output.m_TotalMassLossRate
, which is generally equal to-m_Mdot
,but gets updated to the mass transfer rate (mass loss rate for donors and mass gain rate
for accretors) during a mass transfer episode
Things to keep in mind or improve:
MANDEL
option is used as a fallback.Plots:
Using the new prescription leads to significantly higher core masses at TAMS for single stars, especially for the more massive stars that experience significant mass loss during their life on the MS.
HR diagrams showing the updated SSE tracks.
In this plot, I am varying the initial separation of the binary to test how different extent of case A mass transfer affects the core mass at TAMS. The retained core mass is higher when using the new prescription.
Here is a more detailed view of what happens to the stars during case A mass transfer when the new prescription is used. I am only showing what happens to the stars while the donor is on the main sequence.