1# http://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

4# ---|P------/S----------~Lg---------- 

5 

6import logging 

7 

8from ..common import ldq 

9from pyrocko.squirrel.error import ToolError 

10 

11logger = logging.getLogger('psq.cli.response') 

12 

13headline = 'Print instrument response information.' 

14 

15 

16def indent(prefix, nfirst, n, message): 

17 return '\n'.join( 

18 prefix + ' ' * (nfirst if i == 0 else n) + line 

19 for i, line in enumerate(message.splitlines())) 

20 

21 

22def make_subparser(subparsers): 

23 return subparsers.add_parser( 

24 'response', 

25 help=headline, 

26 description=headline) 

27 

28 

29def setup(parser): 

30 parser.add_squirrel_selection_arguments() 

31 parser.add_squirrel_query_arguments(without=['kinds']) 

32 

33 level_choices = ['response', 'stages'] 

34 

35 parser.add_argument( 

36 '--level', 

37 choices=level_choices, 

38 dest='level', 

39 default='response', 

40 help='Set level of detail to be printed. Choices: %s' 

41 % ldq(level_choices)) 

42 

43 parser.add_argument( 

44 '--problems', 

45 action='store_true', 

46 dest='problems', 

47 default=False, 

48 help='Print attached warnings and error messages.') 

49 

50 parser.add_argument( 

51 '--plot', 

52 action='store_true', 

53 dest='plot', 

54 default=False, 

55 help='Create Bode plot showing the responses.') 

56 

57 parser.add_argument( 

58 '--fmin', 

59 dest='fmin', 

60 type=float, 

61 default=0.01, 

62 help='Minimum frequency [Hz], default: 0.01') 

63 

64 parser.add_argument( 

65 '--fmax', 

66 dest='fmax', 

67 type=float, 

68 default=100., 

69 help='Maximum frequency [Hz], default: 100') 

70 

71 parser.add_argument( 

72 '--normalize', 

73 dest='normalize', 

74 action='store_true', 

75 help='Normalize response to be 1 on flat part.') 

76 

77 parser.add_argument( 

78 '--save', 

79 dest='out_path', 

80 help='Save figure to file.') 

81 

82 parser.add_argument( 

83 '--dpi', 

84 dest='dpi', 

85 type=float, 

86 default=100., 

87 help='DPI setting for pixel image output, default: 100') 

88 

89 parser.add_argument( 

90 '--stages', 

91 dest='stages', 

92 metavar='START:STOP', 

93 help='Show response of selected stages. Indexing is Python style: ' 

94 'count starts at zero, negative values count from the end.') 

95 

96 input_quantity_choices = ['displacement', 'velocity', 'acceleration'] 

97 

98 parser.add_argument( 

99 '--input-quantity', 

100 dest='input_quantity', 

101 choices=input_quantity_choices, 

102 metavar='QUANTITY', 

103 help='Show converted response for given input quantity. choices: %s' 

104 % ldq(input_quantity_choices)) 

105 

106 parser.add_argument( 

107 '--show-breakpoints', 

108 dest='show_breakpoints', 

109 action='store_true', 

110 default=False, 

111 help='Show breakpoints of pole-zero responses.') 

112 

113 parser.add_argument( 

114 '--index-labels', 

115 dest='index_labels', 

116 action='store_true', 

117 default=False, 

118 help='Label graphs only by index and print details to terminal ' 

119 'to save space when many labels would be shown. Aggregate ' 

120 'identical responses under a common index.') 

121 

122 

123def run(parser, args): 

124 squirrel = args.make_squirrel() 

125 

126 stages = (None, None) 

127 if args.stages: 

128 words = args.stages.split(':') 

129 try: 

130 if len(words) == 1: 

131 stages = (int(words[0]), int(words[0])+1) 

132 elif len(words) == 2: 

133 stages = tuple(int(word) if word else None for word in words) 

134 else: 

135 raise ValueError() 

136 

137 except ValueError: 

138 raise ToolError('Invalid --stages argument.') 

139 

140 data = [] 

141 for response in squirrel.get_responses(**args.squirrel_query): 

142 print(response.summary) 

143 if args.problems: 

144 for level, message, _ in response.log: 

145 print('! %s: %s' % ( 

146 level.capitalize(), 

147 indent('!', 0, 5, message))) 

148 

149 if args.level == 'stages': 

150 for stage in response.stages[slice(*stages)]: 

151 print(' %s' % stage.summary) 

152 if args.problems: 

153 for level, message, _ in stage.log: 

154 print('! %s: %s' % ( 

155 level.capitalize(), 

156 indent('!', 0, 7, message))) 

157 

158 data.append(( 

159 ', '.join([ 

160 str(response.codes), 

161 response.str_time_span_short, 

162 response.summary_log, 

163 response.summary_quantities]), 

164 response.get_effective( 

165 input_quantity=args.input_quantity, 

166 stages=stages))) 

167 

168 if args.plot: 

169 if not data: 

170 logger.warning('No response objects found.') 

171 return 

172 

173 labels, resps = [list(x) for x in zip(*data)] 

174 

175 from pyrocko.plot.response import plot 

176 plot( 

177 resps, 

178 fmin=args.fmin, 

179 fmax=args.fmax, 

180 nf=200, 

181 normalize=args.normalize, 

182 labels=labels, 

183 filename=args.out_path, 

184 dpi=args.dpi, 

185 show_breakpoints=args.show_breakpoints, 

186 separate_combined_labels='print' if args.index_labels else None)