SDDSlib
Loading...
Searching...
No Matches
sddszerofind.c
Go to the documentation of this file.
1/**
2 * @file sddszerofind.c
3 * @brief A program to find zero crossings in a column of an SDDS file.
4 *
5 * This program identifies zero-crossing points in one SDDS column as a function of another column.
6 * It performs interpolation to compute zero positions and optionally calculates the slope at each zero.
7 *
8 * ### Key Features
9 * - Supports multiple input and output formats, including piping.
10 * - Allows specification of columns for zero-finding and dependent columns for interpolation.
11 * - Option to include slope information in the output.
12 * - Provides flexible row or column-major ordering for output files.
13 *
14 * ### Usage
15 * ```
16 * sddszerofind [<inputfile>] [<outputfile>] [-pipe=[input][,output]]
17 * -zeroesOf=<columnName> [-columns=<columnNames>] [-offset=<value>]
18 * [-slopeOutput] [-majorOrder=row|column]
19 * ```
20 *
21 * ### Options
22 * - **-zeroesOf=<columnName>**: Specifies the column to find zero crossings.
23 * - **-columns=<columnNames>**: Specifies columns for interpolation (default: all numerical columns).
24 * - **-offset=<value>**: Adjusts the zero-finding threshold by adding an offset.
25 * - **-slopeOutput**: Outputs the slope at zero-crossing points.
26 * - **-majorOrder=row|column**: Sets output ordering in row or column-major format.
27 *
28 * ### Example
29 * ```
30 * sddszerofind input.sdds output.sdds -zeroesOf=ColumnA -columns=ColumnB,ColumnC -offset=0.5 -slopeOutput
31 * ```
32 *
33 * @copyright
34 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
35 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
36 *
37 * @license
38 * This file is distributed under the terms of the Software License Agreement
39 * found in the file LICENSE included with this distribution.
40 *
41 * @author M. Borland, C. Saunders, R. Soliday, H. Shang
42 */
43
44#include "mdb.h"
45#include "SDDS.h"
46#include "scan.h"
47
48typedef enum {
49 CLO_PIPE,
50 CLO_COLUMNS,
51 CLO_SLOPEOUTPUT,
52 CLO_ZEROESOF,
53 CLO_OFFSET,
54 CLO_MAJOR_ORDER,
55 N_OPTIONS
56} option_type;
57
58char *option[N_OPTIONS] =
59 {
60 "pipe",
61 "columns",
62 "slopeoutput",
63 "zeroesof",
64 "offset",
65 "majorOrder",
66 };
67
68static char *USAGE =
69 "sddszerofind [<inputfile>] [<outputfile>] [-pipe=[input][,output]]\n"
70 "-zeroesOf=<columnName> [-columns=<columnNames>] [-offset=<value>] "
71 "[-slopeOutput] [-majorOrder=row|column]\n\n"
72 "Finds values of columns of data at interpolated zero positions in another\n"
73 "column.\n\n"
74 "-zeroesOf Specifies the column for which to find zeroes.\n"
75 "-offset Specifies a value to add to the values of the -zeroesOf column\n"
76 " prior to finding the zeroes. -offset=1 will find places where\n"
77 " the original values are -1.\n"
78 "-columns Specifies the columns to interpolate at the zero positions.\n"
79 " Default is all numerical columns in the file.\n"
80 "-majorOrder Specify output file in row or column order.\n"
81 "-slopeOutput Provide output of the slope of each -column column at the zero\n"
82 " position.\n\n"
83 "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
84
85#define FL_SLOPEOUTPUT 0x00001UL
86
87long resolve_column_names(SDDS_DATASET *SDDSin, char *depen_quantity, char ***indep_quantity, int32_t *indep_quantities);
88
89int main(int argc, char **argv) {
90 SDDS_DATASET in_set, out_set;
91 SCANNED_ARG *s_arg;
92 char *input = NULL, *output = NULL, *zero_name = NULL, **column_name = NULL;
93 long i_arg, page_returned;
94 int64_t rows, zrow;
95 int32_t column_names = 0;
96 double **indep_data, *depen_data, **slope_data, slope, offset = 0;
97 unsigned long pipe_flags = 0, flags = 0, major_order_flag;
98 char s[SDDS_MAXLINE];
99 short column_major_order = -1;
100
102 argc = scanargs(&s_arg, argc, argv);
103 if (argc < 2 || argc > (2 + N_OPTIONS)) {
104 bomb(NULL, USAGE);
105 }
106
107 for (i_arg = 1; i_arg < argc; i_arg++) {
108 if (s_arg[i_arg].arg_type == OPTION) {
109 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
110 case CLO_MAJOR_ORDER:
111 major_order_flag = 0;
112 s_arg[i_arg].n_items--;
113 if (s_arg[i_arg].n_items > 0 &&
114 (!scanItemList(&major_order_flag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
115 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
116 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL))) {
117 SDDS_Bomb("invalid -majorOrder syntax/values");
118 }
119 column_major_order = (major_order_flag & SDDS_COLUMN_MAJOR_ORDER) ? 1 : 0;
120 break;
121 case CLO_PIPE:
122 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipe_flags)) {
123 SDDS_Bomb("invalid -pipe syntax");
124 }
125 break;
126 case CLO_ZEROESOF:
127 if (s_arg[i_arg].n_items != 2) {
128 SDDS_Bomb("invalid -zeroesOf syntax");
129 }
130 zero_name = s_arg[i_arg].list[1];
131 break;
132 case CLO_COLUMNS:
133 if (s_arg[i_arg].n_items < 2) {
134 SDDS_Bomb("invalid -columns syntax");
135 }
136 column_name = tmalloc(sizeof(*column_name) * (column_names = s_arg[i_arg].n_items - 1));
137 for (int i = 0; i < column_names; i++) {
138 column_name[i] = s_arg[i_arg].list[i + 1];
139 }
140 break;
141 case CLO_SLOPEOUTPUT:
142 flags |= FL_SLOPEOUTPUT;
143 break;
144 case CLO_OFFSET:
145 if (s_arg[i_arg].n_items != 2 || sscanf(s_arg[i_arg].list[1], "%le", &offset) != 1) {
146 SDDS_Bomb("invalid -offset syntax");
147 }
148 break;
149 default:
150 fprintf(stderr, "Error (%s): unknown/ambiguous option: %s\n", argv[0], s_arg[i_arg].list[0]);
151 exit(1);
152 }
153 } else {
154 if (input == NULL) {
155 input = s_arg[i_arg].list[0];
156 } else if (output == NULL) {
157 output = s_arg[i_arg].list[0];
158 } else {
159 SDDS_Bomb("too many filenames");
160 }
161 }
162 }
163
164 processFilenames("sddszerofind", &input, &output, pipe_flags, 0, NULL);
165
166 if (!zero_name) {
167 SDDS_Bomb("-zeroesOf option must be given");
168 }
169
170 if (!SDDS_InitializeInput(&in_set, input)) {
171 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
172 }
173
174 if (!resolve_column_names(&in_set, zero_name, &column_name, &column_names) ||
175 !SDDS_InitializeOutput(&out_set, SDDS_BINARY, 0, NULL, "sddszerofind output", output) ||
176 !SDDS_TransferColumnDefinition(&out_set, &in_set, zero_name, NULL)) {
177 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
178 }
179
180 out_set.layout.data_mode.column_major = (column_major_order != -1) ? column_major_order : in_set.layout.data_mode.column_major;
181
182 for (int i = 0; i < column_names; i++) {
183 snprintf(s, SDDS_MAXLINE, "%sSlope", column_name[i]);
184 if (!SDDS_TransferColumnDefinition(&out_set, &in_set, column_name[i], NULL) ||
185 (flags & FL_SLOPEOUTPUT && !SDDS_TransferColumnDefinition(&out_set, &in_set, column_name[i], s))) {
186 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
187 }
188 }
189
190 if (!SDDS_WriteLayout(&out_set)) {
191 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
192 }
193
194 indep_data = tmalloc(sizeof(*indep_data) * column_names);
195 slope_data = tmalloc(sizeof(*slope_data) * column_names);
196
197 while ((page_returned = SDDS_ReadPage(&in_set)) > 0) {
198 if (!SDDS_StartPage(&out_set, 0)) {
199 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
200 }
201
202 if ((rows = SDDS_CountRowsOfInterest(&in_set)) > 1) {
203 depen_data = SDDS_GetColumnInDoubles(&in_set, zero_name);
204 if (!depen_data) {
205 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
206 }
207
208 for (int i = 0; i < column_names; i++) {
209 indep_data[i] = SDDS_GetColumnInDoubles(&in_set, column_name[i]);
210 if (!indep_data[i]) {
211 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
212 }
213
214 if (flags & FL_SLOPEOUTPUT) {
215 slope_data[i] = tmalloc(sizeof(**slope_data) * rows);
216 }
217 }
218
219 if (offset) {
220 for (int row = 0; row < rows; row++) {
221 depen_data[row] += offset;
222 }
223 }
224
225 zrow = 0;
226 for (int row = 0; row < rows - 1; row++) {
227 if ((depen_data[row] <= 0 && depen_data[row + 1] >= 0) ||
228 (depen_data[row] >= 0 && depen_data[row + 1] <= 0)) {
229 for (int i = 0; i < column_names; i++) {
230 if (indep_data[i][row] == indep_data[i][row + 1]) {
231 if (flags & FL_SLOPEOUTPUT) {
232 slope_data[i][zrow] = DBL_MAX;
233 }
234 indep_data[i][zrow] = indep_data[i][row];
235 } else {
236 slope = (depen_data[row + 1] - depen_data[row]) / (indep_data[i][row + 1] - indep_data[i][row]);
237 if (flags & FL_SLOPEOUTPUT) {
238 slope_data[i][zrow] = slope;
239 }
240 indep_data[i][zrow] = (slope) ? (indep_data[i][row] - depen_data[row] / slope) : ((indep_data[i][row] + indep_data[i][row + 1]) / 2);
241 }
242 }
243 depen_data[zrow] = -offset;
244 zrow++;
245 }
246 }
247
248 if (zrow) {
249 if (!SDDS_LengthenTable(&out_set, zrow) ||
250 !SDDS_SetColumnFromDoubles(&out_set, SDDS_SET_BY_NAME, depen_data, zrow, zero_name)) {
251 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
252 }
253
254 for (int i = 0; i < column_names; i++) {
255 snprintf(s, SDDS_MAXLINE, "%sSlope", column_name[i]);
256 if (!SDDS_SetColumnFromDoubles(&out_set, SDDS_SET_BY_NAME, indep_data[i], zrow, column_name[i]) ||
257 (flags & FL_SLOPEOUTPUT && !SDDS_SetColumnFromDoubles(&out_set, SDDS_SET_BY_NAME, slope_data[i], zrow, s))) {
258 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
259 }
260 }
261 }
262
263 free(depen_data);
264 for (int i = 0; i < column_names; i++) {
265 free(indep_data[i]);
266 }
267 if (flags & FL_SLOPEOUTPUT) {
268 for (int i = 0; i < column_names; i++) {
269 free(slope_data[i]);
270 }
271 }
272 }
273
274 if (!SDDS_WritePage(&out_set)) {
275 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
276 }
277 }
278
279 if (!SDDS_Terminate(&in_set) || !SDDS_Terminate(&out_set)) {
280 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
281 exit(1);
282 }
283
284 return 0;
285}
286
287long resolve_column_names(SDDS_DATASET *SDDSin, char *depen_quantity, char ***indep_quantity, int32_t *indep_quantities) {
288 long index;
289 char s[SDDS_MAXLINE];
290
291 index = SDDS_GetColumnIndex(SDDSin, depen_quantity);
292 if (index < 0 || !SDDS_NUMERIC_TYPE(SDDS_GetColumnType(SDDSin, index))) {
293 snprintf(s, SDDS_MAXLINE, "column %s is non-existent or non-numeric", depen_quantity);
294 SDDS_SetError(s);
295 return 0;
296 }
297
298 if (*indep_quantities) {
299 SDDS_SetColumnFlags(SDDSin, 0);
300 for (long i = 0; i < *indep_quantities; i++) {
301 if (!SDDS_SetColumnsOfInterest(SDDSin, SDDS_MATCH_STRING, (*indep_quantity)[i], SDDS_OR)) {
302 return 0;
303 }
304 }
305 } else {
306 SDDS_SetColumnFlags(SDDSin, 1);
307 if (!SDDS_SetColumnsOfInterest(SDDSin, SDDS_MATCH_STRING, depen_quantity, SDDS_NEGATE_MATCH | SDDS_AND)) {
308 return 0;
309 }
310 *indep_quantity = SDDS_GetColumnNames(SDDSin, indep_quantities);
311 if (!(*indep_quantity) || *indep_quantities == 0) {
312 SDDS_SetError("no independent quantities found");
313 return 0;
314 }
315 for (long i = 0; i < *indep_quantities; i++) {
316 index = SDDS_GetColumnIndex(SDDSin, (*indep_quantity)[i]);
317 if (!SDDS_NUMERIC_TYPE(SDDS_GetColumnType(SDDSin, index)) &&
318 !SDDS_AssertColumnFlags(SDDSin, SDDS_INDEX_LIMITS, index, index, 0)) {
319 return 0;
320 }
321 }
322 }
323
324 free(*indep_quantity);
325 *indep_quantity = SDDS_GetColumnNames(SDDSin, indep_quantities);
326 if (!(*indep_quantity) || *indep_quantities == 0) {
327 SDDS_SetError("no independent quantities found");
328 return 0;
329 }
330 return 1;
331}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_LengthenTable(SDDS_DATASET *SDDS_dataset, int64_t n_additional_rows)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_SetColumnFromDoubles(SDDS_DATASET *SDDS_dataset, int32_t mode, double *data, int64_t rows,...)
Sets the values for a single data column using double-precision floating-point numbers.
int32_t SDDS_AssertColumnFlags(SDDS_DATASET *SDDS_dataset, uint32_t mode,...)
Sets acceptance flags for columns based on specified criteria.
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
int32_t SDDS_SetColumnsOfInterest(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
Sets the acceptance flags for columns based on specified naming criteria.
int32_t SDDS_SetColumnFlags(SDDS_DATASET *SDDS_dataset, int32_t column_flag_value)
Sets the acceptance flags for all columns in the current data table of a data set.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_InitializeOutput(SDDS_DATASET *SDDS_dataset, int32_t data_mode, int32_t lines_per_row, const char *description, const char *contents, const char *filename)
Initializes the SDDS output dataset.
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.
int32_t SDDS_TransferColumnDefinition(SDDS_DATASET *target, SDDS_DATASET *source, char *name, char *newName)
Transfers a column definition from a source dataset to a target dataset.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:379
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
char ** SDDS_GetColumnNames(SDDS_DATASET *SDDS_dataset, int32_t *number)
Retrieves the names of all columns in the SDDS dataset.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
int32_t SDDS_GetColumnType(SDDS_DATASET *SDDS_dataset, int32_t index)
Retrieves the data type of a column in the SDDS dataset by its index.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
#define SDDS_NUMERIC_TYPE(type)
Checks if the given type identifier corresponds to any numeric type.
Definition SDDStypes.h:138
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
Definition array.c:59
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
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)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
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.