108 {
109 SCANNED_ARG *s_arg;
111 unsigned long major_order_flag;
112 char *input = NULL, *output = NULL;
113 int64_t j, rows;
114 int32_t columns = 0;
115 char **input_column = NULL, **output_column = NULL;
116
117 long i, i_arg;
118 long verbose = 0;
119 long commutation_mode = 0;
120 long remove_commutation_offset_only = 0;
121 unsigned long pipe_flags = 0;
122 long tmpfile_used = 0, no_warnings = 0;
123 short column_major_order = -1;
124 double *data, offset1 = 0, offset2 = 0, ave_offset = 0;
125 double fhead = 1;
126
128 argc =
scanargs(&s_arg, argc, argv);
129 if (argc == 1)
131
132 for (i_arg = 1; i_arg < argc; i_arg++) {
133 if (s_arg[i_arg].arg_type == OPTION) {
134 switch (
match_string(s_arg[i_arg].list[0], commandline_option, N_OPTIONS, UNIQUE_MATCH)) {
135 case CLO_MAJOR_ORDER:
136 major_order_flag = 0;
137 s_arg[i_arg].n_items--;
138 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)))
139 SDDS_Bomb(
"invalid -majorOrder syntax/values");
140 if (major_order_flag & SDDS_COLUMN_MAJOR_ORDER)
141 column_major_order = 1;
142 else if (major_order_flag & SDDS_ROW_MAJOR_ORDER)
143 column_major_order = 0;
144 break;
145 case CLO_COMMUTATION_MODE:
146 if (s_arg[i_arg].n_items != 2)
147 bomb(
"invalid -commutationMode syntax", NULL);
148 if ((commutation_mode =
match_string(
str_tolower(s_arg[i_arg].list[1]), commutation_mode_list, commutation_modes, EXACT_MATCH)) < 0)
149 SDDS_Bomb(
"invalid commutationMode given!");
150 break;
151 case CLO_VERBOSE:
152 verbose = 1;
153 break;
154 case CLO_REMOVE_COMMUTATION_OFFSET_ONLY:
155 remove_commutation_offset_only = 1;
156 break;
157 case CLO_FHEAD:
158 if (s_arg[i_arg].n_items != 2)
159 bomb(
"invalid -fhead syntax", NULL);
160 if (sscanf(s_arg[i_arg].list[1], "%lf", &fhead) != 1 || fhead <= 0 || fhead > 1)
161 SDDS_Bomb(
"invalid -fhead syntax/value");
162 break;
163 case CLO_PIPE:
164 if (!
processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipe_flags))
166 break;
167 case CLO_COLUMNS:
168 if (columns)
169 SDDS_Bomb(
"only one -columns option may be given");
170 if (s_arg[i_arg].n_items < 2)
172 input_column =
tmalloc(
sizeof(*input_column) * (columns = s_arg[i_arg].n_items - 1));
173 for (i = 0; i < columns; i++)
174 input_column[i] = s_arg[i_arg].list[i + 1];
175 break;
176 default:
178 }
179 } else {
180 if (!input)
181 input = s_arg[i_arg].list[0];
182 else if (!output)
183 output = s_arg[i_arg].list[0];
184 else
186 }
187 }
188
189 processFilenames(
"sddsremoveoffsets", &input, &output, pipe_flags, no_warnings, &tmpfile_used);
190
191 if (!columns)
192 SDDS_Bomb(
"supply the names of columns for offset removal with the -columns option");
193
196
197 if (!resolve_column_names(&sdds_in, &input_column, &columns))
199 if (!columns)
200 SDDS_Bomb(
"no columns selected for offset removal");
201
202 output_column =
tmalloc(
sizeof(*output_column) * columns);
203 for (i = 0; i < columns; i++)
204 output_column[i] = input_column[i];
205
208 if (column_major_order != -1)
209 sdds_out.layout.data_mode.column_major = column_major_order;
210 else
211 sdds_out.layout.data_mode.column_major = sdds_in.layout.data_mode.column_major;
214
219 for (i = 0; i < columns; i++) {
222
223 long repeat_offset = rows > 1 && data[0] != data[1] ? 1 : 0;
224
225 double sum1 = 0, sum2 = 0;
226 unsigned long count1 = 0, count2 = 0;
227 unsigned long half_pattern_length = pattern_length / 2;
228 for (j = 0; j < fhead * rows; j++) {
229 if ((j - repeat_offset) % pattern_length < half_pattern_length) {
230 sum1 += data[j];
231 count1++;
232 } else {
233 sum2 += data[j];
234 count2++;
235 }
236 }
237 if (count1 < half_pattern_length || count2 < half_pattern_length) {
238 fprintf(stderr, "Error: page has too few head rows to determine both commutation offsets for column %s\n", input_column[i]);
239 free(data);
240 exit(EXIT_FAILURE);
241 }
242 offset1 = sum1 / count1;
243 offset2 = sum2 / count2;
244 if (!remove_commutation_offset_only) {
245 for (j = 0; j < rows; j++) {
246 if ((j - repeat_offset) % pattern_length < half_pattern_length)
247 data[j] -= offset1;
248 else
249 data[j] -= offset2;
250 }
251 } else {
252 ave_offset = (offset1 + offset2) / 2.0;
253 for (j = 0; j < rows; j++) {
254 if ((j - repeat_offset) % pattern_length < half_pattern_length)
255 data[j] = data[j] - offset1 + ave_offset;
256 else
257 data[j] = data[j] - offset2 + ave_offset;
258 }
259 }
260
261 if (verbose) {
262 printf("offset1 = %f \t offset2 = %f\n", offset1, offset2);
263 double new_sum = 0;
264 for (j = 0; j < rows; j++) {
265 new_sum += data[j];
266 }
267 double new_mean = new_sum / rows;
268 printf("New average: %f\n", new_mean);
269 }
270
273 free(data);
274 }
275 }
278 }
279
282
284 exit(EXIT_FAILURE);
285
286 return 0;
287}
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_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_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_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.
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
void * tmalloc(uint64_t size_of_block)
Allocates a memory block of the specified size with zero initialization.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
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.
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)
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.