Skip to content

Commit 0192277

Browse files
authored
Merge pull request #1433 from TeamCOMPAS/Hamstars
First implementation of HAMSTARS mass transfer efficiency
2 parents d224356 + 326930c commit 0192277

File tree

10 files changed

+57
-47
lines changed

10 files changed

+57
-47
lines changed

compas_python_utils/preprocessing/compasConfigDefault.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
##~!!~## COMPAS option values
2-
##~!!~## File Created Tue Aug 19 15:39:23 2025 by COMPAS v03.25.00
2+
##~!!~## File Created Tue Sep 2 22:42:52 2025 by COMPAS v03.26.00
33
##~!!~##
44
##~!!~## The default COMPAS YAML file (``compasConfigDefault.yaml``), as distributed, has
55
##~!!~## all COMPAS option entries commented so that the COMPAS default value for the
@@ -264,7 +264,7 @@ stringChoices:
264264
# --critical-mass-ratio-prescription: 'NONE' # Default: 'NONE' # Options: ['HURLEY_HJELLMING_WEBBINK','GE','GE_IC','CLAEYS','NONE']
265265
# --stellar-zeta-prescription: 'SOBERMAN' # Default: 'SOBERMAN' # Options: ['ARBITRARY','HURLEY','SOBERMAN']
266266
# --mass-transfer-angular-momentum-loss-prescription: 'ISOTROPIC' # Default: 'ISOTROPIC' # Options: ['ARBITRARY','KLENCKI_LINEAR','MACLEOD_LINEAR','CIRCUMBINARY','ISOTROPIC','JEANS']
267-
# --mass-transfer-accretion-efficiency-prescription: 'THERMAL' # Default: 'THERMAL' # Options: ['FIXED','THERMAL']
267+
# --mass-transfer-accretion-efficiency-prescription: 'THERMAL' # Default: 'THERMAL' # Options: ['HAMSTARS','FIXED','THERMAL']
268268
# --mass-transfer-rejuvenation-prescription: 'STARTRACK' # Default: 'STARTRACK' # Options: ['STARTRACK','HURLEY']
269269
# --mass-transfer-thermal-limit-accretor-multiplier: 'CFACTOR' # Default: 'CFACTOR' # Options: ['ROCHELOBE','CFACTOR']
270270
# --response-to-spin-up: 'TRANSFER_TO_ORBIT' # Default: 'TRANSFER_TO_ORBIT' # Options: ['NO_LIMIT','KEPLERIAN_LIMIT','TRANSFER_TO_ORBIT']

online-docs/pages/User guide/Program options/program-options-list-defaults.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,7 @@ DEPRECATION NOTICE: this option has been deprecated and will soon be removed. Pl
887887

888888
**--mass-transfer-accretion-efficiency-prescription** |br|
889889
Mass transfer accretion efficiency prescription. |br|
890-
Options: { THERMAL, FIXED } |br|
890+
Options: { THERMAL, FIXED, HAMSTARS } |br|
891891
Default = THERMAL
892892

893893
**--mass-transfer-angular-momentum-loss-prescription** |br|

online-docs/pages/whats-new.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ What's new
33

44
Following is a brief list of important updates to the COMPAS code. A complete record of changes can be found in the file ``changelog.h``.
55

6+
**03.26.00 September 2, 2025**
7+
8+
* Added HAMSTARS mass transfer efficiency prescription
9+
610
**03.25.00 August 19, 2025**
711

812
* Added KLENCKI_LINEAR AM loss, which is linear in the specific AM gamma instead of the orbital separation (as in MACLEOD_LINEAR).

src/BaseBinaryStar.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2092,7 +2092,7 @@ void BaseBinaryStar::CalculateMassTransfer(const double p_Dt) {
20922092
// can the mass transfer happen on a nuclear timescale?
20932093
if (m_Donor->IsOneOf(NON_COMPACT_OBJECTS)) {
20942094
// if MT_ACCRETION_EFFICIENCY_PRESCRIPTION::FIXED_FRACTION, then CalculateMassAcceptanceRate() already computed the correct m_FractionAccreted and massDiffDonor (no difference between nuclear and thermal timescale MT)
2095-
if (OPTIONS->MassTransferAccretionEfficiencyPrescription() == MT_ACCRETION_EFFICIENCY_PRESCRIPTION::THERMALLY_LIMITED) {
2095+
if (OPTIONS->MassTransferAccretionEfficiencyPrescription() == MT_ACCRETION_EFFICIENCY_PRESCRIPTION::THERMALLY_LIMITED || OPTIONS->MassTransferAccretionEfficiencyPrescription() == MT_ACCRETION_EFFICIENCY_PRESCRIPTION::HAMSTARS) {
20962096
// technically, we do not know how much mass the accretor should gain until we do the calculation,
20972097
// which impacts the RL size, so we will check whether a nuclear timescale MT was feasible later
20982098
massDiffDonor = MassLossToFitInsideRocheLobe(this, m_Donor, m_Accretor, -1.0, m_Dt); // use root solver to determine how much mass should be lost from the donor to allow it to fit within the Roche lobe, estimating accretion efficiency based on a mass donation rate of massDiffDonor/m_Dt for self-consistency

src/BaseStar.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,12 +2713,17 @@ DBL_DBL BaseStar::CalculateMassAcceptanceRate(const double p_DonorMassRate, cons
27132713

27142714
switch (OPTIONS->MassTransferAccretionEfficiencyPrescription()) {
27152715

2716-
case MT_ACCRETION_EFFICIENCY_PRESCRIPTION::THERMALLY_LIMITED: // thermally limited mass transfer:
2717-
2716+
case MT_ACCRETION_EFFICIENCY_PRESCRIPTION::THERMALLY_LIMITED: // thermally limited mass transfer
27182717
acceptanceRate = min(OPTIONS->MassTransferCParameter() * p_AccretorMassRate, p_DonorMassRate);
27192718
fractionAccreted = acceptanceRate / p_DonorMassRate;
27202719
break;
27212720

2721+
case MT_ACCRETION_EFFICIENCY_PRESCRIPTION::HAMSTARS: // thermally limited mass transfer, following Lau+, 2024
2722+
// the mass transfer C parameter is fit using the data from Figure (1) of Lau+, 2024
2723+
acceptanceRate = min(PPOW(10.0, (4.0 / PPOW((Mass() + 0.2), 0.3) - 0.6)) * p_AccretorMassRate, p_DonorMassRate);
2724+
fractionAccreted = acceptanceRate / p_DonorMassRate;
2725+
break;
2726+
27222727
case MT_ACCRETION_EFFICIENCY_PRESCRIPTION::FIXED_FRACTION: // fixed fraction of mass accreted, as in StarTrack
27232728
fractionAccreted = OPTIONS->MassTransferFractionAccreted();
27242729
acceptanceRate = min(p_DonorMassRate, fractionAccreted * p_DonorMassRate);

src/CH.cpp

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -286,36 +286,33 @@ void CH::UpdateAgeAfterMassLoss() {
286286

287287

288288
/*
289-
* Calculate the weight for the OB and WR mass loss prescriptions
289+
* CalculateMassLossFractionOB
290290
*
291-
* According to the prescription described in Yoon et al. 2006 (and Szecsi et al. 2015)
292-
* Use OB mass loss rates until Y1 = 0.55, WR mass loss rates above Y2 = 0.7, and
293-
* linearly interpolate for Y1 < Ys < Y2 where Ys is the surface helium fraction.
294-
*
295-
* Since we don't have Ys by default in our models, and detailed models show Ys
296-
* rises ~linearly from 0.2 to 1.0 across the main-sequence, here we simply
297-
* use tau = t / tMS as a proxy for Ys.
291+
* @brief
292+
* Calculate the fraction of mass loss attributable to OB mass loss, per Yoon et al. 2006
293+
*
294+
* The model described in Yoon et al. 2006 (also Szecsi et al. 2015) uses OB mass loss while the
295+
* He surface abundance is below 0.55, WR mass loss when the surface He abundance is above 0.7,
296+
* and linearly interpolate when the He surface abundance is between those limits.
297+
*
298+
* This function calculates the fraction of mass loss attributable to OB mass loss, based on
299+
* the He surface abundance and the abundance limits described in Yoon et al. 2006. The value
300+
* returned will be 1.0 if 100% of the mass loss is attributable to OB mass lass, 0.0 if 100% of
301+
* the mass loss is attributable to WR mass loss, and in the range (0.0, 1.0) if the mass loss is
302+
* a mix of OB and WR.
298303
*
299-
* CalculateMassLossRateWeightOB(const double p_HeliumAbundanceSurface)
300304
*
301-
* @param [IN] p_HeliumAbundanceSurface Surface helium abundance Ys
305+
* double CalculateMassLossFractionOB(const double p_HeAbundanceSurface) const
302306
*
303-
* @return weight for OB mass loss rate
307+
* @param p_HeAbundanceSurface Helium abundance at the surface of the star
308+
* @return Fraction of mass loss attributable to OB mass loss
304309
*/
305-
double CH::CalculateMassLossRateWeightOB(const double p_HeliumAbundanceSurface) {
306-
307-
const double y1 = 0.55;
308-
const double y2 = 0.70;
309-
double Ys = p_HeliumAbundanceSurface; // Get surface helium abundance
310-
double weight = 0.0;
311-
310+
double CH::CalculateMassLossFractionOB(const double p_HeAbundanceSurface) const {
312311

313-
// Calculate the weight as a function of Ys according to the prescription from Yoon et al. 2006
314-
if (Ys < y1) weight = 1.0;
315-
else if (Ys > y2) weight = 0.0;
316-
else weight = (y2 - Ys) / y2 - y1;
312+
constexpr double limOB = 0.55; // per Yoon et al. 2006
313+
constexpr double limWR = 0.70; // per Yoon et al. 2006
317314

318-
return weight;
315+
return std::min(1.0, std::max (0.0, (limWR - p_HeAbundanceSurface) / (limWR - limOB)));
319316
}
320317

321318

@@ -337,7 +334,7 @@ double CH::CalculateMassLossRateBelczynski2010() {
337334
double Mdot = 0.0;
338335
double MdotOB = 0.0;
339336
double MdotWR = 0.0;
340-
double weight = 1.0; // Initialised to 1.0 to allow us to use the OB mass loss rate by default
337+
double fractionOB = 1.0; // Initialised to 1.0 to allow us to use the OB mass loss rate by default
341338

342339
// Calculate OB mass loss rate according to the Vink et al. formalism
343340
MdotOB = BaseStar::CalculateMassLossRateBelczynski2010();
@@ -348,16 +345,16 @@ double CH::CalculateMassLossRateBelczynski2010() {
348345
// Calculate WR mass loss rate
349346
MdotWR = BaseStar::CalculateMassLossRateWolfRayetZDependent(0.0);
350347

351-
// Calculate weight for combining these into total mass-loss rate
352-
weight = CalculateMassLossRateWeightOB(m_HeliumAbundanceSurface);
348+
// Calculate fraction for combining these into total mass-loss rate
349+
fractionOB = CalculateMassLossFractionOB(m_HeliumAbundanceSurface);
353350

354351
}
355352

353+
// Finally, combine each of these prescriptions according to the OB wind fraction
354+
Mdot = (fractionOB * MdotOB) + ((1.0 - fractionOB) * MdotWR);
355+
356356
// Set dominant mass loss rate
357-
m_DominantMassLossRate = weight == 0 ? MASS_LOSS_TYPE::WR : MASS_LOSS_TYPE::OB;
358-
359-
// Finally, combine each of these prescriptions according to the weight
360-
Mdot = (weight * MdotOB) + ((1.0 - weight) * MdotWR);
357+
m_DominantMassLossRate = (fractionOB * MdotOB) > ((1.0 - fractionOB) * MdotWR) ? MASS_LOSS_TYPE::OB : MASS_LOSS_TYPE::WR;
361358

362359
// Enhance mass loss rate due to rotation
363360
Mdot *= CalculateMassLossRateEnhancementRotation();
@@ -384,7 +381,7 @@ double CH::CalculateMassLossRateMerritt2025() {
384381
double Mdot = 0.0;
385382
double MdotOB = 0.0;
386383
double MdotWR = 0.0;
387-
double weight = 1.0; // Initialised to 1.0 to allow us to use the OB mass loss rate by default
384+
double fractionOB = 1.0; // Initialised to 1.0 to allow us to use the OB mass loss rate by default
388385

389386
// Calculate OB mass loss rate according to the chosen prescription
390387
MdotOB = BaseStar::CalculateMassLossRateOB(OPTIONS->OBMassLossPrescription());
@@ -400,14 +397,14 @@ double CH::CalculateMassLossRateMerritt2025() {
400397
delete clone; clone = nullptr; // return the memory allocated for the clone
401398

402399
// Calculate weight for combining these into total mass-loss rate
403-
weight = CalculateMassLossRateWeightOB(m_HeliumAbundanceSurface);
400+
fractionOB = CalculateMassLossFractionOB(m_HeliumAbundanceSurface);
404401
}
405402

403+
// Finally, combine each of these prescriptions according to the OB wind fraction
404+
Mdot = (fractionOB * MdotOB) + ((1.0 - fractionOB) * MdotWR);
405+
406406
// Set dominant mass loss rate
407-
m_DominantMassLossRate = weight == 0 ? MASS_LOSS_TYPE::WR : MASS_LOSS_TYPE::OB;
408-
409-
// Finally, combine each of these prescriptions according to the weight
410-
Mdot = (weight * MdotOB) + ((1.0 - weight) * MdotWR);
407+
m_DominantMassLossRate = (fractionOB * MdotOB) > ((1.0 - fractionOB) * MdotWR) ? MASS_LOSS_TYPE::OB : MASS_LOSS_TYPE::WR;
411408

412409
// Enhance mass loss rate due to rotation
413410
Mdot *= CalculateMassLossRateEnhancementRotation();

src/CH.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class CH: virtual public BaseStar, public MS_gt_07 {
7474
// Mass loss rate
7575
double CalculateMassLossRateBelczynski2010();
7676
double CalculateMassLossRateMerritt2025();
77-
double CalculateMassLossRateWeightOB(const double p_HeliumAbundanceSurface);
77+
double CalculateMassLossFractionOB(const double p_HeAbundanceSurface) const;
7878

7979
// Radius
8080
double CalculateRadiusOnPhase() const { return m_RZAMS; } // Constant from birth

src/Options.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2442,7 +2442,7 @@ std::string Options::OptionValues::CheckAndSetOptions() {
24422442

24432443
if (m_UseMassTransfer && !DEFAULTED("mass-transfer-accretion-efficiency-prescription")) { // mass transfer accretion efficiency prescription
24442444
std::tie(found, m_MassTransferAccretionEfficiencyPrescription.type) = utils::GetMapKey(m_MassTransferAccretionEfficiencyPrescription.typeString, MT_ACCRETION_EFFICIENCY_PRESCRIPTION_LABEL, m_MassTransferAccretionEfficiencyPrescription.type);
2445-
COMPLAIN_IF(!found, "Unknown Mass Transfer Angular Momentum Loss Prescription");
2445+
COMPLAIN_IF(!found, "Unknown Mass Transfer Efficiency Prescription");
24462446
}
24472447

24482448
if (m_UseMassTransfer && !DEFAULTED("mass-transfer-angular-momentum-loss-prescription")) { // mass transfer angular momentum loss prescription

src/changelog.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1664,6 +1664,9 @@
16641664
// - Corrected calculation for Hurley Gamma constant C (C_GAMMA - see Hurley et al. 2000, just after eq 23, should use a(75) <= 1.0, not a(75) == 1.0 - confirmed in BSE Fortran source)
16651665
// - Added abs() to gamma calculation in Mainsequence.cpp::CalculateGamma() (per BSE Fortran source)
16661666
// - Clamped gamma to [0.0, gamma] in Mainsequence.cpp::CalculateGamma() (per discussion just after eq 23 - confirmed in BSE Fortran source)
1667+
// 03.26.00 IM - September 2, 2025 - Enhancement, defect repairs:
1668+
// - First (simplified) implementation of the Lau+ (2024) Hamstars thermally limited accretion prescription
1669+
// - Corrected errors in combining OB and WR winds in CH::CalculateMassLossRateBelczynski2010(), CalculateMassLossRateMerritt2025() and CH::CalculateMassLossFractionOB() [previously CalculateMassLossRateWeightOB()]
16671670
//
16681671
// Version string format is MM.mm.rr, where
16691672
//
@@ -1674,7 +1677,7 @@
16741677
// if MM is incremented, set mm and rr to 00, even if defect repairs and minor enhancements were also made
16751678
// if mm is incremented, set rr to 00, even if defect repairs were also made
16761679

1677-
const std::string VERSION_STRING = "03.25.02";
1680+
const std::string VERSION_STRING = "03.26.00";
16781681

16791682

16801683
# endif // __changelog_h__

src/typedefs.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -643,10 +643,11 @@ const COMPASUnorderedMap<METALLICITY_DISTRIBUTION, std::string> METALLICITY_DIST
643643
};
644644

645645
// mass transfer accretion efficiency prescriptions
646-
enum class MT_ACCRETION_EFFICIENCY_PRESCRIPTION: int { THERMALLY_LIMITED, FIXED_FRACTION };
646+
enum class MT_ACCRETION_EFFICIENCY_PRESCRIPTION: int { THERMALLY_LIMITED, FIXED_FRACTION, HAMSTARS };
647647
const COMPASUnorderedMap<MT_ACCRETION_EFFICIENCY_PRESCRIPTION, std::string> MT_ACCRETION_EFFICIENCY_PRESCRIPTION_LABEL = {
648648
{ MT_ACCRETION_EFFICIENCY_PRESCRIPTION::THERMALLY_LIMITED, "THERMAL" },
649-
{ MT_ACCRETION_EFFICIENCY_PRESCRIPTION::FIXED_FRACTION, "FIXED" }
649+
{ MT_ACCRETION_EFFICIENCY_PRESCRIPTION::FIXED_FRACTION, "FIXED" },
650+
{ MT_ACCRETION_EFFICIENCY_PRESCRIPTION::HAMSTARS, "HAMSTARS"}
650651
};
651652

652653
// mass transfer angular momentum loss prescriptions

0 commit comments

Comments
 (0)