def geom_syn_field(rp0, rp1, N_x, N_y):    
    # Polar grid 2 horizontal scans
    rmin0,rmax0,nr0,phimin0,phimax0,np0,orig0 = rp0
    rmin1,rmax1,nr1,phimin1,phimax1,np1,orig1 = rp1 
    d = orig1-orig0     
    r_0_g, phi_0_g, r_0_t, phi_0_t = geom_polar_grid(rmin0,rmax0,nr0,phimin0,phimax0,np0,-d)
    r_1_g, phi_1_g, r_1_t, phi_1_t = geom_polar_grid(rmin1,rmax1,nr1,phimin1,phimax1,np1,d)
    x_max = np.max(np.r_[(r_0_t*np.cos(phi_0_t)).flatten(),(r_1_t*np.cos(phi_1_t)).flatten()])
    x_min = np.min(np.r_[(r_0_t*np.cos(phi_0_t)).flatten(),(r_1_t*np.cos(phi_1_t)).flatten()])
    y_max = np.max(np.r_[(r_0_t*np.sin(phi_0_t)).flatten(),(r_1_t*np.sin(phi_1_t)).flatten()])
    y_min = np.min(np.r_[(r_0_t*np.sin(phi_0_t)).flatten(),(r_1_t*np.sin(phi_1_t)).flatten()]) 
    L_x = x_max-x_min
    L_y = y_max-y_min
    x = np.linspace(x_min,x_max,N_x)
    y = np.linspace(y_min,y_max,N_y)
    grid = np.meshgrid(x,y) 
    tri = Delaunay(np.c_[grid[0].flatten(),grid[1].flatten()], qhull_options = "QJ")        
    # Square grid for reconstruction
    _,tri_overlap,_,_,_,_,_,_ = wr.grid_over2((r_1_g, np.pi-phi_1_g),(r_0_g, np.pi-phi_0_g),-d)
    
    r_min=np.min(np.sqrt(tri_overlap.x**2+tri_overlap.y**2))
    d_grid = r_min*2*np.pi/180
    n_next = int(2**np.ceil(np.log(L_y/d_grid+1)/np.log(2))) 
    x_new = np.linspace(x.min(),x.max(),n_next)
    y_new = np.linspace(y.min(),y.max(),n_next)
    grid_new = np.meshgrid(x_new,y_new)
    
    return (L_x, L_y, grid, x, y, tri, grid_new,d)
Example #2
0
    indt0 = [df_0.scan.isin(s0[(t0>=t_1h[i]) & (t0<t_1h[i+1])]) for i in range(len(t_1h)-1)]  
    indt1 = [df_1.scan.isin(s1[(t1>=t_1h[i]) & (t1<t_1h[i+1])]) for i in range(len(t_1h)-1)]       
    indt0 = [x for x in indt0 if np.sum(x) > 0]
    indt1 = [x for x in indt1 if np.sum(x) > 0] 
    if (len(indt0)>0)&(len(indt1)>0):
        for i0,i1 in zip(indt0,indt1):
            df0 = df_0.loc[i0]
            df1 = df_1.loc[i1]
            if switch == 0:
                phi0 = df0.azim.unique()
                phi1 = df1.azim.unique()               
                r0 = df0.range_gate.iloc[0].values
                r1 = df1.range_gate.iloc[0].values                
                r_0, phi_0 = np.meshgrid(r0, np.pi/2-np.radians(phi0)) # meshgrid
                r_1, phi_1 = np.meshgrid(r0, np.pi/2-np.radians(phi1)) # meshgrid                
                tree,tri, w0, neigh0, index0, w1, neigh1, index1 =  wr.grid_over2((r_0, phi_0),(r_1,phi_1), -d)
                switch = 1 
            uo, vo, grdu, so = wr.direct_wf_rec(df0.astype(np.float32), df1.astype(np.float32), tri, d, N_grid = chunk) 
            ulist.append(uo)
            vlist.append(vo)
ulist = [item for sublist in ulist for item in sublist]
vlist = [item for sublist in vlist for item in sublist]            


dr0 = np.array(np.r_[-d/2,np.ones(1)]).T 
dr1 = np.array(np.r_[d/2,np.ones(1)]).T

fig0, ax0 = plt.subplots(figsize=(8, 8))
ax0.set_aspect('equal')
ax0.use_sticky_edges = False
ax0.margins(0.07)
def geom_syn_field(rp0, rp1, N_x, N_y):
    # Polar grid 2 horizontal scans
    rmin0, rmax0, nr0, phimin0, phimax0, np0, orig0 = rp0
    rmin1, rmax1, nr1, phimin1, phimax1, np1, orig1 = rp1
    d = orig1 - orig0
    r_0_g, phi_0_g, r_0_t, phi_0_t = geom_polar_grid(
        rmin0, rmax0, nr0, phimin0, phimax0, np0, -d
    )  #km2: you translate it again because you pass only the tuple as an input
    r_1_g, phi_1_g, r_1_t, phi_1_t = geom_polar_grid(rmin1, rmax1, nr1,
                                                     phimin1, phimax1, np1, d)
    #km2: I think that this should be changed in the new version where we have to triangulate the whole long field
    #km change: we must change the limits of the domain x_max x_min y_max y_min so that they will correspond to the long domain !
    u_mean = 15  #remember to pass it as parameter in the function
    #x_max = np.max(np.r_[(r_0_t*np.cos(phi_0_t)).flatten(),(r_1_t*np.cos(phi_1_t)).flatten()])+u_mean*45#km: finds the maximum x in cartesian coordinates by by taking into account both scaners

    x_min = np.min(np.r_[(r_0_t * np.cos(phi_0_t)).flatten(),
                         (r_1_t * np.cos(phi_1_t)).flatten()])
    x_max = 9882.563743135905 - abs(x_min)

    #km: why you use only the translated coordinate systems?
    """ answer la: because when translated both scans are in the same polar coordinate system and represent the size of the whole domain
                   that will be used later in the synthetic wind field generation. This is not our case since the domain might be several times
                   bigger than the domain covered by the two scans, since it is moving
    """
    y_max = np.max(np.r_[(r_0_t * np.sin(phi_0_t)).flatten(),
                         (r_1_t * np.sin(phi_1_t)).flatten()])
    y_min = np.min(np.r_[(r_0_t * np.sin(phi_0_t)).flatten(),
                         (r_1_t * np.sin(phi_1_t)).flatten()])
    L_x = x_max - x_min
    #km: length of the synthetic domain in x direction
    """answer la: yes"""
    L_y = y_max - y_min
    #km: length of the synthetic domain in y direction
    """answer la: yes"""
    x = np.linspace(x_min, x_max, N_x)
    print("x_max=", x_max, "x_min=", x_min)
    print("x_max_lin=", np.max(x), "x_min_lin=", np.min(x))
    #km:new x discretization over the synthetic region?
    """answer la: yes, after knowing the limits of the squared domain covered by the scan, the grid is defined in x"""
    y = np.linspace(y_min, y_max, N_y)
    #km:new y discretization over the synthetic region ?
    """answer la: yes, after knowing the limits of the squared domain covered by the scan, the grid is defined in y"""
    grid = np.meshgrid(x, y)
    #km:overlap cartesian grid ? (N_y x N_x x 2)
    """answer la: it is just the cartesian grid for the synthetic wind filed"""
    tri = Delaunay(np.c_[grid[0].flatten(), grid[1].flatten()],
                   qhull_options="QJ")
    #km: Delauney triangulation of the grid Why dont you triangulate the whole output of the mann model? np.c_ stacks the vectors and creates sets of points
    """answer la: Since the points we will use to interpolate on the scans grid points correspond to the ones in the synthetic wind field,
    the triangulation is done over the wind field cartesian grid. The output of the Mann's turbulence box are u and v,
    the grid (or at least the parameters of the gird, like L_x, L_y and N_x and N_y) is an input, defined previously. The Delaunay trinagulation is an scipy object
    that allows for example the identification of the corresponding triangle for a particular point (interpolation) and can
    be used as an input for a cubic interpolator for example"""
    # Square grid for reconstruction
    #km4: this last part has confused me a lot.
    #km4: You do a triangulation of the intersection set centers of the two scanners and you use the distance of the closest vertex to define a spacing through a formula.
    #km4: Then you generate a strctured grid based on this spacing
    #km4: whats the purpose ?
    """answer la4: As we discussed earlier, this new grid is generated to place the reconstructed wind field,
                   The scans sample from a fine cartesian squared mesh, 
                   to a coarser polar mesh (coarser in tue outer regin of the scan, very fine near the origin of each beam)
                   then it is interpolated back to a cartesian suqared mesh with a different refinement, 
                   this time depending on the smallest element size of the scan polar mesh. The V_los of each scan
                   need to be interpolated to a squared cart. mesh to have V_los and azimuth angles from both scans at more common points
                   than just the intersection points (with this we average less an retain more information)"""
    _, tri_overlap, _, _, _, _, _, _ = wr.grid_over2(
        (r_1_g, np.pi - phi_1_g), (r_0_g, np.pi - phi_0_g), -d)
    """ Comment: this is a function in windfieldrec, that define the tringulation of the intersection points
    of beams coming form the two scans """
    r_min = np.min(np.sqrt(tri_overlap.x**2 + tri_overlap.y**2))
    #km4: find the shortest distance from (0,0)? in cartesian coordinates
    """answer la4: yes, the closest to the lidars"""
    d_grid = r_min * 2 * np.pi / 180
    #km4: splits the perimeter of the smalest circle in steps of 2 degrees ? d_grid holds this spacing?
    """answer la4: yes, 2 deg. is the azimuth step of the lidars"""
    n_next = int(2**np.ceil(np.log(L_y / d_grid + 1) / np.log(2)))
    #km4: some kind of formula that calculates the number of points in each direction. why this formula ?
    """answer la4: It is a formula to estimate the the number of grid points with base 2 (the base can be any number though)"""
    x_new = np.linspace(x.min(), x.max(), n_next)
    y_new = np.linspace(y.min(), y.max(), n_next)
    grid_new = np.meshgrid(x_new, y_new)
    #km4: a structired grid with uniform spacing in both directions in cartesian coordinates
    """answer la4: yes"""

    return (L_x, L_y, grid, x, y, tri, grid_new, d)
def geom_syn_field2(rp0,
                    rp1,
                    N_x,
                    N_y,
                    u_mean,
                    rot_speed,
                    dir_mean,
                    tri_ret=True):
    """WRAP TO 0 TO 2*PI"""
    dir_mean = wrap_angle(dir_mean)
    # Polar grid 2 horizontal scans
    rmin0, rmax0, nr0, phimin0, phimax0, np0, orig0 = rp0
    rmin1, rmax1, nr1, phimin1, phimax1, np1, orig1 = rp1
    d = orig1 - orig0
    r_0_g, phi_0_g, r_0_t, phi_0_t = geom_polar_grid(
        rmin0, rmax0, nr0, phimin0, phimax0, np0, d
    )  #km2: you translate it again because you pass only the tuple as an input
    r_1_g, phi_1_g, r_1_t, phi_1_t = geom_polar_grid(rmin1, rmax1, nr1,
                                                     phimin1, phimax1, np1, -d)
    ################################
    """ No wind direction yet just to locate the scans before any movement
    """
    x_0_t, y_0_t = r_0_t * np.cos(phi_0_t), r_0_t * np.sin(phi_0_t)
    x_1_t, y_1_t = r_1_t * np.cos(phi_1_t), r_1_t * np.sin(phi_1_t)
    """ Rotation and translation: we then rotate according to wind direction.
        To do this we first translate to the position that the midpoint between
        the two lidars should be (see Figure_rot1,2 in the repo), and then rotate
        to wind direction, in local coordinates. The wind rose and cartesian
        have a different orientations that is why I put the 2*pi below)
    """
    ind_max = np.argsort(np.abs(np.r_[x_0_t.flatten(), x_1_t.flatten()]))
    """ center is half way to the most distant point of the scan, in y
    """
    center = np.r_[x_0_t.flatten(), x_1_t.flatten()][ind_max[-1]] / 2
    #print(dir_mean*180/np.pi)
    gamma = -wrap_angle(np.pi - dir_mean)
    y_trans = (center) * np.sin(gamma)
    x_trans = (center) * (1 - np.cos(gamma))
    S11 = np.cos(gamma)
    S12 = np.sin(gamma)
    T1 = np.array([[1, 0, x_trans], [0, 1, y_trans], [0, 0, 1]])
    R = np.array([[S11, S12, 0], [-S12, S11, 0], [0, 0, 1]])
    Xx0 = np.array(np.c_[x_0_t.flatten(),
                         y_0_t.flatten(),
                         np.ones(len(y_0_t.flatten()))]).T
    Xx1 = np.array(np.c_[x_1_t.flatten(),
                         y_1_t.flatten(),
                         np.ones(len(y_1_t.flatten()))]).T

    Xx0 = np.dot(T1, np.dot(R, Xx0))[:2, :].T
    Xx1 = np.dot(T1, np.dot(R, Xx1))[:2, :].T
    """ Once both scans are translated and rotated, we apply the final
        displacement due to wind field advection, we calculate the displacements
        per beam separatdly
    """
    # Here I suppose that the mesh is equally spaced in phi, and it changes in axis 1,
    # you can make it more general
    dphi = np.abs(phimin0 - phimax0) / (np0 - 1)
    t_step = dphi / rot_speed
    t_total = np.abs(phimin0 - phimax0) / rot_speed
    #Below it is t_total+t_step to include the last point
    t_array = np.arange(0, t_total + t_step, t_step)
    """ The displacements array is the same for both scans with the same shape as 
        x_0_t, x_1_t, y_0_t and y_1_t so I repeat the column of displacements per beam 
        nr0 times, or the number of range gates along each beam
    """
    disp_x = np.array([
        list(u_mean * t_array),
    ] * nr0).transpose()
    """ No displacement in y, since the global coordinates are the streamwise and
    lateral components"""
    disp_y = np.zeros(disp_x.shape)
    #Just to check that everything is ok
    #print(disp_x, disp_y)
    """ Finally, the scans translated, rotated and advected to estimate the domain size
    """
    Xx0 = Xx0 - np.c_[disp_x.flatten(), disp_y.flatten()]
    Xx1 = Xx1 - np.c_[disp_x.flatten(), disp_y.flatten()]
    """ Finally, the domain size
    """
    x_max = np.max(np.r_[Xx0[:, 0], Xx1[:, 0]])
    x_min = np.min(np.r_[Xx0[:, 0], Xx1[:, 0]])
    y_max = np.max(np.r_[Xx0[:, 1], Xx1[:, 1]])
    y_min = np.min(np.r_[Xx0[:, 1], Xx1[:, 1]])
    """ Next step is just to return the scans (rta stands for rotated,
       translated, advected), they will be refined in  early_weights routine.
       Nevetheless, both functions could be merged in one function.
    """
    x_0_rta, y_0_rta = np.reshape(Xx0[:, 0], x_0_t.shape), np.reshape(
        Xx0[:, 1], x_0_t.shape)
    x_1_rta, y_1_rta = np.reshape(Xx1[:, 0], x_1_t.shape), np.reshape(
        Xx1[:, 1], x_1_t.shape)

    L_x = x_max - x_min
    L_y = y_max - y_min

    x = np.linspace(x_min, x_max, N_x)
    y = np.linspace(y_min, y_max, N_y)

    grid = np.meshgrid(x, y)

    print(grid[0].shape, x.shape)

    if tri_ret:
        tri = Delaunay(np.c_[grid[0].flatten(), grid[1].flatten()],
                       qhull_options="QJ")
    else:
        tri = []

    _, tri_overlap, _, _, _, _, _, _ = wr.grid_over2((r_1_g, phi_1_g),
                                                     (r_0_g, phi_0_g), d)

    r_min = np.min(np.sqrt(tri_overlap.x**2 + tri_overlap.y**2))

    d_grid = r_min * 2 * np.pi / 180

    n_next = int(2**np.ceil(np.log(L_y / d_grid + 1) / np.log(2)))

    xn = np.r_[x_0_t.flatten(), x_1_t.flatten()]
    yn = np.r_[y_0_t.flatten(), y_1_t.flatten()]

    x_new = np.linspace(xn.min(), xn.max(), n_next)
    y_new = np.linspace(yn.min(), yn.max(), n_next)
    grid_new = np.meshgrid(x_new, y_new)

    return (L_x, L_y, grid, x, y, tri, grid_new, d, x_0_rta, y_0_rta, x_1_rta,
            y_1_rta, center)
    mask_CNR.columns = mask.columns
    mask.mask(mask_CNR, other=False, inplace=True)
    df.ws = df.ws.mask(mask)
    DF.append(df)

phi0w = DF[0].azim.unique()
phi1w = DF[0].azim.unique()
r0w = np.array(
    DF[0].iloc[(DF[0].azim == min(phi0w)).nonzero()[0][0]].range_gate)
r1w = np.array(
    DF[0].iloc[(DF[0].azim == min(phi1w)).nonzero()[0][0]].range_gate)

r_vaw, phi_vaw = np.meshgrid(r0w, np.radians(phi0w))  # meshgrid
r_siw, phi_siw = np.meshgrid(r1w, np.radians(phi1w))  # meshgrid

treew, triw, wvaw, neighvaw, indexvaw, wsiw, neighsiw, indexsiw = wr.grid_over2(
    (r_vaw, phi_vaw), (r_siw, phi_siw), d)

fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.use_sticky_edges = False
ax.margins(0.07)

for scan_n in range(10000, 13000):
    ax.cla()
    plt.title('Scan num. %i' % scan_n)
    ax.contourf(r_vaw * np.cos(phi_vaw),
                r_vaw * np.sin(phi_vaw),
                DF[1].ws.loc[DF[1].scan == scan_n].values,
                100,
                cmap='rainbow')
    plt.pause(.01)
Example #6
0
gamma = -(2 * np.pi - Dir)  # Rotation
# Components in matrix of coefficients
S11 = np.cos(gamma)
S12 = np.sin(gamma)
T = np.array([[S11, S12], [-S12, S11]])
vel = np.array(np.c_[U.flatten(), V.flatten()]).T
vel = np.dot(T, vel)
X = np.array(np.c_[x, y]).T
X = np.dot(T, X)
U_prime = np.reshape(vel[0, :], (N_x, N_y))
V_prime = np.reshape(vel[1, :], (N_x, N_y))

# In[]

tree, tri, wva, neighva, indexva, wsi, neighsi, indexsi = wr.grid_over2(
    (r_v_g, np.pi - phi_v_g), (r_s_g, np.pi - phi_s_g), -d)
r_s_r = np.linspace(150, 7000, 198 * 2)
r_v_r = np.linspace(150, 7000, 198 * 2)
phi_s_r = np.linspace(256, 344, 45 * 2) * np.pi / 180
phi_v_r = np.linspace(196, 284, 45 * 2) * np.pi / 180
r_s_g_r, phi_s_g_r = np.meshgrid(r_s_r, phi_s_r)
r_v_g_r, phi_v_g_r = np.meshgrid(r_v_r, phi_v_r)
tree_r, tri_r, wva_r, neighva_r, indexva_r, wsi_r, neighsi_r, indexsi_r = wr.grid_over2(
    (r_v_g_r, np.pi - phi_v_g_r), (r_s_g_r, np.pi - phi_s_g_r), -d)

# In[]

#vloss0 = num_lidar0(r_s_g, np.pi-phi_s_g,U_prime,V_prime,x,y,d/2)
#vlosv0 = num_lidar0(r_v_g, np.pi-phi_v_g,U_prime,V_prime,x,y,-d/2)

vloss, _ = num_lidar(r_s_g,
Example #7
0
# rmin1,rmax1,nr1,phimin1,phimax1,np1,orig1
rmin1,rmax1,nr1,phimin1,phimax1,np1,orig1 = 105,7000,198,196,284,45,np.array([6327082.4,0])
rp1 = (rmin1,rmax1,nr1,phimin1,phimax1,np1,orig1)

# Grids, polar and cartesian
d = orig1-orig0

# Polar grids for Scan 0 (local and translated)
r_0_g, phi_0_g, r_0_t, phi_0_t = sy.geom_polar_grid(rmin0,rmax0,nr0,phimin0,phimax0,np0,-d)

# Polar grids for Scan 1 (local and translated)
r_1_g, phi_1_g, r_1_t, phi_1_t = sy.geom_polar_grid(rmin1,rmax1,nr1,phimin1,phimax1,np1, d)

L_x, L_y, grid, x, y, tri, grid_new, d = sy.geom_syn_field(rp0, rp1, N_x, N_y)

_,tri_i,_, _, _, _, _, _ = wr.grid_over2((r_1_g, np.pi-phi_1_g),(r_0_g, np.pi-phi_0_g),-d)

# Triangulation and weights for each scan
dl = 75

# From Cartesian coord. to polar in global grid
r_tri_s = np.sqrt(grid_new[0]**2 + grid_new[1]**2)
phi_tri_s = np.arctan2(grid_new[1],grid_new[0])
r_tri_1_s, phi_tri_1_s = wr.translationpolargrid((r_tri_s, phi_tri_s),-d/2)
r_tri_0_s, phi_tri_0_s = wr.translationpolargrid((r_tri_s, phi_tri_s),d/2)

# Mann-model parameters
ae = [0.025, 0.05, 0.075]
L = [62,62.5,125,250,500,750,1000]
G = [0,1,2,2.5,3.5]
seed = np.arange(1,10)