diff --git a/binarycpython/utils/distribution_functions.py b/binarycpython/utils/distribution_functions.py
index f9b0fab6ca465aa474e4b600308e0c649f02bb90..58e48719944ab1ead8d8b63ecc853e6bc1d65f96 100644
--- a/binarycpython/utils/distribution_functions.py
+++ b/binarycpython/utils/distribution_functions.py
@@ -3,33 +3,41 @@ Module containing the predefined distribution functions
 
 The user can use any of these distribution functions to
 generate probability distributions for sampling populations
+
+There are distributions for the following properties:
+- mass
+- period
+- mass ratio
+- binary fraction
+
+TODO: make some things globally present? rob does this in his module..i guess it saves calculations but not sure if im gonna do that now
+TODO: make global constants stuff
+TODO: add eccentricity distribution: thermal
+TODO: Add SFH distributions depending on redshift
+TODO: Add metallicity distributions depending on redshift
+TODO: Add initial rotational velocity distributions
 """
 
 
 import math
 import numpy as np
-
+from typing import Optional, Union
 from binarycpython.utils.useful_funcs import calc_period_from_sep
 
 ###
 # File containing probability distributions
 # Mostly copied from the perl modules
-
-# TODO: make some things globally present? rob does this in his module.
-# i guess it saves calculations but not sure if im gonna do that now
-# TODO: Add the stuff from the IMF file
-# TODO: call all of these functions to check whether they work
-# TODO: make global constants stuff
-# TODO: make description of module submodule
-
 LOG_LN_CONVERTER = 1.0 / math.log(10.0)
-
 distribution_constants = {}  # To store the constants in
 
 
-def prepare_dict(global_dict, list_of_sub_keys):
+def prepare_dict(global_dict: dict, list_of_sub_keys: list) -> None:
     """
-    Function that makes sure that the global dict is prepared to have a value set there
+    Function that makes sure that the global dict is prepared to have a value set there. This dictionary will store values and factors for the distribution functions, so that they dont have to be calculated each time.
+
+    Args:
+        global_dict: globablly acessible dictionary where factors are stored in
+        list_of_sub_keys: List of keys that must become be(come) present in the global_dict
     """
 
     internal_dict_value = global_dict
@@ -44,25 +52,87 @@ def prepare_dict(global_dict, list_of_sub_keys):
         internal_dict_value = internal_dict_value[k]
 
 
-def flat():
+def set_opts(opts: dict, newopts: dict) -> dict:
+    """
+    Function to take a default dict and override it with newer values.
+
+    # TODO: consider changing this to just a dict.update
+
+    Args:
+        opts: dictionary with default values
+        newopts: dictionary with new values
+
+    Returns:
+        returns an updated dictionary
+    """
+
+    if newopts:
+        for opt in newopts.keys():
+            if opt in opts.keys():
+                opts[opt] = newopts[opt]
+
+    return opts
+
+
+def flat() -> float:
     """
     Dummy distribution function that returns 1
+
+    Returns:
+        a flat uniform distribution: 1    
     """
 
-    return 1
+    return 1.0
 
 
-def number(value):
+def number(value: Union[int, float]) -> Union[int, float]:
     """
     Dummy distribution function that returns the input
+    
+    Args:
+        value: the value that will be returned by this function.
+
+    Returns: 
+        the value that was provided
     """
 
     return value
 
 
-def powerlaw_constant(min_val, max_val, k):
+def const(min_bound: Union[int, float], max_bound: Union[int, float], val: float=None) -> Union[int, float]:
+    """
+    a constant distribution function between min=min_bound and max=max_bound.
+
+    Args:
+        min_bound: lower bound of the range
+        max_bound: upper bound of the range
+    
+    Returns:
+            returns the value of 1/(max_bound-min_bound). If val is provided, it will check whether min_bound < val <= max_bound. if not: returns 0
+    """
+
+    if val:
+        if not min_bound < val <= max_bound:
+            print("out of bounds")
+            prob = 0
+            return prob
+    prob = 1.0 / (min_bound - max_bound)
+    return prob
+
+
+def powerlaw_constant(min_val: Union[int, float], max_val: Union[int, float], k: Union[int, float]) -> Union[int, float]:
     """
     Function that returns the constant to normalise a powerlaw
+    
+    TODO: what if k is -1?
+        
+    Args:
+        min_val: lower bound of the range
+        max_val: upper bound of the range
+        k: powerlaw slope
+
+    Returns:
+        constant to normalize the given powerlaw between the min_val and max_val range
     """
 
     k1 = k + 1.0
@@ -76,9 +146,18 @@ def powerlaw_constant(min_val, max_val, k):
     return powerlaw_const
 
 
-def powerlaw(min_val, max_val, k, x):
+def powerlaw(min_val: Union[int, float], max_val: Union[int, float], k: Union[int, float], x: Union[int, float]) -> Union[int, float]:
     """
     Single powerlaw with index k at x from min to max
+
+    Args:
+        min_val: lower bound of the powerlaw
+        max_val: upper bound of the powerlaw
+        k: slope of the power law
+        x: position at which we want to evaluate
+
+    Returns:
+        `probability` at the given position(x)
     """
 
     # Handle faulty value
@@ -102,9 +181,23 @@ def powerlaw(min_val, max_val, k, x):
     return prob
 
 
-def calculate_constants_three_part_powerlaw(m0, m1, m2, m_max, p1, p2, p3):
+def calculate_constants_three_part_powerlaw(m0: Union[int, float], m1: Union[int, float], m2: Union[int, float], m_max: Union[int, float], p1: Union[int, float], p2: Union[int, float], p3: Union[int, float]) -> Union[int, float]:
     """
     Function to calculate the constants for a three-part powerlaw
+
+    TODO: use the powerlaw_constant function to calculate all these values
+
+    Args:
+        m0: lower bound mass
+        m1: second boundary, between the first slope and the second slope
+        m2: third boundary, between the second slope and the third slope
+        m_max: upper bound mass
+        p1: first slope
+        p2: second slope
+        p3: third slope
+
+    Returns:
+        array of normalisation constants
     """
 
     # print("Initialising constants for the three-part powerlaw: m0={} m1={} m2={}\
@@ -152,68 +245,106 @@ def calculate_constants_three_part_powerlaw(m0, m1, m2, m_max, p1, p2, p3):
     # $threepart_powerlaw_consts{"@_"}=[@$array];
 
 
-def three_part_powerlaw(M, M0, M1, M2, M_MAX, P1, P2, P3):
+def three_part_powerlaw(m: Union[int, float], m0: Union[int, float], m1: Union[int, float], m2: Union[int, float], m_max: Union[int, float], p1: Union[int, float], p2: Union[int, float], p3: Union[int, float]) -> Union[int, float]:
     """
     Generalized three-part power law, usually used for mass distributions
+
+    Args:
+        m: mass at which we want to evaluate the distribution.
+        m0: lower bound mass
+        m1: second boundary, between the first slope and the second slope
+        m2: third boundary, between the second slope and the third slope
+        m_max: upper bound mass
+        p1: first slope
+        p2: second slope
+        p3: third slope
+
+    Returns:
+        'probability' at given mass m
     """
 
     # TODO: add check on whether the values exist
 
     three_part_powerlaw_constants = calculate_constants_three_part_powerlaw(
-        M0, M1, M2, M_MAX, P1, P2, P3
+        m0, m1, m2, m_max, p1, p2, p3
     )
 
     #
-    if M < M0:
+    if m < m0:
         prob = 0  # Below lower bound
-    elif M0 < M <= M1:
-        prob = three_part_powerlaw_constants[0] * (M ** P1)  # Between M0 and M1
-    elif M1 < M <= M2:
-        prob = three_part_powerlaw_constants[1] * (M ** P2)  # Between M1 and M2
-    elif M2 < M <= M_MAX:
-        prob = three_part_powerlaw_constants[2] * (M ** P3)  # Between M2 and M_MAX
+    elif m0 < m <= m1:
+        prob = three_part_powerlaw_constants[0] * (m ** p1)  # Between M0 and M1
+    elif m1 < m <= m2:
+        prob = three_part_powerlaw_constants[1] * (m ** p2)  # Between M1 and M2
+    elif m2 < m <= m_max:
+        prob = three_part_powerlaw_constants[2] * (m ** p3)  # Between M2 and M_MAX
     else:
         prob = 0  # Above M_MAX
 
     return prob
 
 
-def const(min_bound, max_bound, val=None):
+def gaussian_normalizing_const(mean: Union[int, float], sigma: Union[int, float], gmin: Union[int, float], gmax: Union[int, float]) -> Union[int, float]:
     """
-    a constant distribution function between min=$_[0] and max=$_[1]
+    Function to calculate the normalisation constant for the gaussian
+
+    Args:
+        mean: mean of the gaussian
+        sigma: standard deviation of the gaussian
+        gmin: lower bound of the range to calculate the probabilities in
+        gmax: upper bound of the range to calculate the probabilities in
+
+    Returns:
+        normalisation constant for the gaussian distribution(mean, sigma) between gmin and gmax
     """
 
-    if val:
-        if not min_bound < val <= max_bound:
-            print("out of bounds")
-            prob = 0
-            return prob
-    prob = 1.0 / (min_bound - max_bound)
-    return prob
+    # First time; calculate multipllier for given mean and sigma
+    ptot = 0
+    resolution = 1000
+    d = (gmax - gmin) / resolution
 
+    for i in range(resolution):
+        y = gmin + i * d
+        ptot += d * gaussian_func(y, mean, sigma)
 
-def set_opts(opts, newopts):
-    """
-    Function to take a default dict and override it with newer values.
+    # TODO: Set value in global
+    return ptot
+
+
+def gaussian_func(x: Union[int, float], mean: Union[int, float], sigma: Union[int, float]) -> Union[int, float]:
     """
+    Function to evaluate a gaussian at a given point, but this time without any boundaries. 
 
-    # DONE: put in check to make sure that the newopts keys are contained in opts
-    # TODO: change this to just a dict.update
+    Args:
+        x: location at which to evaluate the distribution
+        mean: mean of the gaussian
+        sigma: standard deviation of the gaussian
 
-    if newopts:
-        for opt in newopts.keys():
-            if opt in opts.keys():
-                opts[opt] = newopts[opt]
+    Returns:
+        value of the gaussian at x
+    """
+    gaussian_prefactor = 1.0 / math.sqrt(2.0 * math.pi)
 
-    return opts
+    r = 1.0 / (sigma)
+    y = (x - mean) * r
+    return gaussian_prefactor * r * math.exp(-0.5 * y ** 2)
 
 
-def gaussian(x, mean, sigma, gmin, gmax):
+def gaussian(x: Union[int, float], mean: Union[int, float], sigma: Union[int, float], gmin: Union[int, float], gmax: Union[int, float]) -> Union[int, float]:
     """
     Gaussian distribution function. used for e..g Duquennoy + Mayor 1991
 
-    Input: location, mean, sigma, min and max:
+    Args:
+        x: location at which to evaluate the distribution
+        mean: mean of the gaussian
+        sigma: standard deviation of the gaussian
+        gmin: lower bound of the range to calculate the probabilities in
+        gmax: upper bound of the range to calculate the probabilities in
+
+    Returns:
+        'probability' of the gaussian distribution between the boundaries, evaluated at x
     """
+
     # # location (X value), mean and sigma, min and max range
     # my ($x,$mean,$sigma,$gmin,$gmax) = @_;
 
@@ -228,46 +359,21 @@ def gaussian(x, mean, sigma, gmin, gmax):
     return prob
 
 
-def gaussian_normalizing_const(mean, sigma, gmin, gmax):
-    """
-    Function to calculate the normalisation constant for the gaussian
-    """
-
-    # First time; calculate multipllier for given mean and sigma
-    ptot = 0
-    resolution = 1000
-    d = (gmax - gmin) / resolution
-
-    for i in range(resolution):
-        y = gmin + i * d
-        ptot += d * gaussian_func(y, mean, sigma)
-
-    # TODO: Set value in global
-    return ptot
-
-
-def gaussian_func(x, mean, sigma):
-    """
-    Function to evaluate a gaussian at a given point
-    """
-    gaussian_prefactor = 1.0 / math.sqrt(2.0 * math.pi)
-
-    r = 1.0 / (sigma)
-    y = (x - mean) * r
-    return gaussian_prefactor * r * math.exp(-0.5 * y ** 2)
-
-
 #####
 # Mass distributions
 #####
 
 
-def Kroupa2001(m, newopts=None):
+def Kroupa2001(m: Union[int, float], newopts: dict=None) -> Union[int, float]:
     """
-    Probability distribution function for kroupa 2001 IMF
+    Probability distribution function for kroupa 2001 IMF, where the default values to the three_part_powerlaw are: default = {"m0": 0.1, "m1": 0.5, "m2": 1, "mmax": 100, "p1": -1.3, "p2": -2.3,"p3": -2.3}
 
-    Input: Mass, (and optional: dict of new options. Input the
-        default = {'m0':0.1, 'm1':0.5, 'm2':1, 'mmax':100, 'p1':-1.3, 'p2':-2.3, 'p3':-2.3}
+    Args:
+        m: mass to evaluate the distribution at
+        newopts: optional dict to override the default values.
+    
+    Returns:
+        'probability' of distribution function evaluated at m
     """
 
     # Default params and override them
@@ -297,10 +403,16 @@ def Kroupa2001(m, newopts=None):
         value_dict["p3"],
     )
 
-
-def ktg93(m, newopts=None):
+def ktg93(m: Union[int, float], newopts: dict=None) -> Union[int, float]:
     """
-    Wrapper for mass distribution of KTG93
+    Probability distribution function for KTG93 IMF, where the default values to the three_part_powerlaw are: default = {"m0": 0.1, "m1": 0.5, "m2": 1, "mmax": 80, "p1": -1.3, "p2": -2.2,"p3": -2.7}
+
+    Args:
+        m: mass to evaluate the distribution at
+        newopts: optional dict to override the default values.
+    
+    Returns:
+        'probability' of distribution function evaluated at m
     """
     # TODO: ask rob what this means
 
@@ -366,32 +478,60 @@ def ktg93(m, newopts=None):
 # }
 
 
-def imf_tinsley1980(m):
+def imf_tinsley1980(m: Union[int, float]) -> Union[int, float]:
     """
-    From Tinsley 1980 (defined up until 80Msol)
+    Probability distribution function for tinsley 1980 IMF (defined up until 80Msol): three_part_powerlaw(m, 0.1, 2.0, 10.0, 80.0, -2.0, -2.3, -3.3)
+
+    Args:
+        m: mass to evaluate the distribution at
+    
+    Returns:
+        'probability' of distribution function evaluated at m
     """
 
     return three_part_powerlaw(m, 0.1, 2.0, 10.0, 80.0, -2.0, -2.3, -3.3)
 
 
-def imf_scalo1986(m):
+def imf_scalo1986(m: Union[int, float]) -> Union[int, float]:
     """
-    From Scalo 1986 (defined up until 80Msol)
+    Probability distribution function for Scalo 1986 IMF (defined up until 80Msol): three_part_powerlaw(m, 0.1, 1.0, 2.0, 80.0, -2.35, -2.35, -2.70)
+
+    Args:
+        m: mass to evaluate the distribution at
+    
+    Returns:
+        'probability' of distribution function evaluated at m
     """
     return three_part_powerlaw(m, 0.1, 1.0, 2.0, 80.0, -2.35, -2.35, -2.70)
 
 
-def imf_scalo1998(m):
+def imf_scalo1998(m: Union[int, float]) -> Union[int, float]:
     """
     From scalo 1998
+
+    Probability distribution function for Scalo 1998 IMF (defined up until 80Msol): three_part_powerlaw(m, 0.1, 1.0, 10.0, 80.0, -1.2, -2.7, -2.3)
+
+    Args:
+        m: mass to evaluate the distribution at
+    
+    Returns:
+        'probability' of distribution function evaluated at m
     """
+
     return three_part_powerlaw(m, 0.1, 1.0, 10.0, 80.0, -1.2, -2.7, -2.3)
 
 
-def imf_chabrier2003(m):
+def imf_chabrier2003(m: Union[int, float]) -> Union[int, float]:
     """
-    IMF of Chabrier 2003 PASP 115:763-795
+    Probability distribution function for IMF of Chabrier 2003 PASP 115:763-795
+
+    Args:
+        m: mass to evaluate the distribution at
+    
+    Returns:
+        'probability' of distribution function evaluated at m
     """
+
     chabrier_logmc = math.log10(0.079)
     chabrier_sigma2 = 0.69 * 0.69
     chabrier_a1 = 0.158
@@ -413,12 +553,19 @@ def imf_chabrier2003(m):
 ########################################################################
 # Binary fractions
 ########################################################################
-def Arenou2010_binary_fraction(m):
+
+def Arenou2010_binary_fraction(m: Union[int, float]) -> Union[int, float]:
     """
     Arenou 2010 function for the binary fraction as f(M1)
 
     GAIA-C2-SP-OPM-FA-054
     www.rssd.esa.int/doc_fetch.php?id=2969346
+
+    Args:
+        m: mass to evaluate the distribution at
+    
+    Returns:
+        binary fraction at m
     """
 
     return 0.8388 * math.tanh(0.688 * m + 0.079)
@@ -427,7 +574,7 @@ def Arenou2010_binary_fraction(m):
 # print(Arenou2010_binary_fraction(0.4))
 
 
-def raghavan2010_binary_fraction(m):
+def raghavan2010_binary_fraction(m: Union[int, float]) -> Union[int, float]:
     """
     Fit to the Raghavan 2010 binary fraction as a function of
     spectral type (Fig 12). Valid for local stars (Z=Zsolar).
@@ -438,6 +585,12 @@ def raghavan2010_binary_fraction(m):
     (based on Jaschek+Jaschek's Teff-spectral type table).
 
     Rob then fitted the result
+
+    Args:
+        m: mass to evaluate the distribution at
+    
+    Returns:
+        binary fraction at m
     """
 
     return min(
@@ -456,17 +609,21 @@ def raghavan2010_binary_fraction(m):
 ########################################################################
 
 
-def duquennoy1991(logper):
+def duquennoy1991(logper: Union[int, float]) -> Union[int, float]:
     """
-    Period distribution from Duquennoy + Mayor 1991
+    Period distribution from Duquennoy + Mayor 1991. Evaluated the function gaussian(logper, 4.8, 2.3, -2, 12)
 
-    Input:
-        logper: logperiod
+    Args:
+        logper: logarithm of period to evaluate the distribution at
+    
+    Returns:
+        'probability' at gaussian(logper, 4.8, 2.3, -2, 12)
     """
     return gaussian(logper, 4.8, 2.3, -2, 12)
 
 
-def sana12(M1, M2, a, P, amin, amax, x0, x1, p):
+
+def sana12(M1: Union[int, float], M2: Union[int, float], a: Union[int, float], P: Union[int, float], amin: Union[int, float], amax: Union[int, float], x0: Union[int, float], x1: Union[int, float], p: Union[int, float]) -> Union[int, float]:
     """
     distribution of initial orbital periods as found by Sana et al. (2012)
     which is a flat distribution in ln(a) and ln(P) respectively for stars
@@ -480,6 +637,20 @@ def sana12(M1, M2, a, P, amin, amax, x0, x1, p):
     example args: 10, 5, sep(M1, M2, P), sep, ?, -2, 12, -0.55
 
     # TODO: Fix this function!
+    
+    Args:
+        M1: Mass of primary
+        M2: Mass of secondary
+        a: separation of binary
+        P: period of binary
+        amin: minimum separation of the distribution (lower bound of the range)
+        amax: maximum separation of the distribution (upper bound of the range)
+        x0: log of minimum period of the distribution (lower bound of the range)
+        x1: log of maximum period of the distribution (upper bound of the range)
+        p: slope of the distributoon
+    
+    Returns:
+        'probability' of orbital period P given the other parameters
     """
 
     res = 0
@@ -515,8 +686,38 @@ def sana12(M1, M2, a, P, amin, amax, x0, x1, p):
 
     return res
 
+# print(sana12(10, 2, 10, 100, 1, 1000, math.log(10), math.log(1000), 6))
+
+
+def interpolate_in_mass_izzard2012(M: Union[int, float], high: Union[int, float], low: Union[int, float]) -> Union[int, float]:
+    """
+    Function to interpolate in mass
+
+    TODO: fix this function. 
+    TODO: describe the args
+    high: at M=16.3
+    low: at 1.15
+
+    Args:
+        M: mass
+        high:
+        low:
+
+    Returns:
+
+    """
+
+    log_interpolation = False
+
+    if log_interpolation:
+        return (high - low) / (math.log10(16.3) - math.log10(1.15)) * (
+            math.log10(M) - math.log10(1.15)
+        ) + low
+    else:
+        return (high - low) / (16.3 - 1.15) * (M - 1.15) + low
+
 
-def Izzard2012_period_distribution(P, M1, log10Pmin=1):
+def Izzard2012_period_distribution(P: Union[int, float], M1: Union[int, float], log10Pmin: Union[int, float]=1) ->Union[int, float]:
     """
     period distribution which interpolates between
     Duquennoy and Mayor 1991 at low mass (G/K spectral type <~1.15Msun)
@@ -525,10 +726,15 @@ def Izzard2012_period_distribution(P, M1, log10Pmin=1):
     This gives dN/dlogP, i.e. DM/Raghavan's Gaussian in log10P at low mass
     and Sana's power law (as a function of logP) at high mass
 
-    input::
-        P (float): period
-        M1 (float): Primary star mass
-        log10Pmin (float): Minimum period in base log10 (optional)
+    TODO: fix this function
+
+    Args:
+        P: period
+        M1: Primary star mass
+        log10Pmin: minimum period in base log10 (optional)
+
+    Returns:
+        'probability' of interpolated distribution function at P and M1
 
     """
 
@@ -539,7 +745,6 @@ def Izzard2012_period_distribution(P, M1, log10Pmin=1):
     # save mass input and limit mass used (M1 from now on) to fitted range
     Mwas = M1
     M1 = max(1.15, min(16.3, M1))
-
     # print("Izzard2012 called for M={} (trunc'd to {}), P={}\n".format(Mwas, M1, P))
 
     # Calculate the normalisations
@@ -593,38 +798,20 @@ def Izzard2012_period_distribution(P, M1, log10Pmin=1):
             * g
         )
 
-
-def interpolate_in_mass_izzard2012(M, high, low):
-    """
-    Function to interpolate in mass
-
-    high: at M=16.3
-    low: at 1.15
-    """
-
-    log_interpolation = False
-
-    if log_interpolation:
-        return (high - low) / (math.log10(16.3) - math.log10(1.15)) * (
-            math.log10(M) - math.log10(1.15)
-        ) + low
-    else:
-        return (high - low) / (16.3 - 1.15) * (M - 1.15) + low
-
-
-# print(sana12(10, 2, 10, 100, 1, 1000, math.log(10), math.log(1000), 6))
-
 ########################################################################
 # Mass ratio distributions
 ########################################################################
 
-
-def flatsections(x, opts):
+def flatsections(x: float , opts: dict) -> Union[float, int]:
     """
     Function to generate flat distributions, possibly in multiple sections
+    
+    Args:
+        x: mass ratio value
+        opts: list containing the flat sections. Which are themselves dictionaries, with keys "max": upper bound, "min": lower bound and "height": value
 
-    opts: list of dicts with settings for the flat sections
-    x: location to calculate the y value
+    Returns: 
+        probability of that mass ratio.
     """
 
     c = 0
@@ -638,10 +825,23 @@ def flatsections(x, opts):
         if opt["min"] <= x <= opt["max"]:
             y = opt["height"]
             # print("Use this\n")
+
     c = 1.0 / c
     y = y * c
+
     # print("flatsections gives C={}: y={}\n",c,y)
     return y
 
-
 # print(flatsections(1, [{'min': 0, 'max': 2, 'height': 3}]))
+
+########################################################################
+# Eccentricity distributions
+########################################################################
+
+########################################################################
+# Star formation histories
+########################################################################
+
+########################################################################
+# Metallicity distributions
+########################################################################