CONAN._classes.load_lightcurves.add_custom_LC_function
======================================================

.. py:method:: CONAN._classes.load_lightcurves.add_custom_LC_function(func=None, x='time', func_args=dict(), extra_args=dict(), op_func=None, replace_LCmodel=False, verbose=True)

   Define custom model to be combined with or to replace the light-curve model. This must be
   given as a function or a class with a ``get_model()`` function. In both cases, the function
   must be of the form ``func(x, **func_args,extra_args)`` where ``x`` is the independent variable
   of the function. If func is a class, the __init__ method must have a 'data' argument
   i.e. ``def __init__(self, data=None):`` which allows CONAN to load in the dictionary of input data.
   e.g. the data for the first LC can be retrieved as data['lc1.dat'] and its columns as
   data['lc1.dat']['col0'], data['lc1.dat']['col1'] etc. The function must return the signal
   to be combined with the light-curve model using ``op_func``. If ``replace_LCmodel=True``, then
   the function must return the light-curve model.

   :param func: custom function/class to combine with or replace the light-curve model. Must be of the
                form ``func(x,**func_args,extra_args)`` where ``x`` is the independent variable of the
                function. Default is None. if this function replaces the native CONAN lightcurve model
                (using``replace_LCmodel=True``), an additional dictionary argument of zero-initialized
                LC parameters should be given to use in computing the new LCmodel i.e
                `func(x,**func_args,extra_args, LC_pars=dict(Duration=0,rho_star=0,RpRs=0,Impact_para=0,
                T_0=0,Period=0,Eccentricity=0,omega=90,q1=0,q2=0,D_occ=0,Fn=0,ph_off=0,A_ev=0,f1_ev=0,A_db=0))`
   :type func: callable, str, list;
   :param x: the independent variable of the custom function. can be 'time' or 'phase_angle'. Default
             is "time". if 'time', the independent variable is the time array of each light-curve.
             if 'phase_angle', the independent variable is the phase angle computed within the
             transit model. the phase angle is generally given by true_anom+omega-pi/2 or simply
             2pi*phase for circular orbit. If `replace_LCmodel=True`, then x needs to be time.
   :type x: str;
   :param func_args: dictionary of arguments to pass to the custom function. The keys must be the argument
                     names for the custom function. each parameter can be fixed to a value(float/int) or set
                     as a jump parameter (tuple of length 2/3/4). Default is an empty dictionary. tuple of
                     length 2:nnormal prior (mean, std), tuple of length 3: uniform prior (min, start, max),
                     tuple of length 4: truncated normal prior (min,max,mean, std)
   :type func_args: dict;
   :param extra_args: dictionary of extra arguments to pass to the custom function.  this arguments can be
                      strings or any data type needed to be specified in the custom function. Default is an
                      empty dictionary.
   :type extra_args: dict;
   :param op_func: operation function to apply to the output of custom function and transit model to
                   obtain the desired model. Must be of the form ``op_func(transit_model,custom_model)``.
                   Default is None. This function is not required if ``replace_LCmodel=True``.
   :type op_func: callable;
   :param replace_LCmodel: replace the transit model with the custom model. Default is False.
   :type replace_LCmodel: bool;

   .. attribute:: custom_LCfunc

      namespace object containing the custom function, operation function and parameter dictionary.

      :type: SimpleNamespace;

   :returns: **custom_LCfunc** -- namespace object containing the custom function, operation function and parameter dictionary.
   :rtype: SimpleNamespace;

   .. rubric:: Examples

   1. create a custom function in phase angle that adds sinusoidal components to the light curve model

   >>> def custom_func(phase_angle, A, B, C,extra_args={}):     # A,B,C are the custom parameters and no extra arguments
   >>>     return A*np.sin(phase_angle) + B*np.cos(2*phase_angle) + C

   >>> def op_func(transit_model, custom_model):   # operation function to combine the custom model with the transit model
   >>>     return transit_model + custom_model

   >>> # A is fixed, B has uniform prior, C has gaussian prior
   >>> custom_lcfunc = lc_obj.add_custom_LC_function(func=custom_func, x="phase_angle",func_args=dict(A=0.1, B=(0.2,0,0.01), C=(0.3,0.01), op_func=op_func)
   >>> # this custom function has now been registered and will be used in the light-curve model.

   2. replace the transit model with a custom model that has two new parameters beyond the
   standard transit model parameters. Here we create a custom model from `catwoman` that models
   asymmetric transit light curves using two new parameters rp2 and phi.the limb darkening law
   to use in catwoman  can be passed in the extra_args dictionary.

   >>> def catwoman_func(t, rp2, phi, extra_args=dict(ld_law="quadratic"), LC_pars=dict(Duration=0,
   >>>                     rho_star=0,RpRs=0,Impact_para=0,T_0=0,Period=0,Eccentricity=0,omega=90,
   >>>                     q1=0,q2=0,D_occ=0,Fn=0,ph_off=0,A_ev=0,f1_ev=0,A_db=0) ):
   >>>     import catwoman
   >>>     import numpy as np
   >>>     import astropy.constants as c
   >>>     import astropy.units as u
   >>>
   >>>     # create a catwoman model. CONAN transit pars in LDpars can be passed to the function
   >>>     params  = catwoman.TransitParams()
   >>>     params.t0  = LC_pars["T_0"]
   >>>     params.per = LC_pars["Period"]
   >>>     params.rp  = LC_pars["RpRs"]
   >>>     #convert stellar density to a/R*
   >>>     rho = LC_pars["rho_star"]
   >>>     G  = (c.G.to(u.cm**3/(u.g*u.second**2))).value
   >>>     aR = ( rho*G*(P*(u.day.to(u.second)))**2 / (3*np.pi)) **(1/3.)
   >>>     params.a   =  aR
   >>>     params.inc = np.arccos(LC_pars["Impact_para"]/aR)
   >>>     params.ecc = LC_pars["Eccentricity"]
   >>>     params.w   = LC_pars["omega"]
   >>>     params.limb_dark = extra_args["ld_law"]
   >>>     #convert from kipping parameterisation to quadratic
   >>>     u1 = 2*np.sqrt(LC_pars["q1"])*LC_pars["q2"]
   >>>     u2 = np.sqrt(LC_pars["q1"])*(1-2*LC_pars["q2"])
   >>>     params.u = [u1, u2]
   >>>
   >>>     params.phi = phi                        #angle of rotation of top semi-circle (in degrees)
   >>>     params.rp2 = rp2                        #bottom semi-circle radius (in units of stellar radii)
   >>>
   >>>     model = catwoman.TransitModel(params,t)         #initalises model
   >>>     return  model.light_curve(params)                #calculates light curve
   >>>
   >>> lc_obj.add_custom_LC_function(func=catwoman_func, x="time",func_args=dict(rp2=(0.1,0.01),
   >>>             phi=(-90,0,90)),extra_args=dict(ld_law="quadratic") op_func=None,replace_LCmodel=True)

