99 {
100 int iArg;
101 char **inputColumn, **outputColumn, **difColumn;
102 int32_t columns;
103 long despike, median, smooth;
104 int32_t despikeNeighbors, despikePasses, despikeAverageOf;
105 char *input, *output;
106 long i, readCode;
107 int64_t j, rows;
108 int32_t smoothPoints, smoothPasses;
109 long noWarnings, medianWindowSize = 3;
110 unsigned long pipeFlags, flags, despikeFlags, majorOrderFlag, dummyFlags;
111 SCANNED_ARG *scanned;
113 double *data, despikeThreshold;
114 int32_t SGLeft, SGRight, SGOrder, SGDerivOrder;
115 short columnMajorOrder = -1;
116 double gaussianSigma = 0;
117
119 argc =
scanargs(&scanned, argc, argv);
120 if (argc < 3 || argc > (3 + N_OPTIONS))
122
123 output = input = NULL;
124 inputColumn = outputColumn = NULL;
125 columns = 0;
126 pipeFlags = 0;
127 smoothPoints = 3;
128 smoothPasses = 1;
129 flags = 0;
130 despike = 0;
131 median = 0;
132 smooth = 0;
133 noWarnings = 0;
134 SGOrder = -1;
135 SGDerivOrder = 0;
136
137 for (iArg = 1; iArg < argc; iArg++) {
138 if (scanned[iArg].arg_type == OPTION) {
139
140 switch (
match_string(scanned[iArg].list[0], option, N_OPTIONS, 0)) {
141 case CLO_PASSES:
142 smooth = 1;
143 if (scanned[iArg].n_items != 2 ||
144 sscanf(scanned[iArg].list[1], "%" SCNd32, &smoothPasses) != 1 ||
145 smoothPasses < 0)
146 SDDS_Bomb(
"invalid -passes syntax/value");
147 break;
148 case CLO_GAUSSIAN:
149 gaussianSigma = 0;
150 if (scanned[iArg].n_items != 2 ||
151 sscanf(scanned[iArg].list[1], "%lf", &gaussianSigma) != 1 ||
152 gaussianSigma <= 0)
153 SDDS_Bomb(
"invalid -gaussian syntax/value");
154 break;
155 case CLO_POINTS:
156 if (scanned[iArg].n_items != 2 ||
157 sscanf(scanned[iArg].list[1], "%" SCNd32, &smoothPoints) != 1 ||
158 smoothPoints < 1 ||
159 smoothPoints % 2 == 0)
160 SDDS_Bomb(
"invalid -points syntax/value");
161 break;
162 case CLO_COLUMNS:
163 if (scanned[iArg].n_items < 2)
165 inputColumn =
tmalloc(
sizeof(*inputColumn) * (columns = scanned[iArg].n_items - 1));
166 for (i = 0; i < columns; i++)
167 inputColumn[i] = scanned[iArg].list[i + 1];
168 break;
169 case CLO_PIPE:
170 if (!
processPipeOption(scanned[iArg].list + 1, scanned[iArg].n_items - 1, &pipeFlags))
172 break;
173 case CLO_NEWCOLUMNS:
174 flags |= FL_NEWCOLUMNS;
175 break;
176 case CLO_DIFFERENCECOLUMNS:
177 flags |= FL_DIFCOLUMNS;
178 break;
179 case CLO_DESPIKE:
180 scanned[iArg].n_items--;
181 despikeNeighbors = 4;
182 despikePasses = 1;
183 despikeThreshold = 0;
184 despikeAverageOf = 2;
185 if (scanned[iArg].n_items > 0 &&
186 (!
scanItemList(&despikeFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
187 "neighbors",
SDDS_LONG, &despikeNeighbors, 1, 0,
188 "passes",
SDDS_LONG, &despikePasses, 1, 0,
189 "averageof",
SDDS_LONG, &despikeAverageOf, 1, DESPIKE_AVERAGEOF,
190 "threshold",
SDDS_DOUBLE, &despikeThreshold, 1, 0, NULL) ||
191 despikeNeighbors < 2 || despikePasses < 1 || despikeAverageOf < 2 || despikeThreshold < 0)) {
192 fprintf(stderr, "sddssmooth: Invalid -despike syntax/values: neighbors=%" PRId32 ", passes=%" PRId32 ", averageOf=%" PRId32 ", threshold=%e\n", despikeNeighbors, despikePasses, despikeAverageOf, despikeThreshold);
193 exit(EXIT_FAILURE);
194 }
195 if (!(despikeFlags & DESPIKE_AVERAGEOF))
196 despikeAverageOf = despikeNeighbors;
197 if (despikeAverageOf > despikeNeighbors)
198 SDDS_Bomb(
"invalid -despike syntax/values: averageOf>neighbors");
199 despike = 1;
200 break;
201 case CLO_MEDIAN_FILTER:
202 scanned[iArg].n_items--;
203 medianWindowSize = 0;
204 if (scanned[iArg].n_items > 0 &&
205 (!
scanItemList(&dummyFlags, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
206 "windowSize",
SDDS_LONG, &medianWindowSize, 1, 0, NULL) ||
207 medianWindowSize <= 0)) {
208 fprintf(stderr, "sddssmooth: Invalid -medianFilter syntax/values: windowSize=%ld\n", medianWindowSize);
209 exit(EXIT_FAILURE);
210 }
211 median = 1;
212 break;
213 case CLO_NOWARNINGS:
214 noWarnings = 1;
215 break;
216 case CLO_SAVITZKYGOLAY:
217 if ((scanned[iArg].n_items != 4 && scanned[iArg].n_items != 5) ||
218 sscanf(scanned[iArg].list[1], "%" SCNd32, &SGLeft) != 1 ||
219 sscanf(scanned[iArg].list[2], "%" SCNd32, &SGRight) != 1 ||
220 sscanf(scanned[iArg].list[3], "%" SCNd32, &SGOrder) != 1 ||
221 (scanned[iArg].n_items == 5 && sscanf(scanned[iArg].list[4], "%" SCNd32, &SGDerivOrder) != 1) ||
222 SGLeft < 0 ||
223 SGRight < 0 ||
224 (SGLeft + SGRight) < SGOrder ||
225 SGOrder < 0 ||
226 SGDerivOrder < 0)
227 SDDS_Bomb(
"invalid -SavitzkyGolay syntax/values");
228 break;
229 case CLO_MAJOR_ORDER:
230 majorOrderFlag = 0;
231 scanned[iArg].n_items--;
232 if (scanned[iArg].n_items > 0 &&
233 (!
scanItemList(&majorOrderFlag, scanned[iArg].list + 1, &scanned[iArg].n_items, 0,
234 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
235 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
236 SDDS_Bomb(
"invalid -majorOrder syntax/values");
237 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
238 columnMajorOrder = 1;
239 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
240 columnMajorOrder = 0;
241 break;
242 default:
243 fprintf(stderr, "error: unknown/ambiguous option: %s\n", scanned[iArg].list[0]);
244 exit(EXIT_FAILURE);
245 break;
246 }
247 } else {
248 if (!input)
249 input = scanned[iArg].list[0];
250 else if (!output)
251 output = scanned[iArg].list[0];
252 else
254 }
255 }
256
258
259 if (!median)
260 smooth = 1;
261
262 if (!despike && !smoothPasses && !median && !noWarnings)
263 fprintf(stderr, "warning: smoothing parameters won't result in any change in data (sddssmooth)\n");
264
265 if (!columns)
266 SDDS_Bomb(
"supply the names of columns to smooth with the -columns option");
267
270
271 if (!resolveColumnNames(&SDDSin, &inputColumn, &columns))
273 if (!columns)
274 SDDS_Bomb(
"no columns selected for smoothing");
275
278
279 outputColumn =
tmalloc(
sizeof(*outputColumn) * columns);
280
281 if (flags & FL_NEWCOLUMNS) {
282 for (i = 0; i < columns; i++) {
283 if (SGDerivOrder <= 0) {
284 outputColumn[i] =
tmalloc(
sizeof(**outputColumn) * (strlen(inputColumn[i]) + 1 + strlen(
"Smoothed")));
285 sprintf(outputColumn[i], "%sSmoothed", inputColumn[i]);
286 } else {
287 outputColumn[i] =
tmalloc(
sizeof(**outputColumn) * (strlen(inputColumn[i]) + 1 + strlen(
"SmoothedDeriv")) + 5);
288 sprintf(outputColumn[i], "%sSmoothedDeriv%" PRId32, inputColumn[i], SGDerivOrder);
289 }
292 }
293 } else
294 for (i = 0; i < columns; i++)
295 outputColumn[i] = inputColumn[i];
296
297 difColumn = NULL;
298 if (flags & FL_DIFCOLUMNS) {
299 difColumn =
tmalloc(
sizeof(*difColumn) * columns);
300 for (i = 0; i < columns; i++) {
301 difColumn[i] =
tmalloc(
sizeof(**difColumn) * (strlen(inputColumn[i]) + 1 + strlen(
"Unsmooth")));
302 sprintf(difColumn[i], "%sUnsmooth", inputColumn[i]);
305 }
306 }
307
313 if (columnMajorOrder != -1)
314 SDDSout.layout.data_mode.column_major = columnMajorOrder;
315 else
316 SDDSout.layout.data_mode.column_major = SDDSin.layout.data_mode.column_major;
317
320
325 for (i = 0; i < columns; i++) {
328 if (despike)
329 despikeData(data, rows, despikeNeighbors, despikePasses, despikeAverageOf, despikeThreshold, 0);
330 if (gaussianSigma > 0)
331 gaussianConvolution(data, rows, gaussianSigma);
332 if (median) {
333 double *mData = NULL;
334 mData = malloc(sizeof(*mData) * rows);
336 memcpy(data, mData, sizeof(*mData) * rows);
337 free(mData);
338 }
339 if (SGOrder >= 0) {
340 long pass = 0;
341 for (pass = 0; pass < smoothPasses; pass++)
343 } else if (smooth && smoothPasses)
344 smoothData(data, rows, smoothPoints, smoothPasses);
345
348 if (flags & FL_DIFCOLUMNS) {
349 double *data0;
352 for (j = 0; j < rows; j++)
353 data0[j] -= data[j];
356 free(data0);
357 }
358 free(data);
359 }
360 }
363 }
366 exit(EXIT_FAILURE);
367 }
368 return EXIT_SUCCESS;
369}
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_DefineParameter1(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, void *fixed_value)
Defines a data parameter with a fixed numerical value.
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.
int32_t SDDS_GetParameterIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named parameter in the SDDS dataset.
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.
#define SDDS_LONG
Identifier for the signed 32-bit integer data type.
#define SDDS_DOUBLE
Identifier for the double data type.
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 SavitzkyGolaySmooth(double *data, long rows, long order, long nLeft, long nRight, long derivativeOrder)
Applies Savitzky-Golay smoothing or differentiation to a data array.
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.
void smoothData(double *data, long rows, long smoothPoints, long smoothPasses)
Smooth a data array using a moving average.
long despikeData(double *data, long rows, long neighbors, long passes, long averageOf, double threshold, long countLimit)
Remove spikes from a data array by comparing each point to its neighbors.