def pdf_convolver_bifurcation(cod_obj, force_drift, force_struc):
    'set new vector'
    diffxx = force_struc[0]
    diffxy = force_struc[1]
    diffxz = force_struc[2]
    diffyy = force_struc[3]
    diffyz = force_struc[4]
    diffzz = force_struc[5]
    struc_ten = np.array([[diffxx,diffxy,diffxz],[diffxy,diffyy,diffyz],[diffxz,diffyz,diffzz]])
    eig = struc_ten_eig(struc_ten, cod_obj.max_eig, cod_obj.min_eig, cod_obj.proxy_reverse_eig)
    cov = revers_eig(eig)
 
    
    coff = np.linalg.solve(eig[1].T,cod_obj.vector_list[-1])
    #print(coff)
    vector_proj2 = coff[0]*eig[1][0]
    vector_proj3 = coff[1]*eig[1][1]
    vector_proj23 = (vector_proj2+vector_proj3)/np.linalg.norm((vector_proj2+vector_proj3))
    vector_proj23, polar_angle = convert_vector_angle(vector_proj23)
    
    montecarlo_iter = cod_obj.montecarlo_iterations
    bifurcation_aperture = 20
    vector_a = f*G.sphere_vector(bifurcation_aperture, polar_angle[0], cov, np.array([0,0,0]), montecarlo_iter, offset =cod_obj.branching_angle[0], points_on_sphere = 4000, plot = False)
    #vector_a = f*G.sphere_vector(bifurcation_aperture, cod_obj.angle_list[-1], cov, np.array([0,0,0]), montecarlo_iter, offset =cod_obj.bifurcation_angle[0], points_on_sphere = 4000, plot = False)
    vector_b = Quaternions.vec_angle_rot(vector_a,np.array([cod_obj.bifurcation_angle[0]*2]),np.cross(vector_a,cod_obj.vector_list[-1]))
    'new unit vector and its sherical coordinates for growth direction'
    branch_vector_a, branch_angle_a = convert_vector_angle(vector_a)
    vector_b =vector_b+np.random.rand(3)*0.1*np.array([np.random.choice([-1,1]),np.random.choice([-1,1]),np.random.choice([-1,1])])
    vector_b = vector_b/np.linalg.norm(vector_b)
    branch_vector_b, branch_angle_b = convert_vector_angle(vector_b)
                                                           
    return branch_vector_a, branch_angle_a, branch_vector_b, branch_angle_b   
def start_pos_orientation():

    start_angle_list = np.array([np.random.rand(2)*np.array([180,360]) \
                            for i in range(4)])
    start_pos_list = np.array([np.random.rand(3)*np.array([100,100,100]\
                          ) + np.array([78,78,78]) for i in range(4)])

    start_pos_list = np.array([[125, 125, 27], [125, 125, 223], [125, 27, 125],
                               [125, 223, 125], [27, 125, 125],
                               [223, 125, 125]])

    start_angle_list = np.array([[0, 0], [0, 0], [90, 90], [90, 90], [90, 0],
                                 [90, 0]])

    start_pos_list = np.array([  #[42,42,85],[127,42,85],[212,42,85],
        [42, 127, 85],
        [127, 127, 85],
        [212, 127, 85],
        #[42,212,85],[127,212,85],[212,212,85],
        #[42,42,170],[127,42,170],[212,42,170],
        [42, 127, 170],
        [127, 127, 170],
        [212, 127, 170],
        #[42,212,170],[127,212,170],[212,212,170]
    ])
    start_angle_list = np.array([  #[0,0],[0,0],[0,0],
        #[0,0],[0,0],[0,0],
        #[0,0],[0,0],[0,0],
        #[0,0],[0,0],[0,0],
        [0, 0],
        [0, 0],
        [0, 0],
        [0, 0],
        [0, 0],
        [0, 0]
    ])

    start_pos_list = np.array([[124, 124, 124]])
    start_angle_list = np.array([[0, 0]])

    start_pos, start_angle,\
    common_node = EsAG.start_point_generator(start_pos_list,
                                            start_angle_list,
                                            aperture = 180, offset = 0,
                                            points_on_sphere = 30,
                                            metric = np.array([[100,100,100]]),
                                            common_starting_node = False,
                                            tangent_orientation = 'pol')
    return start_pos, start_angle, common_node
def pdf_convolver(cod_obj, force_drift, force_struc):

    'Drift vector components'
    'Drift signal//all directions'
    driftx, drifty, driftz = force_drift

    'Drift mean µ-vector'
    drift_mu = np.array([driftx, drifty, driftz])
    if cod_obj.max_drift != 0:
        drift_mu = drift_mu / cod_obj.max_drift
    #drift_mu = - drift_mu #to move away from borders instead getting attracted

    'Drift/shift covariance //SIGMA'
    struc_ten_drift = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) * 0.01

    'Structure tensor components'
    'Diffusion metric // Diffusive tensor components'
    diffxx = force_struc[0]
    diffxy = force_struc[1]
    diffxz = force_struc[2]
    diffyy = force_struc[3]
    diffyz = force_struc[4]
    diffzz = force_struc[5]

    'Diffusion mena µ-vector'
    diff_mu = np.array([0, 0, 0])

    'Diffuison covariance //SIGMA'
    struc_ten_diff = np.array([[diffxx, diffxy, diffxz],
                               [diffxy, diffyy, diffyz],
                               [diffxz, diffyz, diffzz]])
    'Inverted length scales for real space opjects'
    eigv_diff = struc_ten_eig(struc_ten_diff, cod_obj.max_eig, cod_obj.min_eig,
                              cod_obj.proxy_reverse_eig)
    struc_ten_diff = revers_eig(eigv_diff)

    'Correlation mean µ-vector'
    corr_mu = cod_obj.vec_mem

    'Correlation covariance //SIGMA'
    struc_ten_corr = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) * 0.01
    """Proxy pdf parameter"""
    if cod_obj.proxy_drift == True:
        drift_mu = np.array([0, 0, 0])  #Proxy drift mean vector drift_mu
    if cod_obj.proxy_tensor == True:
        struc_ten_diff = np.array([[0.5, 0, 0], [0, 0.5, 0],
                                   [0, 0, 1]])  #Proxy diffusion tensor
    if cod_obj.proxy_corr == True:
        corr_mu = np.array([0, 0, 0])  #Proxy correlation mean vector corr_mu
    """Calculate all sums:"""

    'Sum of all three covariances'
    struc_ten_sum = struc_ten_drift + struc_ten_diff + struc_ten_corr

    'Sum of all three means'
    shift_mu = drift_mu + diff_mu + corr_mu
    """
    A Monte Carlo Simulation draws the new direction from a distribution 
    constructed out of the covarinaces and means. The cones internal parameter
    like the aperture restricts the new growth direction inside a solid angle.
    """
    new_posvec = f*G.sphere_vector(cod_obj.aperture,
                                   cod_obj.angle_list[-1],
                                   struc_ten_sum,
                                   shift_mu,
                                   cod_obj.montecarlo_iterations,
                                   offset=0,
                                   points_on_sphere=2000,
                                   plot=False)

    return new_posvec / np.linalg.norm(new_posvec)