diff --git a/AUTHORS.md b/AUTHORS.md
index 32f41f250997c53eaa77e2217a7a7326c3be4081..42d22edbc19da2e09d4d7d1d98581acde8fddfb7 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -78,3 +78,4 @@ Tathagata Ghosh
 Virginia d'Emilio
 Vivien Raymond
 Ka-Lok Lo
+Isaac Legred
\ No newline at end of file
diff --git a/bilby/gw/conversion.py b/bilby/gw/conversion.py
index b494dca9f4a947f63cce12004bae181c478e5c7e..24ae47ba406f2d46e10d7c781c1dcc1f5083f45f 100644
--- a/bilby/gw/conversion.py
+++ b/bilby/gw/conversion.py
@@ -210,67 +210,8 @@ def convert_to_lal_binary_black_hole_parameters(parameters):
             converted_parameters[key[:-7]] = converted_parameters[key] * (
                 1 + converted_parameters['redshift'])
 
-    if 'chirp_mass' in converted_parameters.keys():
-        if "mass_1" in converted_parameters.keys():
-            converted_parameters["mass_ratio"] = chirp_mass_and_primary_mass_to_mass_ratio(
-                converted_parameters["chirp_mass"], converted_parameters["mass_1"])
-        if 'total_mass' in converted_parameters.keys():
-            converted_parameters['symmetric_mass_ratio'] =\
-                chirp_mass_and_total_mass_to_symmetric_mass_ratio(
-                    converted_parameters['chirp_mass'],
-                    converted_parameters['total_mass'])
-        if 'symmetric_mass_ratio' in converted_parameters.keys() and "mass_ratio" not in converted_parameters:
-            converted_parameters['mass_ratio'] =\
-                symmetric_mass_ratio_to_mass_ratio(
-                    converted_parameters['symmetric_mass_ratio'])
-        if 'total_mass' not in converted_parameters.keys():
-            converted_parameters['total_mass'] =\
-                chirp_mass_and_mass_ratio_to_total_mass(
-                    converted_parameters['chirp_mass'],
-                    converted_parameters['mass_ratio'])
-        converted_parameters['mass_1'], converted_parameters['mass_2'] = \
-            total_mass_and_mass_ratio_to_component_masses(
-                converted_parameters['mass_ratio'],
-                converted_parameters['total_mass'])
-    elif 'total_mass' in converted_parameters.keys():
-        if 'symmetric_mass_ratio' in converted_parameters.keys():
-            converted_parameters['mass_ratio'] = \
-                symmetric_mass_ratio_to_mass_ratio(
-                    converted_parameters['symmetric_mass_ratio'])
-        if 'mass_ratio' in converted_parameters.keys():
-            converted_parameters['mass_1'], converted_parameters['mass_2'] =\
-                total_mass_and_mass_ratio_to_component_masses(
-                    converted_parameters['mass_ratio'],
-                    converted_parameters['total_mass'])
-        elif 'mass_1' in converted_parameters.keys():
-            converted_parameters['mass_2'] =\
-                converted_parameters['total_mass'] -\
-                converted_parameters['mass_1']
-        elif 'mass_2' in converted_parameters.keys():
-            converted_parameters['mass_1'] = \
-                converted_parameters['total_mass'] - \
-                converted_parameters['mass_2']
-    elif 'symmetric_mass_ratio' in converted_parameters.keys():
-        converted_parameters['mass_ratio'] =\
-            symmetric_mass_ratio_to_mass_ratio(
-                converted_parameters['symmetric_mass_ratio'])
-        if 'mass_1' in converted_parameters.keys():
-            converted_parameters['mass_2'] =\
-                converted_parameters['mass_1'] *\
-                converted_parameters['mass_ratio']
-        elif 'mass_2' in converted_parameters.keys():
-            converted_parameters['mass_1'] =\
-                converted_parameters['mass_2'] /\
-                converted_parameters['mass_ratio']
-    elif 'mass_ratio' in converted_parameters.keys():
-        if 'mass_1' in converted_parameters.keys():
-            converted_parameters['mass_2'] =\
-                converted_parameters['mass_1'] *\
-                converted_parameters['mass_ratio']
-        if 'mass_2' in converted_parameters.keys():
-            converted_parameters['mass_1'] = \
-                converted_parameters['mass_2'] /\
-                converted_parameters['mass_ratio']
+    # we do not require the component masses be added if no mass parameters are present
+    converted_parameters = generate_component_masses(converted_parameters, require_add=False)
 
     for idx in ['1', '2']:
         key = 'chi_{}'.format(idx)
@@ -480,6 +421,33 @@ def total_mass_and_mass_ratio_to_component_masses(mass_ratio, total_mass):
     return mass_1, mass_2
 
 
+def chirp_mass_and_mass_ratio_to_component_masses(chirp_mass, mass_ratio):
+    """
+    Convert total mass and mass ratio of a binary to its component masses.
+
+    Parameters
+    ==========
+    chirp_mass: float
+        Chirp mass of the binary
+    mass_ratio: float
+        Mass ratio (mass_2/mass_1) of the binary
+
+    Returns
+    =======
+    mass_1: float
+        Mass of the heavier object
+    mass_2: float
+        Mass of the lighter object
+    """
+    total_mass = chirp_mass_and_mass_ratio_to_total_mass(chirp_mass=chirp_mass,
+                                                         mass_ratio=mass_ratio)
+    mass_1, mass_2 = (
+        total_mass_and_mass_ratio_to_component_masses(
+            total_mass=total_mass, mass_ratio=mass_ratio)
+    )
+    return mass_1, mass_2
+
+
 def symmetric_mass_ratio_to_mass_ratio(symmetric_mass_ratio):
     """
     Convert the symmetric mass ratio to the normal mass ratio.
@@ -678,6 +646,30 @@ def mass_1_and_chirp_mass_to_mass_ratio(mass_1, chirp_mass):
     return mass_ratio
 
 
+def mass_2_and_chirp_mass_to_mass_ratio(mass_2, chirp_mass):
+    """
+    Calculate mass ratio from mass_1 and chirp_mass.
+
+    This involves solving mc = m2 * (1/q)**(3/5) / (1 + (1/q))**(1/5).
+
+    Parameters
+    ==========
+    mass_2: float
+        Mass of the lighter object
+    chirp_mass: float
+        Chirp mass of the binary
+
+    Returns
+    =======
+    mass_ratio: float
+        Mass ratio of the binary
+    """
+    # Passing mass_2, the expression from the function above
+    # returns 1/q (because chirp mass is invariant under
+    # mass_1 <-> mass_2)
+    return 1 / mass_1_and_chirp_mass_to_mass_ratio(mass_2, chirp_mass)
+
+
 def lambda_1_lambda_2_to_lambda_tilde(lambda_1, lambda_2, mass_1, mass_2):
     """
     Convert from individual tidal parameters to domainant tidal term.
@@ -1009,33 +1001,192 @@ def fill_from_fixed_priors(sample, priors):
     return output_sample
 
 
+def generate_component_masses(sample, require_add=False):
+    """"
+    Add the component masses to the dataframe/dictionary
+    We add:
+        mass_1, mass_2
+    We also add any other masses which may be necessary for
+    intermediate steps, i.e. typically the  total mass is necessary, along
+    with the mass ratio, so these will usually be added to the dictionary
+
+    If `require_add` is True, then having an incomplete set of mass
+    parameters (so that the component mass parameters cannot be added)
+    will throw an error, otherwise it will quietly add nothing to the
+    dictionary.
+
+    Parameters
+    =========
+    sample : dict
+        The input dictionary with at least one
+        component with overall mass scaling (i.e.
+        chirp_mass, mass_1, mass_2, total_mass) and
+        then any other mass parameter.
+
+    Returns
+    dict : the updated dictionary
+    """
+    def check_and_return_quietly(require_add, sample):
+        if require_add:
+            raise KeyError("Insufficient mass parameters in input dictionary")
+        else:
+            return sample
+    output_sample = sample.copy()
+    if "mass_1" in sample.keys():
+        if "mass_2" in sample.keys():
+            return output_sample
+        if "total_mass" in sample.keys():
+            output_sample["mass_2"] = output_sample["total_mass"] - (
+                output_sample["mass_1"]
+            )
+            return output_sample
+
+        elif "mass_ratio" in sample.keys():
+            pass
+        elif "symmetric_mass_ratio" in sample.keys():
+            output_sample["mass_ratio"] = (
+                symmetric_mass_ratio_to_mass_ratio(
+                    output_sample["symmetric_mass_ratio"])
+            )
+        elif "chirp_mass" in sample.keys():
+            output_sample["mass_ratio"] = (
+                mass_1_and_chirp_mass_to_mass_ratio(
+                    mass_1=output_sample["mass_1"],
+                    chirp_mass=output_sample["chirp_mass"])
+            )
+        else:
+            return check_and_return_quietly(require_add, sample)
+
+        output_sample["mass_2"] = (
+            output_sample["mass_ratio"] * output_sample["mass_1"]
+        )
+
+        return output_sample
+
+    elif "mass_2" in sample.keys():
+        # mass_1 is not in the dict
+        if "total_mass" in sample.keys():
+            output_sample["mass_1"] = (
+                output_sample["total_mass"] - output_sample["mass_2"]
+            )
+            return output_sample
+        elif "mass_ratio" in sample.keys():
+            pass
+        elif "symmetric_mass_ratio" in sample.keys():
+            output_sample["mass_ratio"] = (
+                symmetric_mass_ratio_to_mass_ratio(
+                    output_sample["symmetric_mass_ratio"])
+            )
+        elif "chirp_mass" in sample.keys():
+            output_sample["mass_ratio"] = (
+                mass_2_and_chirp_mass_to_mass_ratio(
+                    mass_2=output_sample["mass_2"],
+                    chirp_mass=output_sample["chirp_mass"])
+            )
+        else:
+            check_and_return_quietly(require_add, sample)
+
+        output_sample["mass_1"] = 1 / output_sample["mass_ratio"] * (
+            output_sample["mass_2"]
+        )
+
+        return output_sample
+
+    # Only if neither mass_1 or mass_2 is in the input sample
+    if "total_mass" in sample.keys():
+        if "mass_ratio" in sample.keys():
+            pass  # We have everything we need already
+        elif "symmetric_mass_ratio" in sample.keys():
+            output_sample["mass_ratio"] = (
+                symmetric_mass_ratio_to_mass_ratio(
+                    output_sample["symmetric_mass_ratio"])
+            )
+        elif "chirp_mass" in sample.keys():
+            output_sample["symmetric_mass_ratio"] = (
+                chirp_mass_and_total_mass_to_symmetric_mass_ratio(
+                    chirp_mass=output_sample["chirp_mass"],
+                    total_mass=output_sample["total_mass"])
+            )
+            output_sample["mass_ratio"] = (
+                symmetric_mass_ratio_to_mass_ratio(
+                    output_sample["symmetric_mass_ratio"])
+            )
+        else:
+            return check_and_return_quietly(require_add, sample)
+
+    elif "chirp_mass" in sample.keys():
+        if "mass_ratio" in sample.keys():
+            pass
+        elif "symmetric_mass_ratio" in sample.keys():
+            output_sample["mass_ratio"] = (
+                symmetric_mass_ratio_to_mass_ratio(
+                    sample["symmetric_mass_ratio"])
+            )
+        else:
+            return check_and_return_quietly(require_add, sample)
+
+        output_sample["total_mass"] = (
+            chirp_mass_and_mass_ratio_to_total_mass(
+                chirp_mass=output_sample["chirp_mass"],
+                mass_ratio=output_sample["mass_ratio"])
+        )
+
+    # We haven't matched any of the criteria
+    if "total_mass" not in output_sample.keys() or (
+            "mass_ratio" not in output_sample.keys()):
+        return check_and_return_quietly(require_add, sample)
+    mass_1, mass_2 = (
+        total_mass_and_mass_ratio_to_component_masses(
+            total_mass=output_sample["total_mass"],
+            mass_ratio=output_sample["mass_ratio"])
+    )
+    output_sample["mass_1"] = mass_1
+    output_sample["mass_2"] = mass_2
+    return output_sample
+
+
 def generate_mass_parameters(sample):
     """
-    Add the known mass parameters to the data frame/dictionary.
+    Add the known mass parameters to the data frame/dictionary.  We do
+    not recompute keys already present in the dictionary
 
-    We add:
-        chirp mass, total mass, symmetric mass ratio, mass ratio
+    We add, potentially:
+        chirp mass, total mass, symmetric mass ratio, mass ratio, mass_1, mass_2
 
     Parameters
     ==========
     sample : dict
-        The input dictionary with component masses 'mass_1' and 'mass_2'
-
+        The input dictionary with two "spanning" mass parameters
+        e.g. (mass_1, mass_2), or (chirp_mass, mass_ratio), but not e.g. only
+        (mass_ratio, symmetric_mass_ratio)
     Returns
     =======
     dict: The updated dictionary
 
     """
-    output_sample = sample.copy()
-    output_sample['chirp_mass'] =\
-        component_masses_to_chirp_mass(sample['mass_1'], sample['mass_2'])
-    output_sample['total_mass'] =\
-        component_masses_to_total_mass(sample['mass_1'], sample['mass_2'])
-    output_sample['symmetric_mass_ratio'] =\
-        component_masses_to_symmetric_mass_ratio(sample['mass_1'],
-                                                 sample['mass_2'])
-    output_sample['mass_ratio'] =\
-        component_masses_to_mass_ratio(sample['mass_1'], sample['mass_2'])
+    # Only add the parameters if they're not already present
+    intermediate_sample = generate_component_masses(sample)
+    output_sample = intermediate_sample.copy()
+    if "chirp_mass" not in output_sample.keys():
+        output_sample['chirp_mass'] = (
+            component_masses_to_chirp_mass(output_sample['mass_1'],
+                                           output_sample['mass_2'])
+        )
+    if "total_mass" not in output_sample.keys():
+        output_sample['total_mass'] = (
+            component_masses_to_total_mass(output_sample['mass_1'],
+                                           output_sample['mass_2'])
+        )
+    if "symmetric_mass_ratio" not in output_sample.keys():
+        output_sample['symmetric_mass_ratio'] = (
+            component_masses_to_symmetric_mass_ratio(output_sample['mass_1'],
+                                                     output_sample['mass_2'])
+        )
+    if "mass_ratio" not in output_sample.keys():
+        output_sample['mass_ratio'] = (
+            component_masses_to_mass_ratio(output_sample['mass_1'],
+                                           output_sample['mass_2'])
+        )
 
     return output_sample
 
diff --git a/test/gw/conversion_test.py b/test/gw/conversion_test.py
index e89bdce00164bc24a2440f18dd2a21dc25b41c02..a85cbf8e5dad58fbdba38a8b0a9e2f51d5d72343 100644
--- a/test/gw/conversion_test.py
+++ b/test/gw/conversion_test.py
@@ -3,6 +3,7 @@ import unittest
 import numpy as np
 import pandas as pd
 
+
 import bilby
 from bilby.gw import conversion
 
@@ -99,6 +100,13 @@ class TestBasicConversions(unittest.TestCase):
         )
         self.assertAlmostEqual(self.total_mass, total_mass)
 
+    def test_chirp_mass_and_mass_ratio_to_component_masses(self):
+        mass_1, mass_2 = \
+            conversion.chirp_mass_and_mass_ratio_to_component_masses(
+                self.chirp_mass, self.mass_ratio)
+        self.assertAlmostEqual(self.mass_1, mass_1)
+        self.assertAlmostEqual(self.mass_2, mass_2)
+
     def test_component_masses_to_chirp_mass(self):
         chirp_mass = conversion.component_masses_to_chirp_mass(self.mass_1, self.mass_2)
         self.assertAlmostEqual(self.chirp_mass, chirp_mass)
@@ -523,5 +531,68 @@ class TestDistanceTransformations(unittest.TestCase):
         self.assertAlmostEqual(max(abs(dl - self.distances)), 0, 4)
 
 
+class TestGenerateMassParameters(unittest.TestCase):
+    def setUp(self):
+        self.expected_values = {'mass_1': 2.0,
+                                'mass_2': 1.0,
+                                'chirp_mass': 1.2167286837864113,
+                                'total_mass': 3.0,
+                                'symmetric_mass_ratio': 0.2222222222222222,
+                                'mass_ratio': 0.5}
+
+    def helper_generation_from_keys(self, keys, expected_values,):
+        # Explicitly test the helper generate_component_masses
+        local_test_vars = \
+            {key: expected_values[key] for key in keys}
+        local_test_vars_with_component_masses = \
+            conversion.generate_component_masses(local_test_vars)
+        self.assertTrue("mass_1" in local_test_vars_with_component_masses.keys())
+        self.assertTrue("mass_2" in local_test_vars_with_component_masses.keys())
+        for key in local_test_vars_with_component_masses.keys():
+            self.assertAlmostEqual(
+                local_test_vars_with_component_masses[key],
+                self.expected_values[key])
+
+        # Test the function more generally
+        local_all_mass_parameters = \
+            conversion.generate_mass_parameters(local_test_vars)
+        self.assertEqual(local_all_mass_parameters.keys(),
+                         self.expected_values.keys())
+        for key in expected_values.keys():
+            self.assertAlmostEqual(expected_values[key], local_all_mass_parameters[key])
+
+    def test_from_mass_1_and_mass_2(self):
+        self.helper_generation_from_keys(["mass_1", "mass_2"],
+                                         self.expected_values)
+
+    def test_from_mass_1_and_mass_ratio(self):
+        self.helper_generation_from_keys(["mass_1", "mass_ratio"],
+                                         self.expected_values)
+
+    def test_from_mass_2_and_mass_ratio(self):
+        self.helper_generation_from_keys(["mass_2", "mass_ratio"],
+                                         self.expected_values)
+
+    def test_from_mass_1_and_total_mass(self):
+        self.helper_generation_from_keys(["mass_2", "total_mass"],
+                                         self.expected_values)
+
+    def test_from_chirp_mass_and_mass_ratio(self):
+        self.helper_generation_from_keys(["chirp_mass", "mass_ratio"],
+                                         self.expected_values)
+
+    def test_from_chirp_mass_and_symmetric_mass_ratio(self):
+        self.helper_generation_from_keys(["chirp_mass", "symmetric_mass_ratio"],
+                                         self.expected_values)
+
+    def test_from_chirp_mass_and_symmetric_mass_1(self):
+        self.helper_generation_from_keys(["chirp_mass", "mass_1"],
+                                         self.expected_values)
+
+    def test_from_chirp_mass_and_symmetric_mass_2(self):
+        self.helper_generation_from_keys(["chirp_mass", "mass_2"],
+                                         self.expected_values)
+
+
 if __name__ == "__main__":
     unittest.main()