Skip to content

BUG: BNS parameter conversion can overwrite valid lambda_1 = 0 with a small negative value during post-processing #1114

Description

@physicish

Describe the bug

When convert_to_lal_binary_neutron_star_parameters receives a parameter dictionary containing both the component tidal deformabilities (lambda_1 and lambda_2) and the derived tidal parameters (lambda_tilde and delta_lambda_tilde), it reconstructs and overwrites the existing component values from the derived representation. Due to floating-point round-off, this conversion can change an explicitly supplied lambda_1 = 0.0 into a very small negative value.

I think this occurs during run_sampler post-processing because coversion_function=conversion_function=bilby.gw.conversion.generate_all_bns_parameters is applied to the injection parameters twice. The first call adds lambda_tilde and delta_lambda_tilde and the second call passes the filled dictionary back through convert_to_lal_binary_neutron_star_parameters, triggering the overwrite.

In my case, the (NSBH) injection specified:

lambda_1 = 0.0
lambda_2 = 1097.4026147742702

The sampler completed successfully and produced posterior samples. During post-processing, Bilby converted the injection parameters a second time. Since the first conversion had added lambda_tilde and delta_lambda_tilde, the second conversion reconstructed the component tidal deformabilities from those derived quantities. Due to floating-point round-off, the reconstructed value was approximately:

lambda_1 = -2.46e-14

LALSimulation printed this as:

lambda1 = -0.000000

and rejected the waveform because tidal deformabilities are required to be non-negative.

This appears to be caused by the following logic in convert_to_lal_binary_neutron_star_parameters:

if 'delta_lambda_tilde' in converted_parameters.keys():
    converted_parameters['lambda_1'], converted_parameters['lambda_2'] =\
        lambda_tilde_delta_lambda_tilde_to_lambda_1_lambda_2(
            converted_parameters['lambda_tilde'],
            parameters['delta_lambda_tilde'],
            converted_parameters['mass_1'],
            converted_parameters['mass_2'])
elif 'lambda_tilde' in converted_parameters.keys():
    converted_parameters['lambda_1'], converted_parameters['lambda_2'] =\
        lambda_tilde_to_lambda_1_lambda_2(
            converted_parameters['lambda_tilde'],
            converted_parameters['mass_1'],
            converted_parameters['mass_2'])

These lines overwrite lambda_1 and lambda_2 even when both component values are already present and valid.

To Reproduce

A minimal reproducer:

import bilby

parameters = {
    "mass_1": 7.320188129088971,
    "mass_2": 1.4957247709090036,
    "lambda_1": 0.0,
    "lambda_2": 1097.4026147742702,
}

first_conversion = bilby.gw.conversion.generate_all_bns_parameters(
    parameters
)

print("After first conversion:")
print("lambda_1 =", repr(first_conversion["lambda_1"]))
print("lambda_2 =", repr(first_conversion["lambda_2"]))
print("lambda_tilde =", repr(first_conversion["lambda_tilde"]))
print(
    "delta_lambda_tilde =",
    repr(first_conversion["delta_lambda_tilde"]),
)

second_conversion, _ = (
    bilby.gw.conversion.convert_to_lal_binary_neutron_star_parameters(
        first_conversion
    )
)

print("After second conversion:")
print("lambda_1 =", repr(second_conversion["lambda_1"]))
print("lambda_2 =", repr(second_conversion["lambda_2"]))

For the values above, the second conversion produces a value close to:

lambda_1 = -2.45587692656649e-14

In my run, the relevant runtime sequence was:

bilby INFO    : Rejection sampling nested samples to obtain 6335 posterior samples
bilby INFO    : Sampling time: 1 day, 3:24:28.088555
bilby WARNING : Result.save_to_file called with extension=True. This will default to json, and ignore the extension from the filename.

The failure then occurred after sampling.

Error message

XLAL Error - XLALStoreTidalParametersFromLambdas (LALSimIMRPhenomXHM_tidal.c:71): Tidal deformabilities cannot be negative. Value in LALDict are lambda1 = -0.000000, lambda2 = 1097.402615.
XLAL Error - XLALStoreTidalParametersFromLambdas (LALSimIMRPhenomXHM_tidal.c:71): Invalid argument
XLAL Error - IMRPhenomXSetWaveformVariables (LALSimIMRPhenomX_internals.c:306): Failed to set tidal parameters from lambdas.

XLAL Error - IMRPhenomXSetWaveformVariables (LALSimIMRPhenomX_internals.c:306): Internal function call failed: Invalid argument
XLAL Error - XLALSimIMRPhenomXHMFrequencySequence (LALSimIMRPhenomXHM.c:1785): Error: IMRPhenomXSetWaveformVariables failed.

XLAL Error - XLALSimIMRPhenomXHMFrequencySequence (LALSimIMRPhenomXHM.c:1785): Internal function call failed: Invalid argument
XLAL Error - XLALSimInspiralChooseFDWaveformSequence (LALSimInspiralWaveformCache.c:1710): Internal function call failed: Invalid argument
Traceback (most recent call last):
  File "/ligo/home/ligo.org/ish.gupta/Projects/nsbh_hom/tests/test1/phenom-nsbh/run_1/ECC/runs/run_1/run.py", line 199, in <module>
    result = bilby.run_sampler(
             ^^^^^^^^^^^^^^^^^^
  File "/scratch2/ligo.org/ish.gupta/conda-envs/nsbh-hom/src/bilby/bilby/core/sampler/__init__.py", line 358, in run_sampler
    result.injection_parameters = conversion_function(
                                  ^^^^^^^^^^^^^^^^^^^^
  File "/scratch2/ligo.org/ish.gupta/conda-envs/nsbh-hom/src/bilby/bilby/gw/conversion.py", line 1758, in generate_all_bns_parameters
    output_sample = _generate_all_cbc_parameters(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/scratch2/ligo.org/ish.gupta/conda-envs/nsbh-hom/src/bilby/bilby/gw/conversion.py", line 1653, in _generate_all_cbc_parameters
    compute_per_detector_log_likelihoods(
  File "/scratch2/ligo.org/ish.gupta/conda-envs/nsbh-hom/src/bilby/bilby/gw/conversion.py", line 2317, in compute_per_detector_log_likelihoods
    samples = likelihood.compute_per_detector_log_likelihood(samples)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/scratch2/ligo.org/ish.gupta/conda-envs/nsbh-hom/src/bilby/bilby/gw/likelihood/base.py", line 482, in compute_per_detector_log_likelihood
    self.waveform_generator.frequency_domain_strain(parameters)
  File "/scratch2/ligo.org/ish.gupta/conda-envs/nsbh-hom/src/bilby/bilby/gw/waveform_generator.py", line 135, in frequency_domain_strain
    return self._calculate_strain(model=self.frequency_domain_source_model,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/scratch2/ligo.org/ish.gupta/conda-envs/nsbh-hom/src/bilby/bilby/gw/waveform_generator.py", line 197, in _calculate_strain
    model_strain = self._strain_from_model(model_data_points, model, parameters, xp=xp)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/scratch2/ligo.org/ish.gupta/conda-envs/nsbh-hom/src/bilby/bilby/gw/waveform_generator.py", line 214, in _strain_from_model
    return model(model_data_points, **parameters)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/scratch2/ligo.org/ish.gupta/conda-envs/nsbh-hom/src/bilby/bilby/gw/source.py", line 795, in lal_binary_neutron_star_relative_binning
    return _base_waveform_frequency_sequence(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/scratch2/ligo.org/ish.gupta/conda-envs/nsbh-hom/src/bilby/bilby/gw/source.py", line 1125, in _base_waveform_frequency_sequence
    h_plus, h_cross = lalsim_SimInspiralChooseFDWaveformSequence(
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/scratch2/ligo.org/ish.gupta/conda-envs/nsbh-hom/src/bilby/bilby/gw/utils.py", line 743, in lalsim_SimInspiralChooseFDWaveformSequence
    return SimInspiralChooseFDWaveformSequence(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: Internal function call failed: Invalid argument

Expected behavior

When both lambda_1 and lambda_2 are already present and non-None, Bilby should preserve those component values.

Derived quantities such as lambda_tilde and delta_lambda_tilde should not take precedence over explicitly supplied component tidal deformabilities during a subsequent conversion.

Suggested solution (optional)

Only reconstruct lambda_1 and lambda_2 from the combined tidal quantities when valid component lambdas are not already available.

For example:

have_component_lambdas = all(
    key in converted_parameters
    and converted_parameters[key] is not None
    for key in ("lambda_1", "lambda_2")
)

if (
    "delta_lambda_tilde" in converted_parameters
    and not have_component_lambdas
):
    converted_parameters["lambda_1"], converted_parameters["lambda_2"] = (
        lambda_tilde_delta_lambda_tilde_to_lambda_1_lambda_2(
            converted_parameters["lambda_tilde"],
            converted_parameters["delta_lambda_tilde"],
            converted_parameters["mass_1"],
            converted_parameters["mass_2"],
        )
    )

elif (
    "lambda_tilde" in converted_parameters
    and not have_component_lambdas
):
    converted_parameters["lambda_1"], converted_parameters["lambda_2"] = (
        lambda_tilde_to_lambda_1_lambda_2(
            converted_parameters["lambda_tilde"],
            converted_parameters["mass_1"],
            converted_parameters["mass_2"],
        )
    )

This would:

  1. Preserve explicitly available lambda_1 and lambda_2.
  2. Reconstruct component lambdas from lambda_tilde and delta_lambda_tilde only when the component representation is unavailable.

Environment

  • Bilby version: 2.8.0.dev60+g28fca2270
  • Installation method: source installation inside a Conda environment
  • Python version: 3.11
  • Dynesty version: 3.0.0
  • LAL version: 7.6.1.1
  • LALSimulation version: 6.1.0.1
  • Waveform approximant: IMRPhenomXHM_NSBH (private repo)
  • Source model: bilby.gw.source.lal_binary_neutron_star_relative_binning

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions