/*************************************************************************\ * Copyright (c) 2002 The University of Chicago, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * This file is distributed subject to a Software License Agreement found * in the file LICENSE that is included with this distribution. \*************************************************************************/ /* program: sddsderiv * purpose: differentiate a data set * * Michael Borland, 1995 * based on mpl-format program deriv and sddsinteg $Log: sddsderiv.c,v $ Revision 1.19 2006/12/14 22:21:58 soliday Updated a bunch of programs because SDDS_SaveLayout is now called by SDDS_WriteLayout and it is no longer required to be called directly. Also the AutoCheckMode is turned off by default now so I removed calls to SDDS_SetAutoCheckMode that would attempt to turn it off. It is now up to the programmer to turn it on in new programs until debugging is completed and then remove the call to SDDS_SetAutoCheckMode. Revision 1.18 2005/11/07 21:48:10 soliday Updated to remove Linux compiler warnings. Revision 1.17 2005/11/04 22:46:13 soliday Updated code to be compiled by a 64 bit processor. Revision 1.16 2002/10/26 20:22:30 borland Fixed bug in preparation of symbols and column names when higher-order derivatives were requested. Revision 1.15 2002/09/24 14:11:03 soliday Changed the %y to %%y Revision 1.14 2002/08/14 17:12:43 soliday Added Open License Revision 1.13 2002/06/19 23:13:01 borland Fixed spelling of Savitzky-Golay. Revision 1.12 2002/01/16 17:35:23 soliday Added SDDS_Terminate and free functions. Revision 1.11 2001/01/10 19:35:35 soliday Standardized usage message. Revision 1.10 1999/06/18 18:47:54 borland Added optional use of Savitzky-Golay filters for doing derivatives. Revision 1.9 1999/05/25 19:08:02 soliday Removed compiler warning on linux. Revision 1.8 1999/04/22 13:30:25 borland Now does a better job of dealing with endpoints. Specifically, the x values for the endpoint derivatives are correct. Revision 1.7 1999/01/06 19:54:42 borland Fixed the version number in the usage message. Revision 1.6 1998/12/16 21:26:00 borland Brought up to date with new version of SDDS_TransferAllParameters. Now correctly transfers through parameters, but overwrites them if it needs to do so. Revision 1.5 1998/11/13 22:39:50 borland Now copies through parameters from the input to the output. * Revision 1.4 1996/02/14 01:05:18 borland * Changed over from scan_item_list() to scanItemList(). * * Revision 1.3 1995/09/06 14:56:20 saunders * First test release of SDDS1.5 * */ #include "mdb.h" #include "SDDS.h" #include "SDDSutils.h" #include "scan.h" #include static char *USAGE = "sddsderiv [] []\n\ [-pipe=[input][,output]]\n\ -differentiate=[,]...\n\ [-exclude=[,...]] -versus=\n\ [-interval=] [-SavitzkyGolay=,,[,]] \n\ [-mainTemplates==[,...]] \n\ [-errorTemplates==[,...]] \n\n\ The -templates may be \"name\", \"symbol\" or \"description\".\n\ The default main name, description, and symbol templates are \"%yNameDeriv\",\n\ \"Derivative w.r.t %xSymbol of %ySymbol\", and \"d[%ySymbol]/d[%xSymbol]\", respectively.\n\ The default error name, description, and symbol templates are \"%yNameDerivSigma\",\n\ \"Sigma of derivative w.r.t %xSymbol of %ySymbol\", and \"Sigma[d[%ySymbol]/d[%xSymbol]]\", respectively.\n\ Program by Michael Borland. (This is version 3, December 1998.)" ; #define CLO_DIFFERENTIATE 0 #define CLO_VERSUS 1 #define CLO_INTERVAL 2 #define CLO_MAINTEMPLATE 3 #define CLO_ERRORTEMPLATE 4 #define CLO_PIPE 5 #define CLO_EXCLUDE 6 #define CLO_SAVITZKYGOLAY 7 #define CLO_OPTIONS 8 static char *option[CLO_OPTIONS] = { "differentiate", "versus", "interval", "maintemplate", "errortemplate", "pipe", "exclude", "savitzkygolay", }; long checkErrorNames(char **yErrorName, long nDerivatives); void makeSubstitutions(char *buffer1, char *buffer2, char *template, char *nameRoot, char *symbolRoot, char *xName, char *xSymbol); char *changeInformation(SDDS_DATASET *SDDSout, char *name, char *nameRoot, char *symbolRoot, char *xName, char *xSymbol, char **template, char *newUnits); long setupOutputFile(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, char *output, char ***yOutputName, char ***yOutputErrorName, char ***yOutputUnits, char *xName, char *xErrorName, char **yName, char **yErrorName, long yNames, char **mainTemplate, char **errorTemplate, int32_t interval, long order); long findDerivIndices(long *i1, long *i2, long interval, long i, long rows); void takeDerivative(double *x, double *y, double *sy, long rows, double *deriv, double *derivSigma, double *derivPosition, long interval); void takeSGDerivative(double *x, double *y, long rows, double *deriv, double *derivPosition, long left, long right, long sgOrder, long derivOrder); int main(int argc, char **argv) { double *xData, *yData, *xError, *yError, *derivative, *derivativeError, *derivativePosition; char *input, *output, *xName, *xErrorName, **yName, **yErrorName, **yOutputName, **yOutputErrorName, *ptr; char **yOutputUnits, **yExcludeName; char *mainTemplate[3] = {NULL, NULL, NULL}; char *errorTemplate[3] = {NULL, NULL, NULL}; long i, iArg, yNames, yExcludeNames, rows; int32_t interval; SDDS_DATASET SDDSin, SDDSout; SCANNED_ARG *scanned; unsigned long flags, pipeFlags; long SGLeft, SGRight, SGOrder, SGDerivOrder, intervalGiven, yErrorsSeen; SDDS_RegisterProgramName(argv[0]); argc = scanargs(&scanned, argc, argv); if (argc==1) bomb(NULL, USAGE); input = output = xName = xErrorName = NULL; yName = yErrorName = yExcludeName = NULL; derivative = derivativeError = derivativePosition = yError = yData = xData = xError = NULL; yNames = yExcludeNames = 0; pipeFlags = 0; interval = 2; SGOrder = -1; SGDerivOrder = 1; intervalGiven = 0; yErrorsSeen = 0; for (iArg=1; iArg=0) SDDS_Bomb("-interval and -SavitzkyGolay options are incompatible"); if (SGOrder>=0 && (xErrorName || yErrorsSeen)) SDDS_Bomb("Savitzky-Golay method does not support errors in data"); processFilenames("sddsderiv", &input, &output, pipeFlags, 0, NULL); if (!yNames) SDDS_Bomb("-differentiate option must be given at least once"); if (!checkErrorNames(yErrorName, yNames)) SDDS_Bomb("either all -differentiate quantities must have errors, or none"); if (!SDDS_InitializeInput(&SDDSin, input)) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); if (!(ptr=SDDS_FindColumn(&SDDSin, FIND_NUMERIC_TYPE, xName, NULL))) { fprintf(stderr, "error: column %s doesn't exist\n", xName); exit(1); } free(xName); xName = ptr; if (xErrorName) { if (!(ptr=SDDS_FindColumn(&SDDSin, FIND_NUMERIC_TYPE, xErrorName, NULL))) { fprintf(stderr, "error: column %s doesn't exist\n", xErrorName); exit(1); } else { free(xErrorName); xErrorName = ptr; } } if (!(yNames=expandColumnPairNames(&SDDSin, &yName, &yErrorName, yNames, yExcludeName, yExcludeNames, FIND_NUMERIC_TYPE, 0))) { fprintf(stderr, "error: no quantities to differentiate found in file\n"); exit(1); } setupOutputFile(&SDDSout, &SDDSin, output, &yOutputName, &yOutputErrorName, &yOutputUnits, xName, xErrorName, yName, yErrorName, yNames, mainTemplate, errorTemplate, interval, SGOrder>=0?SGDerivOrder:1); while (SDDS_ReadPage(&SDDSin)>0) { if ((rows = SDDS_CountRowsOfInterest(&SDDSin))<2) SDDS_Bomb("Can't compute derivatives: too little data."); derivative = SDDS_Realloc(derivative, sizeof(*derivative)*rows); derivativeError = SDDS_Realloc(derivativeError, sizeof(*derivativeError)*rows); derivativePosition = SDDS_Realloc(derivativePosition, sizeof(*derivativePosition)*rows); if (!SDDS_StartPage(&SDDSout, rows) || !SDDS_CopyParameters(&SDDSout, &SDDSin)) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); xError = NULL; if (!(xData = SDDS_GetColumnInDoubles(&SDDSin, xName)) || (xErrorName && !(xError=SDDS_GetColumnInDoubles(&SDDSin, xErrorName)))) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); for (i=0; i=0) takeSGDerivative(xData, yData, rows, derivative, derivativePosition, SGLeft, SGRight, SGOrder, SGDerivOrder); else takeDerivative(xData, yData, yError, rows, derivative, derivativeError, derivativePosition, interval); if (!SDDS_SetColumnFromDoubles(&SDDSout, SDDS_BY_NAME, derivative, rows, yOutputName[i]) || (yOutputErrorName && yOutputErrorName[i] && !SDDS_SetColumnFromDoubles(&SDDSout, SDDS_BY_NAME, derivativeError, rows, yOutputErrorName[i]))) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); if (yData) free(yData); if (yError) free(yError); yData = yError = NULL; } if (!SDDS_SetColumnFromDoubles(&SDDSout, SDDS_BY_NAME, derivativePosition, rows, xName) || (xErrorName && !SDDS_SetColumnFromDoubles(&SDDSout, SDDS_BY_NAME, xError, rows, xErrorName))) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); if (!SDDS_WritePage(&SDDSout)) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); if (xData) free(xData); if (xError) free(xError); xData = xError = NULL; } if (!SDDS_Terminate(&SDDSin) || !SDDS_Terminate(&SDDSout)) { SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors); exit(1); } if (derivative) free(derivative); if (derivativeError) free(derivativeError); if (derivativePosition) free(derivativePosition); return(0); } void takeSGDerivative(double *x, double *y, long rows, double *deriv, double *derivPosition, long left, long right, long sgOrder, long derivOrder) { long i; double spacing; spacing = (x[rows-1]-x[0])/(rows-1); for (i=0; i=0) return 1; return 0; } if (*i1==*i2) { if (*i2=0) return 1; return 0; } long setupOutputFile(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, char *output, char ***yOutputName, char ***yOutputErrorName, char ***yOutputUnits, char *xName, char *xErrorName, char **yName, char **yErrorName, long yNames, char **mainTemplate0, char **errorTemplate0, int32_t interval, long order) { long i; char *xSymbol, *ySymbol; char *mainTemplate[3] = {"%yNameDeriv", "Derivative w.r.t. %xSymbol of %ySymbol", "d[%ySymbol]/d[%xSymbol]"}; char *errorTemplate[3] = {"%yNameDerivSigma", "Sigma of derivative w.r.t. %xSymbol of %ySymbol", "Sigma[d[%ySymbol]/d[%xSymbol]]"}; char buffer[1024]; for (i=0; i<3; i++) { if (!mainTemplate0[i]) { if (order!=1) { switch (i) { case 0: /* name */ sprintf(buffer, "%%yNameDeriv%ld", order); break; case 1: /* description */ sprintf(buffer, "Derivative %ld w.r.t. %%xSymbol of %%ySymbol", order); break; case 2: /* symbol */ sprintf(buffer, "d$a%ld$n[%%ySymbol]/d[%%xSymbol]$a%ld$n", order, order); break; } cp_str(&mainTemplate[i], buffer); } } else mainTemplate[i] = mainTemplate0[i]; if (errorTemplate0[i]) errorTemplate[i] = errorTemplate0[i]; } *yOutputName = tmalloc(sizeof(*yOutputName)*yNames); *yOutputErrorName = tmalloc(sizeof(*yOutputErrorName)*yNames); *yOutputUnits = tmalloc(sizeof(*yOutputUnits)*yNames); if (!SDDS_InitializeOutput(SDDSout, SDDS_BINARY, 0, NULL, "sddsderiv output", output) || SDDS_DefineParameter1(SDDSout, "derivInterval", NULL, NULL, NULL, NULL, SDDS_LONG, &interval)<0) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); if (!SDDS_TransferColumnDefinition(SDDSout, SDDSin, xName, NULL) || (xErrorName && !SDDS_TransferColumnDefinition(SDDSout, SDDSin, xErrorName, NULL))) SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); if (SDDS_GetColumnInformation(SDDSout, "symbol", &xSymbol, SDDS_GET_BY_NAME, xName)!=SDDS_STRING) { fprintf(stderr, "error: problem getting symbol for column %s\n", xName); SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors|SDDS_EXIT_PrintErrors); } if (!xSymbol) SDDS_CopyString(&xSymbol, xName); for (i=0; i