52#define THRESHOLD 0x0001UL
53#define FIVEPOINT 0x0002UL
54#define CHANGETHRES 0x0004UL
55#define EZONEFRAC 0x0008UL
56#define PAR_THRESHOLD 0x0010UL
57#define SEVENPOINT 0x0020UL
58#define CURVATURELIMIT 0x0040UL
74static char *option[N_OPTIONS] = {
86 "sddspeakfind [<inputfile>] [<outputfile>] [-pipe=[input][,output]] \n"
87 " -column=<columnName> \n"
88 " [-threshold=<value>|@<parametername>] \n"
89 " [{-fivePoint|-sevenPoint}] \n"
90 " [-exclusionZone=<fraction>] \n"
91 " [-changeThreshold=<fractionalChange>] \n"
92 " [-curvatureLimit=<xColumn>,<minValue>] \n"
93 " [-majorOrder=row|column] \n\n"
94 "Finds peaks in a column of data as a function of row index.\n"
95 "Program by Michael Borland. ("__DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
98void mark_peaks(
double *data, int32_t *row_flag, int64_t rows,
long n_points);
99void unmark_flat_peaks(
double *data, int32_t *row_flag, int64_t rows,
100 double change_threshold,
long five_point,
long seven_point,
101 double *x_data,
double curvature_limit);
102void unmark_excluded_peaks(
double *data, int32_t *row_flag, int64_t rows,
103 double ezone_fraction);
105int main(
int argc,
char **argv) {
108 long i_arg, page_returned;
111 char *input, *output, *column_name, *par_threshold_name, *x_column_name;
112 double *data, *x_data;
113 unsigned long pipe_flags, flags, major_order_flag;
114 double threshold, ezone_fraction, change_threshold, curvature_limit;
115 short column_major_order = -1;
118 argc =
scanargs(&s_arg, argc, argv);
119 if (argc < 2 || argc > (2 + N_OPTIONS))
122 flags = pipe_flags = 0;
123 input = output = NULL;
125 ezone_fraction = change_threshold = curvature_limit = 0;
127 par_threshold_name = NULL;
128 x_column_name = NULL;
131 for (i_arg = 1; i_arg < argc; i_arg++) {
132 if (s_arg[i_arg].arg_type == OPTION) {
133 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
134 case CLO_MAJOR_ORDER:
135 major_order_flag = 0;
136 s_arg[i_arg].n_items--;
137 if (s_arg[i_arg].n_items > 0 &&
138 (!
scanItemList(&major_order_flag, s_arg[i_arg].list + 1,
139 &s_arg[i_arg].n_items, 0,
"row", -1, NULL, 0,
140 SDDS_ROW_MAJOR_ORDER,
"column", -1, NULL, 0,
141 SDDS_COLUMN_MAJOR_ORDER, NULL)))
142 SDDS_Bomb(
"invalid -majorOrder syntax/values");
143 if (major_order_flag & SDDS_COLUMN_MAJOR_ORDER)
144 column_major_order = 1;
145 else if (major_order_flag & SDDS_ROW_MAJOR_ORDER)
146 column_major_order = 0;
149 if (s_arg[i_arg].n_items == 2) {
150 if (s_arg[i_arg].list[1][0] ==
'@') {
152 flags |= PAR_THRESHOLD;
154 if (sscanf(s_arg[i_arg].list[1],
"%lf", &threshold) != 1)
155 SDDS_Bomb(
"incorrect -threshold syntax");
159 SDDS_Bomb(
"incorrect -threshold syntax");
167 case CLO_CHANGETHRESHOLD:
168 if (s_arg[i_arg].n_items != 2 ||
169 sscanf(s_arg[i_arg].list[1],
"%lf", &change_threshold) != 1 ||
170 change_threshold <= 0)
171 SDDS_Bomb(
"incorrect -changeThreshold syntax or values");
172 flags |= CHANGETHRES;
174 case CLO_CURVATURE_LIMIT:
175 if (s_arg[i_arg].n_items != 3 ||
176 !strlen(x_column_name = s_arg[i_arg].list[1]) ||
177 sscanf(s_arg[i_arg].list[2],
"%lf", &curvature_limit) != 1 ||
178 curvature_limit <= 0)
179 SDDS_Bomb(
"incorrect -curvatureLimit syntax or values");
180 flags |= CURVATURELIMIT;
183 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipe_flags))
187 if (s_arg[i_arg].n_items != 2)
189 column_name = s_arg[i_arg].list[1];
191 case CLO_EXCLUSIONZONE:
192 if (s_arg[i_arg].n_items != 2 ||
193 sscanf(s_arg[i_arg].list[1],
"%lf", &ezone_fraction) != 1 ||
195 SDDS_Bomb(
"invalid -exclusionZone syntax or value");
199 fprintf(stderr,
"error: unknown/ambiguous option: %s\n",
200 s_arg[i_arg].list[0]);
206 input = s_arg[i_arg].list[0];
207 else if (output == NULL)
208 output = s_arg[i_arg].list[0];
217 SDDS_Bomb(
"-column option must be given");
223 SDDS_Bomb(
"the given column is nonexistent or nonnumeric");
227 SDDS_Bomb(
"the given x column is nonexistent or nonnumeric");
232 out_set.layout.data_mode.column_major =
233 column_major_order != -1 ? column_major_order : in_set.layout.data_mode.column_major;
252 if (x_column_name && !x_data)
255 row_flag =
SDDS_Realloc(row_flag,
sizeof(*row_flag) * rows);
256 for (row = 0; row < rows; row++)
259 mark_peaks(data, row_flag, rows,
260 flags & SEVENPOINT ? 7 : (flags & FIVEPOINT ? 5 : 3));
262 if (flags & PAR_THRESHOLD)
266 if (flags & THRESHOLD || flags & PAR_THRESHOLD)
267 for (row = 0; row < rows; row++)
268 if (row_flag[row] && data[row] < threshold)
271 if (flags & CHANGETHRES || flags & CURVATURELIMIT)
272 unmark_flat_peaks(data, row_flag, rows, change_threshold,
273 flags & FIVEPOINT, flags & SEVENPOINT, x_data, curvature_limit);
275 if (flags & EZONEFRAC)
276 unmark_excluded_peaks(data, row_flag, rows, ezone_fraction);
294 free(par_threshold_name);
300void mark_peaks(
double *data, int32_t *row_flag, int64_t rows,
long n_points) {
302 int64_t i, rows_minus;
303 short five_point = 0;
316 for (i = 3; i < (rows - 3); i++) {
317 if ((data[i - 3] < data[i - 2] && data[i - 2] < data[i - 1] &&
318 data[i - 1] < data[i] && data[i + 1] < data[i] &&
319 data[i + 2] < data[i + 1] && data[i + 3] < data[i + 2]))
330 rows_minus = rows - (five_point ? 2 : 1);
331 for (i = (five_point ? 2 : 1); i < rows_minus; i++) {
333 if ((y1 > y0 && y1 > y2) || (y1 == y0 && y1 > y2) || (y1 > y0 && y1 == y2)) {
334 if (!five_point || (data[i - 2] < y0 && data[i + 2] < y2))
342void unmark_flat_peaks(
double *data, int32_t *row_flag, int64_t rows,
343 double change_threshold,
long five_point,
long seven_point,
344 double *x_data,
double curvature_limit) {
348 delta = five_point ? 2 : (seven_point ? 3 : 1);
349 rows1 = rows - delta;
351 if (change_threshold > 0) {
352 for (i = delta; i < rows1; i++) {
354 if (!data[i] || (data[i] - data[i + delta]) / data[i] > change_threshold)
356 if (!data[i] || (data[i] - data[i - delta]) / data[i] > change_threshold)
363 if (curvature_limit > 0) {
364 double chi, coef[3], scoef[3], diff[7];
365 int32_t order[3] = {0, 1, 2};
366 for (i = delta; i < rows1; i++) {
368 lsfg(x_data + i - delta, data + i - delta, NULL, 2 * delta + 1,
369 3, order, coef, scoef, &chi, diff,
ipower);
370 if (fabs(coef[2]) < curvature_limit)
377void unmark_excluded_peaks(
double *data, int32_t *row_flag, int64_t rows,
378 double ezone_fraction) {
379 int64_t lower, upper, i, j, rows1;
382 for (i = 0; i < rows; i++) {
384 lower = i - ((int64_t)(ezone_fraction / 2.0 * rows + 0.5));
387 upper = i + ((int64_t)(ezone_fraction / 2.0 * rows + 0.5));
390 for (j = lower; j <= upper; j++) {
391 if (j != i && row_flag[j] && data[j] <= data[i])
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_InitializeCopy(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, char *filename, char *filemode)
int32_t SDDS_CopyPage(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
char * SDDS_FindColumn(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
Finds the first column in the SDDS dataset that matches the specified criteria.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
int32_t SDDS_CopyString(char **target, const char *source)
Copies a source string to a target string with memory allocation.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
long lsfg(double *xd, double *yd, double *sy, long n_pts, long n_terms, int32_t *order, double *coef, double *s_coef, double *chi, double *diff, double(*fn)(double x, long ord))
Computes generalized least squares fits using a function passed by the caller.
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
long processPipeOption(char **item, long items, unsigned long *flags)
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
void free_scanargs(SCANNED_ARG **scanned, int argc)
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.
double ipower(double x, long n)
Evaluate a power function x^n.