Coverage for  / opt / hostedtoolcache / Python / 3.11.14 / x64 / lib / python3.11 / site-packages / rattlesnake / components / random_vibration_sys_id_utilities.py: 12%

52 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-02-27 18:22 +0000

1# -*- coding: utf-8 -*- 

2""" 

3Random Vibration utilities 

4 

5Rattlesnake Vibration Control Software 

6Copyright (C) 2021 National Technology & Engineering Solutions of Sandia, LLC 

7(NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. 

8Government retains certain rights in this software. 

9 

10This program is free software: you can redistribute it and/or modify 

11it under the terms of the GNU General Public License as published by 

12the Free Software Foundation, either version 3 of the License, or 

13(at your option) any later version. 

14 

15This program is distributed in the hope that it will be useful, 

16but WITHOUT ANY WARRANTY; without even the implied warranty of 

17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

18GNU General Public License for more details. 

19 

20You should have received a copy of the GNU General Public License 

21along with this program. If not, see <https://www.gnu.org/licenses/>. 

22""" 

23import os 

24import numpy as np 

25from scipy.io import loadmat 

26from .utilities import reduce_array_by_coordinate 

27 

28_direction_map = { 

29 "X+": 1, 

30 "X": 1, 

31 "+X": 1, 

32 "Y+": 2, 

33 "Y": 2, 

34 "+Y": 2, 

35 "Z+": 3, 

36 "Z": 3, 

37 "+Z": 3, 

38 "RX+": 4, 

39 "RX": 4, 

40 "+RX": 4, 

41 "RY+": 5, 

42 "RY": 5, 

43 "+RY": 5, 

44 "RZ+": 6, 

45 "RZ": 6, 

46 "+RZ": 6, 

47 "X-": -1, 

48 "-X": -1, 

49 "Y-": -2, 

50 "-Y": -2, 

51 "Z-": -3, 

52 "-Z": -3, 

53 "RX-": -4, 

54 "-RX": -4, 

55 "RY-": -5, 

56 "-RY": -5, 

57 "RZ-": -6, 

58 "-RZ": -6, 

59 "": 0, 

60} 

61 

62 

63def load_specification(spec_path, n_freq_lines, df, control_dofs=None): 

64 """Loads a specification CPSD matrix from a file. 

65 

66 Parameters 

67 ---------- 

68 spec_path : str 

69 Loads the specification contained in this file 

70 n_freq_lines : int 

71 The number of frequency lines 

72 df : float 

73 The frequency spacing 

74 control_dofs : list | np.ndarray | None 

75 1-D array of DOFs to use for control. If coordinates are provided in spec file, 

76 the cpsd matrix will be indexed to match the provided control DOFs. 

77 

78 Returns 

79 ------- 

80 frequency_lines : np.ndarray 

81 The frequency lines ``df*np.arange(n_freq_lines)`` 

82 cpsd_matrix : np.ndarray 

83 3D numpy array consisting of a CPSD matrix at each frequency line 

84 """ 

85 _, extension = os.path.splitext(spec_path) 

86 if extension.lower() == ".mat": 

87 data = loadmat(spec_path) 

88 frequencies = data["f"].squeeze() 

89 cpsd = data["cpsd"].transpose(2, 0, 1) 

90 warning_upper = data["warning_upper"].transpose(1, 0) if "warning_upper" in data else None 

91 warning_lower = data["warning_lower"].transpose(1, 0) if "warning_lower" in data else None 

92 abort_upper = data["abort_upper"].transpose(1, 0) if "abort_upper" in data else None 

93 abort_lower = data["abort_lower"].transpose(1, 0) if "abort_lower" in data else None 

94 elif extension.lower() == ".npz": 

95 data = np.load(spec_path) 

96 frequencies = data["f"].squeeze() 

97 cpsd = data["cpsd"] 

98 warning_upper = data["warning_upper"] if "warning_upper" in data else None 

99 warning_lower = data["warning_lower"] if "warning_lower" in data else None 

100 abort_upper = data["abort_upper"] if "abort_upper" in data else None 

101 abort_lower = data["abort_lower"] if "abort_lower" in data else None 

102 coordinate = data["coordinate"] if "coordinate" in data else None 

103 if coordinate is not None and control_dofs is not None: 

104 cpsd = reduce_array_by_coordinate(cpsd, coordinate, control_dofs) 

105 limit_coordinate = coordinate.diagonal().T 

106 warning_upper = ( 

107 reduce_array_by_coordinate(warning_upper, limit_coordinate, control_dofs) 

108 if warning_upper is not None 

109 else None 

110 ) 

111 warning_lower = ( 

112 reduce_array_by_coordinate(warning_lower, limit_coordinate, control_dofs) 

113 if warning_lower is not None 

114 else None 

115 ) 

116 abort_upper = ( 

117 reduce_array_by_coordinate(abort_upper, limit_coordinate, control_dofs) 

118 if abort_upper is not None 

119 else None 

120 ) 

121 abort_lower = ( 

122 reduce_array_by_coordinate(abort_lower, limit_coordinate, control_dofs) 

123 if abort_lower is not None 

124 else None 

125 ) 

126 else: 

127 raise ValueError("Invalid File Format") 

128 # Create the full CPSD matrix 

129 frequency_lines = df * np.arange(n_freq_lines) 

130 cpsd_matrix = np.zeros((n_freq_lines,) + cpsd.shape[1:], dtype="complex128") 

131 warning_matrix = np.empty((2, n_freq_lines, cpsd.shape[-1]), dtype="float64") 

132 warning_matrix[:] = np.nan 

133 abort_matrix = np.empty((2, n_freq_lines, cpsd.shape[-1]), dtype="float64") 

134 abort_matrix[:] = np.nan 

135 for i, (frequency, cpsd_line) in enumerate(zip(frequencies, cpsd)): 

136 index = np.argmin(np.abs(frequency - frequency_lines)) 

137 if abs(frequency - frequency_lines[index]) > 1e-5: 

138 continue 

139 cpsd_matrix[index, ...] = cpsd_line 

140 if warning_lower is not None: 

141 warning_matrix[0, index] = warning_lower[i] 

142 if warning_upper is not None: 

143 warning_matrix[1, index] = warning_upper[i] 

144 if abort_lower is not None: 

145 abort_matrix[0, index] = abort_lower[i] 

146 if abort_upper is not None: 

147 abort_matrix[1, index] = abort_upper[i] 

148 # Deliever specification to data analysis 

149 return frequency_lines, cpsd_matrix, warning_matrix, abort_matrix