SDDS ToolKit Programs and Libraries for C and Python
Loading...
Searching...
No Matches
lsfBasisFns.c
Go to the documentation of this file.
1/**
2 * @file lsfBasisFns.c
3 * @brief Basis functions for Least Squares Fits (LSFs) using ordinary and Chebyshev polynomials.
4 *
5 * This file provides a set of functions for evaluating basis functions and their derivatives
6 * for least squares fitting. It includes functions to set and retrieve scaling offsets,
7 * as well as polynomial and Chebyshev polynomial basis functions and their derivatives.
8 *
9 * @copyright
10 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
11 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
12 *
13 * @license
14 * This file is distributed under the terms of the Software License Agreement
15 * found in the file LICENSE included with this distribution.
16 *
17 * @author M. Borland, C. Saunders, R. Soliday
18 */
19
20#include "mdb.h"
21#include "mdb_thread.h"
22
23static double x_offset = 0;
24static double x_scale = 1;
25static MDB_THREAD_LOCK argument_transform_lock = MDB_THREAD_LOCK_INITIALIZER;
26
27static void get_argument_transform(double *offset, double *scale) {
28 mdb_thread_lock(&argument_transform_lock);
29 *offset = x_offset;
30 *scale = x_scale;
31 mdb_thread_unlock(&argument_transform_lock);
32}
33
34/**
35 * @brief Set the offset applied to the input argument of basis functions.
36 *
37 * This function updates the global variable used to shift the input argument before
38 * evaluating polynomial or Chebyshev functions.
39 *
40 * @param offset The new offset to apply to the argument.
41 */
42void set_argument_offset(double offset) {
43 mdb_thread_lock(&argument_transform_lock);
44 x_offset = offset;
45 mdb_thread_unlock(&argument_transform_lock);
46}
47
48/**
49 * @brief Set the scale factor applied to the input argument of basis functions.
50 *
51 * This function updates the global variable used to scale the input argument before
52 * evaluating polynomial or Chebyshev functions. It ensures the scale factor is not zero.
53 *
54 * @param scale The new scale factor for the argument.
55 */
56void set_argument_scale(double scale) {
57 if (!scale)
58 bomb("argument scale factor is zero", NULL);
59 mdb_thread_lock(&argument_transform_lock);
60 x_scale = scale;
61 mdb_thread_unlock(&argument_transform_lock);
62}
63
64/**
65 * @brief Get the current argument offset applied before function evaluations.
66 *
67 * @return The current argument offset.
68 */
70 double offset;
71 mdb_thread_lock(&argument_transform_lock);
72 offset = x_offset;
73 mdb_thread_unlock(&argument_transform_lock);
74 return offset;
75}
76
77/**
78 * @brief Get the current argument scale factor used before function evaluations.
79 *
80 * @return The current argument scale factor.
81 */
83 double scale;
84 mdb_thread_lock(&argument_transform_lock);
85 scale = x_scale;
86 mdb_thread_unlock(&argument_transform_lock);
87 return scale;
88}
89
90/**
91 * @brief Evaluate the Chebyshev polynomial of the first kind T_n(x).
92 *
93 * Given x and an order n, this function returns T_n((x - x_offset) / x_scale).
94 * If x is out of the domain [-1,1], it is clipped to ±1 before evaluation.
95 *
96 * @param x The point at which to evaluate the Chebyshev polynomial.
97 * @param n The order of the Chebyshev polynomial.
98 * @return The value of T_n(x).
99 */
100double tcheby(double x, long n) {
101 double offset, scale;
102 get_argument_transform(&offset, &scale);
103 x = (x - offset) / scale;
104 if (x > 1 || x < -1) {
105 /* fprintf(stderr, "warning: argument %e is out of range for tcheby()\n",
106 * x); */
107 x = SIGN(x);
108 }
109 return (cos(n * acos(x)));
110}
111
112/**
113 * @brief Evaluate the derivative of the Chebyshev polynomial T_n(x).
114 *
115 * This function returns d/dx [T_n((x - x_offset)/x_scale)].
116 * If x is out of the domain [-1,1], it is clipped to ±1 before evaluation.
117 *
118 * @param x The point at which to evaluate the derivative of T_n.
119 * @param n The order of the Chebyshev polynomial.
120 * @return The derivative dT_n/dx at the given x.
121 */
122double dtcheby(double x, long n) {
123 double offset, scale;
124 get_argument_transform(&offset, &scale);
125 x = (x - offset) / scale;
126 if (x > 1 || x < -1) {
127 /* fprintf(stderr, "warning: argument %e is out of range for tcheby()\n",
128 * x); */
129 x = SIGN(x);
130 }
131 if (x != 1 && x != -1)
132 return (n * sin(n * acos(x)) / sqrt(1 - sqr(x)));
133 return (1.0 * n * n);
134}
135
136/**
137 * @brief Evaluate a power function x^n.
138 *
139 * This function returns ( (x - x_offset)/x_scale )^n.
140 *
141 * @param x The point at which to evaluate the power.
142 * @param n The exponent.
143 * @return The value of ((x - x_offset)/x_scale)^n.
144 */
145double ipower(double x, long n) {
146 double offset, scale;
147 get_argument_transform(&offset, &scale);
148 x = (x - offset) / scale;
149 return (ipow(x, n));
150}
151
152/**
153 * @brief Evaluate the derivative of x^n.
154 *
155 * This function returns d/dx [ (x - x_offset)/x_scale ]^n = n * ((x - x_offset)/x_scale)^(n-1) / x_scale.
156 *
157 * @param x The point at which to evaluate the derivative.
158 * @param n The exponent.
159 * @return The derivative of the power function at the given x.
160 */
161double dipower(double x, long n) {
162 double offset, scale;
163 get_argument_transform(&offset, &scale);
164 x = (x - offset) / scale;
165 return (n * ipow(x, n - 1));
166}
167
168/**
169 * @brief Evaluate a sum of basis functions.
170 *
171 * Given a pointer to a function that evaluates a basis function fn(x,order),
172 * this function computes the weighted sum of these functions at x0 using the provided coefficients.
173 *
174 * @param fn A pointer to the basis function to evaluate (fn(x, order)).
175 * @param coef An array of coefficients for each basis function.
176 * @param order An array of orders corresponding to each coefficient.
177 * @param n_coefs The number of coefficients (and basis functions).
178 * @param x0 The point at which to evaluate the sum.
179 * @return The computed sum of the basis functions.
180 */
181double eval_sum(double (*fn)(double x, long ord), double *coef, int32_t *order,
182 long n_coefs, double x0) {
183 double sum = 0;
184 long i;
185
186 for (i = sum = 0; i < n_coefs; i++)
187 sum += (fn)(x0, order[i]) * coef[i];
188 return (sum);
189}
void bomb(char *error, char *usage)
Reports error messages to the terminal and aborts the program.
Definition bomb.c:26
double ipow(const double x, const int64_t p)
Compute x raised to the power p (x^p).
Definition ipow.c:33
void set_argument_scale(double scale)
Set the scale factor applied to the input argument of basis functions.
Definition lsfBasisFns.c:56
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.
Definition lsfBasisFns.c:42
double ipower(double x, long n)
Evaluate a power function x^n.
double get_argument_offset()
Get the current argument offset applied before function evaluations.
Definition lsfBasisFns.c:69
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 get_argument_scale()
Get the current argument scale factor used before function evaluations.
Definition lsfBasisFns.c:82
double eval_sum(double(*fn)(double x, long ord), double *coef, int32_t *order, long n_coefs, double x0)
Evaluate a sum of basis functions.