From 396f0573518c9cd066c31c1b59505489dd0529d4 Mon Sep 17 00:00:00 2001
From: MatthieuJacobs <matthieu.jacobs@student.kuleuven.be>
Date: Mon, 7 Mar 2022 16:39:56 +0100
Subject: [PATCH] Files from Philip for grid quality assessment

---
 GridQuality/grid_analyze.py | 203 ++++++++++++++++++++++++++++++++++++
 GridQuality/quick_g.py      |  14 +++
 2 files changed, 217 insertions(+)
 create mode 100644 GridQuality/grid_analyze.py
 create mode 100644 GridQuality/quick_g.py

diff --git a/GridQuality/grid_analyze.py b/GridQuality/grid_analyze.py
new file mode 100644
index 0000000..31fc5fa
--- /dev/null
+++ b/GridQuality/grid_analyze.py
@@ -0,0 +1,203 @@
+import numpy as np
+from matplotlib import pyplot as plt
+from combine.quick_g import quick_g_plot
+
+# not whole loop, only tenth -> phi doesnt loop    
+def yield_grid_cells(g, r_lahead=1, tht_lahead=1, phi_lahead=0):
+    g = g[:,:-1] # remove double tht=0,2pi values
+    # implement general looping edges g[r,tht,phi,c]; tht loops, r, phi not
+    ors, othts, ophis, _ = g.shape  # original xxx size
+    g = np.pad(g, [(0,0), (0,tht_lahead), (0,0), (0,0)], mode='wrap')
+    
+    # create smaller output array
+    h = np.empty((ors-r_lahead, othts, ophis-phi_lahead,
+                  1+r_lahead, tht_lahead+1, phi_lahead+1, 3))
+    
+    # iterate over all parameter coordinates
+    for cr in range(ors-r_lahead):
+        for ctht in range(othts): #tht loops
+            for cphi in range(ophis-phi_lahead):
+                h[cr, ctht, cphi] = g[cr:cr+r_lahead+1,
+                                      ctht:ctht+tht_lahead+1,
+                                      cphi:cphi+phi_lahead+1]    
+    return h
+     
+           
+def volume(g):
+    wv = yield_grid_cells(g, 1, 1, 1)  # window view
+    # calculate coord differences 
+    r = wv[...,0,0,0,0]
+    dr = np.diff(wv[...,:,0,0,:], axis=-2)[...,0,:]
+    dz = np.diff(wv[...,0,:,0,:], axis=-2)[...,0,:]
+    drphi = np.diff(wv[...,0,0,:,:], axis=-2)[...,0,:]
+    # change phi angle difference to space difference by multiplying with r
+    drphi *= r.reshape(r.shape + (1,)) # dphi * r
+    # calculate volume from column vector determinant
+    vectors = np.empty(dr.shape + (3,))
+    vectors[...,0], vectors[...,1], vectors[...,2] = dr, dz, drphi
+    vols = np.linalg.det(vectors)
+    return vols
+        
+def non_orthogonality(g):
+    wv = yield_grid_cells(g, 2, 2, 0)  # window view
+    # the two directions of cell edges, along r and along tht
+    rs, thts, phis = wv.shape[:3]
+    # angles on r and tht faces
+    a_r, a_tht = np.empty((rs, thts, phis)), np.empty((rs, thts, phis))
+    
+    # using numpy vector functions is fast, but takes ages to code. will loop
+    for r in range(rs):
+        for tht in range(thts):
+            for phi in range(phis):
+                x = wv[r,tht,phi]
+                # cell centers
+                mid = np.mean(x[0:2,0:2], axis=(0,1))[0]
+                mid_ar = np.mean(x[1:3,0:2], axis=(0,1))[0]
+                mid_atht = np.mean(x[0:2,1:3], axis=(0,1))[0]
+                # direction of cell midpoint connections 
+                v_ar = (mid_ar - mid)/np.linalg.norm(mid_ar - mid)
+                v_atht = (mid_atht - mid)/np.linalg.norm(mid_atht - mid)
+                # direction of edges 
+                t_ar = (x[1,1]-x[1,0])/np.linalg.norm(x[1,1]-x[1,0])
+                t_atht = (x[1,1]-x[0,1])/np.linalg.norm(x[1,1]-x[0,1])
+                # angle between edge direction and midpoint direction
+                a_r[r,tht,phi] = np.abs(np.arcsin(np.dot(t_ar, v_ar)))
+                a_tht[r,tht,phi] = np.abs(np.arcsin(np.dot(t_atht, v_atht)))
+                
+    a_r *= 180/np.pi; a_tht *= 180/np.pi
+    return a_r, a_tht
+    
+def unevenness(g):
+    wv = yield_grid_cells(g, 2, 2, 0)  # window view
+    # the two directions of cell edges, along r and along tht
+    rs, thts, phis = wv.shape[:3]
+    # unevenness on r and tht faces, also named a
+    a_r, a_tht = np.empty((rs, thts, phis)), np.empty((rs, thts, phis))
+    
+    # using numpy vector functions is fast, but takes ages to code. will loop
+    for r in range(rs):
+        for tht in range(thts):
+            for phi in range(phis):
+                x = wv[r,tht,phi,...,:2]
+                # cell centers
+                mid = np.mean(x[0:2,0:2], axis=(0,1))[0]
+                mid_ar = np.mean(x[1:3,0:2], axis=(0,1))[0]
+                mid_atht = np.mean(x[0:2,1:3], axis=(0,1))[0]
+                # direction of cell midpoint connections 
+                v_ar = (mid_ar - mid)/np.linalg.norm(mid_ar - mid)
+                v_atht = (mid_atht - mid)/np.linalg.norm(mid_atht - mid)
+                # cell midpoint line midpoint m_f
+                linemid_ar = np.mean([mid, mid_ar], axis=0)
+                linemid_atht = np.mean([mid, mid_atht], axis=0)
+                # cell corner connection line (edge) midpoint c_f
+                facemid_ar = np.mean(x[1,0:2], axis=0)[0]
+                facemid_atht = np.mean(x[0:2,1], axis=0)[0]
+                # line distance to point
+                ld_ar = np.linalg.norm(np.cross(v_ar, facemid_ar-mid_ar))
+                ld_atht = np.linalg.norm(np.cross(v_atht, facemid_atht-mid_atht))
+                # rotated cell mitpoint dir by 90 deg
+                n_ar = np.array([-v_ar[1], v_ar[0]])
+                n_atht = np.array([-v_atht[1], v_atht[0]])
+                # check if needed to add or remove
+                f_ar = np.sign(np.dot(n_ar, facemid_ar-mid_ar))
+                f_atht = np.sign(np.dot(n_atht, facemid_atht-mid_atht))
+                # move corner connection line (edge) midpoint on line c_f'
+                proj_facemid_ar = facemid_ar - f_ar*ld_ar*n_ar
+                proj_facemid_atht = facemid_atht - f_atht*ld_atht*n_atht
+                # distance of c_f' and m_f
+                num_dist_ar = np.linalg.norm(proj_facemid_ar-linemid_ar)
+                num_dist_atht = np.linalg.norm(proj_facemid_atht-linemid_atht)
+                # distance between two cell midpoints 
+                den_dist_ar = np.linalg.norm(mid_ar - mid)
+                den_dist_atht = np.linalg.norm(mid_atht - mid)
+                # measure of unevenness
+                a_r[r,tht,phi] = num_dist_ar/den_dist_ar
+                a_tht[r,tht,phi] = num_dist_atht/den_dist_atht
+                
+    return a_r, a_tht
+
+def skewness(g):
+    wv = yield_grid_cells(g, 2, 2, 0)  # window view
+    # the two directions of cell edges, along r and along tht
+    rs, thts, phis = wv.shape[:3]
+    # skewness on r and tht faces, also named a
+    a_r, a_tht = np.empty((rs, thts, phis)), np.empty((rs, thts, phis))
+    
+    # using numpy vector functions is fast, but takes ages to code. will loop
+    for r in range(rs):
+        for tht in range(thts):
+            for phi in range(phis):
+                x = wv[r,tht,phi,...,:2]
+                # cell centers
+                mid = np.mean(x[0:2,0:2], axis=(0,1))[0]
+                mid_ar = np.mean(x[1:3,0:2], axis=(0,1))[0]
+                mid_atht = np.mean(x[0:2,1:3], axis=(0,1))[0]
+                # direction of cell midpoint connections 
+                v_ar = (mid_ar - mid)/np.linalg.norm(mid_ar - mid)
+                v_atht = (mid_atht - mid)/np.linalg.norm(mid_atht - mid)
+                # cell corner connection line (edge) midpoint c_f
+                facemid_ar = np.mean(x[1,0:2], axis=0)[0]
+                facemid_atht = np.mean(x[0:2,1], axis=0)[0]
+                # line distance to point == ||c_f' - c_f||
+                ld_ar = np.abs(np.cross(v_ar, facemid_ar-mid_ar))
+                ld_atht = np.abs(np.cross(v_atht, facemid_atht-mid_atht))
+                # distance between two cell midpoints 
+                den_dist_ar = np.linalg.norm(mid_ar - mid)
+                den_dist_atht = np.linalg.norm(mid_atht - mid) 
+                # measure of skewness
+                a_r[r,tht,phi] = ld_ar/den_dist_ar
+                a_tht[r,tht,phi] = ld_atht/den_dist_atht
+                
+    return a_r, a_tht
+
+def nonconvex(g):
+    wv = yield_grid_cells(g, 1, 1, 0)  # window view
+    # the two directions of cell edges, along r and along tht
+    rs, thts, phis = wv.shape[:3]
+    # skewness on r and tht faces, also named a
+    is_convex = np.empty((rs, thts, phis))
+    
+    # using numpy vector functions is fast, but takes ages to code. will loop
+    for r in range(rs):
+        for tht in range(thts):
+            for phi in range(phis):
+                x = wv[r,tht,phi,...,0,:2]
+                # from point, to point, *other point indices to check against
+                # its just looping through the subarray, feel free to improve
+                indices = [[(0,0), (1,0), (1,1), (0,1)],
+                           [(1,0), (1,1), (0,1), (0,0)],
+                           [(1,1), (0,1), (0,0), (1,0)],
+                           [(0,1), (0,0), (1,0), (1,1)]]
+                for (of, to, A, B) in indices:
+                    di = x[to] - x[of] # direction of line
+                    # check if A and B on same side of line. If so, then 
+                    # the crossproduct with the direction has the same sign
+                    vA = np.sign(np.cross(di, x[A]-x[of]))
+                    vB = np.sign(np.cross(di, x[B]-x[of]))
+                    if vA == vB:
+                        is_convex[r,tht,phi] = vA
+                    else:
+                        is_convex[r,tht,phi] = 0
+    
+    return is_convex
+    
+
+if __name__ == "__main__":
+    try:
+        g = np.load("g_possible.npy")
+        # g = np.load("g_kaputt.npy")
+    except:
+        print("Need to generate grid array 'g.npy' with another program")
+        raise
+    
+    
+    #nonc = nonconvex(g) # TODO  1 == good, 0 == nonconvex, -1 == weird
+    
+    # volumes = volume(g)
+    # angles_r, angles_tht = non_orthogonality(g)
+    # uneven_r, uneven_tht = unevenness(g)
+    # skewness_r, skewness_tht = skewness(g)
+    # print(f"{np.sum(volumes):.3E} <- Whole volume in m^3")
+    # print(f"{np.min(volumes):.3E}, {np.max(volumes):.3E} <- Min, Max cell volume in m^3")
+    # print(f"{np.mean(volumes):.3E}, {np.std(volumes):.3E} <- Mean, Std of cell volume in m^3")
+    
\ No newline at end of file
diff --git a/GridQuality/quick_g.py b/GridQuality/quick_g.py
new file mode 100644
index 0000000..5824cbd
--- /dev/null
+++ b/GridQuality/quick_g.py
@@ -0,0 +1,14 @@
+import numpy as np
+from matplotlib import pyplot as plt
+
+def quick_g_plot(g, phi=-1, title=None):
+    R, z, _ = np.transpose(g[:,:,phi,:], (2,0,1))
+    fig, ax = plt.subplots(figsize=(8,8))
+    ax.set_aspect("equal")
+    ax.plot(R,z, c="blue", lw=0.3)
+    ax.plot(R.T,z.T, c="red", lw=0.3)
+    if title:
+        ax.set_title(title)
+    elif title is None:
+        ax.set_title(f"Crossection at the {phi}. slice")
+    fig.tight_layout()
-- 
GitLab