TPCCLIB
Loading...
Searching...
No Matches
constraints.c File Reference

Setting and checking fit parameter constraints and limits. More...

#include "libtpcmodel.h"

Go to the source code of this file.

Functions

int modelCheckParameters (int par_nr, double *lower_p, double *upper_p, double *test_p, double *accept_p, double *penalty)
 
int modelCheckLimits (int par_nr, double *lower_p, double *upper_p, double *test_p)
 
int fitExpDecayNNLS (double *x, double *y, int n, double fittime, double kmin, double kmax, int pnr, double *a, double *k, int *fnr, int verbose)
 Estimate initial values for sum of exponentials to be fitted on decaying x,y-data.
 

Detailed Description

Setting and checking fit parameter constraints and limits.

Author
Vesa Oikonen

Definition in file constraints.c.

Function Documentation

◆ fitExpDecayNNLS()

int fitExpDecayNNLS ( double * x,
double * y,
int n,
double fittime,
double kmin,
double kmax,
int pnr,
double * a,
double * k,
int * fnr,
int verbose )

Estimate initial values for sum of exponentials to be fitted on decaying x,y-data.

Returns
0 when successful, otherwise <>0.
Parameters
xPointer to array of x values; must not contain NaNs; data is not changed; samples must be sorted by increasing x.
yPointer to array of y values; must not contain NaNs; data is not changed.
nNr of x and y samples (x and y array lengths); data is not changed.
fittimeFittime is usually set to <=0 or a very high value to start the search for the best line fit from the last x,y sample towards the first sample; However, to exclude the end phase you may want to set fittime to include only certain time range from the beginning.
kminMinimum eigenvalue, must be >0; for example, 1.0E-06.
kmaxMaximum eigenvalue; for example, 1.0E+03.
pnrMax number of exp functions to save; length of a[] and k[] arrays.
aPointer to an array of length pnr where exp function coefficients will be written; enter NULL if not needed.
kPointer to an array of length pnr where exp function eigenvalues will be written; enter NULL if not needed.
fnrThe number of fitted exponentials will be written in here; note that this number may be higher than pnr; enter NULL if not needed.
verboseVerbose level; if zero, then nothing is printed to stderr or stdout

Definition at line 100 of file constraints.c.

130 {
131 if(verbose>0)
132 printf("fitExpDecayNNLS(x, y, %d, %g, %g, %g, ...)\n", n, fittime, kmin, kmax);
133 if(n<3) return(1);
134 if(fittime>0.0) {
135 while(x[n-1]>fittime && n>0) n--;
136 if(verbose>1) printf(" n := %d\n", n);
137 }
138 if(kmin<1.0E-100) kmin=1.0E-100;
139 if(kmax<=kmin) return(1);
140
141 /* Allocate memory for NNLS */
142 int NNLS_N=100;
143 int nn, mm, nnls_n, nnls_m, nnls_index[NNLS_N];
144 double *nnls_a[NNLS_N], *nnls_b, *nnls_zz, nnls_x[NNLS_N], *nnls_mat,
145 nnls_wp[NNLS_N], *dptr, nnls_rnorm;
146
147 nnls_n=NNLS_N;
148 nnls_m=n;
149 nnls_mat=(double*)malloc(((nnls_n+2)*nnls_m)*sizeof(double));
150 if(nnls_mat==NULL) return(2);
151 for(nn=0, dptr=nnls_mat; nn<nnls_n; nn++) {nnls_a[nn]=dptr; dptr+=nnls_m;}
152 nnls_b=dptr; dptr+=nnls_m; nnls_zz=dptr;
153
154 /* Set exponent function decay parameters */
155 double epar[NNLS_N];
156 {
157 double elnmin, elnmax;
158 elnmin=log(kmin); elnmax=log(kmax);
159 //double elnmin=-12.5, elnmax=6.7;
160 double d, r;
161 r=elnmax-elnmin;
162 d=r/(double)(NNLS_N-1);
163 for(nn=0; nn<nnls_n; nn++) epar[nn]=-exp(elnmin+(double)nn*d);
164 }
165
166 /* Fill NNLS matrix */
167 for(mm=0; mm<nnls_m; mm++) {
168 nnls_b[mm]=y[mm];
169 }
170 for(nn=0; nn<nnls_n; nn++)
171 for(mm=0; mm<nnls_m; mm++)
172 nnls_a[nn][mm]=exp(epar[nn]*x[mm]);
173
174 /* NNLS */
175 int ret;
176 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm,
177 nnls_wp, nnls_zz, nnls_index);
178 if(ret>1) {
179 if(verbose>0) fprintf(stderr, "Error: NNLS solution not possible.\n");
180 free(nnls_mat);
181 return(3);
182 } else if(ret==1) {
183 if(verbose>0) fprintf(stderr, "Warning: max iteration count exceeded in NNLS.\n");
184 }
185 if(verbose>2) {
186 printf("NNLS results:\n");
187 for(nn=0; nn<nnls_n; nn++)
188 printf("\t%e\t%g\t%g\n", epar[nn], nnls_x[nn], nnls_wp[nn]);
189 }
190 if(verbose>1) {
191 printf("Reasonable NNLS results:\n");
192 for(nn=0; nn<nnls_n; nn++)
193 if(nnls_wp[nn]==0.0) printf("\t%e\t%g\n", epar[nn], nnls_x[nn]);
194 }
195
196 /* Reset exponent function decay parameters with the clusters found above */
197 {
198 if(verbose>1) printf("Cluster means:\n");
199 int i, j, nr;
200 double ev;
201 i=j=0;
202 while(1) {
203 /* jump over functions with wp<0 */
204 while(i<nnls_n && nnls_wp[i]<0.0) i++;
205 if(i==nnls_n) break;
206 /* calculate mean of this cluster */
207 nr=0; ev=0.0;
208 while(i<nnls_n && nnls_wp[i]==0.0) {nr++; ev+=epar[i]; i++;}
209 ev/=(double)nr;
210 if(verbose>1) printf("mean_e := %e\n", ev);
211 epar[j++]=ev;
212 }
213 nnls_n=j;
214 }
215
216 /* Fill NNLS matrix with these functions */
217 for(mm=0; mm<nnls_m; mm++) {
218 nnls_b[mm]=y[mm];
219 }
220 for(nn=0; nn<nnls_n; nn++)
221 for(mm=0; mm<nnls_m; mm++)
222 nnls_a[nn][mm]=exp(epar[nn]*x[mm]);
223
224 /* NNLS */
225 ret=nnls(nnls_a, nnls_m, nnls_n, nnls_b, nnls_x, &nnls_rnorm,
226 nnls_wp, nnls_zz, nnls_index);
227 if(ret>1) {
228 if(verbose>0) fprintf(stderr, "Error: NNLS solution not possible.\n");
229 free(nnls_mat);
230 return(3);
231 } else if(ret==1) {
232 if(verbose>0) fprintf(stderr, "Warning: max iteration count exceeded in NNLS.\n");
233 }
234 if(verbose>1) {
235 printf("NNLS results:\n");
236 for(nn=0; nn<nnls_n; nn++)
237 printf("\t%e\t%g\t%g\n", epar[nn], nnls_x[nn], nnls_wp[nn]);
238 }
239
240 /* Return the results */
241 int nr=0;
242 for(nn=0; nn<nnls_n; nn++) {
243 if(nnls_wp[nn]<0.0) continue;
244 if(nr>=pnr) {nr++; continue;}
245 if(a!=NULL) a[nr]=nnls_x[nn];
246 if(k!=NULL) k[nr]=epar[nn];
247 nr++;
248 }
249 if(fnr!=NULL) *fnr=nr;
250
251 free(nnls_mat);
252 return(0);
253}
int nnls(double **a, int m, int n, double *b, double *x, double *rnorm, double *w, double *zz, int *index)
Definition nnls.c:38

◆ modelCheckLimits()

int modelCheckLimits ( int par_nr,
double * lower_p,
double * upper_p,
double * test_p )

Check if model parameters have collided with given limits.

If parameter is fixed (equal lower and upper limit) then it is not counted as collision.

Returns
Return the number of parameters that too close to the limits; 0 in case all are well inside the limits.
Parameters
par_nrNr of parameters
lower_pLower limits
upper_pUpper limits
test_pParameters to test

Definition at line 59 of file constraints.c.

68 {
69 int pi, collision_nr=0;
70 double range, range_factor=0.00001;
71
72 for(pi=0; pi<par_nr; pi++) {
73 // fixed parameters are not checked
74 range=upper_p[pi]-lower_p[pi]; if(range<=0.0) continue;
75 // if parameter exceeds the limit, then that is a collision for sure
76 if(test_p[pi]<=lower_p[pi]) {
77 collision_nr++; continue;
78 } else if(test_p[pi]>upper_p[pi]) {
79 collision_nr++; continue;
80 }
81 // but in addition, accepted range is a bit smaller than constrained range
82 // except if limit is 0, then it is ok that parameter is close to zero
83 range*=range_factor;
84 if(test_p[pi]<lower_p[pi]+range) {
85 if(fabs(lower_p[pi])>=1.0E-06) collision_nr++;
86 } else if(test_p[pi]>upper_p[pi]-range) {
87 if(fabs(upper_p[pi])>=1.0E-06) collision_nr++;
88 }
89 }
90 return collision_nr;
91}

◆ modelCheckParameters()

int modelCheckParameters ( int par_nr,
double * lower_p,
double * upper_p,
double * test_p,
double * accept_p,
double * penalty )

Check that model parameters are within given limits. If not, then compute a penalty factor.

Returns
Return the number of parameters that are inside or at the limits; 0 in case of error or if all are outside of the limits.
Parameters
par_nrNr of parameters
lower_pLower limits
upper_pUpper limits
test_pParameters to test
accept_pPointer to corrected parameters (NULL if not needed)
penaltyPointer to variable in which the possible penalty factor will be written; 1 if no penalty, or >1. Set to NULL if not needed.

Definition at line 15 of file constraints.c.

29 {
30 int pi, accept_nr=0;
31 double range;
32
33 if(penalty!=NULL) *penalty=1.0;
34 for(pi=0; pi<par_nr; pi++) {
35 range=upper_p[pi]-lower_p[pi]; if(range<=0.0) range=1.0;
36 if(test_p[pi]<lower_p[pi]) {
37 if(accept_p!=NULL) accept_p[pi]=lower_p[pi];
38 if(penalty!=NULL) *penalty += (lower_p[pi]-test_p[pi])/range;
39 } else if(test_p[pi]>upper_p[pi]) {
40 if(accept_p!=NULL) accept_p[pi]=upper_p[pi];
41 if(penalty!=NULL) *penalty += (test_p[pi]-upper_p[pi])/range;
42 } else {
43 if(accept_p!=NULL) accept_p[pi]=test_p[pi];
44 accept_nr++;
45 }
46 }
47 return accept_nr;
48}