308 {
309 double **y = NULL, **sy = NULL, **diff = NULL;
310 double *x = NULL, *sx = NULL;
311 double xOffset, xScaleFactor;
312 double *xOrig = NULL, **yOrig = NULL, *sxOrig = NULL, **syOrig = NULL, **sy0 = NULL;
313 long terms, normTerm, ip, ySigmasValid;
314 int64_t i, j, points, pointsOrig;
315 long symmetry, chebyshev, termsGiven;
316 double sigmas, minimumSigma;
317 long sigmasMode, sparseInterval;
318 double **coef = NULL, **coefSigma = NULL;
319 double *chi = NULL, xLow, xHigh, *rmsResidual = NULL;
320 char *xName = NULL, *yName = NULL, **yNames = NULL, *xSigmaName = NULL;
321 char **ySigmaNames = NULL, *ySigmaControlString = NULL;
322 char *input = NULL, *output = NULL;
324 long *isFit = NULL, iArg, modifySigmas, termIndex;
325 long generateSigmas, verbose, ignoreSigmas;
326 long outputInitialized, copyParameters = 0;
327 int32_t *order = NULL;
328 SCANNED_ARG *s_arg;
329 double xMin, xMax, revpowThreshold;
330 double rms_average(double *d_x, int64_t d_n);
331 char *infoFile = NULL;
332 char *fitLabelFormat = "%g";
333 static char fitLabelBuffer[SDDS_MAXLINE];
334 unsigned long pipeFlags, reviseOrders;
336 long rangeFitOnly = 0;
337 long repeatFits = 0;
338
339 long colIndex;
340 long cloDependentIndex = -1, numDependentItems;
341 int32_t numYNames;
342
344 argc =
scanargs(&s_arg, argc, argv);
345 if (argc < 2 || argc > (3 + N_OPTIONS)) {
346 fprintf(stderr, "usage: %s\n", USAGE);
347 fprintf(stderr, "%s%s", additional_help, additional_help2);
348 exit(EXIT_FAILURE);
349 }
350
351 input = output = NULL;
352 xName = yName = xSigmaName = ySigmaControlString = NULL;
353 yNames = ySigmaNames = NULL;
354 numDependentItems = 0;
355 modifySigmas = reviseOrders = chebyshev = 0;
356 order = NULL;
357 symmetry = NO_SYMMETRY;
358 xMin = xMax = 0;
359 generateSigmas = 0;
360 sigmasMode = -1;
361 sigmas = 1;
362 minimumSigma = 0;
363 sparseInterval = 1;
364 terms = 2;
365 verbose = ignoreSigmas = 0;
366 normTerm = -1;
367 xOffset = 0;
368 xScaleFactor = 1;
371 pipeFlags = 0;
372 evalParameters.file = NULL;
373 infoFile = NULL;
374 termsGiven = 0;
375
376 for (iArg = 1; iArg < argc; iArg++) {
377 if (s_arg[iArg].arg_type == OPTION) {
378 switch (
match_string(s_arg[iArg].list[0], option, N_OPTIONS, 0)) {
379 case CLO_REPEATFITS:
380 if (s_arg[iArg].n_items != 2 || sscanf(s_arg[iArg].list[1], "%ld", &repeatFits) != 1 || repeatFits < 1)
382 if (repeatFits<10)
383 SDDS_Bomb(
"The number of repeats should be at least 10");
384 break;
385 case CLO_MODIFYSIGMAS:
386 modifySigmas = 1;
387 break;
388 case CLO_ORDERS:
389 if (termsGiven)
390 SDDS_Bomb(
"give -order or -terms, not both");
391 if (s_arg[iArg].n_items < 2)
393 order =
tmalloc(
sizeof(*order) * (terms = s_arg[iArg].n_items - 1));
394 for (i = 1; i < s_arg[iArg].n_items; i++) {
395 if (sscanf(s_arg[iArg].list[i], "%" SCNd32, order + i - 1) != 1)
396 SDDS_Bomb(
"unable to scan order from -orders list");
397 }
398 break;
399 case CLO_RANGE:
400 rangeFitOnly = 0;
401 if ((s_arg[iArg].n_items != 3 && s_arg[iArg].n_items != 4) || 1 != sscanf(s_arg[iArg].list[1], "%lf", &xMin) || 1 != sscanf(s_arg[iArg].list[2], "%lf", &xMax) || xMin >= xMax)
403 if (s_arg[iArg].n_items == 4) {
404 if (strncmp(
str_tolower(s_arg[iArg].list[3]),
"fitonly", strlen(s_arg[iArg].list[3])) == 0) {
405 rangeFitOnly = 1;
406 } else
408 }
409 break;
410 case CLO_GENERATESIGMAS:
411 generateSigmas = FLGS_GENERATESIGMAS;
412 if (s_arg[iArg].n_items > 1) {
413 if (s_arg[iArg].n_items != 2)
414 SDDS_Bomb(
"incorrect -generateSigmas synax");
415 if (strncmp(s_arg[iArg].list[1], "keepsmallest", strlen(s_arg[iArg].list[1])) == 0)
416 generateSigmas |= FLGS_KEEPSMALLEST;
417 if (strncmp(s_arg[iArg].list[1], "keeplargest", strlen(s_arg[iArg].list[1])) == 0)
418 generateSigmas |= FLGS_KEEPLARGEST;
419 if ((generateSigmas & FLGS_KEEPSMALLEST) && (generateSigmas & FLGS_KEEPLARGEST))
420 SDDS_Bomb(
"ambiguous -generateSigmas synax");
421 }
422 break;
423 case CLO_TERMS:
424 if (order)
425 SDDS_Bomb(
"give -order or -terms, not both");
426 if (s_arg[iArg].n_items != 2 || sscanf(s_arg[iArg].list[1], "%ld", &terms) != 1)
428 termsGiven = 1;
429 break;
430 case CLO_XOFFSET:
431 if (s_arg[iArg].n_items != 2 || sscanf(s_arg[iArg].list[1], "%lf", &xOffset) != 1)
433 break;
434 case CLO_SYMMETRY:
435 if (s_arg[iArg].n_items == 2) {
436 if ((symmetry =
match_string(s_arg[iArg].list[1], symmetry_options, N_SYMMETRY_OPTIONS, 0)) < 0)
437 SDDS_Bomb(
"unknown option used with -symmetry");
438 } else
440 break;
441 case CLO_SIGMAS:
442 if (s_arg[iArg].n_items != 3)
444 if (sscanf(s_arg[iArg].list[1], "%lf", &sigmas) != 1)
445 SDDS_Bomb(
"couldn't scan value for -sigmas");
446 if ((sigmasMode =
match_string(s_arg[iArg].list[2], sigmas_options, N_SIGMAS_OPTIONS, 0)) < 0)
448 break;
449 case CLO_MINSIGMA:
450 if (s_arg[iArg].n_items != 2)
451 SDDS_Bomb(
"incorrect -minimumSigma syntax");
452 if (sscanf(s_arg[iArg].list[1], "%lf", &minimumSigma) != 1)
453 SDDS_Bomb(
"couldn't scan value for -minimumSigma");
454 break;
455 case CLO_SPARSE:
456 if (s_arg[iArg].n_items != 2)
458 if (sscanf(s_arg[iArg].list[1], "%ld", &sparseInterval) != 1)
459 SDDS_Bomb(
"couldn't scan value for -sparse");
460 if (sparseInterval < 1)
462 break;
463 case CLO_VERBOSE:
464 verbose = 1;
465 break;
466 case CLO_NORMALIZE:
467 normTerm = 0;
468 if (s_arg[iArg].n_items > 2 ||
469 (s_arg[iArg].n_items == 2 && sscanf(s_arg[iArg].list[1], "%ld", &normTerm) != 1) ||
470 normTerm < 0)
472 break;
473 case CLO_REVISEORDERS:
474 revpowThreshold = 0.1;
475 s_arg[iArg].n_items -= 1;
476 if (!
scanItemList(&reviseOrders, s_arg[iArg].list + 1, &s_arg[iArg].n_items, 0,
478 "verbose", -1, NULL, 1, REVPOW_VERBOSE, NULL))
479 SDDS_Bomb(
"invalid -reviseOrders syntax");
480 reviseOrders |= REVPOW_ACTIVE;
481 revpowThreshold = fabs(revpowThreshold);
482 break;
483 case CLO_CHEBYSHEV:
484 if (s_arg[iArg].n_items > 2 ||
485 (s_arg[iArg].n_items == 2 && strncmp(s_arg[iArg].list[1], "convert", strlen(s_arg[iArg].list[1])) != 0))
487 chebyshev = s_arg[iArg].n_items;
490 break;
491 case CLO_XFACTOR:
492 if (s_arg[iArg].n_items != 2 ||
493 sscanf(s_arg[iArg].list[1], "%lf", &xScaleFactor) != 1 || xScaleFactor == 0)
495 break;
496 case CLO_INDEPENDENT:
497 if (s_arg[iArg].n_items != 2)
498 SDDS_Bomb(
"invalid -independent syntax");
499 xName = s_arg[iArg].list[1];
500 break;
501 case CLO_DEPENDENT:
502 numDependentItems = s_arg[iArg].n_items - 1;
503 cloDependentIndex = iArg;
504 if (numDependentItems < 1)
506 break;
507 case CLO_SIGMAINDEPENDENT:
508 if (s_arg[iArg].n_items != 2)
509 SDDS_Bomb(
"invalid -sigmaIndependent syntax");
510 xSigmaName = s_arg[iArg].list[1];
511 break;
512 case CLO_SIGMADEPENDENT:
513 if (s_arg[iArg].n_items != 2)
514 SDDS_Bomb(
"invalid -sigmaDependent syntax");
515 ySigmaControlString = s_arg[iArg].list[1];
516 break;
517 case CLO_FITLABELFORMAT:
518 if (s_arg[iArg].n_items != 2)
519 SDDS_Bomb(
"invalid -fitLabelFormat syntax");
520 fitLabelFormat = s_arg[iArg].list[1];
521 break;
522 case CLO_PIPE:
523 if (!
processPipeOption(s_arg[iArg].list + 1, s_arg[iArg].n_items - 1, &pipeFlags))
525 break;
526 case CLO_INFOFILE:
527 if (s_arg[iArg].n_items != 2)
529 infoFile = s_arg[iArg].list[1];
530 break;
531 case CLO_EVALUATE:
532 if (s_arg[iArg].n_items < 2)
534 evalParameters.file = s_arg[iArg].list[1];
535 s_arg[iArg].n_items -= 2;
536 s_arg[iArg].list += 2;
537 if (!
scanItemList(&evalParameters.flags, s_arg[iArg].list, &s_arg[iArg].n_items, 0,
538 "begin",
SDDS_DOUBLE, &evalParameters.begin, 1, EVAL_BEGIN_GIVEN,
539 "end",
SDDS_DOUBLE, &evalParameters.end, 1, EVAL_END_GIVEN,
540 "number",
SDDS_LONG64, &evalParameters.number, 1, EVAL_NUMBER_GIVEN, NULL))
542 break;
543 case CLO_COPYPARAMETERS:
544 copyParameters = 1;
545 break;
546 default:
547 bomb(
"unknown switch", USAGE);
548 break;
549 }
550 } else {
551 if (input == NULL)
552 input = s_arg[iArg].list[0];
553 else if (output == NULL)
554 output = s_arg[iArg].list[0];
555 else
557 }
558 }
559
561
562 if (symmetry && order)
563 SDDS_Bomb(
"can't specify both -symmetry and -orders");
564 if (!xName || !numDependentItems)
565 SDDS_Bomb(
"you must specify a column name for x and y");
566 if (modifySigmas && !xSigmaName)
567 SDDS_Bomb(
"you must specify x sigmas with -modifySigmas");
568 if (generateSigmas) {
569 if (modifySigmas)
570 SDDS_Bomb(
"you can't specify both -generateSigmas and -modifySigmas");
571 }
572 if (ySigmaControlString) {
573 if (sigmasMode != -1)
574 SDDS_Bomb(
"you can't specify both -sigmas and a y sigma name");
575 }
576 ySigmasValid = 0;
577 if (sigmasMode != -1 || generateSigmas || ySigmaControlString || modifySigmas)
578 ySigmasValid = 1;
579
580 if (normTerm >= 0 && normTerm >= terms)
581 SDDS_Bomb(
"can't normalize to that term--not that many terms");
582 if (reviseOrders && !(sigmasMode != -1 || generateSigmas || ySigmaNames))
583 SDDS_Bomb(
"can't use -reviseOrders unless a y sigma or -generateSigmas is given");
584
585 if (symmetry == EVEN_SYMMETRY) {
586 order =
tmalloc(
sizeof(*order) * terms);
587 for (i = 0; i < terms; i++)
588 order[i] = 2 * i;
589 } else if (symmetry == ODD_SYMMETRY) {
590 order =
tmalloc(
sizeof(*order) * terms);
591 for (i = 0; i < terms; i++)
592 order[i] = 2 * i + 1;
593 } else if (!order) {
594 order =
tmalloc(
sizeof(*order) * terms);
595 for (i = 0; i < terms; i++)
596 order[i] = i;
597 }
598
601 outputInitialized = 0;
602 yNames = ResolveColumnNames(&SDDSin, s_arg[cloDependentIndex].list + 1, numDependentItems, &numYNames);
603 if (ySigmaControlString != NULL)
604 ySigmaNames = GenerateYSigmaNames(ySigmaControlString, yNames, numYNames);
605
606 checkInputFile(&SDDSin, xName, yNames, xSigmaName, ySigmaNames, numYNames);
607 sy0 =
tmalloc(
sizeof(
double *) * numYNames);
608 y =
tmalloc(
sizeof(
double *) * numYNames);
609 sy =
tmalloc(
sizeof(
double *) * numYNames);
610 isFit =
tmalloc(
sizeof(
long) * numYNames);
611 chi =
tmalloc(
sizeof(
double) * numYNames);
612 coef =
tmalloc(
sizeof(
double *) * numYNames);
613 coefSigma =
tmalloc(
sizeof(
double *) * numYNames);
614 for (colIndex = 0; colIndex < numYNames; colIndex++) {
615 coef[colIndex] =
tmalloc(
sizeof(
double) * terms);
616 coefSigma[colIndex] =
tmalloc(
sizeof(
double) * terms);
617 }
618 iCoefficient =
tmalloc(
sizeof(
long) * numYNames);
619 iCoefficientSigma =
tmalloc(
sizeof(
long) * numYNames);
620 iCoefficientUnits =
tmalloc(
sizeof(
long) * numYNames);
621
624
625 continue;
626 }
628 fprintf(stderr, "error: unable to read column %s\n", xName);
630 }
631 for (i = 0; i < numYNames; i++) {
633 fprintf(stderr, "error: unable to read column %s\n", yNames[i]);
635 }
636 }
637 sx = NULL;
639 fprintf(stderr, "error: unable to read column %s\n", xSigmaName);
641 }
642 for (colIndex = 0; colIndex < numYNames; colIndex++)
643 sy0[colIndex] =
tmalloc(
sizeof(
double) * points);
644 if (ySigmaNames) {
645 for (i = 0; i < numYNames; i++) {
647 fprintf(stderr, "error: unable to read column %s\n", ySigmaNames[i]);
649 }
650 }
651 }
652
653 if (minimumSigma > 0) {
654 int64_t j;
655 for (i = 0; i < numYNames; i++) {
656 for (j = 0; j < points; j++)
657 if (sy0[i][j] < minimumSigma)
658 sy0[i][j] = minimumSigma;
659 }
660 }
661
662 if (xMin != xMax || sparseInterval != 1) {
663 xOrig =
tmalloc(
sizeof(*xOrig) * points);
664 yOrig =
tmalloc(
sizeof(*yOrig) * numYNames);
665 for (colIndex = 0; colIndex < numYNames; colIndex++)
666 yOrig[colIndex] =
tmalloc(
sizeof(
double) * points);
667 if (sx)
668 sxOrig =
tmalloc(
sizeof(*sxOrig) * points);
669 if (ySigmasValid) {
670 syOrig =
tmalloc(
sizeof(*syOrig) * numYNames);
671 for (colIndex = 0; colIndex < numYNames; colIndex++)
672 syOrig[colIndex] =
tmalloc(
sizeof(
double) * points);
673 }
674 pointsOrig = points;
675 for (i = j = 0; i < points; i++) {
676 xOrig[i] = x[i];
677 if (sx)
678 sxOrig[i] = sx[i];
679 for (colIndex = 0; colIndex < numYNames; colIndex++) {
680 yOrig[colIndex][i] = y[colIndex][i];
681 if (ySigmasValid)
682 syOrig[colIndex][i] = sy0[colIndex][i];
683 }
684 }
685 if (xMin != xMax) {
686 for (i = j = 0; i < points; i++) {
687 if (xOrig[i] <= xMax && xOrig[i] >= xMin) {
688 x[j] = xOrig[i];
689 for (colIndex = 0; colIndex < numYNames; colIndex++) {
690 y[colIndex][j] = yOrig[colIndex][i];
691 if (ySigmasValid)
692 sy0[colIndex][j] = syOrig[colIndex][i];
693 }
694 if (sx)
695 sx[j] = sxOrig[i];
696 j++;
697 }
698 }
699 points = j;
700 }
701 if (sparseInterval != 1) {
702 for (i = j = 0; i < points; i++) {
703 if (i % sparseInterval == 0) {
704 x[j] = x[i];
705 for (colIndex = 0; colIndex < numYNames; colIndex++) {
706 y[colIndex][j] = y[colIndex][i];
707 if (ySigmasValid)
708 sy0[colIndex][j] = sy0[colIndex][i];
709 }
710 if (sx)
711 sx[j] = sx[i];
712 j++;
713 }
714 }
715 points = j;
716 }
717 } else {
718 xOrig = x;
719 yOrig = y;
720 sxOrig = sx;
721 syOrig = sy0;
722 pointsOrig = points;
723 }
724
726
727 if (sigmasMode == ABSOLUTE_SIGMAS) {
728 for (colIndex = 0; colIndex < numYNames; colIndex++) {
729 for (i = 0; i < points; i++)
730 sy0[colIndex][i] = sigmas;
731 if (sy0[colIndex] != syOrig[colIndex])
732 for (i = 0; i < pointsOrig; i++)
733 syOrig[colIndex][i] = sigmas;
734 }
735 } else if (sigmasMode == FRACTIONAL_SIGMAS) {
736 for (colIndex = 0; colIndex < numYNames; colIndex++) {
737 for (i = 0; i < points; i++)
738 sy0[colIndex][i] = sigmas * fabs(y[colIndex][i]);
739 if (sy0[colIndex] != syOrig[colIndex])
740 for (i = 0; i < pointsOrig; i++)
741 syOrig[colIndex][i] = fabs(yOrig[colIndex][i]) * sigmas;
742 }
743 }
744
745 for (i = 0; i < numYNames; i++) {
746 if (minimumSigma > 0) {
747 int64_t j;
748 for (j = 0; j < points; j++)
749 if (sy0[i][j] < minimumSigma)
750 sy0[i][j] = minimumSigma;
751 }
752 }
753
754 if (!ySigmasValid || generateSigmas)
755 for (colIndex = 0; colIndex < numYNames; colIndex++) {
756 for (i = 0; i < points; i++)
757 sy0[colIndex][i] = 1;
758 }
759 else
760 for (i = 0; i < points; i++)
761 for (colIndex = 0; colIndex < numYNames; colIndex++) {
762 if (sy0[colIndex][i] == 0)
763 SDDS_Bomb(
"y sigma = 0 for one or more points.");
764 }
765
766 diff =
tmalloc(
sizeof(*diff) * numYNames);
767 sy =
tmalloc(
sizeof(*sy) * numYNames);
768 for (colIndex = 0; colIndex < numYNames; colIndex++) {
769 diff[colIndex] =
tmalloc(
sizeof(
double) * points);
770 sy[colIndex] =
tmalloc(
sizeof(
double) * points);
771 }
772
773 for (i = 0; i < points; i++) {
774 for (colIndex = 0; colIndex < numYNames; colIndex++)
775 sy[colIndex][i] = sy0[colIndex][i];
776 }
777
780 if (chebyshev) {
781 xOffset = (xHigh + xLow) / 2;
784 }
785
786 if (generateSigmas || modifySigmas) {
787
788 for (colIndex = 0; colIndex < numYNames; colIndex++) {
789 isFit[colIndex] =
lsfg(x, y[colIndex], sy[colIndex], points, terms, order, coef[colIndex], coefSigma[colIndex], &chi[colIndex], diff[colIndex], basis_fn);
790 if (!isFit[colIndex]) {
791 fprintf(stderr, "Column %s: ", yNames[colIndex]);
793 }
794 if (verbose) {
795 fprintf(stderr, "Column %s: ", yNames[colIndex]);
796 fputs("initial_fit:", stderr);
797 print_coefs(stderr, xOffset, xScaleFactor, chebyshev, coef[colIndex], NULL, order, terms, chi[colIndex], normTerm, "");
798 fprintf(stderr, "unweighted rms deviation from fit: %21.15le\n", rms_average(diff[colIndex], points));
799 }
800 if (modifySigmas) {
801 if (!ySigmasValid) {
802 for (i = 0; i < points; i++)
803 sy[colIndex][i] = fabs(
eval_sum(basis_dfn, coef[colIndex], order, terms, x[i]) * sx[i]);
804 } else
805 for (i = 0; i < points; i++) {
806 sy[colIndex][i] = sqrt(sqr(sy0[colIndex][i]) + sqr(
eval_sum(basis_dfn, coef[colIndex], order, terms, x[i]) * sx[i]));
807 }
808 }
809 if (generateSigmas) {
810 double sigma;
811 for (i = sigma = 0; i < points; i++) {
812 sigma += sqr(diff[colIndex][i]);
813 }
814 sigma = sqrt(sigma / (points - terms));
815 for (i = 0; i < points; i++) {
816 if (generateSigmas & FLGS_KEEPSMALLEST) {
817 if (sigma < sy[colIndex][i])
818 sy[colIndex][i] = sigma;
819 } else if (generateSigmas & FLGS_KEEPLARGEST) {
820 if (sigma > sy[colIndex][i])
821 sy[colIndex][i] = sigma;
822 } else {
823 sy[colIndex][i] = sigma;
824 }
825 }
826 for (i = 0; i < pointsOrig; i++) {
827 if (generateSigmas & FLGS_KEEPSMALLEST) {
828 if (sigma < sy0[colIndex][i])
829 sy0[colIndex][i] = sigma;
830 } else if (generateSigmas & FLGS_KEEPLARGEST) {
831 if (sigma > sy0[colIndex][i])
832 sy0[colIndex][i] = sigma;
833 } else {
834 sy0[colIndex][i] = sigma;
835 }
836 }
837 }
838 }
839 }
840
841 if (reviseOrders & REVPOW_ACTIVE) {
842 double bestChi;
843 long bestTerms, newBest;
844 int32_t *bestOrder;
845
846 bestTerms = terms;
847 bestOrder =
tmalloc(
sizeof(*bestOrder) * bestTerms);
848 for (ip = 0; ip < terms; ip++)
849 bestOrder[ip] = order[ip];
850
851 for (colIndex = 0; colIndex < numYNames; colIndex++) {
852 isFit[colIndex] =
lsfg(x, y[colIndex], sy[colIndex], points, bestTerms, bestOrder, coef[colIndex], coefSigma[colIndex], &bestChi, diff[colIndex], basis_fn);
853 if (!isFit[colIndex]) {
854 fprintf(stderr, "Column %s: ", yNames[colIndex]);
856 if (reviseOrders & REVPOW_VERBOSE) {
857 fprintf(stderr, "Column %s: ", yNames[colIndex]);
858 fputs("fit to revise orders:", stderr);
859 print_coefs(stderr, xOffset, xScaleFactor, chebyshev, coef[colIndex], (ySigmasValid ? coefSigma[colIndex] : NULL), bestOrder, bestTerms, bestChi, normTerm, "");
860 fprintf(stderr, "unweighted rms deviation from fit: %21.15le\n", rms_average(diff[colIndex], points));
861 }
862 }
863
864 do {
865 newBest = 0;
866 terms = bestTerms - 1;
867 for (ip = bestTerms - 1; ip >= 0; ip--) {
868 for (i = j = 0; i < bestTerms; i++)
869 if (i != ip)
870 order[j++] = bestOrder[i];
871 isFit[colIndex] =
lsfg(x, y[colIndex], sy[colIndex], points, terms, order, coef[colIndex], coefSigma[colIndex], &chi[colIndex], diff[colIndex], basis_fn);
872 if (!isFit[colIndex]) {
873 fprintf(stderr, "Column %s: ", yNames[colIndex]);
875 }
876 if (reviseOrders & REVPOW_VERBOSE) {
877 fprintf(stderr, "Column %s: ", yNames[colIndex]);
878 fputs("new trial fit:", stderr);
879 print_coefs(stderr, xOffset, xScaleFactor, chebyshev, coef[colIndex], (ySigmasValid ? coefSigma[colIndex] : NULL), order, terms, chi[colIndex], normTerm, "");
880 fprintf(stderr, "unweighted rms deviation from fit: %21.15le\n", rms_average(diff[colIndex], points));
881 }
882 if (chi[colIndex] - bestChi < revpowThreshold) {
883 bestChi = chi[colIndex];
884 bestTerms = terms;
885 newBest = 1;
886 for (i = 0; i < terms; i++)
887 bestOrder[i] = order[i];
888 if (reviseOrders & REVPOW_VERBOSE) {
889 fputs("new best fit:", stderr);
890 print_coefs(stderr, xOffset, xScaleFactor, chebyshev, coef[colIndex], (ySigmasValid ? coefSigma[colIndex] : NULL), bestOrder, bestTerms, bestChi, normTerm, "");
891 fprintf(stderr, "unweighted rms deviation from fit: %21.15le\n", rms_average(diff[colIndex], points));
892 }
893 break;
894 }
895 }
896 if (bestTerms == 1)
897 break;
898 } while (newBest);
899 terms = bestTerms;
900 for (ip = 0; ip < terms; ip++)
901 order[ip] = bestOrder[ip];
902 free(bestOrder);
903 reviseOrders = 0;
904 }
905 }
906
907 if (!outputInitialized) {
908 initializeOutputFile(&SDDSout, &SDDSoutInfo, output, infoFile, &SDDSin, input, xName, yNames, xSigmaName, ySigmaNames, ySigmasValid, order, terms, chebyshev, numYNames, copyParameters, repeatFits);
909 free(output);
910 outputInitialized = 1;
911 }
912 if (evalParameters.file)
913 setupEvaluationFile(&evalParameters, xName, yNames, numYNames, &SDDSin);
914
915 rmsResidual =
tmalloc(
sizeof(
double) * numYNames);
916 for (colIndex = 0; colIndex < numYNames; colIndex++) {
917 if (!repeatFits) {
918 isFit[colIndex] =
lsfg(x, y[colIndex], sy[colIndex], points, terms, order, coef[colIndex], coefSigma[colIndex], &chi[colIndex], diff[colIndex], basis_fn);
919 } else {
920 double *coefRepeat =
tmalloc(
sizeof(*coefRepeat) * terms * repeatFits);
921 double *coefSigmaRepeat =
tmalloc(
sizeof(*coefSigmaRepeat) * terms * repeatFits);
922 long fitIdx;
923 isFit[colIndex] = 1;
924 srand(1);
925 for (fitIdx = 0; fitIdx < repeatFits; fitIdx++) {
926
927 int64_t *indices =
tmalloc(
sizeof(*indices) * points);
928 for (i = 0; i < points; i++) indices[i] = rand() % points;
929 double *xSample =
tmalloc(
sizeof(*xSample) * points);
930 double *ySample =
tmalloc(
sizeof(*ySample) * points);
931 double *sySample =
tmalloc(
sizeof(*sySample) * points);
932 for (i = 0; i < points; i++) {
933 xSample[i] = x[indices[i]];
934 ySample[i] = y[colIndex][indices[i]];
935 sySample[i] = sy[colIndex][i];
936 }
937 double chiTmp;
938 double *diffTmp =
tmalloc(
sizeof(*diffTmp) * points);
939 int fitOk =
lsfg(xSample, ySample, sySample, points, terms, order, coefRepeat + fitIdx * terms, coefSigmaRepeat + fitIdx * terms, &chiTmp, diffTmp, basis_fn);
940 free(indices);
941 free(xSample);
942 free(ySample);
943 free(sySample);
944 free(diffTmp);
945 isFit[colIndex] *= fitOk;
946 }
947
948 for (i = 0; i < terms; i++) {
949 double sum = 0, sum2 = 0;
950 for (j = 0; j < repeatFits; j++) {
951 double v = coefRepeat[j * terms + i];
952 sum += v;
953 sum2 += v * v;
954 }
955 coef[colIndex][i] = sum / repeatFits;
956 coefSigma[colIndex][i] = sqrt(sum2 / repeatFits - (coef[colIndex][i] * coef[colIndex][i]));
957 }
958 free(coefRepeat);
959 free(coefSigmaRepeat);
960
961 chi[colIndex] = 0;
962 for (i = 0; i < points; i++) {
963 double fitValue =
eval_sum(basis_fn, coef[colIndex], order, terms, x[i]);
964 diff[colIndex][i] = fitValue - y[colIndex][i];
965 chi[colIndex] += sqr(diff[colIndex][i]);
966 }
967 chi[colIndex] /= (points-terms);
968 }
969 if (isFit[colIndex]) {
970 rmsResidual[colIndex] = rms_average(diff[colIndex], points);
971 if (verbose) {
972 fprintf(stderr, "Column: %s\n", yNames[colIndex]);
973 print_coefs(stderr, xOffset, xScaleFactor, chebyshev, coef[colIndex], (ySigmasValid ? coefSigma[colIndex] : NULL), order, terms, chi[colIndex], normTerm, "");
974 fprintf(stderr, "unweighted rms deviation from fit: %21.15le\n", rmsResidual[colIndex]);
975 }
976 } else if (verbose)
977 fprintf(stderr, "fit failed for %s.\n", yNames[colIndex]);
978
979 if (evalParameters.file)
980 makeEvaluationTable(&evalParameters, x, points, coef[colIndex], order, terms, xName, yNames, numYNames, colIndex);
981 }
982
983 if (outputInitialized) {
984 if (!
SDDS_StartPage(&SDDSout, rangeFitOnly ? pointsOrig : points) ||
987 if (copyParameters) {
992 }
993 if (!
SDDS_SetColumnFromDoubles(&SDDSout, SDDS_SET_BY_INDEX, rangeFitOnly ? xOrig : x, rangeFitOnly ? pointsOrig : points, ix) ||
996 for (colIndex = 0; colIndex < numYNames; colIndex++) {
997 if (rangeFitOnly) {
998 double *residual, rmsResidual0;
999 compareOriginalToFit(xOrig, yOrig[colIndex], &residual, pointsOrig, &rmsResidual0, coef[colIndex], order, terms);
1003 for (i = 0; i < pointsOrig; i++)
1004 residual[i] = yOrig[colIndex][i] - residual[i];
1007 free(residual);
1008 } else {
1009 for (i = 0; i < points; i++)
1010 diff[colIndex][i] = -diff[colIndex][i];
1014 for (i = 0; i < points; i++)
1015 diff[colIndex][i] = y[colIndex][i] - diff[colIndex][i];
1018 }
1019 }
1020 if (ixSigma != -1 &&
1021 !
SDDS_SetColumnFromDoubles(&SDDSout, SDDS_SET_BY_INDEX, rangeFitOnly ? sxOrig : sx, rangeFitOnly ? pointsOrig : points, ixSigma))
1023 for (colIndex = 0; colIndex < numYNames; colIndex++) {
1024 if (ySigmasValid && iySigma[colIndex] != -1 &&
1025 !
SDDS_SetColumnFromDoubles(&SDDSout, SDDS_SET_BY_INDEX, rangeFitOnly ? syOrig[colIndex] : sy[colIndex], rangeFitOnly ? pointsOrig : points, iySigma[colIndex]))
1027
1028 if (infoFile) {
1029 termIndex = coefficient_index(order, terms, 0);
1030 if (iIntercept[colIndex] != -1 &&
1031 !
SDDS_SetParameters(&SDDSoutInfo, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iIntercept[colIndex], coef[colIndex][termIndex], -1))
1033 if (iInterceptSigma[colIndex] != -1 &&
1034 !
SDDS_SetParameters(&SDDSoutInfo, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iInterceptSigma[colIndex], coefSigma[colIndex][termIndex], -1))
1036
1037 termIndex = coefficient_index(order, terms, 1);
1038 if (iSlope[colIndex] != -1 &&
1039 !
SDDS_SetParameters(&SDDSoutInfo, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iSlope[colIndex], coef[colIndex][termIndex], -1))
1041 if (iSlopeSigma[colIndex] != -1 &&
1042 !
SDDS_SetParameters(&SDDSoutInfo, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iSlopeSigma[colIndex], coefSigma[colIndex][termIndex], -1))
1044
1045 termIndex = coefficient_index(order, terms, 2);
1046 if (iCurvature[colIndex] != -1 &&
1047 !
SDDS_SetParameters(&SDDSoutInfo, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iCurvature[colIndex], coef[colIndex][termIndex], -1))
1049 if (iCurvatureSigma[colIndex] != -1 &&
1050 !
SDDS_SetParameters(&SDDSoutInfo, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iCurvatureSigma[colIndex], coefSigma[colIndex][termIndex], -1))
1052 if (iFitLabel[colIndex] != -1) {
1053 makeFitLabel(fitLabelBuffer, SDDS_MAXLINE, fitLabelFormat, coef[colIndex], (ySigmasValid || repeatFits)?coefSigma[colIndex]:NULL, order, terms, colIndex);
1054 if (!
SDDS_SetParameters(&SDDSoutInfo, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iFitLabel[colIndex], fitLabelBuffer, -1))
1056 }
1058 (ySigmasValid &&
1062 iRmsResidual[colIndex], rmsResidual[colIndex], iChiSq[colIndex], chi[colIndex],
1063 iTerms, terms, iSigLevel[colIndex],
ChiSqrSigLevel(chi[colIndex], points - terms),
1064 iOffset, xOffset, iFactor, xScaleFactor, iFitIsValid[colIndex], isFit[colIndex] ? 'y' : 'n', -1))
1066 }
1067
1068 termIndex = coefficient_index(order, terms, 0);
1069 if (iInterceptO[colIndex] != -1 &&
1070 !
SDDS_SetParameters(&SDDSout, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iInterceptO[colIndex], coef[colIndex][termIndex], -1))
1072 if (iInterceptSigmaO[colIndex] != -1 &&
1073 !
SDDS_SetParameters(&SDDSout, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iInterceptSigmaO[colIndex], coefSigma[colIndex][termIndex], -1))
1075
1076 termIndex = coefficient_index(order, terms, 1);
1077 if (iSlopeO[colIndex] != -1 &&
1078 !
SDDS_SetParameters(&SDDSout, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iSlopeO[colIndex], coef[colIndex][termIndex], -1))
1080 if (iSlopeSigmaO[colIndex] != -1 &&
1081 !
SDDS_SetParameters(&SDDSout, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iSlopeSigmaO[colIndex], coefSigma[colIndex][termIndex], -1))
1083
1084 termIndex = coefficient_index(order, terms, 2);
1085 if (iCurvatureO[colIndex] != -1 &&
1086 !
SDDS_SetParameters(&SDDSout, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iCurvatureO[colIndex], coef[colIndex][termIndex], -1))
1088 if (iCurvatureSigmaO[colIndex] != -1 &&
1089 !
SDDS_SetParameters(&SDDSout, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iCurvatureSigmaO[colIndex], coefSigma[colIndex][termIndex], -1))
1091 if (iFitLabelO[colIndex] != -1) {
1092 makeFitLabel(fitLabelBuffer, SDDS_MAXLINE, fitLabelFormat, coef[colIndex], (ySigmasValid || repeatFits)?coefSigma[colIndex]:NULL, order, terms, colIndex);
1093 if (!
SDDS_SetParameters(&SDDSout, SDDS_SET_BY_INDEX | SDDS_PASS_BY_VALUE, iFitLabelO[colIndex], fitLabelBuffer, -1))
1095 }
1097 iRmsResidualO[colIndex], rmsResidual[colIndex], iChiSqO[colIndex], chi[colIndex],
1098 iTermsO, terms, iSigLevelO[colIndex],
ChiSqrSigLevel(chi[colIndex], points - terms),
1099 iOffsetO, xOffset, iFactorO, xScaleFactor, iFitIsValidO[colIndex], isFit[colIndex] ? 'y' : 'n', -1))
1101 }
1104 }
1105 if (xOrig != x)
1106 free(xOrig);
1107 if (sxOrig != sx)
1108 free(sxOrig);
1109 free(x);
1110 free(sx);
1111 for (colIndex = 0; colIndex < numYNames; colIndex++) {
1112 free(diff[colIndex]);
1113 free(sy[colIndex]);
1114 if (yOrig[colIndex] != y[colIndex])
1115 free(yOrig[colIndex]);
1116 if (syOrig && sy0 && syOrig[colIndex] != sy0[colIndex])
1117 free(syOrig[colIndex]);
1118 free(y[colIndex]);
1119 if (sy0 && sy0[colIndex])
1120 free(sy0[colIndex]);
1121 }
1122 }
1123 return (EXIT_SUCCESS);
1124}
int32_t SDDS_CopyParameters(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
int32_t SDDS_StartPage(SDDS_DATASET *SDDS_dataset, int64_t expected_n_rows)
int32_t SDDS_SetParameters(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
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_SetColumnFromLongs(SDDS_DATASET *SDDS_dataset, int32_t mode, int32_t *data, int64_t rows,...)
Sets the values for a single data column using long integer numbers.
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
#define SDDS_LONG64
Identifier for the signed 64-bit integer data type.
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
int find_min_max(double *min, double *max, double *list, int64_t n)
Finds the minimum and maximum values in a list of doubles.
long lsfg(double *xd, double *yd, double *sy, long n_pts, long n_terms, int32_t *order, double *coef, double *s_coef, double *chi, double *diff, double(*fn)(double x, long ord))
Computes generalized least squares fits using a function passed by the caller.
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)
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 set_argument_scale(double scale)
Set the scale factor applied to the input argument of basis functions.
double dtcheby(double x, long n)
Evaluate the derivative of the Chebyshev polynomial T_n(x).
void set_argument_offset(double offset)
Set the offset applied to the input argument of basis functions.
double ipower(double x, long n)
Evaluate a power function x^n.
double dipower(double x, long n)
Evaluate the derivative of x^n.
double tcheby(double x, long n)
Evaluate the Chebyshev polynomial of the first kind T_n(x).
double ChiSqrSigLevel(double ChiSquared0, long nu)
Computes the probability that a chi-squared variable exceeds a given value.
char * str_tolower(char *s)
Convert a string to lower case.