Skip to content

inf (divide-by-zero) in NS::CalculateAndSetPulsarParameters, NS::CalculateSpinDownRate(), and NS::SpinDownIsolatedPulsar() #1257

@jeffriley

Description

@jeffriley

Running COMPAS with:

./compas -n1 --random-seed 0

results in inf in NS::CalculateAndSetPulsarParameters in the following statement:

m_PulsarDetails.spinFrequency = _2_PI / (m_PulsarDetails.spinPeriod * SECONDS_IN_MS);

because CalculateBirthSpinPeriod() in this statement:

m_PulsarDetails.spinPeriod = CalculateBirthSpinPeriod();                // spin period in ms

returns 0.0 because the default PULSAR_BIRTH_SPIN_PERIOD_DISTRIBUTION is ZERO

void NS::CalculateAndSetPulsarParameters() {

    m_PulsarDetails.magneticField     = PPOW(10.0, CalculateBirthMagneticField()) * GAUSS_TO_TESLA;         // magnetic field in Gauss -> convert to Tesla
    m_PulsarDetails.spinPeriod        = CalculateBirthSpinPeriod();                                         // spin period in ms

    m_PulsarDetails.spinFrequency     = _2_PI / (m_PulsarDetails.spinPeriod * SECONDS_IN_MS);
    m_PulsarDetails.birthPeriod       = m_PulsarDetails.spinPeriod * SECONDS_IN_MS;                         // convert from ms to s 
    
    m_MomentOfInertia_CGS             = CalculateMomentOfInertiaCGS();                                      // in CGS g cm^2
	
    // Note we convert neutronStarMomentOfInertia from CGS to SI here
    m_PulsarDetails.spinDownRate      = CalculateSpinDownRate(m_PulsarDetails.spinFrequency, m_MomentOfInertia_CGS, 
    m_PulsarDetails.magneticField, m_Radius * RSOL_TO_KM);  
    m_PulsarDetails.birthSpinDownRate = m_PulsarDetails.spinDownRate; 
    m_AngularMomentum_CGS             = m_MomentOfInertia_CGS * m_PulsarDetails.spinFrequency;              // in CGS g cm^2 s^-1
}

The naive solution is to change the statement:

m_PulsarDetails.spinFrequency = _2_PI / (m_PulsarDetails.spinPeriod * SECONDS_IN_MS);

to:

m_PulsarDetails.spinFrequency = m_PulsarDetails.spinPeriod > 0.0 ? _2_PI / (m_PulsarDetails.spinPeriod * SECONDS_IN_MS) : 0.0;   // don't use utils::Compare() here

so that m_PulsarDetails.spinFrequency is set to 0.0 if CalculateBirthSpinPeriod() returns 0.0

@yuzhesong , @SimonStevenson, can you confirm that the suggestion above is the best solution?

A related problem occurs in NS::CalculateSpinDownRate(), when parameter p_Omega is passed as 0.0. This statement:

double period = _2_PI / p_Omega;                        // convert frequency to period

results in inf

double NS::CalculateSpinDownRate(const double p_Omega, const double p_MomentOfInteria, const double p_MagField, const double p_Radius) const {

    // pow() is slow - use multiplication

    double period            = _2_PI / p_Omega;                                                                 // convert frequency to period
    double cgsRadius         = p_Radius * KM_TO_CM;                                                             // radius in cm
    double radius_6          = cgsRadius * cgsRadius * cgsRadius * cgsRadius * cgsRadius * cgsRadius;
    double cgsMagField       = p_MagField * TESLA_TO_GAUSS;                                                     // B field in G
    double magField_2        = cgsMagField * cgsMagField;
    constexpr double _8_PI_2 = 8.0 * PI_2;
    constexpr double _3_C_3  = 3.0E6 * C * C * C;                                                               // 3.0 * (C * 100.0) * (C * 100.0) * (C * 100.0)
    double pDotTop           = _8_PI_2 * radius_6 * magField_2;
    double pDotBottom        = _3_C_3 * p_MomentOfInteria * period;
    double pDot              = pDotTop / pDotBottom;                                                            // period derivative 
   
    return -pDot * p_Omega / period;                                                                            // convert period derivative to frequency derivative, which is what is recorded in the output
}

The naive solution is to add the following sanity check as the first line of the function:

if (p_Omega<= 0.0) return 0.0;                                  // don't use utils::Compare() here

so we just return a spin down rate of 0.0 if the spin freqency passed in p_Omega is 0.0

@yuzhesong , @SimonStevenson, can you confirm that the suggestion above is the best solution?

A further related problem becomes evident when the above two problems are addressed: the following statement in NS::SpinDownIsolatedPulsar() results in inf:

double initialSpinPeriod = _2_PI / m_PulsarDetails.spinFrequency;

which can naively be fixed by replacing the statement with:

double initialSpinPeriod = m_PulsarDetails.spinFrequency > 0.0 ? _2_PI / m_PulsarDetails.spinFrequency : 0.0;    // don't use utils::Compare() here

But maybe there's a better solution - can we avoid calling some of these functions if the spin frequency is 0.0?

@yuzhesong, @SimonStevenson Is there a better fix overall when spin frequency is 0.0?

To Reproduce
Run COMPAS with:

./compas -n1 --random-seed 0

Expected behavior
Production code does not cause inf

**Versioning

OS: Ubuntu 22.04
COMPAS v03.07.01

Metadata

Metadata

Labels

bugSomething isn't workingseverity_majorThis is a severe bugurgency_moderateThis is a moderately urgent issue

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions