SDDSlib
Loading...
Searching...
No Matches
sddsremoveoffsets.c
Go to the documentation of this file.
1/**
2 * @file sddsremoveoffsets.c
3 * @brief A program to remove offsets from BPM waveform data in SDDS files.
4 *
5 * This program processes SDDS files to remove offsets in specified data columns, ensuring the resulting
6 * data has a zero average. Supports various options for output format, column selection, and commutation modes.
7 *
8 * ### Features:
9 * - Removes offsets based on user-specified data columns.
10 * - Provides options for pipe input/output.
11 * - Handles commutation modes for advanced offset adjustments.
12 * - Verbose mode for detailed output.
13 *
14 * ### Usage:
15 * ```
16 * sddsremoveoffsets <input-file> <output-file> [options]
17 * ```
18 * Options:
19 * - `-columns=<name>`: Specify data columns to adjust.
20 * - `-verbose`: Enable verbose output.
21 * - `-pipe=[input],[output]`: Use pipes for input/output.
22 * - `-majorOrder=row|column`: Specify output major order.
23 * - `-commutationMode=<string>`: Commutation mode (`a`, `b`, `ab1`, `ab2`).
24 * - `-fhead=<value>`: Fraction of head rows for offset calculation.
25 * - `-removeCommutationOffsetOnly`: Remove only commutation offset.
26 *
27 * @copyright
28 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
29 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
30 *
31 * @license
32 * This file is distributed under the terms of the Software License Agreement
33 * found in the file LICENSE included with this distribution.
34 *
35 * @author L. Emery, Jialun Luo, R. Soliday
36 */
37
38#include "mdb.h"
39#include "scan.h"
40#include "match_string.h"
41#include "SDDS.h"
42
43typedef enum {
44 CLO_COLUMNS,
45 CLO_VERBOSE,
46 CLO_PIPE,
47 CLO_MAJOR_ORDER,
48 CLO_COMMUTATION_MODE,
49 CLO_FHEAD,
50 CLO_REMOVE_COMMUTATION_OFFSET_ONLY,
51 N_OPTIONS
52} option_type;
53
54char *commandline_option[N_OPTIONS] = {
55 "columns",
56 "verbose",
57 "pipe",
58 "majorOrder",
59 "commutationMode",
60 "fhead",
61 "removeCommutationOffsetOnly",
62};
63
64static char *usage =
65 "Usage: sddsremoveoffsets <input-file> <output-file> [options]\n\n"
66 "Options:\n"
67 " -columns=<name> Specify data columns to adjust\n"
68 " -verbose Enable verbose output\n"
69 " -pipe=[input],[output] Use pipes for input/output\n"
70 " -majorOrder=row|column Specify output major order\n"
71 " -commutationMode=<string> Commutation mode (a, b, ab1, ab2)\n"
72 " -fhead=<value> Fraction of head rows for offset calculation\n"
73 " -removeCommutationOffsetOnly Remove only commutation offset\n\n"
74 "Description:\n"
75 " Removes offset from BPM waveform data. Adjusts data such that the resulting file has a zero average.\n"
76 " Supports commutation modes for specific offset handling strategies.\n"
77 "Program by Louis Emery and Jialun Luo, ANL (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
78
79static long commutation_modes = 4;
80static char *commutation_mode_list[4] = {"a", "b", "ab1", "ab2"};
81
82static long pattern_length = 4;
83
84long resolve_column_names(SDDS_DATASET *sdds_in, char ***column, int32_t *columns);
85
86int main(int argc, char **argv) {
87 SCANNED_ARG *s_arg;
88 SDDS_DATASET sdds_in, sdds_out;
89 unsigned long major_order_flag;
90 char *input = NULL, *output = NULL;
91 int64_t j, rows;
92 int32_t columns = 0;
93 char **input_column = NULL, **output_column = NULL;
94
95 long i, i_arg;
96 long verbose = 0;
97 long commutation_mode = 0;
98 long remove_commutation_offset_only = 0;
99 unsigned long pipe_flags = 0;
100 long tmpfile_used = 0, no_warnings = 0;
101 short column_major_order = -1;
102 double *data, offset1 = 0, offset2 = 0, ave_offset = 0;
103 double fhead = 1;
104
106 argc = scanargs(&s_arg, argc, argv);
107 if (argc == 1)
108 bomb(NULL, usage);
109
110 for (i_arg = 1; i_arg < argc; i_arg++) {
111 if (s_arg[i_arg].arg_type == OPTION) {
112 switch (match_string(s_arg[i_arg].list[0], commandline_option, N_OPTIONS, UNIQUE_MATCH)) {
113 case CLO_MAJOR_ORDER:
114 major_order_flag = 0;
115 s_arg[i_arg].n_items--;
116 if (s_arg[i_arg].n_items > 0 && (!scanItemList(&major_order_flag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0, "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER, "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
117 SDDS_Bomb("invalid -majorOrder syntax/values");
118 if (major_order_flag & SDDS_COLUMN_MAJOR_ORDER)
119 column_major_order = 1;
120 else if (major_order_flag & SDDS_ROW_MAJOR_ORDER)
121 column_major_order = 0;
122 break;
123 case CLO_COMMUTATION_MODE:
124 if (s_arg[i_arg].n_items != 2)
125 bomb("invalid -commutationMode syntax", NULL);
126 if ((commutation_mode = match_string(str_tolower(s_arg[i_arg].list[1]), commutation_mode_list, commutation_modes, EXACT_MATCH)) < 0)
127 SDDS_Bomb("invalid commutationMode given!");
128 break;
129 case CLO_VERBOSE:
130 verbose = 1;
131 break;
132 case CLO_REMOVE_COMMUTATION_OFFSET_ONLY:
133 remove_commutation_offset_only = 1;
134 break;
135 case CLO_FHEAD:
136 if (s_arg[i_arg].n_items != 2)
137 bomb("invalid -fhead syntax", NULL);
138 if (sscanf(s_arg[i_arg].list[1], "%lf", &fhead) != 1 || fhead <= 0 || fhead > 1)
139 fprintf(stderr, "Error: invalid -fhead syntax\n");
140 break;
141 case CLO_PIPE:
142 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipe_flags))
143 SDDS_Bomb("invalid -pipe syntax");
144 break;
145 case CLO_COLUMNS:
146 if (columns)
147 SDDS_Bomb("only one -columns option may be given");
148 if (s_arg[i_arg].n_items < 2)
149 SDDS_Bomb("invalid -columns syntax");
150 input_column = tmalloc(sizeof(*input_column) * (columns = s_arg[i_arg].n_items - 1));
151 for (i = 0; i < columns; i++)
152 input_column[i] = s_arg[i_arg].list[i + 1];
153 break;
154 default:
155 SDDS_Bomb("unrecognized option given");
156 }
157 } else {
158 if (!input)
159 input = s_arg[i_arg].list[0];
160 else if (!output)
161 output = s_arg[i_arg].list[0];
162 else
163 SDDS_Bomb("too many filenames seen");
164 }
165 }
166
167 processFilenames("sddsremoveoffsets", &input, &output, pipe_flags, no_warnings, &tmpfile_used);
168
169 if (!columns)
170 SDDS_Bomb("supply the names of columns for offset removal with the -columns option");
171
172 if (!SDDS_InitializeInput(&sdds_in, input))
173 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
174
175 if (!resolve_column_names(&sdds_in, &input_column, &columns))
176 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
177 if (!columns)
178 SDDS_Bomb("no columns selected for offset removal");
179
180 if (!SDDS_InitializeCopy(&sdds_out, &sdds_in, output, "w"))
181 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
182
183 output_column = tmalloc(sizeof(*output_column) * columns);
184 for (i = 0; i < columns; i++)
185 output_column[i] = input_column[i];
186
187 if (!SDDS_InitializeOutput(&sdds_out, SDDS_BINARY, 1, "Remove offset from BPM waveforms", "Modified data", output) ||
188 !SDDS_InitializeCopy(&sdds_out, &sdds_in, output, "w"))
189 SDDS_PrintErrors(stdout, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
190 if (column_major_order != -1)
191 sdds_out.layout.data_mode.column_major = column_major_order;
192 else
193 sdds_out.layout.data_mode.column_major = sdds_in.layout.data_mode.column_major;
194 if (!SDDS_WriteLayout(&sdds_out))
195 SDDS_PrintErrors(stdout, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
196
197 while (SDDS_ReadPage(&sdds_in) > 0) {
198 if (!SDDS_CopyPage(&sdds_out, &sdds_in))
199 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
200 if ((rows = SDDS_CountRowsOfInterest(&sdds_in))) {
201 for (i = 0; i < columns; i++) {
202 if (!(data = SDDS_GetColumnInDoubles(&sdds_in, input_column[i])))
203 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
204
205 long repeat_offset = (data[0] == data[1]) ? 0 : 1;
206
207 double sum1 = 0, sum2 = 0;
208 unsigned long count1 = 0, count2 = 0;
209 unsigned long half_pattern_length = pattern_length / 2;
210 for (j = 0; j < fhead * rows; j++) {
211 if ((j - repeat_offset) % pattern_length < half_pattern_length) {
212 sum1 += data[j];
213 count1++;
214 } else {
215 sum2 += data[j];
216 count2++;
217 }
218 }
219 offset1 = sum1 / count1;
220 offset2 = sum2 / count2;
221 if (!remove_commutation_offset_only) {
222 for (j = 0; j < rows; j++) {
223 if ((j - repeat_offset) % pattern_length < half_pattern_length)
224 data[j] -= offset1;
225 else
226 data[j] -= offset2;
227 }
228 } else {
229 ave_offset = (offset1 + offset2) / 2.0;
230 for (j = 0; j < rows; j++) {
231 if ((j - repeat_offset) % pattern_length < half_pattern_length)
232 data[j] = data[j] - offset1 + ave_offset;
233 else
234 data[j] = data[j] - offset2 + ave_offset;
235 }
236 }
237
238 if (verbose) {
239 printf("offset1 = %f \t offset2 = %f\n", offset1, offset2);
240 double new_sum = 0;
241 for (j = 0; j < rows; j++) {
242 new_sum += data[j];
243 }
244 double new_mean = new_sum / rows;
245 printf("New average: %f\n", new_mean);
246 }
247
248 if (!SDDS_SetColumnFromDoubles(&sdds_out, SDDS_SET_BY_NAME, data, rows, output_column[i]))
249 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
250 free(data);
251 }
252 }
253 if (!SDDS_WritePage(&sdds_out))
254 SDDS_PrintErrors(stdout, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
255 }
256
257 if (!SDDS_Terminate(&sdds_in) || !SDDS_Terminate(&sdds_out))
258 SDDS_PrintErrors(stdout, SDDS_EXIT_PrintErrors | SDDS_VERBOSE_PrintErrors);
259
260 if (tmpfile_used && !replaceFileAndBackUp(input, output))
261 exit(EXIT_FAILURE);
262
263 return 0;
264}
265
266long resolve_column_names(SDDS_DATASET *sdds_in, char ***column, int32_t *columns) {
267 long i;
268
269 SDDS_SetColumnFlags(sdds_in, 0);
270 for (i = 0; i < *columns; i++) {
271 if (!SDDS_SetColumnsOfInterest(sdds_in, SDDS_MATCH_STRING, (*column)[i], SDDS_OR))
272 return 0;
273 }
274 free(*column);
275 if (!(*column = SDDS_GetColumnNames(sdds_in, columns)) || *columns == 0) {
276 SDDS_SetError("no columns found");
277 return 0;
278 }
279 return 1;
280}
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)
Definition SDDS_copy.c:40
int32_t SDDS_CopyPage(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:578
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.
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.
void SDDS_SetError(char *error_text)
Records an error message in the SDDS error stack.
Definition SDDS_utils.c:379
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
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
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.
long replaceFileAndBackUp(char *file, char *replacement)
Replaces a file with a replacement file and creates a backup of the original.
Definition replacefile.c:75
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.
char * str_tolower(char *s)
Convert a string to lower case.
Definition str_tolower.c:27