Introduction

Short description of the problem

We have a torus of arbitrary (non-convex polygonal) cross-section. We consider a semi-line (called LOS, for Line of Sight from now on) define by a starting point and a normalized vector. We want to compute the intersections of that semi-line with the torus.

In particular, we want the first entry point inside the torus (PIn), the first exit point (POut), and for the exit point, we also want the index of the polygon (cross-section) segment on which it stands and the normalized vector to that segment at POut. When the starting point already lies inside the torus, there is no PIn.

That computation should be done for a large number of LOS ($10^{5-6}$), and for cross-section polygons comprising 50-500 segments.

Mathematical solutions and algorithm

The mathematical formulation can be found in , as well as all necessary derivations. Here is a summary of the subsequent algorithm:

If $(O,\underline{e}_R,\underline{e}_{\phi},\underline{e}_Z)$ is a direct orthonormal cylindrical referential, to which the associated cartesian referential is $(O,\underline{e}_X,\underline{e}_Y,\underline{e}_Z)$, the inputs of the function are:

  • Ds (3,Nl) np.ndarray of floats : an array containing the 3D (X,Y,Z) coordinates of the Nl starting points
  • us (3,Nl) np.ndarray of floats : an array containing the 3D (X,Y,Z) coordinates of the Nl normalized vectors
  • VPoly (2,Ns+1) np.ndarray of floats : an array containing the 2D (R,Z) coordinates of the Ns+1 points defining the Ns segments defining the cross-section polygon of the torus vessel
  • VIn (2,Ns) np.ndarray of floats : an array containing the 2D (R,Z) coordinates of the Ns vectors perpendicular to the Ns segments and oriented inwards

For one LOS and one segment, let's find the parameter k such that $\underline{DM}=k\underline{u}$ where M is any intersection between the semi-line and the cone defined by the considered segment. If there are several intersections, their k values will be used to determine which ones are first along the line. To determine if an intersection is a PIn (entry) or a POut (exit), we compute the sign of the scalar product between $\underline{u}$ and the local normalized vector perpendicular to the segment and oriented inwards (entry=positive).

Then, introducing (see for details):

  • $u_{ii,//}\cdot D_{ii,//} = us[0,ii]*Ds[0,ii]+us[1,ii]*Ds[1,ii]$
  • $u_{ii,//}^2 = us[0,ii]^2+us[1,ii]^2$
  • $D_{ii,//}^2 = Ds[0,ii]^2+Ds[1,ii]^2$

Then, the basic algorithm is, for each LOS defined by index ii (Ds[:,ii],us[:,ii]) and for any segment of index jj (VPoly[:,jj:jj+2]) is:

  • if us[2,ii]==0, then, introducing:

    • $q = \frac{Ds[2,ii]-VPoly[1,jj]}{VPoly[1,jj+1]-VPoly[1,jj]}$
    • $C = q^2(VPoly[0,jj+1]-VPoly[0,jj])^2 + 2qVPoly[0,jj](VPoly[0,jj+1]-VPoly[0,jj]) + VPoly[0,jj]$

      There are solution only if:

      • VPoly[1,jj+1] != VPoly[1,jj]
      • $q \in [0;1[$
      • $\delta = (u_{ii,//}\cdot D_{ii,//})^2 - u_{ii,//}^2(D_{ii,//}^2-C) > 0$

      And the solutions are $k_{1,2} = \frac{-u_{ii,//}\cdot D_{ii,//} \pm \sqrt{\delta}}{u_{ii,//}^2}$ (valid only if $\geq0$, because semi-line)

  • if us[2,ii]!=0, then, introducing:

    • $A = (VPoly[0,jj+1]-VPoly[0,jj])^2 - \frac{(VPoly[1,jj+1]-VPoly[1,jj])^2}{us[2,ii]^2}u_{ii,//}^2$
    • $B = VPoly[0,jj](VPoly[0,jj+1]-VPoly[0,jj]) + \frac{VPoly[1,jj+1]-VPoly[1,jj]}{us[2,ii]}\frac{Ds[2,ii]-VPoly[1,jj]}{us[2,ii]}u_{ii,//}^2 - \frac{VPoly[1,jj+1]-VPoly[1,jj]}{us[2,ii]}u_{ii,//}\cdot D_{ii,//}$
    • $C = -\left(\frac{Ds[2,ii]-VPoly[1,jj]}{us[2,ii]}\right)^2u_{ii,//}^2 + 2\frac{Ds[2,ii]-VPoly[1,jj]}{us[2,ii]}u_{ii,//}\cdot D_{ii,//} - D_{ii,//}^2 + VPoly[0,jj]^2$

      There are solution only if:

      • A = 0 and B != 0:
        • $q = -\frac{C}{2B}$ must be $\in [0;1[$
        • $k = q\frac{VPoly[1,jj+1]-VPoly[1,jj]}{us[2,ii]} - \frac{Ds[1,ii]-VPoly[1,jj]}{us[2,ii]}$ must be $\geq0$
      • A != 0:
        • $B^2$ must be > $AC$
        • $q_{1,2} = \frac{-B \pm \sqrt{B^2-AC}}{A}$ must be $\in [0;1[$
        • $k_{1,2} = q_{1,2}\frac{VPoly[1,jj+1]-VPoly[1,jj]}{us[2,ii]} - \frac{Ds[1,ii]-VPoly[1,jj]}{us[2,ii]}$ must be $\geq0$

Safeguard

For solutions to be valid, they have to:

  • lie on a given segment (cf.: $\in [0;1[$)
  • lie on the semi-line (cf. $k\geq0$)
  • In addition, they have to be located on the good side of the torus (no crossing through the center)

The first two conditions are met by the previous algorithm, the last one is enforced (on demand according to keyword argument Forbid) by excluding all solution in an angular sector opposite the sector the semi-line starting point.

In the following, in additon to the (Ds,us,VPoly,VIn) positional arguments, all functions also take a set of keyword arguments specifying in particular:

  • Forbid=True (default)
  • Margins and numeric tolerance values

Function versions


In [1]:
import numpy as np

Naive Python version with for loop


In [8]:
def Calc_LOS_PInOut_python(Ds, us, VPoly, vIn,
                           Forbid=True, RMin=None, EpsUz=1.e-9, EpsVz=1.e-9, EpsA=1.e-9, EpsB=1.e-9):
    
    ################
    # Prepare input
    RMin = 0.95*min(np.min(VPoly[0,:]),np.min(np.hypot(Ds[0,:],Ds[1,:]))) if RMin is None else RMin
    
    ################
    # Prepare output
    Nl, Ns = Ds.shape[1], vIn.shape[1]
    SIn, SOut = np.nan*np.ones((3,Nl),dtype=float), np.nan*np.ones((3,Nl),dtype=float)
    VPerp, indOut = np.nan*np.ones((3,Nl),dtype=float), np.nan*np.ones((Nl,),dtype=int)
    
    ################
    # Compute
    for ii in range(0,Nl):
        upscaDp = us[0,ii]*Ds[0,ii] + us[1,ii]*Ds[1,ii]
        upar2 = us[0,ii]**2 + us[1,ii]**2
        Dpar2 = Ds[0,ii]**2 + Ds[1,ii]**2
        # Prepare in case Forbid is True
        if Forbid:
            # Compute coordinates of the 2 points where the tangents touch the inner circle
            R2 = Ds[0,ii]**2 + Ds[1,ii]**2
            L = np.sqrt(R2-RMin**2)
            S1X = (RMin**2*Ds[0,ii]+RMin*Ds[1,ii]*L)/R2
            S1Y = (RMin**2*Ds[1,ii]-RMin*Ds[0,ii]*L)/R2
            S2X = (RMin**2*Ds[0,ii]-RMin*Ds[1,ii]*L)/R2
            S2Y = (RMin**2*Ds[1,ii]+RMin*Ds[0,ii]*L)/R2
        
        # Compute all solutions
        # Set tolerance value for us[2,ii]
        # EpsUz is the tolerated DZ across 50m (max Tokamak size)
        Crit = EpsUz*np.sqrt(upar2)/50.
        kout, kin, indout = np.inf, np.inf, None
        # Case with horizontal semi-line
        if np.abs(us[2,ii])<Crit:
            for jj in range(0,Ns):
                # Solutions exist only in the case with non-horizontal segment (i.e.: cone, not plane)
                if np.abs(vIn[1,jj])>EpsVz:
                    q = (Ds[2,ii]-VPoly[1,jj])/(VPoly[1,jj+1]-VPoly[1,jj])
                    # The intersection must stand on the segment 
                    if q>=0 and q<1:
                        C = q**2*(VPoly[0,jj+1]-VPoly[0,jj])**2 + 2.*q*VPoly[0,jj]*(VPoly[0,jj+1]-VPoly[0,jj]) + VPoly[0,jj]**2
                        delta = upscaDp**2 - upar2*(Dpar2-C)
                        if delta>0.:
                            sqd = np.sqrt(delta)
                            # The intersection must be on the semi-line (i.e.: k>=0)
                            # First solution
                            if -upscaDp - sqd >=0:
                                k = (-upscaDp - sqd)/upar2
                                sol = Ds[:,ii] + k*us[:,ii]
                                if Forbid:
                                    sca0 = (sol[0]-S1X)*Ds[0,ii] + (sol[1]-S1Y)*Ds[1,ii]
                                    sca1 = (sol[0]-S1X)*S1X + (sol[1]-S1Y)*S1Y
                                    sca2 = (sol[0]-S2X)*S2X + (sol[1]-S2Y)*S2Y
                                if not Forbid or (Forbid and not (sca0<0 and sca1<0 and sca2<0)):
                                    # Get the normalized perpendicular vector at intersection
                                    phi = np.arctan2(sol[1],sol[0])
                                    # Get the scalar product to determine entry or exit point
                                    sca = np.cos(phi)*vIn[0,jj]*us[0,ii] + np.sin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                                    if sca<=0 and k<kout:
                                        kout = k
                                        indout = jj
                                        #print 1, k
                                    elif sca>=0 and k<min(kin,kout):
                                        kin = k
                                        #print 2, k
                                    
                            # Second solution
                            if -upscaDp + sqd >=0:
                                k = (-upscaDp + sqd)/upar2
                                sol = Ds[:,ii] + k*us[:,ii]
                                if Forbid:
                                    sca0 = (sol[0]-S1X)*Ds[0,ii] + (sol[1]-S1Y)*Ds[1,ii]
                                    sca1 = (sol[0]-S1X)*S1X + (sol[1]-S1Y)*S1Y
                                    sca2 = (sol[0]-S2X)*S2X + (sol[1]-S2Y)*S2Y
                                if not Forbid or (Forbid and not (sca0<0 and sca1<0 and sca2<0)):
                                    # Get the normalized perpendicular vector at intersection
                                    phi = np.arctan2(sol[1],sol[0])
                                    # Get the scalar product to determine entry or exit point
                                    sca = np.cos(phi)*vIn[0,jj]*us[0,ii] + np.sin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                                    if sca<=0 and k<kout:
                                        kout = k
                                        indout = jj
                                        #print 3, k
                                    elif sca>=0 and k<min(kin,kout):
                                        kin = k
                                        #print 4, k
                                        
        # More general non-horizontal semi-line case
        else:
            for jj in range(Ns):
                v0, v1 = VPoly[0,jj+1]-VPoly[0,jj], VPoly[1,jj+1]-VPoly[1,jj]
                A = v0**2 - upar2*(v1/us[2,ii])**2
                B = VPoly[0,jj]*v0 + v1*(Ds[2,ii]-VPoly[1,jj])*upar2/us[2,ii]**2 - upscaDp*v1/us[2,ii]
                C = -upar2*(Ds[2,ii]-VPoly[1,jj])**2/us[2,ii]**2 + 2.*upscaDp*(Ds[2,ii]-VPoly[1,jj])/us[2,ii] - Dpar2 + VPoly[0,jj]**2              
               
                if np.abs(A)<EpsA and np.abs(B)>EpsB:
                    q = -C/(2.*B)
                    if q>=0. and q<1.:
                        k = (q*v1 - (Ds[2,ii]-VPoly[2,jj]))/us[2,ii]
                        if k>=0:
                            sol = Ds[:,ii] + k*us[:,ii]
                            if Forbid:
                                sca0 = (sol[0]-S1X)*Ds[0,ii] + (sol[1]-S1Y)*Ds[1,ii]
                                sca1 = (sol[0]-S1X)*S1X + (sol[1]-S1Y)*S1Y
                                sca2 = (sol[0]-S2X)*S2X + (sol[1]-S2Y)*S2Y
                                #print 1, k, kout, sca0, sca1, sca2
                                if sca0<0 and sca1<0 and sca2<0:
                                    continue
                            # Get the normalized perpendicular vector at intersection
                            phi = np.arctan2(sol[1],sol[0])
                            # Get the scalar product to determine entry or exit point
                            sca = np.cos(phi)*vIn[0,jj]*us[0,ii] + np.sin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                            if sca<=0 and k<kout:
                                kout = k
                                indout = jj
                                #print 5, k
                            elif sca>=0 and k<min(kin,kout):
                                kin = k
                                #print 6, k
                                
                elif np.abs(A)>EpsA and B**2>A*C:
                    sqd = np.sqrt(B**2-A*C)
                    # First solution
                    q = (-B + sqd)/A
                    if q>=0. and q<1.:
                        k = (q*v1 - (Ds[2,ii]-VPoly[1,jj]))/us[2,ii]
                        if k>=0.:
                            sol = Ds[:,ii] + k*us[:,ii]
                            if Forbid:
                                sca0 = (sol[0]-S1X)*Ds[0,ii] + (sol[1]-S1Y)*Ds[1,ii]
                                sca1 = (sol[0]-S1X)*S1X + (sol[1]-S1Y)*S1Y
                                sca2 = (sol[0]-S2X)*S2X + (sol[1]-S2Y)*S2Y
                                #print 2, k, kout, sca0, sca1, sca2
                            if not Forbid or (Forbid and not (sca0<0 and sca1<0 and sca2<0)):
                                # Get the normalized perpendicular vector at intersection
                                phi = np.arctan2(sol[1],sol[0])
                                # Get the scalar product to determine entry or exit point
                                sca = np.cos(phi)*vIn[0,jj]*us[0,ii] + np.sin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                                if sca<=0 and k<kout:
                                    kout = k
                                    indout = jj
                                    #print 7, k, q, A, B, C, sqd
                                elif sca>=0 and k<min(kin,kout):
                                    kin = k
                                    #print 8, k, jj
                            
                    # Second solution
                    q = (-B - sqd)/A
                    if q>=0. and q<1.:
                        k = (q*v1 - (Ds[2,ii]-VPoly[1,jj]))/us[2,ii]
                        
                        if k>=0.:
                            sol = Ds[:,ii] + k*us[:,ii]
                            if Forbid:
                                sca0 = (sol[0]-S1X)*Ds[0,ii] + (sol[1]-S1Y)*Ds[1,ii]
                                sca1 = (sol[0]-S1X)*S1X + (sol[1]-S1Y)*S1Y
                                sca2 = (sol[0]-S2X)*S2X + (sol[1]-S2Y)*S2Y
                                #print 3, k, kout, sca0, sca1, sca2
                            if not Forbid or (Forbid and not (sca0<0 and sca1<0 and sca2<0)):
                                # Get the normalized perpendicular vector at intersection
                                phi = np.arctan2(sol[1],sol[0])
                                # Get the scalar product to determine entry or exit point
                                sca = np.cos(phi)*vIn[0,jj]*us[0,ii] + np.sin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                                if sca<=0 and k<kout:
                                    kout = k
                                    indout = jj
                                    #print 9, k, jj
                                elif sca>=0 and k<min(kin,kout):
                                    kin = k
                                    #print 10, k, q, A, B, C, sqd, v0, v1, jj

        if indout is not None:
            indOut[ii] = indout
            SOut[:,ii] = Ds[:,ii] + kout*us[:,ii]
            phi = np.arctan2(SOut[1,ii],SOut[0,ii])
            VPerp[:,ii] = np.cos(phi)*vIn[0,indout], np.sin(phi)*vIn[0,indout], vIn[1,indout]
        if kin<kout:
            SIn[:,ii] = Ds[:,ii] + kin*us[:,ii]
    return SIn, SOut, VPerp, indOut

Numpy version


In [134]:
import numpy as np
def Calc_LOS_PInOut_numpy1(Ds, us, VPoly, vIn,
                          Forbid=True, RMin=None, EpsUz=1.e-6, EpsVz=1.e-9, EpsA=1.e-9, EpsB=1.e-9):

    # Prepare inputs
    RMin = 0.95*min(np.min(VPoly[0,:]),np.min(np.hypot(Ds[0,:],Ds[1,:]))) if RMin is None else RMin
    
    # Pre-define useful quantities
    Cs = VPoly[:,:-1]
    vs = VPoly[:,1:]-VPoly[:,:-1]
    upscaDp = us[0,:]*Ds[0,:] + us[1,:]*Ds[1,:]
    upar2 = us[0,:]**2 + us[1,:]**2
    Dpar2 = Ds[0,:]**2 + Ds[1,:]**2
    MaxErr = 20.
    NL, NS = Ds.shape[1], vIn.shape[1]

    Ds0, Ds1, Ds2 = np.tile(Ds[0,:],(NS,1)).T, np.tile(Ds[1,:],(NS,1)).T, np.tile(Ds[2,:],(NS,1)).T
    us0, us1, us2 = np.tile(us[0,:],(NS,1)).T, np.tile(us[1,:],(NS,1)).T, np.tile(us[2,:],(NS,1)).T
    Cs0, Cs1 = np.tile(Cs[0,:],(NL,1)), np.tile(Cs[1,:],(NL,1))
    vs0, vs1 = np.tile(vs[0,:],(NL,1)), np.tile(vs[1,:],(NL,1))
    upscaDpF = np.tile(upscaDp,(NS,1)).T
    upar2F = np.tile(upar2,(NS,1)).T
    Dpar2F = np.tile(Dpar2,(NS,1)).T

    ########################
    # Find all intersections
    # 1st dim = LOS
    # 2nd dim = VPoly
    ########################

    ###########################
    # Start with horizontal LOS

    # Prepare arrays
    # q, sqd = np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS))
    sqd = np.nan*np.ones((NL,NS))   # Test
    k0, k1 = np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS))
    
    Crit = EpsUz*np.sqrt(upar2F)/MaxErr
    # Compute quasi-horizontal LOS
    ind01 = np.abs(us2) < Crit      # Consider quasi-horizontal cases to avoid near-zero divisions otherwise, EpsUz is the tolerated DZ across 50m (max Tokamak size)
    ind01[ind01] = np.abs(vs1[ind01])>EpsVz
    q = (Ds2[ind01]-Cs1[ind01])/vs1[ind01]
    ii = (q>=0) & (q<1)
    ind01[ind01], q = ii, q[ii]
    C = q**2*vs0[ind01]**2 + 2.*q*Cs0[ind01]*vs0[ind01] + Cs0[ind01]**2
    delta = upscaDpF[ind01]**2 - upar2F[ind01]*(Dpar2F[ind01]-C)
    ind01[ind01] = delta>0.
    sqd[ind01] = np.sqrt(delta)
    ind02 = np.copy(ind01)
    ind01[ind01] = (-upscaDpF[ind01] - sqd[ind01]) >= 0.
    ind02[ind02] = (-upscaDpF[ind02] + sqd[ind02]) >= 0.
    k0[ind01] = (-upscaDpF[ind01] - sqd[ind01])/upar2F[ind01]
    k1[ind02] = (-upscaDpF[ind02] + sqd[ind02])/upar2F[ind02]
    print 'A',k0[ind01], np.any(ind01,axis=0).nonzero()[0], q, C, sqd[ind01]
    print 'A',k1[ind02], np.any(ind02,axis=0).nonzero()[0], q
    del q, C, delta, sqd
    
    # Prepare quantities for general cases
    q, q1, q2 = np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS))
    # Compute general cases
    Au2 = vs0**2*us2**2 - upar2F*vs1**2
    Bu2 = Cs0*vs0*us2**2 + vs1*(Ds2-Cs1)*upar2F - upscaDpF*vs1*us2
    Cu2 = -upar2F*(Ds2-Cs1)**2 + 2.*upscaDpF*(Ds2-Cs1)*us2 + (Cs0**2 - Dpar2F)*us2**2

    ind1 = (np.abs(us2) >= Crit) & (np.abs(Au2)<EpsA*us2**2) & (np.abs(Bu2)>EpsB*us2**2)
    q[ind1] = -Cu2[ind1]/(2.*Bu2[ind1])
    ind1[ind1] = (q[ind1]>=0) & (q[ind1]<1)
    kk = (q[ind1]*vs1[ind1] - (Ds2[ind1]-Cs1[ind1]))/us2[ind1]
    ind1[ind1] = kk>=0.
    k0[ind1] = kk[kk>=0.]
    print 'B',k0[ind1], q[ind1]
    del q, kk, upscaDpF, upar2F, Dpar2F
    
    ind21 = (np.abs(us2) >= Crit) & (np.abs(Au2)>=EpsA*us2**2) & (Bu2**2>Au2*Cu2)
    sqd = np.sqrt(Bu2[ind21]**2-Au2[ind21]*Cu2[ind21])
    q1[ind21] = (-Bu2[ind21] + sqd)/Au2[ind21]
    q2[ind21] = (-Bu2[ind21] - sqd)/Au2[ind21]
    ind22 = np.copy(ind21)
    ind21[ind21] = (q1[ind21]>=0) & (q1[ind21]<1.)
    ind22[ind22] = (q2[ind22]>=0) & (q2[ind22]<1.)
    kk0 = (q1[ind21]*vs1[ind21] - (Ds2[ind21]-Cs1[ind21]))/us2[ind21]
    kk1 = (q2[ind22]*vs1[ind22] - (Ds2[ind22]-Cs1[ind22]))/us2[ind22]
    ind21[ind21] = kk0>=0.
    ind22[ind22] = kk1>=0.
    k0[ind21] = kk0[kk0>=0.]
    k1[ind22] = kk1[kk1>=0.]
    print 'C',k0[ind21], q1[ind21], Au2[ind21], Bu2[ind21], Cu2[ind21]
    print 'C',k1[ind22], q2[ind22], Au2[ind22], Bu2[ind22], Cu2[ind22]
    del Au2, Bu2, Cu2, sqd, q1, q2, kk0, kk1, Cs0, Cs1, vs0, vs1

    # Compute associated solutions
    S00, S01, S02 = np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS))
    S10, S11, S12 = np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS))
    Ind1, Ind2 = [ind01,ind1,ind21], [ind02,ind22]
    for ii in range(0,len(Ind1)):
        S00[Ind1[ii]] = Ds0[Ind1[ii]] + k0[Ind1[ii]]*us0[Ind1[ii]]
        S01[Ind1[ii]] = Ds1[Ind1[ii]] + k0[Ind1[ii]]*us1[Ind1[ii]]
        S02[Ind1[ii]] = Ds2[Ind1[ii]] + k0[Ind1[ii]]*us2[Ind1[ii]]
    for ii in range(0,len(Ind2)):
        S10[Ind2[ii]] = Ds0[Ind2[ii]] + k1[Ind2[ii]]*us0[Ind2[ii]]
        S11[Ind2[ii]] = Ds1[Ind2[ii]] + k1[Ind2[ii]]*us1[Ind2[ii]]
        S12[Ind2[ii]] = Ds2[Ind2[ii]] + k1[Ind2[ii]]*us2[Ind2[ii]]
    Ind0 = ind01 | ind1 | ind21
    Ind1 = ind02 | ind22
    del ind01, ind1, ind21, ind02, ind22

    # Eliminate solution in forbidden area

    RMin = 0.95*min(np.nanmin(VPoly[0,:]), np.nanmin(np.hypot(Ds[0,:],Ds[1,:]))) if RMin is None else RMin
    RMax = 1.05*np.nanmax(VPoly[0,:])
    ZMin, ZMax = np.nanmin(VPoly[1,:])-0.05*np.abs(np.nanmin(VPoly[1,:])), np.nanmax(VPoly[1,:])+0.05*np.abs(np.nanmax(VPoly[1,:]))
    RS0, RS1 = np.hypot(S00,S01), np.hypot(S10,S11)
    iin0, iin1 = ~np.isnan(RS0), ~np.isnan(RS1)
    RS0, RS1 = RS0[iin0], RS1[iin1]
    
    inderr0 = (RS0<RMin) | (RS0>RMax)
    inderr1 = (RS1<RMin) | (RS1>RMax)
    assert inderr0.sum()==0 and inderr1.sum()==0, "Some solutions ({0} in S0 and {1} in S1) are way too far({2})/close({3}) !".format(inderr0.sum(),inderr1.sum(),RMax,RMin)+str(RS0)+" "+str(RS1)+"  "+str(k0[Ind0n])+"  "+str(k1[Ind1n])
    inderr0 = (S02<ZMin) | (S02>ZMax)
    inderr1 = (S12<ZMin) | (S12>ZMax)
    assert inderr0.sum()==0 and inderr1.sum()==0, "Some solutions ({0} in S0 and {1} in S1) are way too high({0})/low({1}) !".format(inderr0.sum(),inderr1.sum(),ZMax,ZMin)+str(S0[2,:])+"  "+str(S1[2,:])
    
    if Forbid:
        # This criterion is the same for both solution k0 and k1
        Ind = Ind0 | Ind1
        # Prepare useful quantities
        R2, L = np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS))
        S1X, S1Y = np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS))
        S2X, S2Y = np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS))
        # Add a little bit of margin to the major radius, just in case
        R2[Ind] = Ds0[Ind]**2+Ds1[Ind]**2
        L[Ind] = np.sqrt(R2[Ind]-RMin**2)
        # Compute coordinates of the 2 points where the tangents touch the inner circle
        S1X[Ind] = (RMin**2*Ds0[Ind]+RMin*Ds1[Ind]*L[Ind])/R2[Ind]
        S1Y[Ind] = (RMin**2*Ds1[Ind]-RMin*Ds0[Ind]*L[Ind])/R2[Ind]
        S2X[Ind] = (RMin**2*Ds0[Ind]-RMin*Ds1[Ind]*L[Ind])/R2[Ind]
        S2Y[Ind] = (RMin**2*Ds1[Ind]+RMin*Ds0[Ind]*L[Ind])/R2[Ind]
        # Check solutiona are on the good side of the 3 planes
        indout = (S00[Ind0]-S1X[Ind0])*Ds0[Ind0] + (S01[Ind0]-S1Y[Ind0])*Ds1[Ind0] < 0.
        indout = indout & ((S00[Ind0]-S1X[Ind0])*S1X[Ind0] + (S01[Ind0]-S1Y[Ind0])*S1Y[Ind0] < 0.)
        indout = indout & ((S00[Ind0]-S2X[Ind0])*S2X[Ind0] + (S01[Ind0]-S2Y[Ind0])*S2Y[Ind0] < 0.)
        Ind0[Ind0] = ~indout
        indout = (S10[Ind1]-S1X[Ind1])*Ds0[Ind1] + (S11[Ind1]-S1Y[Ind1])*Ds1[Ind1] < 0.
        indout = indout & ((S10[Ind1]-S1X[Ind1])*S1X[Ind1] + (S11[Ind1]-S1Y[Ind1])*S1Y[Ind1] < 0.)
        indout = indout & ((S10[Ind1]-S2X[Ind1])*S2X[Ind1] + (S11[Ind1]-S2Y[Ind1])*S2Y[Ind1] < 0.)
        Ind1[Ind1] = ~indout
        del Ind, R2, L, S1X, S1Y, S2X, S2Y, indout

    # Identify the POut (if any) and PIn (if any)
    VIn0, VIn1 = np.tile(vIn[0,:],(NL,1)), np.tile(vIn[1,:],(NL,1))

    sca0, sca1 = np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS))
    sca0[Ind0] = us0[Ind0]*VIn0[Ind0]*np.cos(np.arctan2(S01[Ind0],S00[Ind0])) + us1[Ind0]*VIn0[Ind0]*np.sin(np.arctan2(S01[Ind0],S00[Ind0])) + us2[Ind0]*VIn1[Ind0]
    sca1[Ind1] = us0[Ind1]*VIn0[Ind1]*np.cos(np.arctan2(S11[Ind1],S10[Ind1])) + us1[Ind1]*VIn0[Ind1]*np.sin(np.arctan2(S11[Ind1],S10[Ind1])) + us2[Ind1]*VIn1[Ind1]
    ind0out, ind1out = np.copy(Ind0), np.copy(Ind1)
    ind0out[ind0out] = sca0[ind0out]<0.
    ind1out[ind1out] = sca1[ind1out]<0.
    kk0, kk1 = np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS))
    kk0[ind0out], kk1[ind1out] = k0[ind0out], k1[ind1out]
    kk = np.fmin(kk0,kk1)
    kout = np.nanmin(kk,axis=1)
    SOut = Ds + kout[np.newaxis,:]*us
    indOut = np.nan*np.ones((NL,))
    indok = ~np.isnan(kout)
    indOut[indok] = np.nanargmin(kk[indok,:],axis=1)
    phi = np.arctan2(SOut[1,indok],SOut[0,indok])
    VPerp = np.nan*np.ones((3,NL),dtype=float)
    VPerp[:,indok] = np.array([np.cos(phi)*vIn[0,indOut[indok].astype(int)], np.sin(phi)*vIn[0,indOut[indok].astype(int)], vIn[1,indOut[indok].astype(int)]])
    
    ind0in, ind1in = np.copy(Ind0), np.copy(Ind1)
    ind0in[ind0in] = sca0[ind0in]>0.
    ind1in[ind1in] = sca1[ind1in]>0.
    ind0in[ind0in] = k0[ind0in] < (np.tile(kout,(NS,1)).T)[ind0in]
    ind1in[ind1in] = k1[ind1in] < (np.tile(kout,(NS,1)).T)[ind1in]
    kk0, kk1 = np.nan*np.ones((NL,NS)), np.nan*np.ones((NL,NS))
    kk0[ind0in], kk1[ind1in] = k0[ind0in], k1[ind1in]
    kk = np.fmin(kk0,kk1)
    SIn = Ds + np.nanmin(kk,axis=1)[np.newaxis,:]*us
    
    return SIn, SOut, VPerp, indOut

Cython version


In [121]:
%load_ext cython


The cython extension is already loaded. To reload it, use:
  %reload_ext cython

In [131]:
%%cython -a
cimport cython
import numpy as np
cimport numpy as cnp
import math
from cpython cimport bool
from libc.math cimport sqrt as Csqrt, cos as Ccos, sin as Csin, atan2 as Catan2

@cython.cdivision(True)
@cython.wraparound(False)
@cython.boundscheck(False)
def Calc_LOS_PInOut_cython(double [:,::1] Ds, double [:,::1] us, double [:,::1] VPoly, double [:,::1] vIn,
                           bool Forbid=True, RMin=None, double EpsUz=1.e-6, double EpsVz=1.e-9, double EpsA=1.e-9, double EpsB=1.e-9):

    cdef int ii, jj, Nl=Ds.shape[1], Ns=vIn.shape[1]
    cdef double Rmin, upscaDp, upar2, Dpar2, Crit2, kout, kin
    cdef int indout, Done
    cdef double L, S1X, S1Y, S2X, S2Y, sca, sca0, sca1, sca2
    cdef double q, C, delta, sqd, k, sol0, sol1
    cdef double v0, v1, A, B
    cdef int Forbidbis, Forbid0
    cdef cnp.ndarray[double,ndim=2] SIn_=np.nan*np.ones((3,Nl)), SOut_=np.nan*np.ones((3,Nl))
    cdef cnp.ndarray[double,ndim=2] VPerp_=np.nan*np.ones((3,Nl))
    cdef cnp.ndarray[double,ndim=1] indOut_=np.nan*np.ones((Nl,))

    cdef double[:,::1] SIn=SIn_, SOut=SOut_, VPerp=VPerp_
    cdef double[::1] indOut=indOut_
    
    ################
    # Prepare input
    if RMin is None:
        Rmin = 0.95*min(np.min(VPoly[0,:]),np.min(np.hypot(Ds[0,:],Ds[1,:])))
    else:
        Rmin = RMin
    
    ################
    # Compute
    if Forbid:
        Forbid0, Forbidbis = 1, 1
    else:
        Forbid0, Forbidbis = 0, 0
    for ii in range(0,Nl):
        upscaDp = us[0,ii]*Ds[0,ii] + us[1,ii]*Ds[1,ii]
        upar2 = us[0,ii]**2 + us[1,ii]**2
        Dpar2 = Ds[0,ii]**2 + Ds[1,ii]**2
        # Prepare in case Forbid is True
        if Forbid0 and not Dpar2>0:
            Forbidbis = 0
        if Forbidbis:
            # Compute coordinates of the 2 points where the tangents touch the inner circle
            L = Csqrt(Dpar2-Rmin**2)
            S1X = (Rmin**2*Ds[0,ii]+Rmin*Ds[1,ii]*L)/Dpar2
            S1Y = (Rmin**2*Ds[1,ii]-Rmin*Ds[0,ii]*L)/Dpar2
            S2X = (Rmin**2*Ds[0,ii]-Rmin*Ds[1,ii]*L)/Dpar2
            S2Y = (Rmin**2*Ds[1,ii]+Rmin*Ds[0,ii]*L)/Dpar2
        
        # Compute all solutions
        # Set tolerance value for us[2,ii]
        # EpsUz is the tolerated DZ across 20m (max Tokamak size)
        Crit2 = EpsUz**2*upar2/400.
        kout, kin, Done = 1.e12, 1e12, 0
        # Case with horizontal semi-line
        if us[2,ii]**2<Crit2:
            for jj in range(0,Ns):
                # Solutions exist only in the case with non-horizontal segment (i.e.: cone, not plane)
                if (VPoly[1,jj+1]-VPoly[1,jj])**2>EpsVz**2:
                    q = (Ds[2,ii]-VPoly[1,jj])/(VPoly[1,jj+1]-VPoly[1,jj])
                    # The intersection must stand on the segment 
                    if q>=0 and q<1:
                        C = q**2*(VPoly[0,jj+1]-VPoly[0,jj])**2 + 2.*q*VPoly[0,jj]*(VPoly[0,jj+1]-VPoly[0,jj]) + VPoly[0,jj]**2
                        delta = upscaDp**2 - upar2*(Dpar2-C)
                        if delta>0.:
                            sqd = Csqrt(delta)
                            # The intersection must be on the semi-line (i.e.: k>=0)
                            # First solution
                            if -upscaDp - sqd >=0:
                                k = (-upscaDp - sqd)/upar2
                                sol0, sol1 = Ds[0,ii] + k*us[0,ii], Ds[1,ii] + k*us[1,ii] 
                                if Forbidbis:
                                    sca0 = (sol0-S1X)*Ds[0,ii] + (sol1-S1Y)*Ds[1,ii]
                                    sca1 = (sol0-S1X)*S1X + (sol1-S1Y)*S1Y
                                    sca2 = (sol0-S2X)*S2X + (sol1-S2Y)*S2Y
                                if not Forbidbis or (Forbidbis and not (sca0<0 and sca1<0 and sca2<0)):
                                    # Get the normalized perpendicular vector at intersection
                                    phi = Catan2(sol1,sol0)
                                    # Get the scalar product to determine entry or exit point
                                    sca = Ccos(phi)*vIn[0,jj]*us[0,ii] + Csin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                                    if sca<=0 and k<kout:
                                        kout = k
                                        indout = jj
                                        Done = 1
                                        print 1, k
                                    elif sca>=0 and k<min(kin,kout):
                                        kin = k
                                        print 2, k
                                    
                            # Second solution
                            if -upscaDp + sqd >=0:
                                k = (-upscaDp + sqd)/upar2
                                sol0, sol1 = Ds[0,ii] + k*us[0,ii], Ds[1,ii] + k*us[1,ii]
                                if Forbidbis:
                                    sca0 = (sol0-S1X)*Ds[0,ii] + (sol1-S1Y)*Ds[1,ii]
                                    sca1 = (sol0-S1X)*S1X + (sol1-S1Y)*S1Y
                                    sca2 = (sol0-S2X)*S2X + (sol1-S2Y)*S2Y
                                if not Forbidbis or (Forbidbis and not (sca0<0 and sca1<0 and sca2<0)):
                                    # Get the normalized perpendicular vector at intersection
                                    phi = Catan2(sol1,sol0)
                                    # Get the scalar product to determine entry or exit point
                                    sca = Ccos(phi)*vIn[0,jj]*us[0,ii] + Csin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                                    if sca<=0 and k<kout:
                                        kout = k
                                        indout = jj
                                        Done = 1
                                        print 3, k
                                    elif sca>=0 and k<min(kin,kout):
                                        kin = k
                                        print 4, k
                                        
        # More general non-horizontal semi-line case
        else:
            for jj in range(Ns):
                v0, v1 = VPoly[0,jj+1]-VPoly[0,jj], VPoly[1,jj+1]-VPoly[1,jj]
                A = v0**2 - upar2*(v1/us[2,ii])**2
                B = VPoly[0,jj]*v0 + v1*(Ds[2,ii]-VPoly[1,jj])*upar2/us[2,ii]**2 - upscaDp*v1/us[2,ii]
                C = -upar2*(Ds[2,ii]-VPoly[1,jj])**2/us[2,ii]**2 + 2.*upscaDp*(Ds[2,ii]-VPoly[1,jj])/us[2,ii] - Dpar2 + VPoly[0,jj]**2              
               
                if A**2<EpsA**2 and B**2>EpsB**2:
                    q = -C/(2.*B)
                    if q>=0. and q<1.:
                        k = (q*v1 - (Ds[2,ii]-VPoly[2,jj]))/us[2,ii]
                        if k>=0:
                            sol0, sol1 = Ds[0,ii] + k*us[0,ii], Ds[1,ii] + k*us[1,ii]
                            if Forbidbis:
                                sca0 = (sol0-S1X)*Ds[0,ii] + (sol1-S1Y)*Ds[1,ii]
                                sca1 = (sol0-S1X)*S1X + (sol1-S1Y)*S1Y
                                sca2 = (sol0-S2X)*S2X + (sol1-S2Y)*S2Y
                                #print 1, k, kout, sca0, sca1, sca2
                                if sca0<0 and sca1<0 and sca2<0:
                                    continue
                            # Get the normalized perpendicular vector at intersection
                            phi = Catan2(sol1,sol0)
                            # Get the scalar product to determine entry or exit point
                            sca = Ccos(phi)*vIn[0,jj]*us[0,ii] + Csin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                            if sca<=0 and k<kout:
                                kout = k
                                indout = jj
                                Done = 1
                                print 5, k
                            elif sca>=0 and k<min(kin,kout):
                                kin = k
                                print 6, k
                                
                elif A**2>=EpsA**2 and B**2>A*C:
                    sqd = Csqrt(B**2-A*C)
                    # First solution
                    q = (-B + sqd)/A
                    if q>=0. and q<1.:
                        k = (q*v1 - (Ds[2,ii]-VPoly[1,jj]))/us[2,ii]
                        if k>=0.:
                            sol0, sol1 = Ds[0,ii] + k*us[0,ii], Ds[1,ii] + k*us[1,ii]
                            if Forbidbis:
                                sca0 = (sol0-S1X)*Ds[0,ii] + (sol1-S1Y)*Ds[1,ii]
                                sca1 = (sol0-S1X)*S1X + (sol1-S1Y)*S1Y
                                sca2 = (sol0-S2X)*S2X + (sol1-S2Y)*S2Y
                                #print 2, k, kout, sca0, sca1, sca2
                            if not Forbidbis or (Forbidbis and not (sca0<0 and sca1<0 and sca2<0)):
                                # Get the normalized perpendicular vector at intersection
                                phi = Catan2(sol1,sol0)
                                # Get the scalar product to determine entry or exit point
                                sca = Ccos(phi)*vIn[0,jj]*us[0,ii] + Csin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                                if sca<=0 and k<kout:
                                    kout = k
                                    indout = jj
                                    Done = 1
                                    print 7, k, q, A, B, C, sqd
                                elif sca>=0 and k<min(kin,kout):
                                    kin = k
                                    print 8, k, jj
                            
                    # Second solution
                    q = (-B - sqd)/A
                    if q>=0. and q<1.:
                        k = (q*v1 - (Ds[2,ii]-VPoly[1,jj]))/us[2,ii]
                        
                        if k>=0.:
                            sol0, sol1 = Ds[0,ii] + k*us[0,ii], Ds[1,ii] + k*us[1,ii]
                            if Forbidbis:
                                sca0 = (sol0-S1X)*Ds[0,ii] + (sol1-S1Y)*Ds[1,ii]
                                sca1 = (sol0-S1X)*S1X + (sol1-S1Y)*S1Y
                                sca2 = (sol0-S2X)*S2X + (sol1-S2Y)*S2Y
                                #print 3, k, kout, sca0, sca1, sca2
                            if not Forbidbis or (Forbidbis and not (sca0<0 and sca1<0 and sca2<0)):
                                # Get the normalized perpendicular vector at intersection
                                phi = Catan2(sol1,sol0)
                                # Get the scalar product to determine entry or exit point
                                sca = Ccos(phi)*vIn[0,jj]*us[0,ii] + Csin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                                if sca<=0 and k<kout:
                                    kout = k
                                    indout = jj
                                    Done = 1
                                    print 9, k, jj
                                elif sca>=0 and k<min(kin,kout):
                                    kin = k
                                    print 10, k, q, A, B, C, sqd, v0, v1, jj

        if Done==1:
            indOut[ii] = indout
            SOut[0,ii] = Ds[0,ii] + kout*us[0,ii]
            SOut[1,ii] = Ds[1,ii] + kout*us[1,ii]
            SOut[2,ii] = Ds[2,ii] + kout*us[2,ii]
            phi = Catan2(SOut[1,ii],SOut[0,ii])
            VPerp[0,ii] = Ccos(phi)*vIn[0,indout]
            VPerp[1,ii] = Csin(phi)*vIn[0,indout]
            VPerp[2,ii] = vIn[1,indout]
        if kin<kout:
            SIn[0,ii] = Ds[0,ii] + kin*us[0,ii]
            SIn[1,ii] = Ds[1,ii] + kin*us[1,ii]
            SIn[2,ii] = Ds[2,ii] + kin*us[2,ii]
            

    return np.asarray(SIn), np.asarray(SOut), np.asarray(VPerp), np.asarray(indOut)


Out[131]:
Cython: _cython_magic_163cfc3d2ce7aad39b88b29178aa2d8c.pyx

Generated by Cython 0.25.2

Yellow lines hint at Python interaction.
Click on a line that starts with a "+" to see the C code that Cython generated for it.

+001: cimport cython
  __pyx_t_1 = PyDict_New(); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_test, __pyx_t_1) < 0) __PYX_ERR(0, 1, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+002: import numpy as np
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_numpy, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_np, __pyx_t_1) < 0) __PYX_ERR(0, 2, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 003: cimport numpy as cnp
+004: import math
  __pyx_t_1 = __Pyx_Import(__pyx_n_s_math, 0, -1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_math, __pyx_t_1) < 0) __PYX_ERR(0, 4, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
 005: from cpython cimport bool
 006: from libc.math cimport sqrt as Csqrt, cos as Ccos, sin as Csin, atan2 as Catan2
 007: 
 008: @cython.cdivision(True)
 009: @cython.wraparound(False)
 010: @cython.boundscheck(False)
+011: def Calc_LOS_PInOut_cython(double [:,::1] Ds, double [:,::1] us, double [:,::1] VPoly, double [:,::1] vIn,
/* Python wrapper */
static PyObject *__pyx_pw_46_cython_magic_163cfc3d2ce7aad39b88b29178aa2d8c_1Calc_LOS_PInOut_cython(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyMethodDef __pyx_mdef_46_cython_magic_163cfc3d2ce7aad39b88b29178aa2d8c_1Calc_LOS_PInOut_cython = {"Calc_LOS_PInOut_cython", (PyCFunction)__pyx_pw_46_cython_magic_163cfc3d2ce7aad39b88b29178aa2d8c_1Calc_LOS_PInOut_cython, METH_VARARGS|METH_KEYWORDS, 0};
static PyObject *__pyx_pw_46_cython_magic_163cfc3d2ce7aad39b88b29178aa2d8c_1Calc_LOS_PInOut_cython(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  __Pyx_memviewslice __pyx_v_Ds = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_us = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_VPoly = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_vIn = { 0, 0, { 0 }, { 0 }, { 0 } };
  PyBoolObject *__pyx_v_Forbid = 0;
  PyObject *__pyx_v_RMin = 0;
  double __pyx_v_EpsUz;
  double __pyx_v_EpsVz;
  double __pyx_v_EpsA;
  double __pyx_v_EpsB;
  PyObject *__pyx_r = 0;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("Calc_LOS_PInOut_cython (wrapper)", 0);
  {
    static PyObject **__pyx_pyargnames[] = {&__pyx_n_s_Ds,&__pyx_n_s_us,&__pyx_n_s_VPoly,&__pyx_n_s_vIn,&__pyx_n_s_Forbid,&__pyx_n_s_RMin,&__pyx_n_s_EpsUz,&__pyx_n_s_EpsVz,&__pyx_n_s_EpsA,&__pyx_n_s_EpsB,0};
    PyObject* values[10] = {0,0,0,0,0,0,0,0,0,0};
/* … */
  /* function exit code */
  goto __pyx_L0;
  __pyx_L1_error:;
  __pyx_r = NULL;
  __pyx_L0:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}

static PyObject *__pyx_pf_46_cython_magic_163cfc3d2ce7aad39b88b29178aa2d8c_Calc_LOS_PInOut_cython(CYTHON_UNUSED PyObject *__pyx_self, __Pyx_memviewslice __pyx_v_Ds, __Pyx_memviewslice __pyx_v_us, __Pyx_memviewslice __pyx_v_VPoly, __Pyx_memviewslice __pyx_v_vIn, PyBoolObject *__pyx_v_Forbid, PyObject *__pyx_v_RMin, double __pyx_v_EpsUz, double __pyx_v_EpsVz, double __pyx_v_EpsA, double __pyx_v_EpsB) {
  int __pyx_v_ii;
  int __pyx_v_jj;
  int __pyx_v_Nl;
  int __pyx_v_Ns;
  double __pyx_v_Rmin;
  double __pyx_v_upscaDp;
  double __pyx_v_upar2;
  double __pyx_v_Dpar2;
  double __pyx_v_Crit2;
  double __pyx_v_kout;
  double __pyx_v_kin;
  int __pyx_v_indout;
  int __pyx_v_Done;
  double __pyx_v_L;
  double __pyx_v_S1X;
  double __pyx_v_S1Y;
  double __pyx_v_S2X;
  double __pyx_v_S2Y;
  double __pyx_v_sca;
  double __pyx_v_sca0;
  double __pyx_v_sca1;
  double __pyx_v_sca2;
  double __pyx_v_q;
  double __pyx_v_C;
  double __pyx_v_delta;
  double __pyx_v_sqd;
  double __pyx_v_k;
  double __pyx_v_sol0;
  double __pyx_v_sol1;
  double __pyx_v_v0;
  double __pyx_v_v1;
  double __pyx_v_A;
  double __pyx_v_B;
  int __pyx_v_Forbidbis;
  int __pyx_v_Forbid0;
  PyArrayObject *__pyx_v_SIn_ = 0;
  PyArrayObject *__pyx_v_SOut_ = 0;
  PyArrayObject *__pyx_v_VPerp_ = 0;
  PyArrayObject *__pyx_v_indOut_ = 0;
  __Pyx_memviewslice __pyx_v_SIn = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_SOut = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_VPerp = { 0, 0, { 0 }, { 0 }, { 0 } };
  __Pyx_memviewslice __pyx_v_indOut = { 0, 0, { 0 }, { 0 }, { 0 } };
  double __pyx_v_phi;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_SIn_;
  __Pyx_Buffer __pyx_pybuffer_SIn_;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_SOut_;
  __Pyx_Buffer __pyx_pybuffer_SOut_;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_VPerp_;
  __Pyx_Buffer __pyx_pybuffer_VPerp_;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_indOut_;
  __Pyx_Buffer __pyx_pybuffer_indOut_;
  PyObject *__pyx_r = NULL;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("Calc_LOS_PInOut_cython", 0);
  __pyx_pybuffer_SIn_.pybuffer.buf = NULL;
  __pyx_pybuffer_SIn_.refcount = 0;
  __pyx_pybuffernd_SIn_.data = NULL;
  __pyx_pybuffernd_SIn_.rcbuffer = &__pyx_pybuffer_SIn_;
  __pyx_pybuffer_SOut_.pybuffer.buf = NULL;
  __pyx_pybuffer_SOut_.refcount = 0;
  __pyx_pybuffernd_SOut_.data = NULL;
  __pyx_pybuffernd_SOut_.rcbuffer = &__pyx_pybuffer_SOut_;
  __pyx_pybuffer_VPerp_.pybuffer.buf = NULL;
  __pyx_pybuffer_VPerp_.refcount = 0;
  __pyx_pybuffernd_VPerp_.data = NULL;
  __pyx_pybuffernd_VPerp_.rcbuffer = &__pyx_pybuffer_VPerp_;
  __pyx_pybuffer_indOut_.pybuffer.buf = NULL;
  __pyx_pybuffer_indOut_.refcount = 0;
  __pyx_pybuffernd_indOut_.data = NULL;
  __pyx_pybuffernd_indOut_.rcbuffer = &__pyx_pybuffer_indOut_;
/* … */
  /* function exit code */
  __pyx_L1_error:;
  __Pyx_XDECREF(__pyx_t_1);
  __Pyx_XDECREF(__pyx_t_2);
  __Pyx_XDECREF(__pyx_t_3);
  __Pyx_XDECREF(__pyx_t_4);
  __Pyx_XDECREF(__pyx_t_5);
  __Pyx_XDECREF(__pyx_t_6);
  __PYX_XDEC_MEMVIEW(&__pyx_t_10, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
  __Pyx_XDECREF(__pyx_t_14);
  __Pyx_XDECREF(__pyx_t_16);
  __Pyx_XDECREF(__pyx_t_254);
  __Pyx_XDECREF(__pyx_t_255);
  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
    __Pyx_PyThreadState_declare
    __Pyx_PyThreadState_assign
    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_SIn_.rcbuffer->pybuffer);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_SOut_.rcbuffer->pybuffer);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_VPerp_.rcbuffer->pybuffer);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_indOut_.rcbuffer->pybuffer);
  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
  __Pyx_AddTraceback("_cython_magic_163cfc3d2ce7aad39b88b29178aa2d8c.Calc_LOS_PInOut_cython", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __pyx_r = NULL;
  goto __pyx_L2;
  __pyx_L0:;
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_SIn_.rcbuffer->pybuffer);
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_SOut_.rcbuffer->pybuffer);
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_VPerp_.rcbuffer->pybuffer);
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_indOut_.rcbuffer->pybuffer);
  __pyx_L2:;
  __Pyx_XDECREF((PyObject *)__pyx_v_SIn_);
  __Pyx_XDECREF((PyObject *)__pyx_v_SOut_);
  __Pyx_XDECREF((PyObject *)__pyx_v_VPerp_);
  __Pyx_XDECREF((PyObject *)__pyx_v_indOut_);
  __PYX_XDEC_MEMVIEW(&__pyx_v_SIn, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_v_SOut, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_v_VPerp, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_v_indOut, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_v_Ds, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_v_us, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_v_VPoly, 1);
  __PYX_XDEC_MEMVIEW(&__pyx_v_vIn, 1);
  __Pyx_XGIVEREF(__pyx_r);
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
/* … */
  __pyx_tuple__23 = PyTuple_Pack(54, __pyx_n_s_Ds, __pyx_n_s_us, __pyx_n_s_VPoly, __pyx_n_s_vIn, __pyx_n_s_Forbid, __pyx_n_s_RMin, __pyx_n_s_EpsUz, __pyx_n_s_EpsVz, __pyx_n_s_EpsA, __pyx_n_s_EpsB, __pyx_n_s_ii, __pyx_n_s_jj, __pyx_n_s_Nl, __pyx_n_s_Ns, __pyx_n_s_Rmin, __pyx_n_s_upscaDp, __pyx_n_s_upar2, __pyx_n_s_Dpar2, __pyx_n_s_Crit2, __pyx_n_s_kout, __pyx_n_s_kin, __pyx_n_s_indout, __pyx_n_s_Done, __pyx_n_s_L, __pyx_n_s_S1X, __pyx_n_s_S1Y, __pyx_n_s_S2X, __pyx_n_s_S2Y, __pyx_n_s_sca, __pyx_n_s_sca0, __pyx_n_s_sca1, __pyx_n_s_sca2, __pyx_n_s_q, __pyx_n_s_C, __pyx_n_s_delta, __pyx_n_s_sqd, __pyx_n_s_k, __pyx_n_s_sol0, __pyx_n_s_sol1, __pyx_n_s_v0, __pyx_n_s_v1, __pyx_n_s_A, __pyx_n_s_B, __pyx_n_s_Forbidbis, __pyx_n_s_Forbid0, __pyx_n_s_SIn, __pyx_n_s_SOut, __pyx_n_s_VPerp, __pyx_n_s_indOut, __pyx_n_s_SIn_2, __pyx_n_s_SOut_2, __pyx_n_s_VPerp_2, __pyx_n_s_indOut_2, __pyx_n_s_phi); if (unlikely(!__pyx_tuple__23)) __PYX_ERR(0, 11, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_tuple__23);
  __Pyx_GIVEREF(__pyx_tuple__23);
/* … */
  __pyx_t_1 = PyCFunction_NewEx(&__pyx_mdef_46_cython_magic_163cfc3d2ce7aad39b88b29178aa2d8c_1Calc_LOS_PInOut_cython, NULL, __pyx_n_s_cython_magic_163cfc3d2ce7aad39b); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 11, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  if (PyDict_SetItem(__pyx_d, __pyx_n_s_Calc_LOS_PInOut_cython, __pyx_t_1) < 0) __PYX_ERR(0, 11, __pyx_L1_error)
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_codeobj__24 = (PyObject*)__Pyx_PyCode_New(10, 0, 54, 0, 0, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__23, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_Home_DV226270_cache_ipython_cyt, __pyx_n_s_Calc_LOS_PInOut_cython, 11, __pyx_empty_bytes); if (unlikely(!__pyx_codeobj__24)) __PYX_ERR(0, 11, __pyx_L1_error)
+012:                            bool Forbid=True, RMin=None, double EpsUz=1.e-6, double EpsVz=1.e-9, double EpsA=1.e-9, double EpsB=1.e-9):
    values[4] = (PyObject *)((PyBoolObject *)Py_True);
    values[5] = ((PyObject *)Py_None);
    if (unlikely(__pyx_kwds)) {
      Py_ssize_t kw_args;
      const Py_ssize_t pos_args = PyTuple_GET_SIZE(__pyx_args);
      switch (pos_args) {
        case 10: values[9] = PyTuple_GET_ITEM(__pyx_args, 9);
        case  9: values[8] = PyTuple_GET_ITEM(__pyx_args, 8);
        case  8: values[7] = PyTuple_GET_ITEM(__pyx_args, 7);
        case  7: values[6] = PyTuple_GET_ITEM(__pyx_args, 6);
        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
        case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        case  3: values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        case  2: values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        case  1: values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        case  0: break;
        default: goto __pyx_L5_argtuple_error;
      }
      kw_args = PyDict_Size(__pyx_kwds);
      switch (pos_args) {
        case  0:
        if (likely((values[0] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_Ds)) != 0)) kw_args--;
        else goto __pyx_L5_argtuple_error;
        case  1:
        if (likely((values[1] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_us)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("Calc_LOS_PInOut_cython", 0, 4, 10, 1); __PYX_ERR(0, 11, __pyx_L3_error)
        }
        case  2:
        if (likely((values[2] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_VPoly)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("Calc_LOS_PInOut_cython", 0, 4, 10, 2); __PYX_ERR(0, 11, __pyx_L3_error)
        }
        case  3:
        if (likely((values[3] = PyDict_GetItem(__pyx_kwds, __pyx_n_s_vIn)) != 0)) kw_args--;
        else {
          __Pyx_RaiseArgtupleInvalid("Calc_LOS_PInOut_cython", 0, 4, 10, 3); __PYX_ERR(0, 11, __pyx_L3_error)
        }
        case  4:
        if (kw_args > 0) {
          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_Forbid);
          if (value) { values[4] = value; kw_args--; }
        }
        case  5:
        if (kw_args > 0) {
          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_RMin);
          if (value) { values[5] = value; kw_args--; }
        }
        case  6:
        if (kw_args > 0) {
          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_EpsUz);
          if (value) { values[6] = value; kw_args--; }
        }
        case  7:
        if (kw_args > 0) {
          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_EpsVz);
          if (value) { values[7] = value; kw_args--; }
        }
        case  8:
        if (kw_args > 0) {
          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_EpsA);
          if (value) { values[8] = value; kw_args--; }
        }
        case  9:
        if (kw_args > 0) {
          PyObject* value = PyDict_GetItem(__pyx_kwds, __pyx_n_s_EpsB);
          if (value) { values[9] = value; kw_args--; }
        }
      }
      if (unlikely(kw_args > 0)) {
        if (unlikely(__Pyx_ParseOptionalKeywords(__pyx_kwds, __pyx_pyargnames, 0, values, pos_args, "Calc_LOS_PInOut_cython") < 0)) __PYX_ERR(0, 11, __pyx_L3_error)
      }
    } else {
      switch (PyTuple_GET_SIZE(__pyx_args)) {
        case 10: values[9] = PyTuple_GET_ITEM(__pyx_args, 9);
        case  9: values[8] = PyTuple_GET_ITEM(__pyx_args, 8);
        case  8: values[7] = PyTuple_GET_ITEM(__pyx_args, 7);
        case  7: values[6] = PyTuple_GET_ITEM(__pyx_args, 6);
        case  6: values[5] = PyTuple_GET_ITEM(__pyx_args, 5);
        case  5: values[4] = PyTuple_GET_ITEM(__pyx_args, 4);
        case  4: values[3] = PyTuple_GET_ITEM(__pyx_args, 3);
        values[2] = PyTuple_GET_ITEM(__pyx_args, 2);
        values[1] = PyTuple_GET_ITEM(__pyx_args, 1);
        values[0] = PyTuple_GET_ITEM(__pyx_args, 0);
        break;
        default: goto __pyx_L5_argtuple_error;
      }
    }
    __pyx_v_Ds = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(values[0]); if (unlikely(!__pyx_v_Ds.memview)) __PYX_ERR(0, 11, __pyx_L3_error)
    __pyx_v_us = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(values[1]); if (unlikely(!__pyx_v_us.memview)) __PYX_ERR(0, 11, __pyx_L3_error)
    __pyx_v_VPoly = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(values[2]); if (unlikely(!__pyx_v_VPoly.memview)) __PYX_ERR(0, 11, __pyx_L3_error)
    __pyx_v_vIn = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(values[3]); if (unlikely(!__pyx_v_vIn.memview)) __PYX_ERR(0, 11, __pyx_L3_error)
    __pyx_v_Forbid = ((PyBoolObject *)values[4]);
    __pyx_v_RMin = values[5];
    if (values[6]) {
      __pyx_v_EpsUz = __pyx_PyFloat_AsDouble(values[6]); if (unlikely((__pyx_v_EpsUz == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 12, __pyx_L3_error)
    } else {
      __pyx_v_EpsUz = ((double)1.e-6);
    }
    if (values[7]) {
      __pyx_v_EpsVz = __pyx_PyFloat_AsDouble(values[7]); if (unlikely((__pyx_v_EpsVz == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 12, __pyx_L3_error)
    } else {
      __pyx_v_EpsVz = ((double)1.e-9);
    }
    if (values[8]) {
      __pyx_v_EpsA = __pyx_PyFloat_AsDouble(values[8]); if (unlikely((__pyx_v_EpsA == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 12, __pyx_L3_error)
    } else {
      __pyx_v_EpsA = ((double)1.e-9);
    }
    if (values[9]) {
      __pyx_v_EpsB = __pyx_PyFloat_AsDouble(values[9]); if (unlikely((__pyx_v_EpsB == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 12, __pyx_L3_error)
    } else {
      __pyx_v_EpsB = ((double)1.e-9);
    }
  }
  goto __pyx_L4_argument_unpacking_done;
  __pyx_L5_argtuple_error:;
  __Pyx_RaiseArgtupleInvalid("Calc_LOS_PInOut_cython", 0, 4, 10, PyTuple_GET_SIZE(__pyx_args)); __PYX_ERR(0, 11, __pyx_L3_error)
  __pyx_L3_error:;
  __Pyx_AddTraceback("_cython_magic_163cfc3d2ce7aad39b88b29178aa2d8c.Calc_LOS_PInOut_cython", __pyx_clineno, __pyx_lineno, __pyx_filename);
  __Pyx_RefNannyFinishContext();
  return NULL;
  __pyx_L4_argument_unpacking_done:;
  if (unlikely(!__Pyx_ArgTypeTest(((PyObject *)__pyx_v_Forbid), __pyx_ptype_7cpython_4bool_bool, 1, "Forbid", 0))) __PYX_ERR(0, 12, __pyx_L1_error)
  __pyx_r = __pyx_pf_46_cython_magic_163cfc3d2ce7aad39b88b29178aa2d8c_Calc_LOS_PInOut_cython(__pyx_self, __pyx_v_Ds, __pyx_v_us, __pyx_v_VPoly, __pyx_v_vIn, __pyx_v_Forbid, __pyx_v_RMin, __pyx_v_EpsUz, __pyx_v_EpsVz, __pyx_v_EpsA, __pyx_v_EpsB);
 013: 
+014:     cdef int ii, jj, Nl=Ds.shape[1], Ns=vIn.shape[1]
  __pyx_v_Nl = (__pyx_v_Ds.shape[1]);
  __pyx_v_Ns = (__pyx_v_vIn.shape[1]);
 015:     cdef double Rmin, upscaDp, upar2, Dpar2, Crit2, kout, kin
 016:     cdef int indout, Done
 017:     cdef double L, S1X, S1Y, S2X, S2Y, sca, sca0, sca1, sca2
 018:     cdef double q, C, delta, sqd, k, sol0, sol1
 019:     cdef double v0, v1, A, B
 020:     cdef int Forbidbis, Forbid0
+021:     cdef cnp.ndarray[double,ndim=2] SIn_=np.nan*np.ones((3,Nl)), SOut_=np.nan*np.ones((3,Nl))
  __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_nan); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_ones); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = __Pyx_PyInt_From_int(__pyx_v_Nl); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_INCREF(__pyx_int_3);
  __Pyx_GIVEREF(__pyx_int_3);
  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_int_3);
  __Pyx_GIVEREF(__pyx_t_3);
  PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_3);
  __pyx_t_3 = 0;
  __pyx_t_3 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_4))) {
    __pyx_t_3 = PyMethod_GET_SELF(__pyx_t_4);
    if (likely(__pyx_t_3)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_4);
      __Pyx_INCREF(__pyx_t_3);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_4, function);
    }
  }
  if (!__pyx_t_3) {
    __pyx_t_1 = __Pyx_PyObject_CallOneArg(__pyx_t_4, __pyx_t_5); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 21, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    __Pyx_GOTREF(__pyx_t_1);
  } else {
    #if CYTHON_FAST_PYCALL
    if (PyFunction_Check(__pyx_t_4)) {
      PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_t_5};
      __pyx_t_1 = __Pyx_PyFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 21, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    } else
    #endif
    #if CYTHON_FAST_PYCCALL
    if (__Pyx_PyFastCFunction_Check(__pyx_t_4)) {
      PyObject *__pyx_temp[2] = {__pyx_t_3, __pyx_t_5};
      __pyx_t_1 = __Pyx_PyCFunction_FastCall(__pyx_t_4, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 21, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_3); __pyx_t_3 = 0;
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    } else
    #endif
    {
      __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 21, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_6);
      __Pyx_GIVEREF(__pyx_t_3); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_3); __pyx_t_3 = NULL;
      __Pyx_GIVEREF(__pyx_t_5);
      PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_5);
      __pyx_t_5 = 0;
      __pyx_t_1 = __Pyx_PyObject_Call(__pyx_t_4, __pyx_t_6, NULL); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 21, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
    }
  }
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  __pyx_t_4 = PyNumber_Multiply(__pyx_t_2, __pyx_t_1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  if (!(likely(((__pyx_t_4) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_4, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 21, __pyx_L1_error)
  __pyx_t_7 = ((PyArrayObject *)__pyx_t_4);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_SIn_.rcbuffer->pybuffer, (PyObject*)__pyx_t_7, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_STRIDES, 2, 0, __pyx_stack) == -1)) {
      __pyx_v_SIn_ = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_SIn_.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 21, __pyx_L1_error)
    } else {__pyx_pybuffernd_SIn_.diminfo[0].strides = __pyx_pybuffernd_SIn_.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_SIn_.diminfo[0].shape = __pyx_pybuffernd_SIn_.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_SIn_.diminfo[1].strides = __pyx_pybuffernd_SIn_.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_SIn_.diminfo[1].shape = __pyx_pybuffernd_SIn_.rcbuffer->pybuffer.shape[1];
    }
  }
  __pyx_t_7 = 0;
  __pyx_v_SIn_ = ((PyArrayObject *)__pyx_t_4);
  __pyx_t_4 = 0;
  __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_t_1 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_nan); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  __pyx_t_2 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_2, __pyx_n_s_ones); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_2 = __Pyx_PyInt_From_int(__pyx_v_Nl); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_INCREF(__pyx_int_3);
  __Pyx_GIVEREF(__pyx_int_3);
  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_int_3);
  __Pyx_GIVEREF(__pyx_t_2);
  PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_2);
  __pyx_t_2 = 0;
  __pyx_t_2 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) {
    __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6);
    if (likely(__pyx_t_2)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
      __Pyx_INCREF(__pyx_t_2);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_6, function);
    }
  }
  if (!__pyx_t_2) {
    __pyx_t_4 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_5); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 21, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    __Pyx_GOTREF(__pyx_t_4);
  } else {
    #if CYTHON_FAST_PYCALL
    if (PyFunction_Check(__pyx_t_6)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_5};
      __pyx_t_4 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 21, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    } else
    #endif
    #if CYTHON_FAST_PYCCALL
    if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_5};
      __pyx_t_4 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 21, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    } else
    #endif
    {
      __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 21, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); __pyx_t_2 = NULL;
      __Pyx_GIVEREF(__pyx_t_5);
      PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_t_5);
      __pyx_t_5 = 0;
      __pyx_t_4 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_3, NULL); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 21, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    }
  }
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_t_6 = PyNumber_Multiply(__pyx_t_1, __pyx_t_4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 21, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  if (!(likely(((__pyx_t_6) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_6, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 21, __pyx_L1_error)
  __pyx_t_7 = ((PyArrayObject *)__pyx_t_6);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_SOut_.rcbuffer->pybuffer, (PyObject*)__pyx_t_7, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_STRIDES, 2, 0, __pyx_stack) == -1)) {
      __pyx_v_SOut_ = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_SOut_.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 21, __pyx_L1_error)
    } else {__pyx_pybuffernd_SOut_.diminfo[0].strides = __pyx_pybuffernd_SOut_.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_SOut_.diminfo[0].shape = __pyx_pybuffernd_SOut_.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_SOut_.diminfo[1].strides = __pyx_pybuffernd_SOut_.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_SOut_.diminfo[1].shape = __pyx_pybuffernd_SOut_.rcbuffer->pybuffer.shape[1];
    }
  }
  __pyx_t_7 = 0;
  __pyx_v_SOut_ = ((PyArrayObject *)__pyx_t_6);
  __pyx_t_6 = 0;
+022:     cdef cnp.ndarray[double,ndim=2] VPerp_=np.nan*np.ones((3,Nl))
  __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __pyx_t_4 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_nan); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_ones); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
  __pyx_t_1 = __Pyx_PyInt_From_int(__pyx_v_Nl); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_1);
  __pyx_t_5 = PyTuple_New(2); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_INCREF(__pyx_int_3);
  __Pyx_GIVEREF(__pyx_int_3);
  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_int_3);
  __Pyx_GIVEREF(__pyx_t_1);
  PyTuple_SET_ITEM(__pyx_t_5, 1, __pyx_t_1);
  __pyx_t_1 = 0;
  __pyx_t_1 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_1 = PyMethod_GET_SELF(__pyx_t_3);
    if (likely(__pyx_t_1)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
      __Pyx_INCREF(__pyx_t_1);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_3, function);
    }
  }
  if (!__pyx_t_1) {
    __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_5); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 22, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    __Pyx_GOTREF(__pyx_t_6);
  } else {
    #if CYTHON_FAST_PYCALL
    if (PyFunction_Check(__pyx_t_3)) {
      PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_t_5};
      __pyx_t_6 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 22, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
      __Pyx_GOTREF(__pyx_t_6);
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    } else
    #endif
    #if CYTHON_FAST_PYCCALL
    if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
      PyObject *__pyx_temp[2] = {__pyx_t_1, __pyx_t_5};
      __pyx_t_6 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 22, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_1); __pyx_t_1 = 0;
      __Pyx_GOTREF(__pyx_t_6);
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    } else
    #endif
    {
      __pyx_t_2 = PyTuple_New(1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 22, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_2);
      __Pyx_GIVEREF(__pyx_t_1); PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_t_1); __pyx_t_1 = NULL;
      __Pyx_GIVEREF(__pyx_t_5);
      PyTuple_SET_ITEM(__pyx_t_2, 0+1, __pyx_t_5);
      __pyx_t_5 = 0;
      __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_2, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 22, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_6);
      __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    }
  }
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = PyNumber_Multiply(__pyx_t_4, __pyx_t_6); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 22, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  if (!(likely(((__pyx_t_3) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_3, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 22, __pyx_L1_error)
  __pyx_t_8 = ((PyArrayObject *)__pyx_t_3);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_VPerp_.rcbuffer->pybuffer, (PyObject*)__pyx_t_8, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_STRIDES, 2, 0, __pyx_stack) == -1)) {
      __pyx_v_VPerp_ = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_VPerp_.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 22, __pyx_L1_error)
    } else {__pyx_pybuffernd_VPerp_.diminfo[0].strides = __pyx_pybuffernd_VPerp_.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_VPerp_.diminfo[0].shape = __pyx_pybuffernd_VPerp_.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_VPerp_.diminfo[1].strides = __pyx_pybuffernd_VPerp_.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_VPerp_.diminfo[1].shape = __pyx_pybuffernd_VPerp_.rcbuffer->pybuffer.shape[1];
    }
  }
  __pyx_t_8 = 0;
  __pyx_v_VPerp_ = ((PyArrayObject *)__pyx_t_3);
  __pyx_t_3 = 0;
+023:     cdef cnp.ndarray[double,ndim=1] indOut_=np.nan*np.ones((Nl,))
  __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_nan); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 23, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 23, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_t_2 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_ones); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 23, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  __pyx_t_4 = __Pyx_PyInt_From_int(__pyx_v_Nl); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 23, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_t_5 = PyTuple_New(1); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 23, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_5);
  __Pyx_GIVEREF(__pyx_t_4);
  PyTuple_SET_ITEM(__pyx_t_5, 0, __pyx_t_4);
  __pyx_t_4 = 0;
  __pyx_t_4 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_2))) {
    __pyx_t_4 = PyMethod_GET_SELF(__pyx_t_2);
    if (likely(__pyx_t_4)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_2);
      __Pyx_INCREF(__pyx_t_4);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_2, function);
    }
  }
  if (!__pyx_t_4) {
    __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_2, __pyx_t_5); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    __Pyx_GOTREF(__pyx_t_3);
  } else {
    #if CYTHON_FAST_PYCALL
    if (PyFunction_Check(__pyx_t_2)) {
      PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_5};
      __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    } else
    #endif
    #if CYTHON_FAST_PYCCALL
    if (__Pyx_PyFastCFunction_Check(__pyx_t_2)) {
      PyObject *__pyx_temp[2] = {__pyx_t_4, __pyx_t_5};
      __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_2, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_4); __pyx_t_4 = 0;
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    } else
    #endif
    {
      __pyx_t_1 = PyTuple_New(1+1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 23, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_1);
      __Pyx_GIVEREF(__pyx_t_4); PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_t_4); __pyx_t_4 = NULL;
      __Pyx_GIVEREF(__pyx_t_5);
      PyTuple_SET_ITEM(__pyx_t_1, 0+1, __pyx_t_5);
      __pyx_t_5 = 0;
      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_2, __pyx_t_1, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
    }
  }
  __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
  __pyx_t_2 = PyNumber_Multiply(__pyx_t_6, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 23, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_2);
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  if (!(likely(((__pyx_t_2) == Py_None) || likely(__Pyx_TypeTest(__pyx_t_2, __pyx_ptype_5numpy_ndarray))))) __PYX_ERR(0, 23, __pyx_L1_error)
  __pyx_t_9 = ((PyArrayObject *)__pyx_t_2);
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_indOut_.rcbuffer->pybuffer, (PyObject*)__pyx_t_9, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_STRIDES, 1, 0, __pyx_stack) == -1)) {
      __pyx_v_indOut_ = ((PyArrayObject *)Py_None); __Pyx_INCREF(Py_None); __pyx_pybuffernd_indOut_.rcbuffer->pybuffer.buf = NULL;
      __PYX_ERR(0, 23, __pyx_L1_error)
    } else {__pyx_pybuffernd_indOut_.diminfo[0].strides = __pyx_pybuffernd_indOut_.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_indOut_.diminfo[0].shape = __pyx_pybuffernd_indOut_.rcbuffer->pybuffer.shape[0];
    }
  }
  __pyx_t_9 = 0;
  __pyx_v_indOut_ = ((PyArrayObject *)__pyx_t_2);
  __pyx_t_2 = 0;
 024: 
+025:     cdef double[:,::1] SIn=SIn_, SOut=SOut_, VPerp=VPerp_
  __pyx_t_10 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(((PyObject *)__pyx_v_SIn_));
  if (unlikely(!__pyx_t_10.memview)) __PYX_ERR(0, 25, __pyx_L1_error)
  __pyx_v_SIn = __pyx_t_10;
  __pyx_t_10.memview = NULL;
  __pyx_t_10.data = NULL;
  __pyx_t_10 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(((PyObject *)__pyx_v_SOut_));
  if (unlikely(!__pyx_t_10.memview)) __PYX_ERR(0, 25, __pyx_L1_error)
  __pyx_v_SOut = __pyx_t_10;
  __pyx_t_10.memview = NULL;
  __pyx_t_10.data = NULL;
  __pyx_t_10 = __Pyx_PyObject_to_MemoryviewSlice_d_dc_double(((PyObject *)__pyx_v_VPerp_));
  if (unlikely(!__pyx_t_10.memview)) __PYX_ERR(0, 25, __pyx_L1_error)
  __pyx_v_VPerp = __pyx_t_10;
  __pyx_t_10.memview = NULL;
  __pyx_t_10.data = NULL;
+026:     cdef double[::1] indOut=indOut_
  __pyx_t_11 = __Pyx_PyObject_to_MemoryviewSlice_dc_double(((PyObject *)__pyx_v_indOut_));
  if (unlikely(!__pyx_t_11.memview)) __PYX_ERR(0, 26, __pyx_L1_error)
  __pyx_v_indOut = __pyx_t_11;
  __pyx_t_11.memview = NULL;
  __pyx_t_11.data = NULL;
 027: 
 028:     ################
 029:     # Prepare input
+030:     if RMin is None:
  __pyx_t_12 = (__pyx_v_RMin == Py_None);
  __pyx_t_13 = (__pyx_t_12 != 0);
  if (__pyx_t_13) {
/* … */
    goto __pyx_L3;
  }
+031:         Rmin = 0.95*min(np.min(VPoly[0,:]),np.min(np.hypot(Ds[0,:],Ds[1,:])))
    __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_min); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_6);
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_1 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
    __pyx_t_5 = __Pyx_PyObject_GetAttrStr(__pyx_t_1, __pyx_n_s_hypot); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_5);
    __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
    __pyx_t_11.data = __pyx_v_Ds.data;
    __pyx_t_11.memview = __pyx_v_Ds.memview;
    __PYX_INC_MEMVIEW(&__pyx_t_11, 0);
    {
    Py_ssize_t __pyx_tmp_idx = 0;
    Py_ssize_t __pyx_tmp_shape = __pyx_v_Ds.shape[0];
    Py_ssize_t __pyx_tmp_stride = __pyx_v_Ds.strides[0];
    if (0 && (__pyx_tmp_idx < 0))
        __pyx_tmp_idx += __pyx_tmp_shape;
    if (0 && (__pyx_tmp_idx < 0 || __pyx_tmp_idx >= __pyx_tmp_shape)) {
        PyErr_SetString(PyExc_IndexError, "Index out of bounds (axis 0)");
        __PYX_ERR(0, 31, __pyx_L1_error)
    }
        __pyx_t_11.data += __pyx_tmp_idx * __pyx_tmp_stride;
}

__pyx_t_11.shape[0] = __pyx_v_Ds.shape[1];
__pyx_t_11.strides[0] = __pyx_v_Ds.strides[1];
    __pyx_t_11.suboffsets[0] = -1;

__pyx_t_1 = __pyx_memoryview_fromslice(__pyx_t_11, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_1);
    __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
    __pyx_t_11.memview = NULL;
    __pyx_t_11.data = NULL;
    __pyx_t_11.data = __pyx_v_Ds.data;
    __pyx_t_11.memview = __pyx_v_Ds.memview;
    __PYX_INC_MEMVIEW(&__pyx_t_11, 0);
    {
    Py_ssize_t __pyx_tmp_idx = 1;
    Py_ssize_t __pyx_tmp_shape = __pyx_v_Ds.shape[0];
    Py_ssize_t __pyx_tmp_stride = __pyx_v_Ds.strides[0];
    if (0 && (__pyx_tmp_idx < 0))
        __pyx_tmp_idx += __pyx_tmp_shape;
    if (0 && (__pyx_tmp_idx < 0 || __pyx_tmp_idx >= __pyx_tmp_shape)) {
        PyErr_SetString(PyExc_IndexError, "Index out of bounds (axis 0)");
        __PYX_ERR(0, 31, __pyx_L1_error)
    }
        __pyx_t_11.data += __pyx_tmp_idx * __pyx_tmp_stride;
}

__pyx_t_11.shape[0] = __pyx_v_Ds.shape[1];
__pyx_t_11.strides[0] = __pyx_v_Ds.strides[1];
    __pyx_t_11.suboffsets[0] = -1;

__pyx_t_4 = __pyx_memoryview_fromslice(__pyx_t_11, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_4);
    __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
    __pyx_t_11.memview = NULL;
    __pyx_t_11.data = NULL;
    __pyx_t_14 = NULL;
    __pyx_t_15 = 0;
    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_5))) {
      __pyx_t_14 = PyMethod_GET_SELF(__pyx_t_5);
      if (likely(__pyx_t_14)) {
        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_5);
        __Pyx_INCREF(__pyx_t_14);
        __Pyx_INCREF(function);
        __Pyx_DECREF_SET(__pyx_t_5, function);
        __pyx_t_15 = 1;
      }
    }
    #if CYTHON_FAST_PYCALL
    if (PyFunction_Check(__pyx_t_5)) {
      PyObject *__pyx_temp[3] = {__pyx_t_14, __pyx_t_1, __pyx_t_4};
      __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_15, 2+__pyx_t_15); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 31, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0;
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
    } else
    #endif
    #if CYTHON_FAST_PYCCALL
    if (__Pyx_PyFastCFunction_Check(__pyx_t_5)) {
      PyObject *__pyx_temp[3] = {__pyx_t_14, __pyx_t_1, __pyx_t_4};
      __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_5, __pyx_temp+1-__pyx_t_15, 2+__pyx_t_15); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 31, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_14); __pyx_t_14 = 0;
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
    } else
    #endif
    {
      __pyx_t_16 = PyTuple_New(2+__pyx_t_15); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 31, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_16);
      if (__pyx_t_14) {
        __Pyx_GIVEREF(__pyx_t_14); PyTuple_SET_ITEM(__pyx_t_16, 0, __pyx_t_14); __pyx_t_14 = NULL;
      }
      __Pyx_GIVEREF(__pyx_t_1);
      PyTuple_SET_ITEM(__pyx_t_16, 0+__pyx_t_15, __pyx_t_1);
      __Pyx_GIVEREF(__pyx_t_4);
      PyTuple_SET_ITEM(__pyx_t_16, 1+__pyx_t_15, __pyx_t_4);
      __pyx_t_1 = 0;
      __pyx_t_4 = 0;
      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_5, __pyx_t_16, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 31, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
    }
    __Pyx_DECREF(__pyx_t_5); __pyx_t_5 = 0;
    __pyx_t_5 = NULL;
    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) {
      __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_6);
      if (likely(__pyx_t_5)) {
        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
        __Pyx_INCREF(__pyx_t_5);
        __Pyx_INCREF(function);
        __Pyx_DECREF_SET(__pyx_t_6, function);
      }
    }
    if (!__pyx_t_5) {
      __pyx_t_2 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 31, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
      __Pyx_GOTREF(__pyx_t_2);
    } else {
      #if CYTHON_FAST_PYCALL
      if (PyFunction_Check(__pyx_t_6)) {
        PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_3};
        __pyx_t_2 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 31, __pyx_L1_error)
        __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
        __Pyx_GOTREF(__pyx_t_2);
        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
      } else
      #endif
      #if CYTHON_FAST_PYCCALL
      if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) {
        PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_3};
        __pyx_t_2 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 31, __pyx_L1_error)
        __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
        __Pyx_GOTREF(__pyx_t_2);
        __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
      } else
      #endif
      {
        __pyx_t_16 = PyTuple_New(1+1); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 31, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_16);
        __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_16, 0, __pyx_t_5); __pyx_t_5 = NULL;
        __Pyx_GIVEREF(__pyx_t_3);
        PyTuple_SET_ITEM(__pyx_t_16, 0+1, __pyx_t_3);
        __pyx_t_3 = 0;
        __pyx_t_2 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_16, NULL); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 31, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_2);
        __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
      }
    }
    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
    __pyx_t_16 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_16);
    __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_16, __pyx_n_s_min); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_3);
    __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
    __pyx_t_11.data = __pyx_v_VPoly.data;
    __pyx_t_11.memview = __pyx_v_VPoly.memview;
    __PYX_INC_MEMVIEW(&__pyx_t_11, 0);
    {
    Py_ssize_t __pyx_tmp_idx = 0;
    Py_ssize_t __pyx_tmp_shape = __pyx_v_VPoly.shape[0];
    Py_ssize_t __pyx_tmp_stride = __pyx_v_VPoly.strides[0];
    if (0 && (__pyx_tmp_idx < 0))
        __pyx_tmp_idx += __pyx_tmp_shape;
    if (0 && (__pyx_tmp_idx < 0 || __pyx_tmp_idx >= __pyx_tmp_shape)) {
        PyErr_SetString(PyExc_IndexError, "Index out of bounds (axis 0)");
        __PYX_ERR(0, 31, __pyx_L1_error)
    }
        __pyx_t_11.data += __pyx_tmp_idx * __pyx_tmp_stride;
}

__pyx_t_11.shape[0] = __pyx_v_VPoly.shape[1];
__pyx_t_11.strides[0] = __pyx_v_VPoly.strides[1];
    __pyx_t_11.suboffsets[0] = -1;

__pyx_t_16 = __pyx_memoryview_fromslice(__pyx_t_11, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_16);
    __PYX_XDEC_MEMVIEW(&__pyx_t_11, 1);
    __pyx_t_11.memview = NULL;
    __pyx_t_11.data = NULL;
    __pyx_t_5 = NULL;
    if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
      __pyx_t_5 = PyMethod_GET_SELF(__pyx_t_3);
      if (likely(__pyx_t_5)) {
        PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
        __Pyx_INCREF(__pyx_t_5);
        __Pyx_INCREF(function);
        __Pyx_DECREF_SET(__pyx_t_3, function);
      }
    }
    if (!__pyx_t_5) {
      __pyx_t_6 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_16); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 31, __pyx_L1_error)
      __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
      __Pyx_GOTREF(__pyx_t_6);
    } else {
      #if CYTHON_FAST_PYCALL
      if (PyFunction_Check(__pyx_t_3)) {
        PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_16};
        __pyx_t_6 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 31, __pyx_L1_error)
        __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
        __Pyx_GOTREF(__pyx_t_6);
        __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
      } else
      #endif
      #if CYTHON_FAST_PYCCALL
      if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
        PyObject *__pyx_temp[2] = {__pyx_t_5, __pyx_t_16};
        __pyx_t_6 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 31, __pyx_L1_error)
        __Pyx_XDECREF(__pyx_t_5); __pyx_t_5 = 0;
        __Pyx_GOTREF(__pyx_t_6);
        __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
      } else
      #endif
      {
        __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 31, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_4);
        __Pyx_GIVEREF(__pyx_t_5); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_5); __pyx_t_5 = NULL;
        __Pyx_GIVEREF(__pyx_t_16);
        PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_16);
        __pyx_t_16 = 0;
        __pyx_t_6 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_4, NULL); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 31, __pyx_L1_error)
        __Pyx_GOTREF(__pyx_t_6);
        __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
      }
    }
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_4 = PyObject_RichCompare(__pyx_t_2, __pyx_t_6, Py_LT); __Pyx_XGOTREF(__pyx_t_4); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 31, __pyx_L1_error)
    __pyx_t_13 = __Pyx_PyObject_IsTrue(__pyx_t_4); if (unlikely(__pyx_t_13 < 0)) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
    if (__pyx_t_13) {
      __Pyx_INCREF(__pyx_t_2);
      __pyx_t_3 = __pyx_t_2;
    } else {
      __Pyx_INCREF(__pyx_t_6);
      __pyx_t_3 = __pyx_t_6;
    }
    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_t_2 = PyNumber_Multiply(__pyx_float_0_95, __pyx_t_3); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_GOTREF(__pyx_t_2);
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __pyx_t_17 = __pyx_PyFloat_AsDouble(__pyx_t_2); if (unlikely((__pyx_t_17 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 31, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
    __pyx_v_Rmin = __pyx_t_17;
 032:     else:
+033:         Rmin = RMin
  /*else*/ {
    __pyx_t_17 = __pyx_PyFloat_AsDouble(__pyx_v_RMin); if (unlikely((__pyx_t_17 == (double)-1) && PyErr_Occurred())) __PYX_ERR(0, 33, __pyx_L1_error)
    __pyx_v_Rmin = __pyx_t_17;
  }
  __pyx_L3:;
 034: 
 035:     ################
 036:     # Compute
+037:     if Forbid:
  __pyx_t_13 = __Pyx_PyObject_IsTrue(((PyObject *)__pyx_v_Forbid)); if (unlikely(__pyx_t_13 < 0)) __PYX_ERR(0, 37, __pyx_L1_error)
  if (__pyx_t_13) {
/* … */
    goto __pyx_L4;
  }
+038:         Forbid0, Forbidbis = 1, 1
    __pyx_t_15 = 1;
    __pyx_t_18 = 1;
    __pyx_v_Forbid0 = __pyx_t_15;
    __pyx_v_Forbidbis = __pyx_t_18;
 039:     else:
+040:         Forbid0, Forbidbis = 0, 0
  /*else*/ {
    __pyx_t_18 = 0;
    __pyx_t_15 = 0;
    __pyx_v_Forbid0 = __pyx_t_18;
    __pyx_v_Forbidbis = __pyx_t_15;
  }
  __pyx_L4:;
+041:     for ii in range(0,Nl):
  __pyx_t_15 = __pyx_v_Nl;
  for (__pyx_t_18 = 0; __pyx_t_18 < __pyx_t_15; __pyx_t_18+=1) {
    __pyx_v_ii = __pyx_t_18;
+042:         upscaDp = us[0,ii]*Ds[0,ii] + us[1,ii]*Ds[1,ii]
    __pyx_t_19 = 0;
    __pyx_t_20 = __pyx_v_ii;
    __pyx_t_21 = 0;
    __pyx_t_22 = __pyx_v_ii;
    __pyx_t_23 = 1;
    __pyx_t_24 = __pyx_v_ii;
    __pyx_t_25 = 1;
    __pyx_t_26 = __pyx_v_ii;
    __pyx_v_upscaDp = (((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_19 * __pyx_v_us.strides[0]) )) + __pyx_t_20)) ))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_21 * __pyx_v_Ds.strides[0]) )) + __pyx_t_22)) )))) + ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_23 * __pyx_v_us.strides[0]) )) + __pyx_t_24)) ))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_25 * __pyx_v_Ds.strides[0]) )) + __pyx_t_26)) )))));
+043:         upar2 = us[0,ii]**2 + us[1,ii]**2
    __pyx_t_27 = 0;
    __pyx_t_28 = __pyx_v_ii;
    __pyx_t_29 = 1;
    __pyx_t_30 = __pyx_v_ii;
    __pyx_v_upar2 = (pow((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_27 * __pyx_v_us.strides[0]) )) + __pyx_t_28)) ))), 2.0) + pow((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_29 * __pyx_v_us.strides[0]) )) + __pyx_t_30)) ))), 2.0));
+044:         Dpar2 = Ds[0,ii]**2 + Ds[1,ii]**2
    __pyx_t_31 = 0;
    __pyx_t_32 = __pyx_v_ii;
    __pyx_t_33 = 1;
    __pyx_t_34 = __pyx_v_ii;
    __pyx_v_Dpar2 = (pow((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_31 * __pyx_v_Ds.strides[0]) )) + __pyx_t_32)) ))), 2.0) + pow((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_33 * __pyx_v_Ds.strides[0]) )) + __pyx_t_34)) ))), 2.0));
 045:         # Prepare in case Forbid is True
+046:         if Forbid0 and not Dpar2>0:
    __pyx_t_12 = (__pyx_v_Forbid0 != 0);
    if (__pyx_t_12) {
    } else {
      __pyx_t_13 = __pyx_t_12;
      goto __pyx_L8_bool_binop_done;
    }
    __pyx_t_12 = ((!((__pyx_v_Dpar2 > 0.0) != 0)) != 0);
    __pyx_t_13 = __pyx_t_12;
    __pyx_L8_bool_binop_done:;
    if (__pyx_t_13) {
/* … */
    }
+047:             Forbidbis = 0
      __pyx_v_Forbidbis = 0;
+048:         if Forbidbis:
    __pyx_t_13 = (__pyx_v_Forbidbis != 0);
    if (__pyx_t_13) {
/* … */
    }
 049:             # Compute coordinates of the 2 points where the tangents touch the inner circle
+050:             L = Csqrt(Dpar2-Rmin**2)
      __pyx_v_L = sqrt((__pyx_v_Dpar2 - pow(__pyx_v_Rmin, 2.0)));
+051:             S1X = (Rmin**2*Ds[0,ii]+Rmin*Ds[1,ii]*L)/Dpar2
      __pyx_t_35 = 0;
      __pyx_t_36 = __pyx_v_ii;
      __pyx_t_37 = 1;
      __pyx_t_38 = __pyx_v_ii;
      __pyx_v_S1X = (((pow(__pyx_v_Rmin, 2.0) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_35 * __pyx_v_Ds.strides[0]) )) + __pyx_t_36)) )))) + ((__pyx_v_Rmin * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_37 * __pyx_v_Ds.strides[0]) )) + __pyx_t_38)) )))) * __pyx_v_L)) / __pyx_v_Dpar2);
+052:             S1Y = (Rmin**2*Ds[1,ii]-Rmin*Ds[0,ii]*L)/Dpar2
      __pyx_t_39 = 1;
      __pyx_t_40 = __pyx_v_ii;
      __pyx_t_41 = 0;
      __pyx_t_42 = __pyx_v_ii;
      __pyx_v_S1Y = (((pow(__pyx_v_Rmin, 2.0) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_39 * __pyx_v_Ds.strides[0]) )) + __pyx_t_40)) )))) - ((__pyx_v_Rmin * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_41 * __pyx_v_Ds.strides[0]) )) + __pyx_t_42)) )))) * __pyx_v_L)) / __pyx_v_Dpar2);
+053:             S2X = (Rmin**2*Ds[0,ii]-Rmin*Ds[1,ii]*L)/Dpar2
      __pyx_t_43 = 0;
      __pyx_t_44 = __pyx_v_ii;
      __pyx_t_45 = 1;
      __pyx_t_46 = __pyx_v_ii;
      __pyx_v_S2X = (((pow(__pyx_v_Rmin, 2.0) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_43 * __pyx_v_Ds.strides[0]) )) + __pyx_t_44)) )))) - ((__pyx_v_Rmin * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_45 * __pyx_v_Ds.strides[0]) )) + __pyx_t_46)) )))) * __pyx_v_L)) / __pyx_v_Dpar2);
+054:             S2Y = (Rmin**2*Ds[1,ii]+Rmin*Ds[0,ii]*L)/Dpar2
      __pyx_t_47 = 1;
      __pyx_t_48 = __pyx_v_ii;
      __pyx_t_49 = 0;
      __pyx_t_50 = __pyx_v_ii;
      __pyx_v_S2Y = (((pow(__pyx_v_Rmin, 2.0) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_47 * __pyx_v_Ds.strides[0]) )) + __pyx_t_48)) )))) + ((__pyx_v_Rmin * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_49 * __pyx_v_Ds.strides[0]) )) + __pyx_t_50)) )))) * __pyx_v_L)) / __pyx_v_Dpar2);
 055: 
 056:         # Compute all solutions
 057:         # Set tolerance value for us[2,ii]
 058:         # EpsUz is the tolerated DZ across 20m (max Tokamak size)
+059:         Crit2 = EpsUz**2*upar2/400.
    __pyx_v_Crit2 = ((pow(__pyx_v_EpsUz, 2.0) * __pyx_v_upar2) / 400.);
+060:         kout, kin, Done = 1.e12, 1e12, 0
    __pyx_t_17 = 1.e12;
    __pyx_t_51 = 1e12;
    __pyx_t_52 = 0;
    __pyx_v_kout = __pyx_t_17;
    __pyx_v_kin = __pyx_t_51;
    __pyx_v_Done = __pyx_t_52;
 061:         # Case with horizontal semi-line
+062:         if us[2,ii]**2<Crit2:
    __pyx_t_53 = 2;
    __pyx_t_54 = __pyx_v_ii;
    __pyx_t_13 = ((pow((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_53 * __pyx_v_us.strides[0]) )) + __pyx_t_54)) ))), 2.0) < __pyx_v_Crit2) != 0);
    if (__pyx_t_13) {
/* … */
      goto __pyx_L11;
    }
+063:             for jj in range(0,Ns):
      __pyx_t_52 = __pyx_v_Ns;
      for (__pyx_t_55 = 0; __pyx_t_55 < __pyx_t_52; __pyx_t_55+=1) {
        __pyx_v_jj = __pyx_t_55;
 064:                 # Solutions exist only in the case with non-horizontal segment (i.e.: cone, not plane)
+065:                 if (VPoly[1,jj+1]-VPoly[1,jj])**2>EpsVz**2:
        __pyx_t_56 = 1;
        __pyx_t_57 = (__pyx_v_jj + 1);
        __pyx_t_58 = 1;
        __pyx_t_59 = __pyx_v_jj;
        __pyx_t_13 = ((pow(((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_56 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_57)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_58 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_59)) )))), 2.0) > pow(__pyx_v_EpsVz, 2.0)) != 0);
        if (__pyx_t_13) {
/* … */
        }
      }
+066:                     q = (Ds[2,ii]-VPoly[1,jj])/(VPoly[1,jj+1]-VPoly[1,jj])
          __pyx_t_60 = 2;
          __pyx_t_61 = __pyx_v_ii;
          __pyx_t_62 = 1;
          __pyx_t_63 = __pyx_v_jj;
          __pyx_t_64 = 1;
          __pyx_t_65 = (__pyx_v_jj + 1);
          __pyx_t_66 = 1;
          __pyx_t_67 = __pyx_v_jj;
          __pyx_v_q = (((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_60 * __pyx_v_Ds.strides[0]) )) + __pyx_t_61)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_62 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_63)) )))) / ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_64 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_65)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_66 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_67)) )))));
 067:                     # The intersection must stand on the segment 
+068:                     if q>=0 and q<1:
          __pyx_t_12 = ((__pyx_v_q >= 0.0) != 0);
          if (__pyx_t_12) {
          } else {
            __pyx_t_13 = __pyx_t_12;
            goto __pyx_L16_bool_binop_done;
          }
          __pyx_t_12 = ((__pyx_v_q < 1.0) != 0);
          __pyx_t_13 = __pyx_t_12;
          __pyx_L16_bool_binop_done:;
          if (__pyx_t_13) {
/* … */
          }
+069:                         C = q**2*(VPoly[0,jj+1]-VPoly[0,jj])**2 + 2.*q*VPoly[0,jj]*(VPoly[0,jj+1]-VPoly[0,jj]) + VPoly[0,jj]**2
            __pyx_t_68 = 0;
            __pyx_t_69 = (__pyx_v_jj + 1);
            __pyx_t_70 = 0;
            __pyx_t_71 = __pyx_v_jj;
            __pyx_t_72 = 0;
            __pyx_t_73 = __pyx_v_jj;
            __pyx_t_74 = 0;
            __pyx_t_75 = (__pyx_v_jj + 1);
            __pyx_t_76 = 0;
            __pyx_t_77 = __pyx_v_jj;
            __pyx_t_78 = 0;
            __pyx_t_79 = __pyx_v_jj;
            __pyx_v_C = (((pow(__pyx_v_q, 2.0) * pow(((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_68 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_69)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_70 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_71)) )))), 2.0)) + (((2. * __pyx_v_q) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_72 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_73)) )))) * ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_74 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_75)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_76 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_77)) )))))) + pow((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_78 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_79)) ))), 2.0));
+070:                         delta = upscaDp**2 - upar2*(Dpar2-C)
            __pyx_v_delta = (pow(__pyx_v_upscaDp, 2.0) - (__pyx_v_upar2 * (__pyx_v_Dpar2 - __pyx_v_C)));
+071:                         if delta>0.:
            __pyx_t_13 = ((__pyx_v_delta > 0.) != 0);
            if (__pyx_t_13) {
/* … */
            }
+072:                             sqd = Csqrt(delta)
              __pyx_v_sqd = sqrt(__pyx_v_delta);
 073:                             # The intersection must be on the semi-line (i.e.: k>=0)
 074:                             # First solution
+075:                             if -upscaDp - sqd >=0:
              __pyx_t_13 = ((((-__pyx_v_upscaDp) - __pyx_v_sqd) >= 0.0) != 0);
              if (__pyx_t_13) {
/* … */
              }
+076:                                 k = (-upscaDp - sqd)/upar2
                __pyx_v_k = (((-__pyx_v_upscaDp) - __pyx_v_sqd) / __pyx_v_upar2);
+077:                                 sol0, sol1 = Ds[0,ii] + k*us[0,ii], Ds[1,ii] + k*us[1,ii]
                __pyx_t_80 = 0;
                __pyx_t_81 = __pyx_v_ii;
                __pyx_t_82 = 0;
                __pyx_t_83 = __pyx_v_ii;
                __pyx_t_51 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_80 * __pyx_v_Ds.strides[0]) )) + __pyx_t_81)) ))) + (__pyx_v_k * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_82 * __pyx_v_us.strides[0]) )) + __pyx_t_83)) )))));
                __pyx_t_84 = 1;
                __pyx_t_85 = __pyx_v_ii;
                __pyx_t_86 = 1;
                __pyx_t_87 = __pyx_v_ii;
                __pyx_t_17 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_84 * __pyx_v_Ds.strides[0]) )) + __pyx_t_85)) ))) + (__pyx_v_k * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_86 * __pyx_v_us.strides[0]) )) + __pyx_t_87)) )))));
                __pyx_v_sol0 = __pyx_t_51;
                __pyx_v_sol1 = __pyx_t_17;
+078:                                 if Forbidbis:
                __pyx_t_13 = (__pyx_v_Forbidbis != 0);
                if (__pyx_t_13) {
/* … */
                }
+079:                                     sca0 = (sol0-S1X)*Ds[0,ii] + (sol1-S1Y)*Ds[1,ii]
                  __pyx_t_88 = 0;
                  __pyx_t_89 = __pyx_v_ii;
                  __pyx_t_90 = 1;
                  __pyx_t_91 = __pyx_v_ii;
                  __pyx_v_sca0 = (((__pyx_v_sol0 - __pyx_v_S1X) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_88 * __pyx_v_Ds.strides[0]) )) + __pyx_t_89)) )))) + ((__pyx_v_sol1 - __pyx_v_S1Y) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_90 * __pyx_v_Ds.strides[0]) )) + __pyx_t_91)) )))));
+080:                                     sca1 = (sol0-S1X)*S1X + (sol1-S1Y)*S1Y
                  __pyx_v_sca1 = (((__pyx_v_sol0 - __pyx_v_S1X) * __pyx_v_S1X) + ((__pyx_v_sol1 - __pyx_v_S1Y) * __pyx_v_S1Y));
+081:                                     sca2 = (sol0-S2X)*S2X + (sol1-S2Y)*S2Y
                  __pyx_v_sca2 = (((__pyx_v_sol0 - __pyx_v_S2X) * __pyx_v_S2X) + ((__pyx_v_sol1 - __pyx_v_S2Y) * __pyx_v_S2Y));
+082:                                 if not Forbidbis or (Forbidbis and not (sca0<0 and sca1<0 and sca2<0)):
                __pyx_t_12 = ((!(__pyx_v_Forbidbis != 0)) != 0);
                if (!__pyx_t_12) {
                } else {
                  __pyx_t_13 = __pyx_t_12;
                  goto __pyx_L22_bool_binop_done;
                }
                __pyx_t_12 = (__pyx_v_Forbidbis != 0);
                if (__pyx_t_12) {
                } else {
                  __pyx_t_13 = __pyx_t_12;
                  goto __pyx_L22_bool_binop_done;
                }
                __pyx_t_92 = ((__pyx_v_sca0 < 0.0) != 0);
                if (__pyx_t_92) {
                } else {
                  __pyx_t_12 = __pyx_t_92;
                  goto __pyx_L25_bool_binop_done;
                }
                __pyx_t_92 = ((__pyx_v_sca1 < 0.0) != 0);
                if (__pyx_t_92) {
                } else {
                  __pyx_t_12 = __pyx_t_92;
                  goto __pyx_L25_bool_binop_done;
                }
                __pyx_t_92 = ((__pyx_v_sca2 < 0.0) != 0);
                __pyx_t_12 = __pyx_t_92;
                __pyx_L25_bool_binop_done:;
                __pyx_t_92 = ((!__pyx_t_12) != 0);
                __pyx_t_13 = __pyx_t_92;
                __pyx_L22_bool_binop_done:;
                if (__pyx_t_13) {
/* … */
                }
 083:                                     # Get the normalized perpendicular vector at intersection
+084:                                     phi = Catan2(sol1,sol0)
                  __pyx_v_phi = atan2(__pyx_v_sol1, __pyx_v_sol0);
 085:                                     # Get the scalar product to determine entry or exit point
+086:                                     sca = Ccos(phi)*vIn[0,jj]*us[0,ii] + Csin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                  __pyx_t_93 = 0;
                  __pyx_t_94 = __pyx_v_jj;
                  __pyx_t_95 = 0;
                  __pyx_t_96 = __pyx_v_ii;
                  __pyx_t_97 = 0;
                  __pyx_t_98 = __pyx_v_jj;
                  __pyx_t_99 = 1;
                  __pyx_t_100 = __pyx_v_ii;
                  __pyx_t_101 = 1;
                  __pyx_t_102 = __pyx_v_jj;
                  __pyx_t_103 = 2;
                  __pyx_t_104 = __pyx_v_ii;
                  __pyx_v_sca = ((((cos(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_93 * __pyx_v_vIn.strides[0]) )) + __pyx_t_94)) )))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_95 * __pyx_v_us.strides[0]) )) + __pyx_t_96)) )))) + ((sin(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_97 * __pyx_v_vIn.strides[0]) )) + __pyx_t_98)) )))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_99 * __pyx_v_us.strides[0]) )) + __pyx_t_100)) ))))) + ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_101 * __pyx_v_vIn.strides[0]) )) + __pyx_t_102)) ))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_103 * __pyx_v_us.strides[0]) )) + __pyx_t_104)) )))));
+087:                                     if sca<=0 and k<kout:
                  __pyx_t_92 = ((__pyx_v_sca <= 0.0) != 0);
                  if (__pyx_t_92) {
                  } else {
                    __pyx_t_13 = __pyx_t_92;
                    goto __pyx_L29_bool_binop_done;
                  }
                  __pyx_t_92 = ((__pyx_v_k < __pyx_v_kout) != 0);
                  __pyx_t_13 = __pyx_t_92;
                  __pyx_L29_bool_binop_done:;
                  if (__pyx_t_13) {
/* … */
                    goto __pyx_L28;
                  }
+088:                                         kout = k
                    __pyx_v_kout = __pyx_v_k;
+089:                                         indout = jj
                    __pyx_v_indout = __pyx_v_jj;
+090:                                         Done = 1
                    __pyx_v_Done = 1;
+091:                                         print 1, k
                    __pyx_t_2 = PyFloat_FromDouble(__pyx_v_k); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 91, __pyx_L1_error)
                    __Pyx_GOTREF(__pyx_t_2);
                    __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 91, __pyx_L1_error)
                    __Pyx_GOTREF(__pyx_t_3);
                    __Pyx_INCREF(__pyx_int_1);
                    __Pyx_GIVEREF(__pyx_int_1);
                    PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_int_1);
                    __Pyx_GIVEREF(__pyx_t_2);
                    PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2);
                    __pyx_t_2 = 0;
                    if (__Pyx_Print(0, __pyx_t_3, 1) < 0) __PYX_ERR(0, 91, __pyx_L1_error)
                    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+092:                                     elif sca>=0 and k<min(kin,kout):
                  __pyx_t_92 = ((__pyx_v_sca >= 0.0) != 0);
                  if (__pyx_t_92) {
                  } else {
                    __pyx_t_13 = __pyx_t_92;
                    goto __pyx_L31_bool_binop_done;
                  }
                  __pyx_t_17 = __pyx_v_kout;
                  __pyx_t_51 = __pyx_v_kin;
                  if (((__pyx_t_17 < __pyx_t_51) != 0)) {
                    __pyx_t_105 = __pyx_t_17;
                  } else {
                    __pyx_t_105 = __pyx_t_51;
                  }
                  __pyx_t_92 = ((__pyx_v_k < __pyx_t_105) != 0);
                  __pyx_t_13 = __pyx_t_92;
                  __pyx_L31_bool_binop_done:;
                  if (__pyx_t_13) {
/* … */
                  }
                  __pyx_L28:;
+093:                                         kin = k
                    __pyx_v_kin = __pyx_v_k;
+094:                                         print 2, k
                    __pyx_t_3 = PyFloat_FromDouble(__pyx_v_k); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 94, __pyx_L1_error)
                    __Pyx_GOTREF(__pyx_t_3);
                    __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 94, __pyx_L1_error)
                    __Pyx_GOTREF(__pyx_t_2);
                    __Pyx_INCREF(__pyx_int_2);
                    __Pyx_GIVEREF(__pyx_int_2);
                    PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_int_2);
                    __Pyx_GIVEREF(__pyx_t_3);
                    PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_3);
                    __pyx_t_3 = 0;
                    if (__Pyx_Print(0, __pyx_t_2, 1) < 0) __PYX_ERR(0, 94, __pyx_L1_error)
                    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 095: 
 096:                             # Second solution
+097:                             if -upscaDp + sqd >=0:
              __pyx_t_13 = ((((-__pyx_v_upscaDp) + __pyx_v_sqd) >= 0.0) != 0);
              if (__pyx_t_13) {
/* … */
              }
+098:                                 k = (-upscaDp + sqd)/upar2
                __pyx_v_k = (((-__pyx_v_upscaDp) + __pyx_v_sqd) / __pyx_v_upar2);
+099:                                 sol0, sol1 = Ds[0,ii] + k*us[0,ii], Ds[1,ii] + k*us[1,ii]
                __pyx_t_106 = 0;
                __pyx_t_107 = __pyx_v_ii;
                __pyx_t_108 = 0;
                __pyx_t_109 = __pyx_v_ii;
                __pyx_t_105 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_106 * __pyx_v_Ds.strides[0]) )) + __pyx_t_107)) ))) + (__pyx_v_k * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_108 * __pyx_v_us.strides[0]) )) + __pyx_t_109)) )))));
                __pyx_t_110 = 1;
                __pyx_t_111 = __pyx_v_ii;
                __pyx_t_112 = 1;
                __pyx_t_113 = __pyx_v_ii;
                __pyx_t_17 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_110 * __pyx_v_Ds.strides[0]) )) + __pyx_t_111)) ))) + (__pyx_v_k * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_112 * __pyx_v_us.strides[0]) )) + __pyx_t_113)) )))));
                __pyx_v_sol0 = __pyx_t_105;
                __pyx_v_sol1 = __pyx_t_17;
+100:                                 if Forbidbis:
                __pyx_t_13 = (__pyx_v_Forbidbis != 0);
                if (__pyx_t_13) {
/* … */
                }
+101:                                     sca0 = (sol0-S1X)*Ds[0,ii] + (sol1-S1Y)*Ds[1,ii]
                  __pyx_t_114 = 0;
                  __pyx_t_115 = __pyx_v_ii;
                  __pyx_t_116 = 1;
                  __pyx_t_117 = __pyx_v_ii;
                  __pyx_v_sca0 = (((__pyx_v_sol0 - __pyx_v_S1X) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_114 * __pyx_v_Ds.strides[0]) )) + __pyx_t_115)) )))) + ((__pyx_v_sol1 - __pyx_v_S1Y) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_116 * __pyx_v_Ds.strides[0]) )) + __pyx_t_117)) )))));
+102:                                     sca1 = (sol0-S1X)*S1X + (sol1-S1Y)*S1Y
                  __pyx_v_sca1 = (((__pyx_v_sol0 - __pyx_v_S1X) * __pyx_v_S1X) + ((__pyx_v_sol1 - __pyx_v_S1Y) * __pyx_v_S1Y));
+103:                                     sca2 = (sol0-S2X)*S2X + (sol1-S2Y)*S2Y
                  __pyx_v_sca2 = (((__pyx_v_sol0 - __pyx_v_S2X) * __pyx_v_S2X) + ((__pyx_v_sol1 - __pyx_v_S2Y) * __pyx_v_S2Y));
+104:                                 if not Forbidbis or (Forbidbis and not (sca0<0 and sca1<0 and sca2<0)):
                __pyx_t_92 = ((!(__pyx_v_Forbidbis != 0)) != 0);
                if (!__pyx_t_92) {
                } else {
                  __pyx_t_13 = __pyx_t_92;
                  goto __pyx_L36_bool_binop_done;
                }
                __pyx_t_92 = (__pyx_v_Forbidbis != 0);
                if (__pyx_t_92) {
                } else {
                  __pyx_t_13 = __pyx_t_92;
                  goto __pyx_L36_bool_binop_done;
                }
                __pyx_t_12 = ((__pyx_v_sca0 < 0.0) != 0);
                if (__pyx_t_12) {
                } else {
                  __pyx_t_92 = __pyx_t_12;
                  goto __pyx_L39_bool_binop_done;
                }
                __pyx_t_12 = ((__pyx_v_sca1 < 0.0) != 0);
                if (__pyx_t_12) {
                } else {
                  __pyx_t_92 = __pyx_t_12;
                  goto __pyx_L39_bool_binop_done;
                }
                __pyx_t_12 = ((__pyx_v_sca2 < 0.0) != 0);
                __pyx_t_92 = __pyx_t_12;
                __pyx_L39_bool_binop_done:;
                __pyx_t_12 = ((!__pyx_t_92) != 0);
                __pyx_t_13 = __pyx_t_12;
                __pyx_L36_bool_binop_done:;
                if (__pyx_t_13) {
/* … */
                }
 105:                                     # Get the normalized perpendicular vector at intersection
+106:                                     phi = Catan2(sol1,sol0)
                  __pyx_v_phi = atan2(__pyx_v_sol1, __pyx_v_sol0);
 107:                                     # Get the scalar product to determine entry or exit point
+108:                                     sca = Ccos(phi)*vIn[0,jj]*us[0,ii] + Csin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                  __pyx_t_118 = 0;
                  __pyx_t_119 = __pyx_v_jj;
                  __pyx_t_120 = 0;
                  __pyx_t_121 = __pyx_v_ii;
                  __pyx_t_122 = 0;
                  __pyx_t_123 = __pyx_v_jj;
                  __pyx_t_124 = 1;
                  __pyx_t_125 = __pyx_v_ii;
                  __pyx_t_126 = 1;
                  __pyx_t_127 = __pyx_v_jj;
                  __pyx_t_128 = 2;
                  __pyx_t_129 = __pyx_v_ii;
                  __pyx_v_sca = ((((cos(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_118 * __pyx_v_vIn.strides[0]) )) + __pyx_t_119)) )))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_120 * __pyx_v_us.strides[0]) )) + __pyx_t_121)) )))) + ((sin(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_122 * __pyx_v_vIn.strides[0]) )) + __pyx_t_123)) )))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_124 * __pyx_v_us.strides[0]) )) + __pyx_t_125)) ))))) + ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_126 * __pyx_v_vIn.strides[0]) )) + __pyx_t_127)) ))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_128 * __pyx_v_us.strides[0]) )) + __pyx_t_129)) )))));
+109:                                     if sca<=0 and k<kout:
                  __pyx_t_12 = ((__pyx_v_sca <= 0.0) != 0);
                  if (__pyx_t_12) {
                  } else {
                    __pyx_t_13 = __pyx_t_12;
                    goto __pyx_L43_bool_binop_done;
                  }
                  __pyx_t_12 = ((__pyx_v_k < __pyx_v_kout) != 0);
                  __pyx_t_13 = __pyx_t_12;
                  __pyx_L43_bool_binop_done:;
                  if (__pyx_t_13) {
/* … */
                    goto __pyx_L42;
                  }
+110:                                         kout = k
                    __pyx_v_kout = __pyx_v_k;
+111:                                         indout = jj
                    __pyx_v_indout = __pyx_v_jj;
+112:                                         Done = 1
                    __pyx_v_Done = 1;
+113:                                         print 3, k
                    __pyx_t_2 = PyFloat_FromDouble(__pyx_v_k); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 113, __pyx_L1_error)
                    __Pyx_GOTREF(__pyx_t_2);
                    __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 113, __pyx_L1_error)
                    __Pyx_GOTREF(__pyx_t_3);
                    __Pyx_INCREF(__pyx_int_3);
                    __Pyx_GIVEREF(__pyx_int_3);
                    PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_int_3);
                    __Pyx_GIVEREF(__pyx_t_2);
                    PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2);
                    __pyx_t_2 = 0;
                    if (__Pyx_Print(0, __pyx_t_3, 1) < 0) __PYX_ERR(0, 113, __pyx_L1_error)
                    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+114:                                     elif sca>=0 and k<min(kin,kout):
                  __pyx_t_12 = ((__pyx_v_sca >= 0.0) != 0);
                  if (__pyx_t_12) {
                  } else {
                    __pyx_t_13 = __pyx_t_12;
                    goto __pyx_L45_bool_binop_done;
                  }
                  __pyx_t_17 = __pyx_v_kout;
                  __pyx_t_105 = __pyx_v_kin;
                  if (((__pyx_t_17 < __pyx_t_105) != 0)) {
                    __pyx_t_51 = __pyx_t_17;
                  } else {
                    __pyx_t_51 = __pyx_t_105;
                  }
                  __pyx_t_12 = ((__pyx_v_k < __pyx_t_51) != 0);
                  __pyx_t_13 = __pyx_t_12;
                  __pyx_L45_bool_binop_done:;
                  if (__pyx_t_13) {
/* … */
                  }
                  __pyx_L42:;
+115:                                         kin = k
                    __pyx_v_kin = __pyx_v_k;
+116:                                         print 4, k
                    __pyx_t_3 = PyFloat_FromDouble(__pyx_v_k); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 116, __pyx_L1_error)
                    __Pyx_GOTREF(__pyx_t_3);
                    __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 116, __pyx_L1_error)
                    __Pyx_GOTREF(__pyx_t_2);
                    __Pyx_INCREF(__pyx_int_4);
                    __Pyx_GIVEREF(__pyx_int_4);
                    PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_int_4);
                    __Pyx_GIVEREF(__pyx_t_3);
                    PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_3);
                    __pyx_t_3 = 0;
                    if (__Pyx_Print(0, __pyx_t_2, 1) < 0) __PYX_ERR(0, 116, __pyx_L1_error)
                    __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 117: 
 118:         # More general non-horizontal semi-line case
 119:         else:
+120:             for jj in range(Ns):
    /*else*/ {
      __pyx_t_52 = __pyx_v_Ns;
      for (__pyx_t_55 = 0; __pyx_t_55 < __pyx_t_52; __pyx_t_55+=1) {
        __pyx_v_jj = __pyx_t_55;
+121:                 v0, v1 = VPoly[0,jj+1]-VPoly[0,jj], VPoly[1,jj+1]-VPoly[1,jj]
        __pyx_t_130 = 0;
        __pyx_t_131 = (__pyx_v_jj + 1);
        __pyx_t_132 = 0;
        __pyx_t_133 = __pyx_v_jj;
        __pyx_t_51 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_130 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_131)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_132 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_133)) ))));
        __pyx_t_134 = 1;
        __pyx_t_135 = (__pyx_v_jj + 1);
        __pyx_t_136 = 1;
        __pyx_t_137 = __pyx_v_jj;
        __pyx_t_17 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_134 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_135)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_136 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_137)) ))));
        __pyx_v_v0 = __pyx_t_51;
        __pyx_v_v1 = __pyx_t_17;
+122:                 A = v0**2 - upar2*(v1/us[2,ii])**2
        __pyx_t_138 = 2;
        __pyx_t_139 = __pyx_v_ii;
        __pyx_v_A = (pow(__pyx_v_v0, 2.0) - (__pyx_v_upar2 * pow((__pyx_v_v1 / (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_138 * __pyx_v_us.strides[0]) )) + __pyx_t_139)) )))), 2.0)));
+123:                 B = VPoly[0,jj]*v0 + v1*(Ds[2,ii]-VPoly[1,jj])*upar2/us[2,ii]**2 - upscaDp*v1/us[2,ii]
        __pyx_t_140 = 0;
        __pyx_t_141 = __pyx_v_jj;
        __pyx_t_142 = 2;
        __pyx_t_143 = __pyx_v_ii;
        __pyx_t_144 = 1;
        __pyx_t_145 = __pyx_v_jj;
        __pyx_t_146 = 2;
        __pyx_t_147 = __pyx_v_ii;
        __pyx_t_148 = 2;
        __pyx_t_149 = __pyx_v_ii;
        __pyx_v_B = ((((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_140 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_141)) ))) * __pyx_v_v0) + (((__pyx_v_v1 * ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_142 * __pyx_v_Ds.strides[0]) )) + __pyx_t_143)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_144 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_145)) ))))) * __pyx_v_upar2) / pow((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_146 * __pyx_v_us.strides[0]) )) + __pyx_t_147)) ))), 2.0))) - ((__pyx_v_upscaDp * __pyx_v_v1) / (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_148 * __pyx_v_us.strides[0]) )) + __pyx_t_149)) )))));
+124:                 C = -upar2*(Ds[2,ii]-VPoly[1,jj])**2/us[2,ii]**2 + 2.*upscaDp*(Ds[2,ii]-VPoly[1,jj])/us[2,ii] - Dpar2 + VPoly[0,jj]**2
        __pyx_t_150 = 2;
        __pyx_t_151 = __pyx_v_ii;
        __pyx_t_152 = 1;
        __pyx_t_153 = __pyx_v_jj;
        __pyx_t_154 = 2;
        __pyx_t_155 = __pyx_v_ii;
        __pyx_t_156 = 2;
        __pyx_t_157 = __pyx_v_ii;
        __pyx_t_158 = 1;
        __pyx_t_159 = __pyx_v_jj;
        __pyx_t_160 = 2;
        __pyx_t_161 = __pyx_v_ii;
        __pyx_t_162 = 0;
        __pyx_t_163 = __pyx_v_jj;
        __pyx_v_C = ((((((-__pyx_v_upar2) * pow(((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_150 * __pyx_v_Ds.strides[0]) )) + __pyx_t_151)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_152 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_153)) )))), 2.0)) / pow((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_154 * __pyx_v_us.strides[0]) )) + __pyx_t_155)) ))), 2.0)) + (((2. * __pyx_v_upscaDp) * ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_156 * __pyx_v_Ds.strides[0]) )) + __pyx_t_157)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_158 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_159)) ))))) / (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_160 * __pyx_v_us.strides[0]) )) + __pyx_t_161)) ))))) - __pyx_v_Dpar2) + pow((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_162 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_163)) ))), 2.0));
 125: 
+126:                 if A**2<EpsA**2 and B**2>EpsB**2:
        __pyx_t_12 = ((pow(__pyx_v_A, 2.0) < pow(__pyx_v_EpsA, 2.0)) != 0);
        if (__pyx_t_12) {
        } else {
          __pyx_t_13 = __pyx_t_12;
          goto __pyx_L50_bool_binop_done;
        }
        __pyx_t_12 = ((pow(__pyx_v_B, 2.0) > pow(__pyx_v_EpsB, 2.0)) != 0);
        __pyx_t_13 = __pyx_t_12;
        __pyx_L50_bool_binop_done:;
        if (__pyx_t_13) {
/* … */
          goto __pyx_L49;
        }
+127:                     q = -C/(2.*B)
          __pyx_v_q = ((-__pyx_v_C) / (2. * __pyx_v_B));
+128:                     if q>=0. and q<1.:
          __pyx_t_12 = ((__pyx_v_q >= 0.) != 0);
          if (__pyx_t_12) {
          } else {
            __pyx_t_13 = __pyx_t_12;
            goto __pyx_L53_bool_binop_done;
          }
          __pyx_t_12 = ((__pyx_v_q < 1.) != 0);
          __pyx_t_13 = __pyx_t_12;
          __pyx_L53_bool_binop_done:;
          if (__pyx_t_13) {
/* … */
          }
+129:                         k = (q*v1 - (Ds[2,ii]-VPoly[2,jj]))/us[2,ii]
            __pyx_t_164 = 2;
            __pyx_t_165 = __pyx_v_ii;
            __pyx_t_166 = 2;
            __pyx_t_167 = __pyx_v_jj;
            __pyx_t_168 = 2;
            __pyx_t_169 = __pyx_v_ii;
            __pyx_v_k = (((__pyx_v_q * __pyx_v_v1) - ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_164 * __pyx_v_Ds.strides[0]) )) + __pyx_t_165)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_166 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_167)) ))))) / (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_168 * __pyx_v_us.strides[0]) )) + __pyx_t_169)) ))));
+130:                         if k>=0:
            __pyx_t_13 = ((__pyx_v_k >= 0.0) != 0);
            if (__pyx_t_13) {
/* … */
            }
+131:                             sol0, sol1 = Ds[0,ii] + k*us[0,ii], Ds[1,ii] + k*us[1,ii]
              __pyx_t_170 = 0;
              __pyx_t_171 = __pyx_v_ii;
              __pyx_t_172 = 0;
              __pyx_t_173 = __pyx_v_ii;
              __pyx_t_17 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_170 * __pyx_v_Ds.strides[0]) )) + __pyx_t_171)) ))) + (__pyx_v_k * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_172 * __pyx_v_us.strides[0]) )) + __pyx_t_173)) )))));
              __pyx_t_174 = 1;
              __pyx_t_175 = __pyx_v_ii;
              __pyx_t_176 = 1;
              __pyx_t_177 = __pyx_v_ii;
              __pyx_t_51 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_174 * __pyx_v_Ds.strides[0]) )) + __pyx_t_175)) ))) + (__pyx_v_k * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_176 * __pyx_v_us.strides[0]) )) + __pyx_t_177)) )))));
              __pyx_v_sol0 = __pyx_t_17;
              __pyx_v_sol1 = __pyx_t_51;
+132:                             if Forbidbis:
              __pyx_t_13 = (__pyx_v_Forbidbis != 0);
              if (__pyx_t_13) {
/* … */
              }
+133:                                 sca0 = (sol0-S1X)*Ds[0,ii] + (sol1-S1Y)*Ds[1,ii]
                __pyx_t_178 = 0;
                __pyx_t_179 = __pyx_v_ii;
                __pyx_t_180 = 1;
                __pyx_t_181 = __pyx_v_ii;
                __pyx_v_sca0 = (((__pyx_v_sol0 - __pyx_v_S1X) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_178 * __pyx_v_Ds.strides[0]) )) + __pyx_t_179)) )))) + ((__pyx_v_sol1 - __pyx_v_S1Y) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_180 * __pyx_v_Ds.strides[0]) )) + __pyx_t_181)) )))));
+134:                                 sca1 = (sol0-S1X)*S1X + (sol1-S1Y)*S1Y
                __pyx_v_sca1 = (((__pyx_v_sol0 - __pyx_v_S1X) * __pyx_v_S1X) + ((__pyx_v_sol1 - __pyx_v_S1Y) * __pyx_v_S1Y));
+135:                                 sca2 = (sol0-S2X)*S2X + (sol1-S2Y)*S2Y
                __pyx_v_sca2 = (((__pyx_v_sol0 - __pyx_v_S2X) * __pyx_v_S2X) + ((__pyx_v_sol1 - __pyx_v_S2Y) * __pyx_v_S2Y));
 136:                                 #print 1, k, kout, sca0, sca1, sca2
+137:                                 if sca0<0 and sca1<0 and sca2<0:
                __pyx_t_12 = ((__pyx_v_sca0 < 0.0) != 0);
                if (__pyx_t_12) {
                } else {
                  __pyx_t_13 = __pyx_t_12;
                  goto __pyx_L58_bool_binop_done;
                }
                __pyx_t_12 = ((__pyx_v_sca1 < 0.0) != 0);
                if (__pyx_t_12) {
                } else {
                  __pyx_t_13 = __pyx_t_12;
                  goto __pyx_L58_bool_binop_done;
                }
                __pyx_t_12 = ((__pyx_v_sca2 < 0.0) != 0);
                __pyx_t_13 = __pyx_t_12;
                __pyx_L58_bool_binop_done:;
                if (__pyx_t_13) {
/* … */
                }
+138:                                     continue
                  goto __pyx_L47_continue;
 139:                             # Get the normalized perpendicular vector at intersection
+140:                             phi = Catan2(sol1,sol0)
              __pyx_v_phi = atan2(__pyx_v_sol1, __pyx_v_sol0);
 141:                             # Get the scalar product to determine entry or exit point
+142:                             sca = Ccos(phi)*vIn[0,jj]*us[0,ii] + Csin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
              __pyx_t_182 = 0;
              __pyx_t_183 = __pyx_v_jj;
              __pyx_t_184 = 0;
              __pyx_t_185 = __pyx_v_ii;
              __pyx_t_186 = 0;
              __pyx_t_187 = __pyx_v_jj;
              __pyx_t_188 = 1;
              __pyx_t_189 = __pyx_v_ii;
              __pyx_t_190 = 1;
              __pyx_t_191 = __pyx_v_jj;
              __pyx_t_192 = 2;
              __pyx_t_193 = __pyx_v_ii;
              __pyx_v_sca = ((((cos(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_182 * __pyx_v_vIn.strides[0]) )) + __pyx_t_183)) )))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_184 * __pyx_v_us.strides[0]) )) + __pyx_t_185)) )))) + ((sin(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_186 * __pyx_v_vIn.strides[0]) )) + __pyx_t_187)) )))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_188 * __pyx_v_us.strides[0]) )) + __pyx_t_189)) ))))) + ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_190 * __pyx_v_vIn.strides[0]) )) + __pyx_t_191)) ))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_192 * __pyx_v_us.strides[0]) )) + __pyx_t_193)) )))));
+143:                             if sca<=0 and k<kout:
              __pyx_t_12 = ((__pyx_v_sca <= 0.0) != 0);
              if (__pyx_t_12) {
              } else {
                __pyx_t_13 = __pyx_t_12;
                goto __pyx_L62_bool_binop_done;
              }
              __pyx_t_12 = ((__pyx_v_k < __pyx_v_kout) != 0);
              __pyx_t_13 = __pyx_t_12;
              __pyx_L62_bool_binop_done:;
              if (__pyx_t_13) {
/* … */
                goto __pyx_L61;
              }
+144:                                 kout = k
                __pyx_v_kout = __pyx_v_k;
+145:                                 indout = jj
                __pyx_v_indout = __pyx_v_jj;
+146:                                 Done = 1
                __pyx_v_Done = 1;
+147:                                 print 5, k
                __pyx_t_2 = PyFloat_FromDouble(__pyx_v_k); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 147, __pyx_L1_error)
                __Pyx_GOTREF(__pyx_t_2);
                __pyx_t_3 = PyTuple_New(2); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 147, __pyx_L1_error)
                __Pyx_GOTREF(__pyx_t_3);
                __Pyx_INCREF(__pyx_int_5);
                __Pyx_GIVEREF(__pyx_int_5);
                PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_int_5);
                __Pyx_GIVEREF(__pyx_t_2);
                PyTuple_SET_ITEM(__pyx_t_3, 1, __pyx_t_2);
                __pyx_t_2 = 0;
                if (__Pyx_Print(0, __pyx_t_3, 1) < 0) __PYX_ERR(0, 147, __pyx_L1_error)
                __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
+148:                             elif sca>=0 and k<min(kin,kout):
              __pyx_t_12 = ((__pyx_v_sca >= 0.0) != 0);
              if (__pyx_t_12) {
              } else {
                __pyx_t_13 = __pyx_t_12;
                goto __pyx_L64_bool_binop_done;
              }
              __pyx_t_51 = __pyx_v_kout;
              __pyx_t_17 = __pyx_v_kin;
              if (((__pyx_t_51 < __pyx_t_17) != 0)) {
                __pyx_t_105 = __pyx_t_51;
              } else {
                __pyx_t_105 = __pyx_t_17;
              }
              __pyx_t_12 = ((__pyx_v_k < __pyx_t_105) != 0);
              __pyx_t_13 = __pyx_t_12;
              __pyx_L64_bool_binop_done:;
              if (__pyx_t_13) {
/* … */
              }
              __pyx_L61:;
+149:                                 kin = k
                __pyx_v_kin = __pyx_v_k;
+150:                                 print 6, k
                __pyx_t_3 = PyFloat_FromDouble(__pyx_v_k); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 150, __pyx_L1_error)
                __Pyx_GOTREF(__pyx_t_3);
                __pyx_t_2 = PyTuple_New(2); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 150, __pyx_L1_error)
                __Pyx_GOTREF(__pyx_t_2);
                __Pyx_INCREF(__pyx_int_6);
                __Pyx_GIVEREF(__pyx_int_6);
                PyTuple_SET_ITEM(__pyx_t_2, 0, __pyx_int_6);
                __Pyx_GIVEREF(__pyx_t_3);
                PyTuple_SET_ITEM(__pyx_t_2, 1, __pyx_t_3);
                __pyx_t_3 = 0;
                if (__Pyx_Print(0, __pyx_t_2, 1) < 0) __PYX_ERR(0, 150, __pyx_L1_error)
                __Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
 151: 
+152:                 elif A**2>=EpsA**2 and B**2>A*C:
        __pyx_t_12 = ((pow(__pyx_v_A, 2.0) >= pow(__pyx_v_EpsA, 2.0)) != 0);
        if (__pyx_t_12) {
        } else {
          __pyx_t_13 = __pyx_t_12;
          goto __pyx_L66_bool_binop_done;
        }
        __pyx_t_12 = ((pow(__pyx_v_B, 2.0) > (__pyx_v_A * __pyx_v_C)) != 0);
        __pyx_t_13 = __pyx_t_12;
        __pyx_L66_bool_binop_done:;
        if (__pyx_t_13) {
/* … */
        }
        __pyx_L49:;
        __pyx_L47_continue:;
      }
    }
    __pyx_L11:;
+153:                     sqd = Csqrt(B**2-A*C)
          __pyx_v_sqd = sqrt((pow(__pyx_v_B, 2.0) - (__pyx_v_A * __pyx_v_C)));
 154:                     # First solution
+155:                     q = (-B + sqd)/A
          __pyx_v_q = (((-__pyx_v_B) + __pyx_v_sqd) / __pyx_v_A);
+156:                     if q>=0. and q<1.:
          __pyx_t_12 = ((__pyx_v_q >= 0.) != 0);
          if (__pyx_t_12) {
          } else {
            __pyx_t_13 = __pyx_t_12;
            goto __pyx_L69_bool_binop_done;
          }
          __pyx_t_12 = ((__pyx_v_q < 1.) != 0);
          __pyx_t_13 = __pyx_t_12;
          __pyx_L69_bool_binop_done:;
          if (__pyx_t_13) {
/* … */
          }
+157:                         k = (q*v1 - (Ds[2,ii]-VPoly[1,jj]))/us[2,ii]
            __pyx_t_194 = 2;
            __pyx_t_195 = __pyx_v_ii;
            __pyx_t_196 = 1;
            __pyx_t_197 = __pyx_v_jj;
            __pyx_t_198 = 2;
            __pyx_t_199 = __pyx_v_ii;
            __pyx_v_k = (((__pyx_v_q * __pyx_v_v1) - ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_194 * __pyx_v_Ds.strides[0]) )) + __pyx_t_195)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_196 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_197)) ))))) / (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_198 * __pyx_v_us.strides[0]) )) + __pyx_t_199)) ))));
+158:                         if k>=0.:
            __pyx_t_13 = ((__pyx_v_k >= 0.) != 0);
            if (__pyx_t_13) {
/* … */
            }
+159:                             sol0, sol1 = Ds[0,ii] + k*us[0,ii], Ds[1,ii] + k*us[1,ii]
              __pyx_t_200 = 0;
              __pyx_t_201 = __pyx_v_ii;
              __pyx_t_202 = 0;
              __pyx_t_203 = __pyx_v_ii;
              __pyx_t_105 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_200 * __pyx_v_Ds.strides[0]) )) + __pyx_t_201)) ))) + (__pyx_v_k * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_202 * __pyx_v_us.strides[0]) )) + __pyx_t_203)) )))));
              __pyx_t_204 = 1;
              __pyx_t_205 = __pyx_v_ii;
              __pyx_t_206 = 1;
              __pyx_t_207 = __pyx_v_ii;
              __pyx_t_51 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_204 * __pyx_v_Ds.strides[0]) )) + __pyx_t_205)) ))) + (__pyx_v_k * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_206 * __pyx_v_us.strides[0]) )) + __pyx_t_207)) )))));
              __pyx_v_sol0 = __pyx_t_105;
              __pyx_v_sol1 = __pyx_t_51;
+160:                             if Forbidbis:
              __pyx_t_13 = (__pyx_v_Forbidbis != 0);
              if (__pyx_t_13) {
/* … */
              }
+161:                                 sca0 = (sol0-S1X)*Ds[0,ii] + (sol1-S1Y)*Ds[1,ii]
                __pyx_t_208 = 0;
                __pyx_t_209 = __pyx_v_ii;
                __pyx_t_210 = 1;
                __pyx_t_211 = __pyx_v_ii;
                __pyx_v_sca0 = (((__pyx_v_sol0 - __pyx_v_S1X) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_208 * __pyx_v_Ds.strides[0]) )) + __pyx_t_209)) )))) + ((__pyx_v_sol1 - __pyx_v_S1Y) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_210 * __pyx_v_Ds.strides[0]) )) + __pyx_t_211)) )))));
+162:                                 sca1 = (sol0-S1X)*S1X + (sol1-S1Y)*S1Y
                __pyx_v_sca1 = (((__pyx_v_sol0 - __pyx_v_S1X) * __pyx_v_S1X) + ((__pyx_v_sol1 - __pyx_v_S1Y) * __pyx_v_S1Y));
+163:                                 sca2 = (sol0-S2X)*S2X + (sol1-S2Y)*S2Y
                __pyx_v_sca2 = (((__pyx_v_sol0 - __pyx_v_S2X) * __pyx_v_S2X) + ((__pyx_v_sol1 - __pyx_v_S2Y) * __pyx_v_S2Y));
 164:                                 #print 2, k, kout, sca0, sca1, sca2
+165:                             if not Forbidbis or (Forbidbis and not (sca0<0 and sca1<0 and sca2<0)):
              __pyx_t_12 = ((!(__pyx_v_Forbidbis != 0)) != 0);
              if (!__pyx_t_12) {
              } else {
                __pyx_t_13 = __pyx_t_12;
                goto __pyx_L74_bool_binop_done;
              }
              __pyx_t_12 = (__pyx_v_Forbidbis != 0);
              if (__pyx_t_12) {
              } else {
                __pyx_t_13 = __pyx_t_12;
                goto __pyx_L74_bool_binop_done;
              }
              __pyx_t_92 = ((__pyx_v_sca0 < 0.0) != 0);
              if (__pyx_t_92) {
              } else {
                __pyx_t_12 = __pyx_t_92;
                goto __pyx_L77_bool_binop_done;
              }
              __pyx_t_92 = ((__pyx_v_sca1 < 0.0) != 0);
              if (__pyx_t_92) {
              } else {
                __pyx_t_12 = __pyx_t_92;
                goto __pyx_L77_bool_binop_done;
              }
              __pyx_t_92 = ((__pyx_v_sca2 < 0.0) != 0);
              __pyx_t_12 = __pyx_t_92;
              __pyx_L77_bool_binop_done:;
              __pyx_t_92 = ((!__pyx_t_12) != 0);
              __pyx_t_13 = __pyx_t_92;
              __pyx_L74_bool_binop_done:;
              if (__pyx_t_13) {
/* … */
              }
 166:                                 # Get the normalized perpendicular vector at intersection
+167:                                 phi = Catan2(sol1,sol0)
                __pyx_v_phi = atan2(__pyx_v_sol1, __pyx_v_sol0);
 168:                                 # Get the scalar product to determine entry or exit point
+169:                                 sca = Ccos(phi)*vIn[0,jj]*us[0,ii] + Csin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                __pyx_t_212 = 0;
                __pyx_t_213 = __pyx_v_jj;
                __pyx_t_214 = 0;
                __pyx_t_215 = __pyx_v_ii;
                __pyx_t_216 = 0;
                __pyx_t_217 = __pyx_v_jj;
                __pyx_t_218 = 1;
                __pyx_t_219 = __pyx_v_ii;
                __pyx_t_220 = 1;
                __pyx_t_221 = __pyx_v_jj;
                __pyx_t_222 = 2;
                __pyx_t_223 = __pyx_v_ii;
                __pyx_v_sca = ((((cos(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_212 * __pyx_v_vIn.strides[0]) )) + __pyx_t_213)) )))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_214 * __pyx_v_us.strides[0]) )) + __pyx_t_215)) )))) + ((sin(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_216 * __pyx_v_vIn.strides[0]) )) + __pyx_t_217)) )))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_218 * __pyx_v_us.strides[0]) )) + __pyx_t_219)) ))))) + ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_220 * __pyx_v_vIn.strides[0]) )) + __pyx_t_221)) ))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_222 * __pyx_v_us.strides[0]) )) + __pyx_t_223)) )))));
+170:                                 if sca<=0 and k<kout:
                __pyx_t_92 = ((__pyx_v_sca <= 0.0) != 0);
                if (__pyx_t_92) {
                } else {
                  __pyx_t_13 = __pyx_t_92;
                  goto __pyx_L81_bool_binop_done;
                }
                __pyx_t_92 = ((__pyx_v_k < __pyx_v_kout) != 0);
                __pyx_t_13 = __pyx_t_92;
                __pyx_L81_bool_binop_done:;
                if (__pyx_t_13) {
/* … */
                  goto __pyx_L80;
                }
+171:                                     kout = k
                  __pyx_v_kout = __pyx_v_k;
+172:                                     indout = jj
                  __pyx_v_indout = __pyx_v_jj;
+173:                                     Done = 1
                  __pyx_v_Done = 1;
+174:                                     print 7, k, q, A, B, C, sqd
                  __pyx_t_2 = PyFloat_FromDouble(__pyx_v_k); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 174, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_2);
                  __pyx_t_3 = PyFloat_FromDouble(__pyx_v_q); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 174, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_3);
                  __pyx_t_6 = PyFloat_FromDouble(__pyx_v_A); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 174, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_6);
                  __pyx_t_4 = PyFloat_FromDouble(__pyx_v_B); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 174, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_4);
                  __pyx_t_16 = PyFloat_FromDouble(__pyx_v_C); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 174, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_16);
                  __pyx_t_5 = PyFloat_FromDouble(__pyx_v_sqd); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 174, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_5);
                  __pyx_t_1 = PyTuple_New(7); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 174, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_1);
                  __Pyx_INCREF(__pyx_int_7);
                  __Pyx_GIVEREF(__pyx_int_7);
                  PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_int_7);
                  __Pyx_GIVEREF(__pyx_t_2);
                  PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_2);
                  __Pyx_GIVEREF(__pyx_t_3);
                  PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_t_3);
                  __Pyx_GIVEREF(__pyx_t_6);
                  PyTuple_SET_ITEM(__pyx_t_1, 3, __pyx_t_6);
                  __Pyx_GIVEREF(__pyx_t_4);
                  PyTuple_SET_ITEM(__pyx_t_1, 4, __pyx_t_4);
                  __Pyx_GIVEREF(__pyx_t_16);
                  PyTuple_SET_ITEM(__pyx_t_1, 5, __pyx_t_16);
                  __Pyx_GIVEREF(__pyx_t_5);
                  PyTuple_SET_ITEM(__pyx_t_1, 6, __pyx_t_5);
                  __pyx_t_2 = 0;
                  __pyx_t_3 = 0;
                  __pyx_t_6 = 0;
                  __pyx_t_4 = 0;
                  __pyx_t_16 = 0;
                  __pyx_t_5 = 0;
                  if (__Pyx_Print(0, __pyx_t_1, 1) < 0) __PYX_ERR(0, 174, __pyx_L1_error)
                  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+175:                                 elif sca>=0 and k<min(kin,kout):
                __pyx_t_92 = ((__pyx_v_sca >= 0.0) != 0);
                if (__pyx_t_92) {
                } else {
                  __pyx_t_13 = __pyx_t_92;
                  goto __pyx_L83_bool_binop_done;
                }
                __pyx_t_51 = __pyx_v_kout;
                __pyx_t_105 = __pyx_v_kin;
                if (((__pyx_t_51 < __pyx_t_105) != 0)) {
                  __pyx_t_17 = __pyx_t_51;
                } else {
                  __pyx_t_17 = __pyx_t_105;
                }
                __pyx_t_92 = ((__pyx_v_k < __pyx_t_17) != 0);
                __pyx_t_13 = __pyx_t_92;
                __pyx_L83_bool_binop_done:;
                if (__pyx_t_13) {
/* … */
                }
                __pyx_L80:;
+176:                                     kin = k
                  __pyx_v_kin = __pyx_v_k;
+177:                                     print 8, k, jj
                  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_k); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 177, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_1);
                  __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_jj); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 177, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_5);
                  __pyx_t_16 = PyTuple_New(3); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 177, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_16);
                  __Pyx_INCREF(__pyx_int_8);
                  __Pyx_GIVEREF(__pyx_int_8);
                  PyTuple_SET_ITEM(__pyx_t_16, 0, __pyx_int_8);
                  __Pyx_GIVEREF(__pyx_t_1);
                  PyTuple_SET_ITEM(__pyx_t_16, 1, __pyx_t_1);
                  __Pyx_GIVEREF(__pyx_t_5);
                  PyTuple_SET_ITEM(__pyx_t_16, 2, __pyx_t_5);
                  __pyx_t_1 = 0;
                  __pyx_t_5 = 0;
                  if (__Pyx_Print(0, __pyx_t_16, 1) < 0) __PYX_ERR(0, 177, __pyx_L1_error)
                  __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
 178: 
 179:                     # Second solution
+180:                     q = (-B - sqd)/A
          __pyx_v_q = (((-__pyx_v_B) - __pyx_v_sqd) / __pyx_v_A);
+181:                     if q>=0. and q<1.:
          __pyx_t_92 = ((__pyx_v_q >= 0.) != 0);
          if (__pyx_t_92) {
          } else {
            __pyx_t_13 = __pyx_t_92;
            goto __pyx_L86_bool_binop_done;
          }
          __pyx_t_92 = ((__pyx_v_q < 1.) != 0);
          __pyx_t_13 = __pyx_t_92;
          __pyx_L86_bool_binop_done:;
          if (__pyx_t_13) {
/* … */
          }
+182:                         k = (q*v1 - (Ds[2,ii]-VPoly[1,jj]))/us[2,ii]
            __pyx_t_224 = 2;
            __pyx_t_225 = __pyx_v_ii;
            __pyx_t_226 = 1;
            __pyx_t_227 = __pyx_v_jj;
            __pyx_t_228 = 2;
            __pyx_t_229 = __pyx_v_ii;
            __pyx_v_k = (((__pyx_v_q * __pyx_v_v1) - ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_224 * __pyx_v_Ds.strides[0]) )) + __pyx_t_225)) ))) - (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPoly.data + __pyx_t_226 * __pyx_v_VPoly.strides[0]) )) + __pyx_t_227)) ))))) / (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_228 * __pyx_v_us.strides[0]) )) + __pyx_t_229)) ))));
 183: 
+184:                         if k>=0.:
            __pyx_t_13 = ((__pyx_v_k >= 0.) != 0);
            if (__pyx_t_13) {
/* … */
            }
+185:                             sol0, sol1 = Ds[0,ii] + k*us[0,ii], Ds[1,ii] + k*us[1,ii]
              __pyx_t_230 = 0;
              __pyx_t_231 = __pyx_v_ii;
              __pyx_t_232 = 0;
              __pyx_t_233 = __pyx_v_ii;
              __pyx_t_17 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_230 * __pyx_v_Ds.strides[0]) )) + __pyx_t_231)) ))) + (__pyx_v_k * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_232 * __pyx_v_us.strides[0]) )) + __pyx_t_233)) )))));
              __pyx_t_234 = 1;
              __pyx_t_235 = __pyx_v_ii;
              __pyx_t_236 = 1;
              __pyx_t_237 = __pyx_v_ii;
              __pyx_t_51 = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_234 * __pyx_v_Ds.strides[0]) )) + __pyx_t_235)) ))) + (__pyx_v_k * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_236 * __pyx_v_us.strides[0]) )) + __pyx_t_237)) )))));
              __pyx_v_sol0 = __pyx_t_17;
              __pyx_v_sol1 = __pyx_t_51;
+186:                             if Forbidbis:
              __pyx_t_13 = (__pyx_v_Forbidbis != 0);
              if (__pyx_t_13) {
/* … */
              }
+187:                                 sca0 = (sol0-S1X)*Ds[0,ii] + (sol1-S1Y)*Ds[1,ii]
                __pyx_t_238 = 0;
                __pyx_t_239 = __pyx_v_ii;
                __pyx_t_240 = 1;
                __pyx_t_241 = __pyx_v_ii;
                __pyx_v_sca0 = (((__pyx_v_sol0 - __pyx_v_S1X) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_238 * __pyx_v_Ds.strides[0]) )) + __pyx_t_239)) )))) + ((__pyx_v_sol1 - __pyx_v_S1Y) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_240 * __pyx_v_Ds.strides[0]) )) + __pyx_t_241)) )))));
+188:                                 sca1 = (sol0-S1X)*S1X + (sol1-S1Y)*S1Y
                __pyx_v_sca1 = (((__pyx_v_sol0 - __pyx_v_S1X) * __pyx_v_S1X) + ((__pyx_v_sol1 - __pyx_v_S1Y) * __pyx_v_S1Y));
+189:                                 sca2 = (sol0-S2X)*S2X + (sol1-S2Y)*S2Y
                __pyx_v_sca2 = (((__pyx_v_sol0 - __pyx_v_S2X) * __pyx_v_S2X) + ((__pyx_v_sol1 - __pyx_v_S2Y) * __pyx_v_S2Y));
 190:                                 #print 3, k, kout, sca0, sca1, sca2
+191:                             if not Forbidbis or (Forbidbis and not (sca0<0 and sca1<0 and sca2<0)):
              __pyx_t_92 = ((!(__pyx_v_Forbidbis != 0)) != 0);
              if (!__pyx_t_92) {
              } else {
                __pyx_t_13 = __pyx_t_92;
                goto __pyx_L91_bool_binop_done;
              }
              __pyx_t_92 = (__pyx_v_Forbidbis != 0);
              if (__pyx_t_92) {
              } else {
                __pyx_t_13 = __pyx_t_92;
                goto __pyx_L91_bool_binop_done;
              }
              __pyx_t_12 = ((__pyx_v_sca0 < 0.0) != 0);
              if (__pyx_t_12) {
              } else {
                __pyx_t_92 = __pyx_t_12;
                goto __pyx_L94_bool_binop_done;
              }
              __pyx_t_12 = ((__pyx_v_sca1 < 0.0) != 0);
              if (__pyx_t_12) {
              } else {
                __pyx_t_92 = __pyx_t_12;
                goto __pyx_L94_bool_binop_done;
              }
              __pyx_t_12 = ((__pyx_v_sca2 < 0.0) != 0);
              __pyx_t_92 = __pyx_t_12;
              __pyx_L94_bool_binop_done:;
              __pyx_t_12 = ((!__pyx_t_92) != 0);
              __pyx_t_13 = __pyx_t_12;
              __pyx_L91_bool_binop_done:;
              if (__pyx_t_13) {
/* … */
              }
 192:                                 # Get the normalized perpendicular vector at intersection
+193:                                 phi = Catan2(sol1,sol0)
                __pyx_v_phi = atan2(__pyx_v_sol1, __pyx_v_sol0);
 194:                                 # Get the scalar product to determine entry or exit point
+195:                                 sca = Ccos(phi)*vIn[0,jj]*us[0,ii] + Csin(phi)*vIn[0,jj]*us[1,ii] + vIn[1,jj]*us[2,ii]
                __pyx_t_242 = 0;
                __pyx_t_243 = __pyx_v_jj;
                __pyx_t_244 = 0;
                __pyx_t_245 = __pyx_v_ii;
                __pyx_t_246 = 0;
                __pyx_t_247 = __pyx_v_jj;
                __pyx_t_248 = 1;
                __pyx_t_249 = __pyx_v_ii;
                __pyx_t_250 = 1;
                __pyx_t_251 = __pyx_v_jj;
                __pyx_t_252 = 2;
                __pyx_t_253 = __pyx_v_ii;
                __pyx_v_sca = ((((cos(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_242 * __pyx_v_vIn.strides[0]) )) + __pyx_t_243)) )))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_244 * __pyx_v_us.strides[0]) )) + __pyx_t_245)) )))) + ((sin(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_246 * __pyx_v_vIn.strides[0]) )) + __pyx_t_247)) )))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_248 * __pyx_v_us.strides[0]) )) + __pyx_t_249)) ))))) + ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_250 * __pyx_v_vIn.strides[0]) )) + __pyx_t_251)) ))) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_252 * __pyx_v_us.strides[0]) )) + __pyx_t_253)) )))));
+196:                                 if sca<=0 and k<kout:
                __pyx_t_12 = ((__pyx_v_sca <= 0.0) != 0);
                if (__pyx_t_12) {
                } else {
                  __pyx_t_13 = __pyx_t_12;
                  goto __pyx_L98_bool_binop_done;
                }
                __pyx_t_12 = ((__pyx_v_k < __pyx_v_kout) != 0);
                __pyx_t_13 = __pyx_t_12;
                __pyx_L98_bool_binop_done:;
                if (__pyx_t_13) {
/* … */
                  goto __pyx_L97;
                }
+197:                                     kout = k
                  __pyx_v_kout = __pyx_v_k;
+198:                                     indout = jj
                  __pyx_v_indout = __pyx_v_jj;
+199:                                     Done = 1
                  __pyx_v_Done = 1;
+200:                                     print 9, k, jj
                  __pyx_t_16 = PyFloat_FromDouble(__pyx_v_k); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 200, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_16);
                  __pyx_t_5 = __Pyx_PyInt_From_int(__pyx_v_jj); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 200, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_5);
                  __pyx_t_1 = PyTuple_New(3); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 200, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_1);
                  __Pyx_INCREF(__pyx_int_9);
                  __Pyx_GIVEREF(__pyx_int_9);
                  PyTuple_SET_ITEM(__pyx_t_1, 0, __pyx_int_9);
                  __Pyx_GIVEREF(__pyx_t_16);
                  PyTuple_SET_ITEM(__pyx_t_1, 1, __pyx_t_16);
                  __Pyx_GIVEREF(__pyx_t_5);
                  PyTuple_SET_ITEM(__pyx_t_1, 2, __pyx_t_5);
                  __pyx_t_16 = 0;
                  __pyx_t_5 = 0;
                  if (__Pyx_Print(0, __pyx_t_1, 1) < 0) __PYX_ERR(0, 200, __pyx_L1_error)
                  __Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
+201:                                 elif sca>=0 and k<min(kin,kout):
                __pyx_t_12 = ((__pyx_v_sca >= 0.0) != 0);
                if (__pyx_t_12) {
                } else {
                  __pyx_t_13 = __pyx_t_12;
                  goto __pyx_L100_bool_binop_done;
                }
                __pyx_t_51 = __pyx_v_kout;
                __pyx_t_17 = __pyx_v_kin;
                if (((__pyx_t_51 < __pyx_t_17) != 0)) {
                  __pyx_t_105 = __pyx_t_51;
                } else {
                  __pyx_t_105 = __pyx_t_17;
                }
                __pyx_t_12 = ((__pyx_v_k < __pyx_t_105) != 0);
                __pyx_t_13 = __pyx_t_12;
                __pyx_L100_bool_binop_done:;
                if (__pyx_t_13) {
/* … */
                }
                __pyx_L97:;
+202:                                     kin = k
                  __pyx_v_kin = __pyx_v_k;
+203:                                     print 10, k, q, A, B, C, sqd, v0, v1, jj
                  __pyx_t_1 = PyFloat_FromDouble(__pyx_v_k); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 203, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_1);
                  __pyx_t_5 = PyFloat_FromDouble(__pyx_v_q); if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 203, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_5);
                  __pyx_t_16 = PyFloat_FromDouble(__pyx_v_A); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 203, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_16);
                  __pyx_t_4 = PyFloat_FromDouble(__pyx_v_B); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 203, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_4);
                  __pyx_t_6 = PyFloat_FromDouble(__pyx_v_C); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 203, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_6);
                  __pyx_t_3 = PyFloat_FromDouble(__pyx_v_sqd); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 203, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_3);
                  __pyx_t_2 = PyFloat_FromDouble(__pyx_v_v0); if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 203, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_2);
                  __pyx_t_14 = PyFloat_FromDouble(__pyx_v_v1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 203, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_14);
                  __pyx_t_254 = __Pyx_PyInt_From_int(__pyx_v_jj); if (unlikely(!__pyx_t_254)) __PYX_ERR(0, 203, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_254);
                  __pyx_t_255 = PyTuple_New(10); if (unlikely(!__pyx_t_255)) __PYX_ERR(0, 203, __pyx_L1_error)
                  __Pyx_GOTREF(__pyx_t_255);
                  __Pyx_INCREF(__pyx_int_10);
                  __Pyx_GIVEREF(__pyx_int_10);
                  PyTuple_SET_ITEM(__pyx_t_255, 0, __pyx_int_10);
                  __Pyx_GIVEREF(__pyx_t_1);
                  PyTuple_SET_ITEM(__pyx_t_255, 1, __pyx_t_1);
                  __Pyx_GIVEREF(__pyx_t_5);
                  PyTuple_SET_ITEM(__pyx_t_255, 2, __pyx_t_5);
                  __Pyx_GIVEREF(__pyx_t_16);
                  PyTuple_SET_ITEM(__pyx_t_255, 3, __pyx_t_16);
                  __Pyx_GIVEREF(__pyx_t_4);
                  PyTuple_SET_ITEM(__pyx_t_255, 4, __pyx_t_4);
                  __Pyx_GIVEREF(__pyx_t_6);
                  PyTuple_SET_ITEM(__pyx_t_255, 5, __pyx_t_6);
                  __Pyx_GIVEREF(__pyx_t_3);
                  PyTuple_SET_ITEM(__pyx_t_255, 6, __pyx_t_3);
                  __Pyx_GIVEREF(__pyx_t_2);
                  PyTuple_SET_ITEM(__pyx_t_255, 7, __pyx_t_2);
                  __Pyx_GIVEREF(__pyx_t_14);
                  PyTuple_SET_ITEM(__pyx_t_255, 8, __pyx_t_14);
                  __Pyx_GIVEREF(__pyx_t_254);
                  PyTuple_SET_ITEM(__pyx_t_255, 9, __pyx_t_254);
                  __pyx_t_1 = 0;
                  __pyx_t_5 = 0;
                  __pyx_t_16 = 0;
                  __pyx_t_4 = 0;
                  __pyx_t_6 = 0;
                  __pyx_t_3 = 0;
                  __pyx_t_2 = 0;
                  __pyx_t_14 = 0;
                  __pyx_t_254 = 0;
                  if (__Pyx_Print(0, __pyx_t_255, 1) < 0) __PYX_ERR(0, 203, __pyx_L1_error)
                  __Pyx_DECREF(__pyx_t_255); __pyx_t_255 = 0;
 204: 
+205:         if Done==1:
    __pyx_t_13 = ((__pyx_v_Done == 1) != 0);
    if (__pyx_t_13) {
/* … */
    }
+206:             indOut[ii] = indout
      __pyx_t_256 = __pyx_v_ii;
      *((double *) ( /* dim=0 */ ((char *) (((double *) __pyx_v_indOut.data) + __pyx_t_256)) )) = __pyx_v_indout;
+207:             SOut[0,ii] = Ds[0,ii] + kout*us[0,ii]
      __pyx_t_257 = 0;
      __pyx_t_258 = __pyx_v_ii;
      __pyx_t_259 = 0;
      __pyx_t_260 = __pyx_v_ii;
      __pyx_t_261 = 0;
      __pyx_t_262 = __pyx_v_ii;
      *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_SOut.data + __pyx_t_261 * __pyx_v_SOut.strides[0]) )) + __pyx_t_262)) )) = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_257 * __pyx_v_Ds.strides[0]) )) + __pyx_t_258)) ))) + (__pyx_v_kout * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_259 * __pyx_v_us.strides[0]) )) + __pyx_t_260)) )))));
+208:             SOut[1,ii] = Ds[1,ii] + kout*us[1,ii]
      __pyx_t_263 = 1;
      __pyx_t_264 = __pyx_v_ii;
      __pyx_t_265 = 1;
      __pyx_t_266 = __pyx_v_ii;
      __pyx_t_267 = 1;
      __pyx_t_268 = __pyx_v_ii;
      *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_SOut.data + __pyx_t_267 * __pyx_v_SOut.strides[0]) )) + __pyx_t_268)) )) = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_263 * __pyx_v_Ds.strides[0]) )) + __pyx_t_264)) ))) + (__pyx_v_kout * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_265 * __pyx_v_us.strides[0]) )) + __pyx_t_266)) )))));
+209:             SOut[2,ii] = Ds[2,ii] + kout*us[2,ii]
      __pyx_t_269 = 2;
      __pyx_t_270 = __pyx_v_ii;
      __pyx_t_271 = 2;
      __pyx_t_272 = __pyx_v_ii;
      __pyx_t_273 = 2;
      __pyx_t_274 = __pyx_v_ii;
      *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_SOut.data + __pyx_t_273 * __pyx_v_SOut.strides[0]) )) + __pyx_t_274)) )) = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_269 * __pyx_v_Ds.strides[0]) )) + __pyx_t_270)) ))) + (__pyx_v_kout * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_271 * __pyx_v_us.strides[0]) )) + __pyx_t_272)) )))));
+210:             phi = Catan2(SOut[1,ii],SOut[0,ii])
      __pyx_t_275 = 1;
      __pyx_t_276 = __pyx_v_ii;
      __pyx_t_277 = 0;
      __pyx_t_278 = __pyx_v_ii;
      __pyx_v_phi = atan2((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_SOut.data + __pyx_t_275 * __pyx_v_SOut.strides[0]) )) + __pyx_t_276)) ))), (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_SOut.data + __pyx_t_277 * __pyx_v_SOut.strides[0]) )) + __pyx_t_278)) ))));
+211:             VPerp[0,ii] = Ccos(phi)*vIn[0,indout]
      __pyx_t_279 = 0;
      __pyx_t_280 = __pyx_v_indout;
      __pyx_t_281 = 0;
      __pyx_t_282 = __pyx_v_ii;
      *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPerp.data + __pyx_t_281 * __pyx_v_VPerp.strides[0]) )) + __pyx_t_282)) )) = (cos(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_279 * __pyx_v_vIn.strides[0]) )) + __pyx_t_280)) ))));
+212:             VPerp[1,ii] = Csin(phi)*vIn[0,indout]
      __pyx_t_283 = 0;
      __pyx_t_284 = __pyx_v_indout;
      __pyx_t_285 = 1;
      __pyx_t_286 = __pyx_v_ii;
      *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPerp.data + __pyx_t_285 * __pyx_v_VPerp.strides[0]) )) + __pyx_t_286)) )) = (sin(__pyx_v_phi) * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_283 * __pyx_v_vIn.strides[0]) )) + __pyx_t_284)) ))));
+213:             VPerp[2,ii] = vIn[1,indout]
      __pyx_t_287 = 1;
      __pyx_t_288 = __pyx_v_indout;
      __pyx_t_289 = 2;
      __pyx_t_290 = __pyx_v_ii;
      *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_VPerp.data + __pyx_t_289 * __pyx_v_VPerp.strides[0]) )) + __pyx_t_290)) )) = (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_vIn.data + __pyx_t_287 * __pyx_v_vIn.strides[0]) )) + __pyx_t_288)) )));
+214:         if kin<kout:
    __pyx_t_13 = ((__pyx_v_kin < __pyx_v_kout) != 0);
    if (__pyx_t_13) {
/* … */
    }
  }
+215:             SIn[0,ii] = Ds[0,ii] + kin*us[0,ii]
      __pyx_t_291 = 0;
      __pyx_t_292 = __pyx_v_ii;
      __pyx_t_293 = 0;
      __pyx_t_294 = __pyx_v_ii;
      __pyx_t_295 = 0;
      __pyx_t_296 = __pyx_v_ii;
      *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_SIn.data + __pyx_t_295 * __pyx_v_SIn.strides[0]) )) + __pyx_t_296)) )) = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_291 * __pyx_v_Ds.strides[0]) )) + __pyx_t_292)) ))) + (__pyx_v_kin * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_293 * __pyx_v_us.strides[0]) )) + __pyx_t_294)) )))));
+216:             SIn[1,ii] = Ds[1,ii] + kin*us[1,ii]
      __pyx_t_297 = 1;
      __pyx_t_298 = __pyx_v_ii;
      __pyx_t_299 = 1;
      __pyx_t_300 = __pyx_v_ii;
      __pyx_t_301 = 1;
      __pyx_t_302 = __pyx_v_ii;
      *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_SIn.data + __pyx_t_301 * __pyx_v_SIn.strides[0]) )) + __pyx_t_302)) )) = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_297 * __pyx_v_Ds.strides[0]) )) + __pyx_t_298)) ))) + (__pyx_v_kin * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_299 * __pyx_v_us.strides[0]) )) + __pyx_t_300)) )))));
+217:             SIn[2,ii] = Ds[2,ii] + kin*us[2,ii]
      __pyx_t_303 = 2;
      __pyx_t_304 = __pyx_v_ii;
      __pyx_t_305 = 2;
      __pyx_t_306 = __pyx_v_ii;
      __pyx_t_307 = 2;
      __pyx_t_308 = __pyx_v_ii;
      *((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_SIn.data + __pyx_t_307 * __pyx_v_SIn.strides[0]) )) + __pyx_t_308)) )) = ((*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_Ds.data + __pyx_t_303 * __pyx_v_Ds.strides[0]) )) + __pyx_t_304)) ))) + (__pyx_v_kin * (*((double *) ( /* dim=1 */ ((char *) (((double *) ( /* dim=0 */ (__pyx_v_us.data + __pyx_t_305 * __pyx_v_us.strides[0]) )) + __pyx_t_306)) )))));
+218:     return np.asarray(SIn), np.asarray(SOut), np.asarray(VPerp), np.asarray(indOut)
  __Pyx_XDECREF(__pyx_r);
  __pyx_t_254 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_254)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_254);
  __pyx_t_14 = __Pyx_PyObject_GetAttrStr(__pyx_t_254, __pyx_n_s_asarray); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_14);
  __Pyx_DECREF(__pyx_t_254); __pyx_t_254 = 0;
  __pyx_t_254 = __pyx_memoryview_fromslice(__pyx_v_SIn, 2, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_254)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_254);
  __pyx_t_2 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_14))) {
    __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_14);
    if (likely(__pyx_t_2)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_14);
      __Pyx_INCREF(__pyx_t_2);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_14, function);
    }
  }
  if (!__pyx_t_2) {
    __pyx_t_255 = __Pyx_PyObject_CallOneArg(__pyx_t_14, __pyx_t_254); if (unlikely(!__pyx_t_255)) __PYX_ERR(0, 218, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_254); __pyx_t_254 = 0;
    __Pyx_GOTREF(__pyx_t_255);
  } else {
    #if CYTHON_FAST_PYCALL
    if (PyFunction_Check(__pyx_t_14)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_254};
      __pyx_t_255 = __Pyx_PyFunction_FastCall(__pyx_t_14, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_255)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_255);
      __Pyx_DECREF(__pyx_t_254); __pyx_t_254 = 0;
    } else
    #endif
    #if CYTHON_FAST_PYCCALL
    if (__Pyx_PyFastCFunction_Check(__pyx_t_14)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_254};
      __pyx_t_255 = __Pyx_PyCFunction_FastCall(__pyx_t_14, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_255)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_255);
      __Pyx_DECREF(__pyx_t_254); __pyx_t_254 = 0;
    } else
    #endif
    {
      __pyx_t_3 = PyTuple_New(1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_3, 0, __pyx_t_2); __pyx_t_2 = NULL;
      __Pyx_GIVEREF(__pyx_t_254);
      PyTuple_SET_ITEM(__pyx_t_3, 0+1, __pyx_t_254);
      __pyx_t_254 = 0;
      __pyx_t_255 = __Pyx_PyObject_Call(__pyx_t_14, __pyx_t_3, NULL); if (unlikely(!__pyx_t_255)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_255);
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    }
  }
  __Pyx_DECREF(__pyx_t_14); __pyx_t_14 = 0;
  __pyx_t_3 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_254 = __Pyx_PyObject_GetAttrStr(__pyx_t_3, __pyx_n_s_asarray); if (unlikely(!__pyx_t_254)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_254);
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_3 = __pyx_memoryview_fromslice(__pyx_v_SOut, 2, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __pyx_t_2 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_254))) {
    __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_254);
    if (likely(__pyx_t_2)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_254);
      __Pyx_INCREF(__pyx_t_2);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_254, function);
    }
  }
  if (!__pyx_t_2) {
    __pyx_t_14 = __Pyx_PyObject_CallOneArg(__pyx_t_254, __pyx_t_3); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 218, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    __Pyx_GOTREF(__pyx_t_14);
  } else {
    #if CYTHON_FAST_PYCALL
    if (PyFunction_Check(__pyx_t_254)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_3};
      __pyx_t_14 = __Pyx_PyFunction_FastCall(__pyx_t_254, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_14);
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    } else
    #endif
    #if CYTHON_FAST_PYCCALL
    if (__Pyx_PyFastCFunction_Check(__pyx_t_254)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_3};
      __pyx_t_14 = __Pyx_PyCFunction_FastCall(__pyx_t_254, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_14);
      __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
    } else
    #endif
    {
      __pyx_t_6 = PyTuple_New(1+1); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_6);
      __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_2); __pyx_t_2 = NULL;
      __Pyx_GIVEREF(__pyx_t_3);
      PyTuple_SET_ITEM(__pyx_t_6, 0+1, __pyx_t_3);
      __pyx_t_3 = 0;
      __pyx_t_14 = __Pyx_PyObject_Call(__pyx_t_254, __pyx_t_6, NULL); if (unlikely(!__pyx_t_14)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_14);
      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
    }
  }
  __Pyx_DECREF(__pyx_t_254); __pyx_t_254 = 0;
  __pyx_t_6 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __pyx_t_3 = __Pyx_PyObject_GetAttrStr(__pyx_t_6, __pyx_n_s_asarray); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_3);
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_t_6 = __pyx_memoryview_fromslice(__pyx_v_VPerp, 2, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __pyx_t_2 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_3))) {
    __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_3);
    if (likely(__pyx_t_2)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_3);
      __Pyx_INCREF(__pyx_t_2);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_3, function);
    }
  }
  if (!__pyx_t_2) {
    __pyx_t_254 = __Pyx_PyObject_CallOneArg(__pyx_t_3, __pyx_t_6); if (unlikely(!__pyx_t_254)) __PYX_ERR(0, 218, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
    __Pyx_GOTREF(__pyx_t_254);
  } else {
    #if CYTHON_FAST_PYCALL
    if (PyFunction_Check(__pyx_t_3)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_6};
      __pyx_t_254 = __Pyx_PyFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_254)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_254);
      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
    } else
    #endif
    #if CYTHON_FAST_PYCCALL
    if (__Pyx_PyFastCFunction_Check(__pyx_t_3)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_6};
      __pyx_t_254 = __Pyx_PyCFunction_FastCall(__pyx_t_3, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_254)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_254);
      __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
    } else
    #endif
    {
      __pyx_t_4 = PyTuple_New(1+1); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_4);
      __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_4, 0, __pyx_t_2); __pyx_t_2 = NULL;
      __Pyx_GIVEREF(__pyx_t_6);
      PyTuple_SET_ITEM(__pyx_t_4, 0+1, __pyx_t_6);
      __pyx_t_6 = 0;
      __pyx_t_254 = __Pyx_PyObject_Call(__pyx_t_3, __pyx_t_4, NULL); if (unlikely(!__pyx_t_254)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_254);
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
    }
  }
  __Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
  __pyx_t_4 = __Pyx_GetModuleGlobalName(__pyx_n_s_np); if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_t_6 = __Pyx_PyObject_GetAttrStr(__pyx_t_4, __pyx_n_s_asarray); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
  __pyx_t_4 = __pyx_memoryview_fromslice(__pyx_v_indOut, 1, (PyObject *(*)(char *)) __pyx_memview_get_double, (int (*)(char *, PyObject *)) __pyx_memview_set_double, 0);; if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_4);
  __pyx_t_2 = NULL;
  if (CYTHON_UNPACK_METHODS && unlikely(PyMethod_Check(__pyx_t_6))) {
    __pyx_t_2 = PyMethod_GET_SELF(__pyx_t_6);
    if (likely(__pyx_t_2)) {
      PyObject* function = PyMethod_GET_FUNCTION(__pyx_t_6);
      __Pyx_INCREF(__pyx_t_2);
      __Pyx_INCREF(function);
      __Pyx_DECREF_SET(__pyx_t_6, function);
    }
  }
  if (!__pyx_t_2) {
    __pyx_t_3 = __Pyx_PyObject_CallOneArg(__pyx_t_6, __pyx_t_4); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 218, __pyx_L1_error)
    __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
    __Pyx_GOTREF(__pyx_t_3);
  } else {
    #if CYTHON_FAST_PYCALL
    if (PyFunction_Check(__pyx_t_6)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_4};
      __pyx_t_3 = __Pyx_PyFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
    } else
    #endif
    #if CYTHON_FAST_PYCCALL
    if (__Pyx_PyFastCFunction_Check(__pyx_t_6)) {
      PyObject *__pyx_temp[2] = {__pyx_t_2, __pyx_t_4};
      __pyx_t_3 = __Pyx_PyCFunction_FastCall(__pyx_t_6, __pyx_temp+1-1, 1+1); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_XDECREF(__pyx_t_2); __pyx_t_2 = 0;
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_DECREF(__pyx_t_4); __pyx_t_4 = 0;
    } else
    #endif
    {
      __pyx_t_16 = PyTuple_New(1+1); if (unlikely(!__pyx_t_16)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_16);
      __Pyx_GIVEREF(__pyx_t_2); PyTuple_SET_ITEM(__pyx_t_16, 0, __pyx_t_2); __pyx_t_2 = NULL;
      __Pyx_GIVEREF(__pyx_t_4);
      PyTuple_SET_ITEM(__pyx_t_16, 0+1, __pyx_t_4);
      __pyx_t_4 = 0;
      __pyx_t_3 = __Pyx_PyObject_Call(__pyx_t_6, __pyx_t_16, NULL); if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 218, __pyx_L1_error)
      __Pyx_GOTREF(__pyx_t_3);
      __Pyx_DECREF(__pyx_t_16); __pyx_t_16 = 0;
    }
  }
  __Pyx_DECREF(__pyx_t_6); __pyx_t_6 = 0;
  __pyx_t_6 = PyTuple_New(4); if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 218, __pyx_L1_error)
  __Pyx_GOTREF(__pyx_t_6);
  __Pyx_GIVEREF(__pyx_t_255);
  PyTuple_SET_ITEM(__pyx_t_6, 0, __pyx_t_255);
  __Pyx_GIVEREF(__pyx_t_14);
  PyTuple_SET_ITEM(__pyx_t_6, 1, __pyx_t_14);
  __Pyx_GIVEREF(__pyx_t_254);
  PyTuple_SET_ITEM(__pyx_t_6, 2, __pyx_t_254);
  __Pyx_GIVEREF(__pyx_t_3);
  PyTuple_SET_ITEM(__pyx_t_6, 3, __pyx_t_3);
  __pyx_t_255 = 0;
  __pyx_t_14 = 0;
  __pyx_t_254 = 0;
  __pyx_t_3 = 0;
  __pyx_r = __pyx_t_6;
  __pyx_t_6 = 0;
  goto __pyx_L0;

Pythran version


In [ ]:

Numba version


In [ ]:

Benchmark overview

Test data


In [9]:
# Useful functions for defining input data

C, a = [3.,0.], 1.
def makeVesPoly(NS, C=C, a=a):
    theta = np.linspace(0,2.*np.pi,NS+1)
    VP = np.array([C[0]+a*np.cos(theta), C[1]+a*np.sin(theta)])
    ind = (VP[1,:]<C[1]-0.85*a).nonzero()[0]
    div = np.array([[C[0]-0.2*a, C[0], C[0]+0.2*a],[C[1]-1.2*a, C[1]-0.75*a, C[1]-1.2*a]])
    VP = np.concatenate((VP[:,:ind[0]],div,VP[:,ind[-1]+1:-1],VP[:,0:1]), axis=1)
    return VP

phi = [0.,np.pi/3.,np.pi/2.,np.pi]
Dr = [-0.1,0.1]
def makeLOS(NL, phi=phi, theta=phi, Dr=Dr, dphi=0., Dthet=np.pi/2., C=C, a=a):
    Ntot = len(phi)*len(theta)*len(Dr)
    nn = np.ceil(Ntot/NL)
    Ds, us = [], []
    for ii in range(len(Dr)):
        for jj in range(len(phi)):
            for kk in range(len(theta)):
                D = np.array([(C[0]+(a+Dr[ii])*np.cos(theta[kk]))*np.cos(phi[jj]), (C[0]+(a+Dr[ii])*np.cos(theta[kk]))*np.sin(phi[jj]), C[1]+(a+Dr[ii])*np.sin(theta[kk])])
                Ref = np.array([C[0]*np.cos(phi[jj]), C[0]*np.sin(phi[jj]), C[1]])
                duRef = (Ref-D)/np.linalg.norm(Ref-D)
                if NL==1:
                    dus = duRef.reshape((3,1))
                else:
                    ephi = np.array([-np.sin(phi[jj]),np.cos(phi[jj]),0.])
                    eperp = np.cross(ephi,duRef)/np.linalg.norm(np.cross(ephi,duRef))
                    epar = duRef*np.cos(dphi) + ephi*np.sin(dphi)
                    DThet = np.linspace(-Dthet,Dthet,NL)[np.newaxis,:]
                    dus = epar[:,np.newaxis]*np.cos(DThet) + eperp[:,np.newaxis]*np.sin(DThet)
                    dus = np.concatenate((duRef.reshape((3,1)),dus),axis=1)
                dus = dus/(np.sqrt(np.sum(dus**2,axis=0))[np.newaxis,:])
                Ds.append(np.tile(D,(dus.shape[1],1)).T)
                us.append(dus)
    Ds = np.concatenate(tuple(Ds),axis=1)
    us = np.concatenate(tuple(us),axis=1)
    return Ds, us

Results

Preliminary checks and debugging


In [12]:
VPoly = makeVesPoly(50)
vIn = np.array([-(VPoly[1,1:]-VPoly[1,:-1]), VPoly[0,1:]-VPoly[0,:-1]])
vIn = vIn/np.tile(np.sqrt(np.sum(vIn**2,axis=0)),(2,1))
Ds, us = makeLOS(100)

N, nN = 0, Ds.shape[1]
SIn0, SOut0, VPerp0, indOut0 = Calc_LOS_PInOut_python(Ds[:,N:N+nN], us[:,N:N+nN], VPoly, vIn, Forbid=True)#[:,N:N+nN]
SIn1, SOut1, VPerp1, indOut1 = Calc_LOS_PInOut_numpy1(Ds[:,N:N+nN], us[:,N:N+nN], VPoly, vIn, Forbid=True)


/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:40: RuntimeWarning: divide by zero encountered in double_scalars
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:62: RuntimeWarning: divide by zero encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:62: RuntimeWarning: invalid value encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:63: RuntimeWarning: divide by zero encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:63: RuntimeWarning: invalid value encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:63: RuntimeWarning: invalid value encountered in subtract
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:64: RuntimeWarning: divide by zero encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:64: RuntimeWarning: invalid value encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:64: RuntimeWarning: invalid value encountered in add
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:66: RuntimeWarning: invalid value encountered in less
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:66: RuntimeWarning: invalid value encountered in greater
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:75: RuntimeWarning: invalid value encountered in greater
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:121: RuntimeWarning: invalid value encountered in less
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:121: RuntimeWarning: invalid value encountered in greater
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:122: RuntimeWarning: invalid value encountered in less
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:122: RuntimeWarning: invalid value encountered in greater
/Applications/Anaconda/python27/lib/python2.7/site-packages/numpy/lib/nanfunctions.py:236: RuntimeWarning: All-NaN axis encountered
  warnings.warn("All-NaN axis encountered", RuntimeWarning)

In [13]:
print np.allclose(SIn0, SIn1,atol=1.e-9,rtol=0., equal_nan=True)
print np.allclose(SOut0, SOut1,atol=1.e-9,rtol=0., equal_nan=True)
print np.allclose(VPerp0, VPerp1,atol=1.e-9,rtol=0., equal_nan=True)
print np.allclose(indOut0, indOut1,atol=1.e-9,rtol=0., equal_nan=True)


True
True
True
True

In [14]:
d = np.sqrt(np.sum((SIn0-SIn1)**2,axis=0))
print np.nanmax(d), (d>0.1*np.nanmax(d)).nonzero()[0]
print (np.any(np.isnan(SOut0),axis=0) & np.all(~np.isnan(SOut1),axis=0)).nonzero()[0]
print (np.any(np.isnan(SOut1),axis=0) & np.all(~np.isnan(SOut0),axis=0)).nonzero()[0]
print (np.any(np.isnan(SIn0),axis=0) & np.all(~np.isnan(SIn1),axis=0)).nonzero()[0]
print (np.any(np.isnan(SIn1),axis=0) & np.all(~np.isnan(SIn0),axis=0)).nonzero()[0]
print (np.sqrt(np.sum((SOut0-SOut1)**2,axis=0))>1.e-9).nonzero()[0]
print (np.sqrt(np.sum((SIn0-SIn1)**2,axis=0))>1.e-9).nonzero()[0]


0.0 []
[]
[]
[]
[]
[]
[]
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:2: RuntimeWarning: invalid value encountered in greater
  from ipykernel import kernelapp as app
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:7: RuntimeWarning: invalid value encountered in greater
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:8: RuntimeWarning: invalid value encountered in greater

Benchmark


In [32]:
import datetime as dtm

######################################## (to be edited)
# Dictionnary of functions to be tested (add key to add a function)
Tests = {'python':{'func':Calc_LOS_PInOut_python, 'c':'k'},
         'numpy1':{'func':Calc_LOS_PInOut_numpy1, 'c':'r'},
         'cython':{'func':Calc_LOS_PInOut_cython, 'c':'b'}}

######################################## (can be edited)
# Parameters of the benchmark

# Number of segments constituting the vessel polygon 
# (i.e.: the polygon representing the cross-section of the toroial vessel) 
LS = [50]#[50,200]#,500]

# Number of Lines of Sight for which the function should be run
#, (i.e.: semi-lines)
LL = [1,4,10,40,100,400]#,100000,400000]
NS, NL = len(LS), len(LL)

# Number of times each function is executed (average and standard deviation are computed)
NRepeat = 6

######################################## (no editing)
# Benchmark and plot

Keys = Tests.keys()
for kk in range(len(Keys)):
    Tests[Keys[kk]]['t'] = np.nan*np.ones((NS,NL))
    Tests[Keys[kk]]['check'] = dict([(nn,np.zeros((NS,NL),dtype=bool)) for nn in ['SIn','SOut','VPerp','indOut']])

# Compute execution times
LSr, LLr = [], []
for ii in range(NS):
    VPoly = np.ascontiguousarray(makeVesPoly(LS[ii]))
    vIn = np.array([-(VPoly[1,1:]-VPoly[1,:-1]), VPoly[0,1:]-VPoly[0,:-1]])
    vIn = np.ascontiguousarray(vIn/np.tile(np.sqrt(np.sum(vIn**2,axis=0)),(2,1)))
    LSr.append(vIn.shape[1])
    print("")
    print("LS = "+str(LS[ii]))
    for jj in range(NL):
        Ds, us = makeLOS(LL[jj])
        Ds = np.ascontiguousarray(Ds)
        us = np.ascontiguousarray(us)
        if ii==0:
            LLr.append(Ds.shape[1])
        print("    LL = "+str(LL[jj]))
        for kk in range(len(Keys)):
            t = []
            for tt in range(NRepeat):
                t0 = dtm.datetime.now()
                SIn, SOut, VPerp, indOut = Tests[Keys[kk]]['func'](Ds, us, VPoly, vIn)
                t.append( (dtm.datetime.now()-t0).total_seconds() )
                if tt==NRepeat-1:
                        SIn0, SOut0, VPerp0, indOut0 = SIn, SOut, VPerp, indOut
            
            Tests[Keys[kk]]['t'][ii,jj] = np.median(t)
            Str = "        "+Keys[kk]+" "+str(np.median(t))+" / "+str(np.std(t))
            if kk>0:
                Tests[Keys[kk]]['check']['SIn'][ii,jj] = np.allclose(SIn,SIn0,atol=1.e-9,rtol=0.,equal_nan=True)
                Tests[Keys[kk]]['check']['SOut'][ii,jj] = np.allclose(SOut,SOut0,atol=1.e-9,rtol=0.,equal_nan=True)
                Tests[Keys[kk]]['check']['VPerp'][ii,jj] = np.allclose(VPerp,VPerp0,atol=1.e-9,rtol=0.,equal_nan=True)
                Tests[Keys[kk]]['check']['indOut'][ii,jj] = np.allclose(indOut,indOut0,atol=1.e-9,rtol=0.,equal_nan=True)
                Tests[Keys[kk]]['check']['vs'] = Keys[kk-1]
                allok = all([Tests[Keys[kk]]['check'][cc][ii,jj] for cc in ['SIn','SOut','VPerp','indOut']])
                Str += "   "+str(allok)+" vs "+Keys[kk-1]
            print(Str)
        
# Plot results  
f = plt.figure(figsize=(14,10),facecolor='w')
ax = f.add_axes([0.1,0.1,0.7,0.8], frameon=True,xscale='log',yscale='log')
ax.set_xlabel(r"Nb. LOS")
ax.set_ylabel(r"CPU time (s)")
m = ['o','x','^','+','s']
for kk in range(len(Keys)):
    for ii in range(NS):
        ax.plot(LLr, Tests[Keys[kk]]['t'][ii,:], ls='-', lw=1., c=Tests[Keys[kk]]['c'], marker=m[ii])

# Legend proxys
for kk in range(len(Keys)):
    ax.plot([],[], ls='-',lw=1.,c=Tests[Keys[kk]]['c'],label=Keys[kk])
for ii in range(NS):
    ax.plot([],[],ls='None',lw=0.,c='k',marker=m[ii], label="{0}".format(LS[ii]))
        
        
ax.legend(loc="upper left", ncol=2)
        
plt.show()


LS = 50
    LL = 1
        python 0.0191445 / 0.000610945010255
        cython 0.000199 / 4.98820831785e-05   True vs python
        numpy1 0.003128 / 0.0014264099068   True vs cython
    LL = 4
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:40: RuntimeWarning: divide by zero encountered in double_scalars
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:62: RuntimeWarning: divide by zero encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:62: RuntimeWarning: invalid value encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:63: RuntimeWarning: divide by zero encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:63: RuntimeWarning: invalid value encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:63: RuntimeWarning: invalid value encountered in subtract
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:64: RuntimeWarning: divide by zero encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:64: RuntimeWarning: invalid value encountered in divide
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:64: RuntimeWarning: invalid value encountered in add
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:66: RuntimeWarning: invalid value encountered in less
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:66: RuntimeWarning: invalid value encountered in greater
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:75: RuntimeWarning: invalid value encountered in greater
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:121: RuntimeWarning: invalid value encountered in less
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:121: RuntimeWarning: invalid value encountered in greater
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:122: RuntimeWarning: invalid value encountered in less
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:122: RuntimeWarning: invalid value encountered in greater
        python 0.122824 / 0.0189960652124
        cython 0.000407 / 5.26743137908e-05   True vs python
        numpy1 0.0062755 / 0.000329268591815   True vs cython
    LL = 10
        python 0.284569 / 0.00505746370614
        cython 0.0007995 / 0.000143224765084   True vs python
        numpy1 0.012043 / 0.000852165216115   True vs cython
    LL = 40
        python 1.1191715 / 0.00588616891299
        cython 0.002464 / 0.000253885418163   True vs python
        numpy1 0.043131 / 0.00111199696492   True vs cython
    LL = 100
        python 2.7928785 / 0.00647867684536
        cython 0.005834 / 0.000253289963393   True vs python
        numpy1 0.1099845 / 0.00597864986849   True vs cython
    LL = 400
        python 11.084091 / 0.0302316658347
        cython 0.022572 / 0.000288738299426   True vs python
        numpy1 0.4673885 / 0.0165061515949   True vs cython

In [130]:
plt.gcf().savefig('./Fig_IPyNb_Stats_Cython_Last.png')

Debug special cases


In [36]:
VPoly = np.array([[ 1.26499999,  1.26499999,  1.60800004 , 1.68299997,  1.63100004 , 1.57799995 ,                                                               
   1.59300005  ,1.62600005,  2.00600004,  2.23300004  ,2.2349999  , 2.26300001 ,                                                               
   2.2980001 ,  2.31599998 , 2.31599998 , 2.2980001 ,  2.26300001 , 2.2349999,                                                                 
   2.23300004  ,2.00600004 , 1.62600005 , 1.59300005  ,1.57799995 , 1.63100004   ,                                                             
   1.68299997  ,1.60800004 , 1.26499999]    ,                                                                                               
 [ 1.08500004, -1.08500004, -1.42900002, -1.43099999, -1.32599997, -1.32000005 ,                                                               
  -1.153  ,    -1.09000003, -0.773   ,   -0.44400001 ,-0.36899999 ,-0.31  ,     -0.189 ,                                                        
  -0.062   ,    0.062     ,  0.189  ,     0.31       , 0.36899999 , 0.44400001   ,                                                             
   0.773   ,    1.09000003 , 1.153   ,    1.32000005 , 1.32599997 , 1.43099999  ,                                                              
   1.42900002 , 1.08500004]])

VIn = np.array([[ 1. ,         0.70813522 , 0.02665687, -0.89612787 ,-0.1124874 , -0.99599034   ,                                                             
  -0.88583147, -0.64058188 ,-0.82309181, -0.99964469, -0.90342508, -0.96061987  ,                                                              
  -0.99010493, -1.         ,-0.99010493, -0.96061987, -0.90342508, -0.99964469   ,                                                             
  -0.82309181 ,-0.64058188 ,-0.88583147, -0.99599034, -0.1124874 , -0.89612787  ,                                                              
   0.02665687 , 0.70813522]   ,                                                                                                            
 [ 0.       ,   0.70607684 , 0.99964464, -0.44379595, -0.99365315,  0.08946081   ,                                                             
   0.46400713 , 0.76788987 , 0.56790833,  0.02665525,  0.42874599 , 0.27786592  ,                                                              
   0.14032896 , 0.        , -0.14032896, -0.27786592 ,-0.42874599, -0.02665525  ,                                                              
  -0.56790833 ,-0.76788987, -0.46400713, -0.08946081,  0.99365315 , 0.44379595 ,                                                               
  -0.99964464 ,-0.70607684]])

#Ds =np.array([[6.098],[-0.03115],[0.134175]])
Ds = np.array([[6.098],[-0.03115],[0.134175]])

#dus = np.array([[-9.85837500e-01],[1.67701586e-01],[-7.75785190e-04]])
dus = np.array([[-9.86046458e-01],[1.66470367e-01],[5.86903767e-09]])

In [135]:
SInn, SOutn, VPerpn, indOutn = Calc_LOS_PInOut_numpy1(Ds, dus, VPoly, VIn)
SInc, SOutc, VPerpc, indOutc = Calc_LOS_PInOut_cython(Ds, dus, VPoly, VIn)


A [ 5.22365342  3.93303256] [ 0 14] [ 0.43816821  0.56830709] [ 1.60022497  5.31657769] [ 0.79444343  2.08506429]
A [ 6.81254028  8.10316114] [ 0 14] [ 0.43816821  0.56830709]
B [] []
C [] [] [] [] []
C [] [] [] [] []
1 5.22365341838
2 3.93303256252
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:120: RuntimeWarning: invalid value encountered in less
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:120: RuntimeWarning: invalid value encountered in greater
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:121: RuntimeWarning: invalid value encountered in less
/Applications/Anaconda/python27/lib/python2.7/site-packages/ipykernel/__main__.py:121: RuntimeWarning: invalid value encountered in greater

In [136]:
print "RIn", np.hypot(SInn[0,:],SInn[1,:]), np.hypot(SInc[0,:],SInc[1,:])
print "ROut", np.hypot(SOutn[0,:],SOutn[1,:]), np.hypot(SOutc[0,:],SOutc[1,:])

for (A,B) in [(SInn,SInc),(SOutn,SOutc),(VPerpn,VPerpc),(indOutn,indOutc)]:
    print ""
    print A.flatten()
    print B.flatten()


RIn [ 2.30577052] [ 2.30577052]
ROut [ 1.26499999] [ 1.26499999]

[ 2.21984717  0.62358337  0.13417502]
[ 2.21984717  0.62358337  0.13417502]

[ 0.94723505  0.8384335   0.13417503]
[ 0.94723505  0.8384335   0.13417503]

[ 0.74880242  0.66279329  0.        ]
[ 0.74880242  0.66279329  0.        ]

[ 0.]
[ 0.]

In [64]:
import matplotlib.pyplot as plt
f = plt.figure(figsize=(14,10))
ax = f.add_axes([0.1,0.1,0.8,0.8])
the = np.linspace(0.,2.*np.pi,1000)
ax.plot(np.nanmin(VPoly[0,:])*np.cos(the), np.nanmin(VPoly[0,:])*np.sin(the),'-k')
ax.plot(np.nanmax(VPoly[0,:])*np.cos(the), np.nanmax(VPoly[0,:])*np.sin(the),'-k')
k = 5.5
ax.plot([Ds[0,0],Ds[0,0]+k*dus[0,0]],[Ds[1,0],Ds[1,0]+k*dus[1,0]], '-r')

f = plt.figure(figsize=(14,10))
ax = f.add_axes([0.1,0.1,0.8,0.8])
ax.plot(VPoly[0,:],VPoly[1,:],'-k')
k = 5.5
ax.plot([np.hypot(Ds[0,0],Ds[1,0]),np.hypot(Ds[0,0]+k*dus[0,0],Ds[1,0]+k*dus[1,0])],[Ds[2,0],Ds[2,0]+k*dus[2,0]], '-r')

plt.show()



In [ ]: