68#define THRESHOLD 0x0001UL
69#define FIVEPOINT 0x0002UL
70#define CHANGETHRES 0x0004UL
71#define EZONEFRAC 0x0008UL
72#define PAR_THRESHOLD 0x0010UL
73#define SEVENPOINT 0x0020UL
74#define CURVATURELIMIT 0x0040UL
90static char *option[N_OPTIONS] = {
102 "sddspeakfind [<inputfile>] [<outputfile>] [-pipe=[input][,output]] \n"
103 " -column=<columnName> \n"
104 " [-threshold=<value>|@<parametername>] \n"
105 " [{-fivePoint|-sevenPoint}] \n"
106 " [-exclusionZone=<fraction>] \n"
107 " [-changeThreshold=<fractionalChange>] \n"
108 " [-curvatureLimit=<xColumn>,<minValue>] \n"
109 " [-majorOrder=row|column] \n\n"
110 "Finds peaks in a column of data as a function of row index.\n"
111 "Program by Michael Borland. ("__DATE__
" " __TIME__
", SVN revision: " SVN_VERSION
")\n";
114void mark_peaks(
double *data, int32_t *row_flag, int64_t rows,
long n_points);
115void unmark_flat_peaks(
double *data, int32_t *row_flag, int64_t rows,
116 double change_threshold,
long five_point,
long seven_point,
117 double *x_data,
double curvature_limit);
118void unmark_excluded_peaks(
double *data, int32_t *row_flag, int64_t rows,
119 double ezone_fraction);
121int main(
int argc,
char **argv) {
124 long i_arg, page_returned;
127 char *input, *output, *column_name, *par_threshold_name, *x_column_name;
128 double *data, *x_data;
129 unsigned long pipe_flags, flags, major_order_flag;
130 double threshold, ezone_fraction, change_threshold, curvature_limit;
131 short column_major_order = -1;
134 argc =
scanargs(&s_arg, argc, argv);
135 if (argc < 2 || argc > (2 + N_OPTIONS))
138 flags = pipe_flags = 0;
139 input = output = NULL;
141 ezone_fraction = change_threshold = curvature_limit = 0;
143 par_threshold_name = NULL;
144 x_column_name = NULL;
147 for (i_arg = 1; i_arg < argc; i_arg++) {
148 if (s_arg[i_arg].arg_type == OPTION) {
149 switch (
match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
150 case CLO_MAJOR_ORDER:
151 major_order_flag = 0;
152 s_arg[i_arg].n_items--;
153 if (s_arg[i_arg].n_items > 0 &&
154 (!
scanItemList(&major_order_flag, s_arg[i_arg].list + 1,
155 &s_arg[i_arg].n_items, 0,
"row", -1, NULL, 0,
156 SDDS_ROW_MAJOR_ORDER,
"column", -1, NULL, 0,
157 SDDS_COLUMN_MAJOR_ORDER, NULL)))
158 SDDS_Bomb(
"invalid -majorOrder syntax/values");
159 if (major_order_flag & SDDS_COLUMN_MAJOR_ORDER)
160 column_major_order = 1;
161 else if (major_order_flag & SDDS_ROW_MAJOR_ORDER)
162 column_major_order = 0;
165 if (s_arg[i_arg].n_items == 2) {
166 if (s_arg[i_arg].list[1][0] ==
'@') {
168 flags |= PAR_THRESHOLD;
170 if (sscanf(s_arg[i_arg].list[1],
"%lf", &threshold) != 1)
171 SDDS_Bomb(
"incorrect -threshold syntax");
175 SDDS_Bomb(
"incorrect -threshold syntax");
183 case CLO_CHANGETHRESHOLD:
184 if (s_arg[i_arg].n_items != 2 ||
185 sscanf(s_arg[i_arg].list[1],
"%lf", &change_threshold) != 1 ||
186 change_threshold <= 0)
187 SDDS_Bomb(
"incorrect -changeThreshold syntax or values");
188 flags |= CHANGETHRES;
190 case CLO_CURVATURE_LIMIT:
191 if (s_arg[i_arg].n_items != 3 ||
192 !strlen(x_column_name = s_arg[i_arg].list[1]) ||
193 sscanf(s_arg[i_arg].list[2],
"%lf", &curvature_limit) != 1 ||
194 curvature_limit <= 0)
195 SDDS_Bomb(
"incorrect -curvatureLimit syntax or values");
196 flags |= CURVATURELIMIT;
199 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipe_flags))
203 if (s_arg[i_arg].n_items != 2)
205 column_name = s_arg[i_arg].list[1];
207 case CLO_EXCLUSIONZONE:
208 if (s_arg[i_arg].n_items != 2 ||
209 sscanf(s_arg[i_arg].list[1],
"%lf", &ezone_fraction) != 1 ||
211 SDDS_Bomb(
"invalid -exclusionZone syntax or value");
215 fprintf(stderr,
"error: unknown/ambiguous option: %s\n",
216 s_arg[i_arg].list[0]);
222 input = s_arg[i_arg].list[0];
223 else if (output == NULL)
224 output = s_arg[i_arg].list[0];
233 SDDS_Bomb(
"-column option must be given");
239 SDDS_Bomb(
"the given column is nonexistent or nonnumeric");
243 SDDS_Bomb(
"the given x column is nonexistent or nonnumeric");
248 out_set.layout.data_mode.column_major =
249 column_major_order != -1 ? column_major_order : in_set.layout.data_mode.column_major;
268 if (x_column_name && !x_data)
271 row_flag =
SDDS_Realloc(row_flag,
sizeof(*row_flag) * rows);
272 for (row = 0; row < rows; row++)
275 mark_peaks(data, row_flag, rows,
276 flags & SEVENPOINT ? 7 : (flags & FIVEPOINT ? 5 : 3));
278 if (flags & PAR_THRESHOLD)
282 if (flags & THRESHOLD || flags & PAR_THRESHOLD)
283 for (row = 0; row < rows; row++)
284 if (row_flag[row] && data[row] < threshold)
287 if (flags & CHANGETHRES || flags & CURVATURELIMIT)
288 unmark_flat_peaks(data, row_flag, rows, change_threshold,
289 flags & FIVEPOINT, flags & SEVENPOINT, x_data, curvature_limit);
291 if (flags & EZONEFRAC)
292 unmark_excluded_peaks(data, row_flag, rows, ezone_fraction);
310 free(par_threshold_name);
316void mark_peaks(
double *data, int32_t *row_flag, int64_t rows,
long n_points) {
318 int64_t i, rows_minus;
319 short five_point = 0;
332 for (i = 3; i < (rows - 3); i++) {
333 if ((data[i - 3] < data[i - 2] && data[i - 2] < data[i - 1] &&
334 data[i - 1] < data[i] && data[i + 1] < data[i] &&
335 data[i + 2] < data[i + 1] && data[i + 3] < data[i + 2]))
346 rows_minus = rows - (five_point ? 2 : 1);
347 for (i = (five_point ? 2 : 1); i < rows_minus; i++) {
349 if ((y1 > y0 && y1 > y2) || (y1 == y0 && y1 > y2) || (y1 > y0 && y1 == y2)) {
350 if (!five_point || (data[i - 2] < y0 && data[i + 2] < y2))
358void unmark_flat_peaks(
double *data, int32_t *row_flag, int64_t rows,
359 double change_threshold,
long five_point,
long seven_point,
360 double *x_data,
double curvature_limit) {
364 delta = five_point ? 2 : (seven_point ? 3 : 1);
365 rows1 = rows - delta;
367 if (change_threshold > 0) {
368 for (i = delta; i < rows1; i++) {
370 if (!data[i] || (data[i] - data[i + delta]) / data[i] > change_threshold)
372 if (!data[i] || (data[i] - data[i - delta]) / data[i] > change_threshold)
379 if (curvature_limit > 0) {
380 double chi, coef[3], scoef[3], diff[7];
381 int32_t order[3] = {0, 1, 2};
382 for (i = delta; i < rows1; i++) {
384 lsfg(x_data + i - delta, data + i - delta, NULL, 2 * delta + 1,
385 3, order, coef, scoef, &chi, diff,
ipower);
386 if (fabs(coef[2]) < curvature_limit)
393void unmark_excluded_peaks(
double *data, int32_t *row_flag, int64_t rows,
394 double ezone_fraction) {
395 int64_t lower, upper, i, j, rows1;
398 for (i = 0; i < rows; i++) {
400 lower = i - ((int64_t)(ezone_fraction / 2.0 * rows + 0.5));
403 upper = i + ((int64_t)(ezone_fraction / 2.0 * rows + 0.5));
406 for (j = lower; j <= upper; j++) {
407 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.