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

1import numpy as np 

2import pandas as pd 

3from tqdm import tqdm 

4from typing import List, Optional 

5from pysagas.geometry import Cell 

6 

7 

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. 

17 

18 Parameters 

19 ---------- 

20 cells : List[Cell] 

21 A list of cell objects. 

22 

23 data : pd.DataFrame 

24 The sensitivity data to be transcribed onto the cells. 

25 

26 verbosity : int, optional 

27 The verbosity. The default is 1. 

28 

29 match_tolerance : float, optional 

30 The precision tolerance for matching point coordinates. The 

31 default is 1e-5. 

32 

33 rounding_tolerance : float, optional 

34 The tolerance to round data off to. The default is 1e-8. 

35 

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. 

41 

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]) 

52 

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 ) 

63 

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 

69 

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 

73 

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] 

89 

90 # Round off infinitesimally small values 

91 matched_data[abs(matched_data) < rounding_tolerance] = 0 

92 

93 # avoid slow string indexing 

94 dvdp[3 * pt_idx : 3 * (pt_idx + 1), :] = ( 

95 matched_data.to_numpy().reshape(-1, 3).T 

96 ) 

97 

98 # Update match count 

99 matched_points += 1 

100 

101 except IndexError: 

102 # No match found, leave as zero sensitivity 

103 pass 

104 

105 # Update total_points 

106 total_points += 1 

107 

108 cell._add_sensitivities(np.array(dvdp)) 

109 

110 else: 

111 # Skip this cell 

112 skipped_cells += 1 

113 

114 # Update progress bar 

115 if verbosity > 0: 

116 pbar.update(1) 

117 

118 try: 

119 match_fraction = matched_points / total_points 

120 except: 

121 match_fraction = 1 

122 

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 ) 

129 

130 # TODO - allow dumping data to file 

131 

132 return match_fraction