Coverage for /opt/hostedtoolcache/Python/3.11.10/x64/lib/python3.11/site-packages/pysagas/utilities.py: 12%
49 statements
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-30 04:27 +0000
« prev ^ index » next coverage.py v7.6.4, created at 2024-10-30 04:27 +0000
1import numpy as np
2import pandas as pd
3from tqdm import tqdm
4from typing import List, Optional
5from pysagas.geometry import Cell
8def add_sens_data(
9 cells: List[Cell],
10 data: pd.DataFrame,
11 verbosity: Optional[int] = 1,
12 match_tolerance: Optional[float] = 1e-5,
13 rounding_tolerance: Optional[float] = 1e-8,
14 force: Optional[bool] = False,
15) -> float:
16 """Appends shape sensitivity data to a list of Cell objects.
18 Parameters
19 ----------
20 cells : List[Cell]
21 A list of cell objects.
23 data : pd.DataFrame
24 The sensitivity data to be transcribed onto the cells.
26 verbosity : int, optional
27 The verbosity. The default is 1.
29 match_tolerance : float, optional
30 The precision tolerance for matching point coordinates. The
31 default is 1e-5.
33 rounding_tolerance : float, optional
34 The tolerance to round data off to. The default is 1e-8.
36 force : bool, optional
37 Force the sensitivity data to be added, even if a cell
38 already has sensitivity data. This can be used if new
39 data is being used, or if the append is being repeated with
40 a different matching tolerance. The default is False.
42 Returns
43 --------
44 match_fraction : float
45 The fraction of points matched.
46 """
47 # Extract parameters
48 parameters = []
49 param_cols = data.columns[3:]
50 for i in range(int(len(param_cols) / 3)):
51 parameters.append(param_cols[int(i * 3)].split("dxd")[-1])
53 # Construct progress bar
54 if verbosity > 0:
55 print()
56 desc = "Adding geometry-parameter sensitivity data to cells"
57 pbar = tqdm(
58 total=len(cells),
59 desc=desc,
60 position=0,
61 leave=True,
62 )
64 # Perform graph matching first
65 pts_xyz = [[[p.x, p.y, p.z] for p in [c.p0, c.p1, c.p2]] for c in cells]
66 pts_xyz = np.array(pts_xyz).reshape(-1, 3)
67 data_xyz = np.array([data["x"], data["y"], data["z"]]).T
68 from scipy.spatial.distance import cdist
70 dist = cdist(pts_xyz, data_xyz)
71 min_idx = np.argmin(dist, axis=1) # index of min distance to data for each cell
72 # min_dist = np.min(dist, axis=1) # value of min distance to data for each cell
74 matched_points = 0
75 total_points = 0
76 skipped_cells = 0
77 total_cells = 0
78 for cell_idx, cell in enumerate(cells):
79 # Check if cell already has sensitivity data
80 total_cells += 1
81 if cell.dvdp is None or force:
82 # Initialise sensitivity
83 dvdp = np.zeros((9, len(parameters)))
84 for pt_idx in range(3):
85 try:
86 # Optional chack that distance is less than threshold.
87 # if np.abs(min_dist[3*cell_idx + pt_idx]) < match_tolerance:
88 matched_data = data.iloc[min_idx[3 * cell_idx + pt_idx]][param_cols]
90 # Round off infinitesimally small values
91 matched_data[abs(matched_data) < rounding_tolerance] = 0
93 # avoid slow string indexing
94 dvdp[3 * pt_idx : 3 * (pt_idx + 1), :] = (
95 matched_data.to_numpy().reshape(-1, 3).T
96 )
98 # Update match count
99 matched_points += 1
101 except IndexError:
102 # No match found, leave as zero sensitivity
103 pass
105 # Update total_points
106 total_points += 1
108 cell._add_sensitivities(np.array(dvdp))
110 else:
111 # Skip this cell
112 skipped_cells += 1
114 # Update progress bar
115 if verbosity > 0:
116 pbar.update(1)
118 try:
119 match_fraction = matched_points / total_points
120 except:
121 match_fraction = 1
123 if verbosity > 0:
124 pbar.close()
125 print(
126 f"Done - matched {100*match_fraction:.2f}% of points "
127 + f"(skipped {100*skipped_cells/total_cells:.2f}% of cells)."
128 )
130 # TODO - allow dumping data to file
132 return match_fraction