eclipse 0.13.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. eclipse/__init__.py +95 -0
  2. eclipse/analysis.py +853 -0
  3. eclipse/atmosphere.py +859 -0
  4. eclipse/band.py +477 -0
  5. eclipse/cli.py +138 -0
  6. eclipse/config.py +1710 -0
  7. eclipse/continuum.py +413 -0
  8. eclipse/data/eis_response/EIS_EffArea_A.004 +61 -0
  9. eclipse/data/eis_response/EIS_EffArea_B.004 +60 -0
  10. eclipse/data/eis_response/EIS_EffArea_B.005 +64 -0
  11. eclipse/data/eis_response/README_dz2025 +50 -0
  12. eclipse/data/eis_response/fit_eis_ea_2023-05-04_smooth.sav +0 -0
  13. eclipse/data/eis_response/source.txt +33 -0
  14. eclipse/data/science_cases.yaml +365 -0
  15. eclipse/data/throughput/grating_reflection_efficiency.dat +25 -0
  16. eclipse/data/throughput/primary_mirror_coating_reflectance.dat +25 -0
  17. eclipse/data/throughput/source.txt +6 -0
  18. eclipse/data/throughput/throughput_aluminium_1000_angstrom.dat +503 -0
  19. eclipse/data/throughput/throughput_aluminium_oxide_1000_angstrom.dat +503 -0
  20. eclipse/data/throughput/throughput_carbon_1000_angstrom.dat +503 -0
  21. eclipse/data_processing.py +904 -0
  22. eclipse/deprecated.py +161 -0
  23. eclipse/eis_calibration.py +573 -0
  24. eclipse/extern/__init__.py +0 -0
  25. eclipse/extern/mpfit.py +2388 -0
  26. eclipse/fitting.py +1734 -0
  27. eclipse/frame.py +594 -0
  28. eclipse/full_frame.py +944 -0
  29. eclipse/main.py +1646 -0
  30. eclipse/monte_carlo.py +660 -0
  31. eclipse/pinhole_diffraction.py +409 -0
  32. eclipse/psf.py +6 -0
  33. eclipse/radiometric.py +1328 -0
  34. eclipse/raster.py +869 -0
  35. eclipse/readout.py +1002 -0
  36. eclipse/resolution_budget.py +108 -0
  37. eclipse/results_file.py +1226 -0
  38. eclipse/sampling.py +351 -0
  39. eclipse/science_cases.py +364 -0
  40. eclipse/synthesis.py +2492 -0
  41. eclipse/synthesis_cli.py +12 -0
  42. eclipse/synthesis_file.py +882 -0
  43. eclipse/utils.py +1145 -0
  44. eclipse-0.13.0.dist-info/METADATA +70 -0
  45. eclipse-0.13.0.dist-info/RECORD +50 -0
  46. eclipse-0.13.0.dist-info/WHEEL +5 -0
  47. eclipse-0.13.0.dist-info/entry_points.txt +7 -0
  48. eclipse-0.13.0.dist-info/licenses/LICENSE +3 -0
  49. eclipse-0.13.0.dist-info/top_level.txt +2 -0
  50. euvst_response/__init__.py +129 -0
@@ -0,0 +1,2388 @@
1
+ """
2
+ Perform Levenberg-Marquardt least-squares minimization, based on MINPACK-1.
3
+
4
+ AUTHORS
5
+ -------
6
+ The original version of this software, called LMFIT, was written in FORTRAN
7
+ as part of the MINPACK-1 package by XXX.
8
+
9
+ Craig Markwardt converted the FORTRAN code to IDL.
10
+ The information for the IDL version is:
11
+ Craig B. Markwardt, NASA/GSFC Code 662, Greenbelt, MD 20770
12
+ craigm@lheamail.gsfc.nasa.gov
13
+ UPDATED VERSIONs can be found on my WEB PAGE:
14
+ http://cow.physics.wisc.edu/~craigm/idl/idl.html
15
+
16
+ Mark Rivers created this Python version from Craig's IDL version.
17
+ Mark Rivers, University of Chicago
18
+ Building 434A, Argonne National Laboratory
19
+ 9700 South Cass Avenue, Argonne, IL 60439
20
+ rivers@cars.uchicago.edu
21
+ Updated versions can be found at:
22
+ http://cars.uchicago.edu/software
23
+
24
+ Sergey Koposov converted the Mark's Python version from Numeric to numpy
25
+ Sergey Koposov, University of Cambridge, Institute of Astronomy,
26
+ Madingley road, CB3 0HA, Cambridge, UK
27
+ koposov@ast.cam.ac.uk
28
+ Updated versions can be found at:
29
+ https://github.com/segasai/astrolibpy
30
+
31
+ DESCRIPTION
32
+ -----------
33
+
34
+ MPFIT uses the Levenberg-Marquardt technique to solve the least-squares
35
+ problem. In its typical use, MPFIT will be used to fit a user-supplied
36
+ function (the "model") to user-supplied data points (the "data") by
37
+ adjusting a set of parameters. MPFIT is based upon MINPACK-1 (LMDIF.F)
38
+ by More' and collaborators.
39
+
40
+ For example, a researcher may think that a set of observed data points
41
+ is best modelled with a Gaussian curve. A Gaussian curve is parameterized
42
+ by its mean, standard deviation and normalization. MPFIT will, within
43
+ certain constraints, find the set of parameters which best fits the data.
44
+ The fit is "best" in the least-squares sense; that is, the sum of the
45
+ weighted squared differences between the model and data is minimized.
46
+
47
+ The Levenberg-Marquardt technique is a particular strategy for iteratively
48
+ searching for the best fit. This particular implementation is drawn from
49
+ MINPACK-1 (see NETLIB), and is much faster and more accurate than the
50
+ version provided in the Scientific Python package in
51
+ Scientific.Functions.LeastSquares. This version allows upper and lower
52
+ bounding constraints to be placed on each parameter, or the parameter can
53
+ be held fixed.
54
+
55
+ The user-supplied Python function should return an array of weighted
56
+ deviations between model and data. In a typical scientific problem the
57
+ residuals should be weighted so that each deviate has a gaussian sigma
58
+ of 1.0. If X represents values of the independent variable, Y represents
59
+ a measurement for each value of X, and ERR represents the error in the
60
+ measurements, then the deviates could be calculated as follows:
61
+
62
+ DEVIATES = (Y - F(X)) / ERR
63
+
64
+ where F is the analytical function representing the model. You are
65
+ recommended to use the convenience functions MPFITFUN and MPFITEXPR,
66
+ which are driver functions that calculate the deviates for you.
67
+ If ERR are the 1-sigma uncertainties in Y, then
68
+
69
+ TOTAL( DEVIATES^2 )
70
+
71
+ will be the total chi-squared value. MPFIT will minimize the chi-square
72
+ value. The values of X, Y and ERR are passed through MPFIT to the
73
+ user-supplied function via the FUNCTKW keyword.
74
+
75
+ Simple constraints can be placed on parameter values by using the
76
+ PARINFO keyword to MPFIT. See below for a description of this keyword.
77
+
78
+ MPFIT does not perform more general optimization tasks. See TNMIN
79
+ instead. MPFIT is customized, based on MINPACK-1, to the least-squares
80
+ minimization problem.
81
+
82
+
83
+ USER FUNCTION
84
+ -------------
85
+
86
+ The user must define a function which returns the appropriate values
87
+ as specified above. The function should return the weighted deviations
88
+ between the model and the data. It should also return a status flag
89
+ and an optional partial derivative array. For applications which use
90
+ finite-difference derivatives -- the default -- the user function should
91
+ be declared in the following way:
92
+
93
+ def myfunct(p, fjac=None, x=None, y=None, err=None)
94
+ # Parameter values are passed in "p"
95
+ # If fjac==None then partial derivatives should not be
96
+ # computed. It will always be None if MPFIT is called with
97
+ # default flag.
98
+ model = F(x, p)
99
+ # Non-negative status value means MPFIT should continue,
100
+ # negative means stop the calculation.
101
+ status = 0
102
+ return([status, (y-model)/err]
103
+
104
+ See below for applications with analytical derivatives.
105
+
106
+ The keyword parameters X, Y, and ERR in the example above are suggestive
107
+ but not required. Any parameters can be passed to MYFUNCT by using the
108
+ functkw keyword to MPFIT. Use MPFITFUN and MPFITEXPR if you need ideas
109
+ on how to do that. The function *must* accept a parameter list, P.
110
+
111
+ In general there are no restrictions on the number of dimensions in X, Y,
112
+ or ERR. However the deviates *must* be returned in a one-dimensional
113
+ Numeric array of type Float.
114
+
115
+ User functions may also indicate a fatal error condition using the status
116
+ return described above. If status is set to a number between -15 and -1
117
+ then MPFIT will stop the calculation and return to the caller.
118
+
119
+
120
+ ANALYTIC DERIVATIVES
121
+ --------------------
122
+
123
+ In the search for the best-fit solution, MPFIT by default calculates
124
+ derivatives numerically via a finite difference approximation. The
125
+ user-supplied function need not calculate the derivatives explicitly.
126
+ However, if you desire to compute them analytically, then the
127
+ AUTODERIVATIVE=0 keyword must be passed to MPFIT. As a practical matter,
128
+ it is often sufficient and even faster to allow MPFIT to calculate the
129
+ derivatives numerically, and so AUTODERIVATIVE=0 is not necessary.
130
+
131
+ If AUTODERIVATIVE=0 is used then the user function must check the parameter
132
+ FJAC, and if FJAC!=None then return the partial derivative array in the
133
+ return list.
134
+
135
+ def myfunct(p, fjac=None, x=None, y=None, err=None)
136
+ # Parameter values are passed in "p"
137
+ # If FJAC!=None then partial derivatives must be comptuer.
138
+ # FJAC contains an array of len(p), where each entry
139
+ # is 1 if that parameter is free and 0 if it is fixed.
140
+ model = F(x, p)
141
+ # Non-negative status value means MPFIT should continue,
142
+ # negative means stop the calculation.
143
+ status = 0
144
+ if (dojac):
145
+ pderiv = zeros([len(x), len(p)], Float)
146
+ for j in range(len(p)):
147
+ pderiv[:,j] = FGRAD(x, p, j)
148
+ else:
149
+ pderiv = None
150
+ return([status, (y-model)/err, pderiv]
151
+
152
+ where FGRAD(x, p, i) is a user function which must compute the derivative
153
+ of the model with respect to parameter P[i] at X. When finite differencing
154
+ is used for computing derivatives (i.e., when AUTODERIVATIVE=1), or when
155
+ MPFIT needs only the errors but not the derivatives the parameter
156
+ FJAC=None.
157
+
158
+ Derivatives should be returned in the PDERIV array. PDERIV should be an
159
+ MxN array, where M is the number of data points and N is the number of
160
+ parameters. dp[i,j] is the derivative at the ith point with respect to
161
+ the jth parameter.
162
+
163
+ The derivatives with respect to fixed parameters are ignored; zero is an
164
+ appropriate value to insert for those derivatives. Upon input to the user
165
+ function, FJAC is set to a vector with the same length as P, with a value
166
+ of 1 for a parameter which is free, and a value of zero for a parameter
167
+ which is fixed (and hence no derivative needs to be calculated).
168
+
169
+ If the data is higher than one dimensional, then the *last* dimension
170
+ should be the parameter dimension.
171
+ Example: fitting a 50x50 image, "dp" should be 50x50xNPAR.
172
+
173
+
174
+ CONSTRAINING PARAMETER VALUES WITH THE PARINFO KEYWORD
175
+ ------------------------------------------------------
176
+
177
+ The behavior of MPFIT can be modified with respect to each parameter to
178
+ be fitted. A parameter value can be fixed; simple boundary constraints
179
+ can be imposed; limitations on the parameter changes can be imposed;
180
+ properties of the automatic derivative can be modified; and parameters
181
+ can be tied to one another.
182
+
183
+ These properties are governed by the PARINFO structure, which is passed
184
+ as a keyword parameter to MPFIT.
185
+
186
+ PARINFO should be a list of dictionaries, one list entry for each
187
+ parameter. Each parameter is associated with one element of the array,
188
+ in numerical order. The dictionary can have the following keys (none
189
+ are required, keys are case insensitive):
190
+
191
+ 'value' - the starting parameter value (but see the START_PARAMS
192
+ parameter for more information).
193
+
194
+ 'fixed' - a boolean value, whether the parameter is to be held
195
+ fixed or not. Fixed parameters are not varied by MPFIT, but are
196
+ passed on to MYFUNCT for evaluation.
197
+
198
+ 'limited' - a two-element boolean array. If the first/second element
199
+ is set, then the parameter is bounded on the lower/upper side.
200
+ A parameter can be bounded on both sides. Both LIMITED and LIMITS
201
+ must be given together.
202
+
203
+ 'limits' - a two-element float array. Gives the parameter limits
204
+ on the lower and upper sides, respectively. Zero, one or two of
205
+ these values can be set, depending on the values of LIMITED.
206
+ Both LIMITED and LIMITS must be given together.
207
+
208
+ 'parname' - a string, giving the name of the parameter. The fitting
209
+ code of MPFIT does not use this tag in any way. However, the
210
+ default iterfunct will print the parameter name if available.
211
+
212
+ 'step' - the step size to be used in calculating the numerical
213
+ derivatives. If set to zero, then the step size is computed
214
+ automatically. Ignored when AUTODERIVATIVE=0.
215
+
216
+ 'mpside' - the sidedness of the finite difference when computing
217
+ numerical derivatives. This field can take four values:
218
+
219
+ 0 - one-sided derivative computed automatically
220
+ 1 - one-sided derivative (f(x+h) - f(x))/h
221
+ -1 - one-sided derivative (f(x) - f(x-h))/h
222
+ 2 - two-sided derivative (f(x+h) - f(x-h))/(2*h)
223
+
224
+ Where H is the STEP parameter described above. The "automatic"
225
+ one-sided derivative method will chose a direction for the
226
+ finite difference which does not violate any constraints. The
227
+ other methods do not perform this check. The two-sided method
228
+ is in principle more precise, but requires twice as many
229
+ function evaluations. Default: 0.
230
+
231
+ 'mpmaxstep' - the maximum change to be made in the parameter value.
232
+ During the fitting process, the parameter will never be changed
233
+ by more than this value in one iteration. A value of 0 indicates
234
+ no maximum. Default: 0.
235
+
236
+ 'tied' - a string expression which "ties" the parameter to other
237
+ free or fixed parameters. Any expression involving constants and
238
+ the parameter array P are permitted. Example: if parameter 2 is
239
+ always to be twice parameter 1 then use the following:
240
+ parinfo(2).tied = '2 * p(1)'.
241
+ Since they are totally constrained, tied parameters are considered
242
+ to be fixed; no errors are computed for them. NOTE: the PARNAME
243
+ can't be used in expressions.
244
+
245
+ 'mpprint' - if set to 1, then the default iterfunct will print the
246
+ parameter value. If set to 0, the parameter value will not be
247
+ printed. This tag can be used to selectively print only a few
248
+ parameter values out of many. Default: 1 (all parameters printed)
249
+
250
+ Future modifications to the PARINFO structure, if any, will involve
251
+ adding dictionary tags beginning with the two letters "MP". Therefore
252
+ programmers are urged to avoid using tags starting with the same letters;
253
+ otherwise they are free to include their own fields within the PARINFO
254
+ structure, and they will be ignored.
255
+
256
+ PARINFO Example:
257
+ parinfo = [{'value':0., 'fixed':0, 'limited':[0,0],
258
+ 'limits':[0.,0.]} for i in range(5)]
259
+ parinfo[0]['fixed'] = 1
260
+ parinfo[4]['limited'][0] = 1
261
+ parinfo[4]['limits'][0] = 50.
262
+ values = [5.7, 2.2, 500., 1.5, 2000.]
263
+ for i in range(5):
264
+ parinfo[i]['value']=values[i]
265
+
266
+ A total of 5 parameters, with starting values of 5.7, 2.2, 500, 1.5,
267
+ and 2000 are given. The first parameter is fixed at a value of 5.7,
268
+ and the last parameter is constrained to be above 50.
269
+
270
+ EXAMPLE
271
+ -------
272
+
273
+ import mpfit
274
+ import numpy.oldnumeric as Numeric
275
+ x = arange(100, float)
276
+ p0 = [5.7, 2.2, 500., 1.5, 2000.]
277
+ y = (p[0] + p[1]*[x] + p[2]*[x**2] + p[3]*sqrt(x) +
278
+ p[4]*log(x))
279
+ fa = {'x':x, 'y':y, 'err':err}
280
+ m = mpfit('myfunct', p0, functkw=fa)
281
+ print 'status = ', m.status
282
+ if (m.status <= 0):
283
+ print 'error message = ', m.errmsg
284
+ print 'parameters = ', m.params
285
+
286
+ Minimizes sum of squares of MYFUNCT. MYFUNCT is called with the X, Y,
287
+ and ERR keyword parameters that are given by FUNCTKW. The results can
288
+ be obtained from the returned object m.
289
+
290
+ THEORY OF OPERATION
291
+ -------------------
292
+
293
+ There are many specific strategies for function minimization. One very
294
+ popular technique is to use function gradient information to realize the
295
+ local structure of the function. Near a local minimum the function value
296
+ can be taylor expanded about x0 as follows:
297
+
298
+ f(x) = f(x0) + f'(x0) . (x-x0) + (1/2) (x-x0) . f''(x0) . (x-x0)
299
+ ----- --------------- ------------------------------- (1)
300
+ Order 0th 1st 2nd
301
+
302
+ Here f'(x) is the gradient vector of f at x, and f''(x) is the Hessian
303
+ matrix of second derivatives of f at x. The vector x is the set of
304
+ function parameters, not the measured data vector. One can find the
305
+ minimum of f, f(xm) using Newton's method, and arrives at the following
306
+ linear equation:
307
+
308
+ f''(x0) . (xm-x0) = - f'(x0) (2)
309
+
310
+ If an inverse can be found for f''(x0) then one can solve for (xm-x0),
311
+ the step vector from the current position x0 to the new projected minimum.
312
+ Here the problem has been linearized (ie, the gradient information is known
313
+ to first order). f''(x0) is symmetric n x n matrix, and should be positive
314
+ definite.
315
+
316
+ The Levenberg-Marquardt technique is a variation on this theme. It adds an
317
+ additional diagonal term to the equation which may aid the convergence
318
+ properties:
319
+
320
+ (f''(x0) + nu I) . (xm-x0) = -f'(x0) (2a)
321
+
322
+ where I is the identity matrix. When nu is large, the overall matrix is
323
+ diagonally dominant, and the iterations follow steepest descent. When nu
324
+ is small, the iterations are quadratically convergent.
325
+
326
+ In principle, if f''(x0) and f'(x0) are known then xm-x0 can be determined.
327
+ However the Hessian matrix is often difficult or impossible to compute.
328
+ The gradient f'(x0) may be easier to compute, if even by finite difference
329
+ techniques. So-called quasi-Newton techniques attempt to successively
330
+ estimate f''(x0) by building up gradient information as the iterations
331
+ proceed.
332
+
333
+ In the least squares problem there are further simplifications which assist
334
+ in solving eqn (2). The function to be minimized is a sum of squares:
335
+
336
+ f = Sum(hi^2) (3)
337
+
338
+ where hi is the ith residual out of m residuals as described above.
339
+ This can be substituted back into eqn (2) after computing the derivatives:
340
+
341
+ f' = 2 Sum(hi hi')
342
+ f'' = 2 Sum(hi' hj') + 2 Sum(hi hi'') (4)
343
+
344
+ If one assumes that the parameters are already close enough to a minimum,
345
+ then one typically finds that the second term in f'' is negligible (or,
346
+ in any case, is too difficult to compute). Thus, equation (2) can be solved,
347
+ at least approximately, using only gradient information.
348
+
349
+ In matrix notation, the combination of eqns (2) and (4) becomes:
350
+
351
+ hT' . h' . dx = - hT' . h (5)
352
+
353
+ Where h is the residual vector (length m), hT is its transpose, h' is the
354
+ Jacobian matrix (dimensions n x m), and dx is (xm-x0). The user function
355
+ supplies the residual vector h, and in some cases h' when it is not found
356
+ by finite differences (see MPFIT_FDJAC2, which finds h and hT'). Even if
357
+ dx is not the best absolute step to take, it does provide a good estimate
358
+ of the best *direction*, so often a line minimization will occur along the
359
+ dx vector direction.
360
+
361
+ The method of solution employed by MINPACK is to form the Q . R
362
+ factorization of h', where Q is an orthogonal matrix such that QT . Q = I,
363
+ and R is upper right triangular. Using h' = Q . R and the ortogonality of
364
+ Q, eqn (5) becomes
365
+
366
+ (RT . QT) . (Q . R) . dx = - (RT . QT) . h
367
+ RT . R . dx = - RT . QT . h (6)
368
+ R . dx = - QT . h
369
+
370
+ where the last statement follows because R is upper triangular. Here, R,
371
+ QT, and h are known so this is a matter of solving for dx. The routine
372
+ MPFIT_QRFAC provides the QR factorization of h, with pivoting, and
373
+ MPFIT_QRSOLV provides the solution for dx.
374
+
375
+ REFERENCES
376
+ ----------
377
+
378
+ MINPACK-1, Jorge More', available from netlib (www.netlib.org).
379
+ "Optimization Software Guide," Jorge More' and Stephen Wright,
380
+ SIAM, *Frontiers in Applied Mathematics*, Number 14.
381
+ More', Jorge J., "The Levenberg-Marquardt Algorithm: Implementation
382
+ and Theory," in *Numerical Analysis*, ed. Watson, G. A., Lecture
383
+ Notes in Mathematics 630, Springer-Verlag, 1977.
384
+
385
+ MODIFICATION HISTORY
386
+ --------------------
387
+
388
+ Translated from MINPACK-1 in FORTRAN, Apr-Jul 1998, CM
389
+ Copyright (C) 1997-2002, Craig Markwardt
390
+ This software is provided as is without any warranty whatsoever.
391
+ Permission to use, copy, modify, and distribute modified or unmodified
392
+ copies is granted, provided this copyright and disclaimer are included
393
+ unchanged.
394
+
395
+ Translated from MPFIT (Craig Markwardt's IDL package) to Python,
396
+ August, 2002. Mark Rivers
397
+ Converted from Numeric to numpy (Sergey Koposov, July 2008)
398
+ Added full Python 3 compatibility (Sergey Koposov, Feb 2017)
399
+ """
400
+
401
+ __all__ = ['mpfit']
402
+
403
+ import numpy
404
+ import types
405
+ import scipy.linalg.blas
406
+
407
+ # Original FORTRAN documentation
408
+ # **********
409
+ #
410
+ # subroutine lmdif
411
+ #
412
+ # the purpose of lmdif is to minimize the sum of the squares of
413
+ # m nonlinear functions in n variables by a modification of
414
+ # the levenberg-marquardt algorithm. the user must provide a
415
+ # subroutine which calculates the functions. the jacobian is
416
+ # then calculated by a forward-difference approximation.
417
+ #
418
+ # the subroutine statement is
419
+ #
420
+ # subroutine lmdif(fcn,m,n,x,fvec,ftol,xtol,gtol,maxfev,epsfcn,
421
+ # diag,mode,factor,nprint,info,nfev,fjac,
422
+ # ldfjac,ipvt,qtf,wa1,wa2,wa3,wa4)
423
+ #
424
+ # where
425
+ #
426
+ # fcn is the name of the user-supplied subroutine which
427
+ # calculates the functions. fcn must be declared
428
+ # in an external statement in the user calling
429
+ # program, and should be written as follows.
430
+ #
431
+ # subroutine fcn(m,n,x,fvec,iflag)
432
+ # integer m,n,iflag
433
+ # double precision x(n),fvec(m)
434
+ # ----------
435
+ # calculate the functions at x and
436
+ # return this vector in fvec.
437
+ # ----------
438
+ # return
439
+ # end
440
+ #
441
+ # the value of iflag should not be changed by fcn unless
442
+ # the user wants to terminate execution of lmdif.
443
+ # in this case set iflag to a negative integer.
444
+ #
445
+ # m is a positive integer input variable set to the number
446
+ # of functions.
447
+ #
448
+ # n is a positive integer input variable set to the number
449
+ # of variables. n must not exceed m.
450
+ #
451
+ # x is an array of length n. on input x must contain
452
+ # an initial estimate of the solution vector. on output x
453
+ # contains the final estimate of the solution vector.
454
+ #
455
+ # fvec is an output array of length m which contains
456
+ # the functions evaluated at the output x.
457
+ #
458
+ # ftol is a nonnegative input variable. termination
459
+ # occurs when both the actual and predicted relative
460
+ # reductions in the sum of squares are at most ftol.
461
+ # therefore, ftol measures the relative error desired
462
+ # in the sum of squares.
463
+ #
464
+ # xtol is a nonnegative input variable. termination
465
+ # occurs when the relative error between two consecutive
466
+ # iterates is at most xtol. therefore, xtol measures the
467
+ # relative error desired in the approximate solution.
468
+ #
469
+ # gtol is a nonnegative input variable. termination
470
+ # occurs when the cosine of the angle between fvec and
471
+ # any column of the jacobian is at most gtol in absolute
472
+ # value. therefore, gtol measures the orthogonality
473
+ # desired between the function vector and the columns
474
+ # of the jacobian.
475
+ #
476
+ # maxfev is a positive integer input variable. termination
477
+ # occurs when the number of calls to fcn is at least
478
+ # maxfev by the end of an iteration.
479
+ #
480
+ # epsfcn is an input variable used in determining a suitable
481
+ # step length for the forward-difference approximation. this
482
+ # approximation assumes that the relative errors in the
483
+ # functions are of the order of epsfcn. if epsfcn is less
484
+ # than the machine precision, it is assumed that the relative
485
+ # errors in the functions are of the order of the machine
486
+ # precision.
487
+ #
488
+ # diag is an array of length n. if mode = 1 (see
489
+ # below), diag is internally set. if mode = 2, diag
490
+ # must contain positive entries that serve as
491
+ # multiplicative scale factors for the variables.
492
+ #
493
+ # mode is an integer input variable. if mode = 1, the
494
+ # variables will be scaled internally. if mode = 2,
495
+ # the scaling is specified by the input diag. other
496
+ # values of mode are equivalent to mode = 1.
497
+ #
498
+ # factor is a positive input variable used in determining the
499
+ # initial step bound. this bound is set to the product of
500
+ # factor and the euclidean norm of diag*x if nonzero, or else
501
+ # to factor itself. in most cases factor should lie in the
502
+ # interval (.1,100.). 100. is a generally recommended value.
503
+ #
504
+ # nprint is an integer input variable that enables controlled
505
+ # printing of iterates if it is positive. in this case,
506
+ # fcn is called with iflag = 0 at the beginning of the first
507
+ # iteration and every nprint iterations thereafter and
508
+ # immediately prior to return, with x and fvec available
509
+ # for printing. if nprint is not positive, no special calls
510
+ # of fcn with iflag = 0 are made.
511
+ #
512
+ # info is an integer output variable. if the user has
513
+ # terminated execution, info is set to the (negative)
514
+ # value of iflag. see description of fcn. otherwise,
515
+ # info is set as follows.
516
+ #
517
+ # info = 0 improper input parameters.
518
+ #
519
+ # info = 1 both actual and predicted relative reductions
520
+ # in the sum of squares are at most ftol.
521
+ #
522
+ # info = 2 relative error between two consecutive iterates
523
+ # is at most xtol.
524
+ #
525
+ # info = 3 conditions for info = 1 and info = 2 both hold.
526
+ #
527
+ # info = 4 the cosine of the angle between fvec and any
528
+ # column of the jacobian is at most gtol in
529
+ # absolute value.
530
+ #
531
+ # info = 5 number of calls to fcn has reached or
532
+ # exceeded maxfev.
533
+ #
534
+ # info = 6 ftol is too small. no further reduction in
535
+ # the sum of squares is possible.
536
+ #
537
+ # info = 7 xtol is too small. no further improvement in
538
+ # the approximate solution x is possible.
539
+ #
540
+ # info = 8 gtol is too small. fvec is orthogonal to the
541
+ # columns of the jacobian to machine precision.
542
+ #
543
+ # nfev is an integer output variable set to the number of
544
+ # calls to fcn.
545
+ #
546
+ # fjac is an output m by n array. the upper n by n submatrix
547
+ # of fjac contains an upper triangular matrix r with
548
+ # diagonal elements of nonincreasing magnitude such that
549
+ #
550
+ # t t t
551
+ # p *(jac *jac)*p = r *r,
552
+ #
553
+ # where p is a permutation matrix and jac is the final
554
+ # calculated jacobian. column j of p is column ipvt(j)
555
+ # (see below) of the identity matrix. the lower trapezoidal
556
+ # part of fjac contains information generated during
557
+ # the computation of r.
558
+ #
559
+ # ldfjac is a positive integer input variable not less than m
560
+ # which specifies the leading dimension of the array fjac.
561
+ #
562
+ # ipvt is an integer output array of length n. ipvt
563
+ # defines a permutation matrix p such that jac*p = q*r,
564
+ # where jac is the final calculated jacobian, q is
565
+ # orthogonal (not stored), and r is upper triangular
566
+ # with diagonal elements of nonincreasing magnitude.
567
+ # column j of p is column ipvt(j) of the identity matrix.
568
+ #
569
+ # qtf is an output array of length n which contains
570
+ # the first n elements of the vector (q transpose)*fvec.
571
+ #
572
+ # wa1, wa2, and wa3 are work arrays of length n.
573
+ #
574
+ # wa4 is a work array of length m.
575
+ #
576
+ # subprograms called
577
+ #
578
+ # user-supplied ...... fcn
579
+ #
580
+ # minpack-supplied ... dpmpar,enorm,fdjac2,,qrfac
581
+ #
582
+ # fortran-supplied ... dabs,dmax1,dmin1,dsqrt,mod
583
+ #
584
+ # argonne national laboratory. minpack project. march 1980.
585
+ # burton s. garbow, kenneth e. hillstrom, jorge j. more
586
+ #
587
+ # **********
588
+
589
+ class mpfit:
590
+ """
591
+ Perform Levenberg-Marquardt least-squares minimization, based on MINPACK-1.
592
+
593
+ Parameters
594
+ ----------
595
+ fcn : function
596
+ The function to be minimized. The function should return the weighted
597
+ deviations between the model and the data, as described above.
598
+
599
+ xall : array-like
600
+ An array of starting values for each of the parameters of the model.
601
+ The number of parameters should be fewer than the number of measurements.
602
+ This parameter is optional if the parinfo keyword is used (but see
603
+ parinfo). The parinfo keyword provides a mechanism to fix or constrain
604
+ individual parameters.
605
+
606
+ autoderivative : {1, 0}
607
+ If this is set (1), derivatives of the function will be computed
608
+ automatically via a finite differencing procedure. If not set (0),
609
+ then fcn must provide the (analytical) derivatives. To supply your
610
+ own analytical derivatives, explicitly pass autoderivative=0.
611
+ Default: set (=1)
612
+
613
+ ftol : float, optional
614
+ A nonnegative input variable. Termination occurs when both the actual
615
+ and predicted relative reductions in the sum of squares are at most
616
+ ftol (and status is accordingly set to 1 or 3). Therefore, ftol
617
+ measures the relative error desired in the sum of squares.
618
+ Default: 1E-10
619
+
620
+ functkw : dict, optional
621
+ A dictionary which contains the parameters to be passed to the
622
+ user-supplied function specified by fcn via the standard Python
623
+ keyword dictionary mechanism. This is the way you can pass additional
624
+ data to your user-supplied function without using global variables.
625
+
626
+ Consider the following example, if functkw =
627
+ {'xval':[1.,2.,3.], 'yval':[1.,4.,9.], 'errval':[1.,1.,1.]}
628
+ then the user-supplied function should be declared like this:
629
+ def myfunct(p, fjac=None, xval=None, yval=None, errval=None):
630
+
631
+ Default: {}, No extra parameters are passed to the function
632
+
633
+ gtol : float, optional
634
+ A nonnegative input variable. Termination occurs when the cosine of
635
+ the angle between fvec and any column of the jacobian is at most gtol
636
+ in absolute value (and status is accordingly set to 4). Therefore,
637
+ gtol measures the orthogonality desired between the function vector
638
+ and the columns of the jacobian.
639
+ Default: 1e-10
640
+
641
+ iterkw : dict, optional
642
+ The keyword arguments to be passed to iterfunct via the dictionary
643
+ keyword mechanism. This should be a dictionary and is similar in
644
+ operation to FUNCTKW.
645
+ Default: {}, No arguments are passed.
646
+
647
+ iterfunct : function
648
+ The name of a function to be called upon each NPRINT iteration of the
649
+ MPFIT routine. It should be declared in the following way:
650
+ def iterfunct(myfunct, p, iter, fnorm, functkw=None, parinfo=None,
651
+ quiet=0, dof=None, [iterkw keywords here])
652
+ # perform custom iteration update
653
+
654
+ iterfunct must accept all three keyword parameters (FUNCTKW, PARINFO
655
+ and QUIET).
656
+
657
+ myfunct - The user-supplied function to be minimized,
658
+ p - The current set of model parameters
659
+ iter - The iteration number
660
+ functkw - The arguments to be passed to myfunct.
661
+ fnorm - The chi-squared value.
662
+ quiet - Set when no textual output should be printed.
663
+ dof - The number of degrees of freedom, normally the number of
664
+ points less the number of free parameters.
665
+ See below for documentation of parinfo.
666
+
667
+ In implementation, iterfunct can perform updates to the terminal or
668
+ graphical user interface, to provide feedback while the fit proceeds.
669
+ If the fit is to be stopped for any reason, then iterfunct should return
670
+ a status value between -15 and -1. Otherwise it should return None
671
+ (e.g. no return statement) or 0. In principle, iterfunct should probably
672
+ not modify the parameter values, because it may interfere with the
673
+ algorithm's stability. In practice it is allowed. Set iterfunct=None
674
+ if there is no user-defined routine and you don't want the internal
675
+ default routine be called.
676
+
677
+ Default: an internal routine is used to print the parameter values.
678
+
679
+ maxiter : int, optional
680
+ The maximum number of iterations to perform. If the number is exceeded,
681
+ then the status value is set to 5 and MPFIT returns.
682
+ Default: 200 iterations
683
+
684
+ nocovar : {0, 1}
685
+ Set this keyword to prevent the calculation of the covariance matrix
686
+ before returning (see COVAR)
687
+ Default: clear (=0), The covariance matrix is returned
688
+
689
+ nprint : int, optional
690
+ The frequency with which iterfunct is called. A value of 1 indicates
691
+ that iterfunct is called with every iteration, while 2 indicates every
692
+ other iteration, etc. Note that several Levenberg-Marquardt attempts
693
+ can be made in a single iteration.
694
+ Default: 1
695
+
696
+ parinfo : list of dicts, optional
697
+ Provides a mechanism for more sophisticated constraints to be placed on
698
+ parameter values. When parinfo is not passed, then it is assumed that
699
+ all parameters are free and unconstrained. Values in parinfo are never
700
+ modified during a call to MPFIT. PARINFO should be a list of
701
+ dictionaries, one list entry for each parameter. The dictionary can
702
+ have the following keys (all keys are optional and case insensitive):
703
+
704
+ 'value' : float
705
+ the starting parameter value (see also the XALL parameter).
706
+
707
+ 'fixed' : {0, 1}
708
+ If set (1), the parameter value will be held fixed. Fixed
709
+ parameters are not varied by MPFIT, but are passed on to
710
+ MYFUNCT for evaluation.
711
+
712
+ 'limited' : two-element int array.
713
+ If the first/second element is set (1), then the parameter is
714
+ bounded on the lower/upper side. A parameter can be bounded
715
+ on both sides. Both LIMITED and LIMITS must be given together.
716
+
717
+ 'limits' : two-element float array.
718
+ Gives the parameter limits on the lower and upper sides,
719
+ respectively. A value will only be used as a limit if the
720
+ corresponding value of LIMITED is set (=1). Both LIMITED
721
+ and LIMITS must be given together.
722
+
723
+ 'parname' : str
724
+ Name of the parameter. The fitting code of MPFIT does not
725
+ use this tag in any way. However, the default iterfunct will
726
+ print the parameter name, if available.
727
+
728
+ 'step' : float
729
+ Step size to be used in calculating the numerical derivatives.
730
+ If set to zero, then the step size is computed automatically.
731
+ Ignored when AUTODERIVATIVE=0.
732
+
733
+ 'mpside' : {0, 1, -1, 2}
734
+ The sidedness of the finite difference when computing
735
+ numerical derivatives. This field can take four values:
736
+
737
+ 0 - one-sided derivative computed automatically
738
+ 1 - one-sided derivative (f(x+h) - f(x))/h
739
+ -1 - one-sided derivative (f(x) - f(x-h))/h
740
+ 2 - two-sided derivative (f(x+h) - f(x-h))/(2*h)
741
+
742
+ Where H is the STEP parameter described above. The "automatic"
743
+ one-sided derivative method will chose a direction for the
744
+ finite difference which does not violate any constraints. The
745
+ other methods do not perform this check. The two-sided method
746
+ is in principle more precise, but requires twice as many
747
+ function evaluations. Default: 0.
748
+
749
+ 'mpmaxstep' : float
750
+ The maximum change to be made in the parameter value.
751
+ During the fitting process, the parameter will never be changed
752
+ by more than this value in one iteration. A value of 0 indicates
753
+ no maximum. Default: 0.
754
+
755
+ 'tied' : str
756
+ String expression which "ties" the parameter to other free or
757
+ fixed parameters. Any expression involving constants and the
758
+ parameter array "P" are permitted. Example: if parameter 2 is
759
+ always to be twice parameter 1 then use the following:
760
+ parinfo[2].tied = '2 * p[1]'.
761
+ Since they are totally constrained, tied parameters are
762
+ considered to be fixed; no errors are computed for them.
763
+ NOTE: the PARNAME can't be used in expressions.
764
+
765
+ 'mpprint' : {1, 0}
766
+ If set to 1, then the default iterfunct will print the
767
+ parameter value. If set to 0, the parameter value will not
768
+ be printed. This tag can be used to selectively print only
769
+ a few parameter values out of many. Default: 1 (all
770
+ parameters printed)
771
+
772
+ Default value: None, All parameters are free and unconstrained.
773
+
774
+ quiet : {0, 1}
775
+ Set this keyword = 1 when no textual output should be printed by MPFIT
776
+
777
+ damp : float, optional
778
+ A scalar number, indicating the cut-off value of residuals where
779
+ "damping" will occur. Residuals with magnitudes greater than this
780
+ number will be replaced by their hyperbolic tangent. This partially
781
+ mitigates the so-called large residual problem inherent in
782
+ least-squares solvers (as for the test problem CURVI,
783
+ http://www.maxthis.com/curviex.htm). A value of 0 indicates no damping.
784
+ Note: DAMP doesn't work with autoderivative=0. Default: 0
785
+
786
+ xtol : float, optional
787
+ A nonnegative input variable. Termination occurs when the relative error
788
+ between two consecutive iterates is at most xtol (and status is
789
+ accordingly set to 2 or 3). Therefore, xtol measures the relative error
790
+ desired in the approximate solution. Default: 1E-10
791
+
792
+ Returns
793
+ -------
794
+ mpfit class object
795
+ The results are attributes of this class, e.g. mpfit.status,
796
+ mpfit.errmsg, mpfit.params, npfit.niter, mpfit.covar.
797
+
798
+ .status : int
799
+ An integer status code is returned. All values greater than zero
800
+ can represent success (however .status == 5 may indicate failure to
801
+ converge). It can have one of the following values:
802
+
803
+ -16
804
+ A parameter or function value has become infinite or an undefined
805
+ number. This is usually a consequence of numerical overflow in the
806
+ user's model function, which must be avoided.
807
+
808
+ -15 to -1
809
+ These are error codes that either MYFUNCT or iterfunct may return to
810
+ terminate the fitting process. Values from -15 to -1 are reserved
811
+ for the user functions and will not clash with MPFIT.
812
+
813
+ 0 Improper input parameters.
814
+
815
+ 1 Both actual and predicted relative reductions in the sum of squares
816
+ are at most ftol.
817
+
818
+ 2 Relative error between two consecutive iterates is at most xtol
819
+
820
+ 3 Conditions for status = 1 and status = 2 both hold.
821
+
822
+ 4 The cosine of the angle between fvec and any column of the jacobian
823
+ is at most gtol in absolute value.
824
+
825
+ 5 The maximum number of iterations has been reached.
826
+
827
+ 6 ftol is too small. No further reduction in the sum of squares is
828
+ possible.
829
+
830
+ 7 xtol is too small. No further improvement in the approximate solution
831
+ x is possible.
832
+
833
+ 8 gtol is too small. fvec is orthogonal to the columns of the jacobian
834
+ to machine precision.
835
+
836
+ .fnorm : float
837
+ The value of the summed squared residuals for the returned parameter
838
+ values.
839
+
840
+ .covar : array-like
841
+ The covariance matrix for the set of parameters returned by MPFIT.
842
+ The matrix is NxN where N is the number of parameters. The square root
843
+ of the diagonal elements gives the formal 1-sigma statistical errors on
844
+ the parameters if errors were treated "properly" in fcn.
845
+ Parameter errors are also returned in .perror.
846
+
847
+ To compute the correlation matrix, pcor, use this example:
848
+ cov = mpfit.covar
849
+ pcor = cov * 0.
850
+ for i in range(n):
851
+ for j in range(n):
852
+ pcor[i,j] = cov[i,j]/sqrt(cov[i,i]*cov[j,j])
853
+
854
+ If nocovar is set or MPFIT terminated abnormally, then .covar is set to
855
+ a scalar with value None.
856
+
857
+ .errmsg : str
858
+ A string error or warning message is returned.
859
+
860
+ .nfev : int
861
+ The number of calls to MYFUNCT performed.
862
+
863
+ .niter : int
864
+ The number of iterations completed.
865
+
866
+ .perror : array-like
867
+ The formal 1-sigma errors in each parameter, computed from the
868
+ covariance matrix. If a parameter is held fixed, or if it touches a
869
+ boundary, then the error is reported as zero.
870
+
871
+ If the fit is unweighted (i.e. no errors were given, or the weights
872
+ were uniformly set to unity), then .perror will probably not represent
873
+ the true parameter uncertainties.
874
+
875
+ *If* you can assume that the true reduced chi-squared value is unity --
876
+ meaning that the fit is implicitly assumed to be of good quality --
877
+ then the estimated parameter uncertainties can be computed by scaling
878
+ .perror by the measured chi-squared value.
879
+
880
+ dof = len(x) - len(mpfit.params) # deg of freedom
881
+ # scaled uncertainties
882
+ pcerror = mpfit.perror * sqrt(mpfit.fnorm / dof)
883
+ """
884
+ blas_enorm32, = scipy.linalg.blas.get_blas_funcs(['nrm2'],numpy.array([0],dtype=numpy.float32))
885
+ blas_enorm64, = scipy.linalg.blas.get_blas_funcs(['nrm2'],numpy.array([0],dtype=numpy.float64))
886
+
887
+
888
+ def __init__(self, fcn, xall=None, functkw={}, parinfo=None,
889
+ ftol=1.e-10, xtol=1.e-10, gtol=1.e-10,
890
+ damp=0., maxiter=200, factor=100., nprint=1,
891
+ iterfunct='default', iterkw={}, nocovar=0,
892
+ rescale=0, autoderivative=1, quiet=0,
893
+ diag=None, epsfcn=None, debug=0):
894
+
895
+ self.niter = 0
896
+ self.params = None
897
+ self.covar = None
898
+ self.perror = None
899
+ self.status = 0 # Invalid input flag set while we check inputs
900
+ self.debug = debug
901
+ self.errmsg = ''
902
+ self.nfev = 0
903
+ self.damp = damp
904
+ self.dof=0
905
+
906
+ if fcn==None:
907
+ self.errmsg = "Usage: parms = mpfit('myfunt', ... )"
908
+ return
909
+
910
+ if iterfunct == 'default':
911
+ iterfunct = self.defiter
912
+
913
+ # Parameter damping doesn't work when user is providing their own
914
+ # gradients.
915
+ if (self.damp != 0) and (autoderivative == 0):
916
+ self.errmsg = 'ERROR: keywords DAMP and AUTODERIVATIVE are mutually exclusive'
917
+ return
918
+
919
+ # Parameters can either be stored in parinfo, or x. x takes precedence if it exists
920
+ if (xall is None) and (parinfo is None):
921
+ self.errmsg = 'ERROR: must pass parameters in P or PARINFO'
922
+ return
923
+
924
+ # Be sure that PARINFO is of the right type
925
+ if parinfo is not None:
926
+ if type(parinfo) is not list:
927
+ self.errmsg = 'ERROR: PARINFO must be a list of dictionaries.'
928
+ return
929
+ else:
930
+ if type(parinfo[0]) is not dict:
931
+ self.errmsg = 'ERROR: PARINFO must be a list of dictionaries.'
932
+ return
933
+ if ((xall is not None) and (len(xall) != len(parinfo))):
934
+ self.errmsg = 'ERROR: number of elements in PARINFO and P must agree'
935
+ return
936
+
937
+ # If the parameters were not specified at the command line, then
938
+ # extract them from PARINFO
939
+ if xall is None:
940
+ xall = self.parinfo(parinfo, 'value')
941
+ if xall is None:
942
+ self.errmsg = 'ERROR: either P or PARINFO(*)["value"] must be supplied.'
943
+ return
944
+
945
+ # Make sure parameters are numpy arrays
946
+ xall = numpy.asarray(xall)
947
+ # In the case if the xall is not float or if is float but has less
948
+ # than 64 bits we do convert it into double
949
+ if xall.dtype.kind != 'f' or xall.dtype.itemsize<=4:
950
+ xall = xall.astype(numpy.float)
951
+
952
+ npar = len(xall)
953
+ self.fnorm = -1.
954
+ fnorm1 = -1.
955
+
956
+ # TIED parameters?
957
+ ptied = self.parinfo(parinfo, 'tied', default='', n=npar)
958
+ self.qanytied = 0
959
+ for i in range(npar):
960
+ ptied[i] = ptied[i].strip()
961
+ if ptied[i] != '':
962
+ self.qanytied = 1
963
+ self.ptied = ptied
964
+
965
+ # FIXED parameters ?
966
+ pfixed = self.parinfo(parinfo, 'fixed', default=0, n=npar)
967
+ pfixed = (pfixed == 1)
968
+ for i in range(npar):
969
+ pfixed[i] = pfixed[i] or (ptied[i] != '') # Tied parameters are also effectively fixed
970
+
971
+ # Finite differencing step, absolute and relative, and sidedness of deriv.
972
+ step = self.parinfo(parinfo, 'step', default=0., n=npar)
973
+ dstep = self.parinfo(parinfo, 'relstep', default=0., n=npar)
974
+ dside = self.parinfo(parinfo, 'mpside', default=0, n=npar)
975
+
976
+ # Maximum and minimum steps allowed to be taken in one iteration
977
+ maxstep = self.parinfo(parinfo, 'mpmaxstep', default=0., n=npar)
978
+ minstep = self.parinfo(parinfo, 'mpminstep', default=0., n=npar)
979
+ qmin = minstep != 0
980
+ qmin[:] = False # Remove minstep for now!!
981
+ qmax = maxstep != 0
982
+ if numpy.any(qmin & qmax & (maxstep<minstep)):
983
+ self.errmsg = 'ERROR: MPMINSTEP is greater than MPMAXSTEP'
984
+ return
985
+ wh = (numpy.nonzero((qmin!=0.) | (qmax!=0.)))[0]
986
+ qminmax = len(wh > 0)
987
+
988
+ # Finish up the free parameters
989
+ ifree = (numpy.nonzero(pfixed != 1))[0]
990
+ nfree = len(ifree)
991
+ if nfree == 0:
992
+ self.errmsg = 'ERROR: no free parameters'
993
+ return
994
+
995
+ # Compose only VARYING parameters
996
+ self.params = xall.copy() # self.params is the set of parameters to be returned
997
+ x = self.params[ifree] # x is the set of free parameters
998
+
999
+ # LIMITED parameters ?
1000
+ limited = self.parinfo(parinfo, 'limited', default=[0,0], n=npar)
1001
+ limits = self.parinfo(parinfo, 'limits', default=[0.,0.], n=npar)
1002
+ if (limited is not None) and (limits is not None):
1003
+ # Error checking on limits in parinfo
1004
+ if numpy.any((limited[:,0] & (xall < limits[:,0])) |
1005
+ (limited[:,1] & (xall > limits[:,1]))):
1006
+ self.errmsg = 'ERROR: parameters are not within PARINFO limits'
1007
+ return
1008
+ if numpy.any((limited[:,0] & limited[:,1]) &
1009
+ (limits[:,0] >= limits[:,1]) &
1010
+ (pfixed == 0)):
1011
+ self.errmsg = 'ERROR: PARINFO parameter limits are not consistent'
1012
+ return
1013
+
1014
+ # Transfer structure values to local variables
1015
+ qulim = (limited[:,1])[ifree]
1016
+ ulim = (limits [:,1])[ifree]
1017
+ qllim = (limited[:,0])[ifree]
1018
+ llim = (limits [:,0])[ifree]
1019
+
1020
+ if numpy.any((qulim!=0.) | (qllim!=0.)):
1021
+ qanylim = 1
1022
+ else:
1023
+ qanylim = 0
1024
+ else:
1025
+ # Fill in local variables with dummy values
1026
+ qulim = numpy.zeros(nfree)
1027
+ ulim = x * 0.
1028
+ qllim = qulim
1029
+ llim = x * 0.
1030
+ qanylim = 0
1031
+
1032
+ n = len(x)
1033
+ # Check input parameters for errors
1034
+ if (n < 0) or (ftol <= 0) or (xtol <= 0) or (gtol <= 0) \
1035
+ or (maxiter < 0) or (factor <= 0):
1036
+ self.errmsg = 'ERROR: input keywords are inconsistent'
1037
+ return
1038
+
1039
+ if rescale != 0:
1040
+ self.errmsg = 'ERROR: DIAG parameter scales are inconsistent'
1041
+ if len(diag) < n:
1042
+ return
1043
+ if numpy.any(diag <= 0):
1044
+ return
1045
+ self.errmsg = ''
1046
+
1047
+ [self.status, fvec] = self.call(fcn, self.params, functkw)
1048
+
1049
+ if self.status < 0:
1050
+ self.errmsg = 'ERROR: first call to "'+str(fcn)+'" failed'
1051
+ return
1052
+ # If the returned fvec has more than four bits I assume that we have
1053
+ # double precision
1054
+ # It is important that the machar is determined by the precision of
1055
+ # the returned value, not by the precision of the input array
1056
+ if numpy.array([fvec]).dtype.itemsize>4:
1057
+ self.machar = machar(double=1)
1058
+ self.blas_enorm = mpfit.blas_enorm64
1059
+ else:
1060
+ self.machar = machar(double=0)
1061
+ self.blas_enorm = mpfit.blas_enorm32
1062
+ machep = self.machar.machep
1063
+
1064
+ m = len(fvec)
1065
+ if m < n:
1066
+ self.errmsg = 'ERROR: number of parameters must not exceed data'
1067
+ return
1068
+ self.dof = m-nfree
1069
+ self.fnorm = self.enorm(fvec)
1070
+
1071
+ # Initialize Levelberg-Marquardt parameter and iteration counter
1072
+
1073
+ par = 0.
1074
+ self.niter = 1
1075
+ qtf = x * 0.
1076
+ self.status = 0
1077
+
1078
+ # Beginning of the outer loop
1079
+
1080
+ while(1):
1081
+
1082
+ # If requested, call fcn to enable printing of iterates
1083
+ self.params[ifree] = x
1084
+ if self.qanytied:
1085
+ self.params = self.tie(self.params, ptied)
1086
+
1087
+ if (nprint > 0) and (iterfunct is not None):
1088
+ if ((self.niter-1) % nprint) == 0:
1089
+ mperr = 0
1090
+ xnew0 = self.params.copy()
1091
+
1092
+ dof = numpy.max([len(fvec) - len(x), 0])
1093
+ status = iterfunct(fcn, self.params, self.niter, self.fnorm**2,
1094
+ functkw=functkw, parinfo=parinfo, quiet=quiet,
1095
+ dof=dof, **iterkw)
1096
+ if status is not None:
1097
+ self.status = status
1098
+
1099
+ # Check for user termination
1100
+ if self.status < 0:
1101
+ self.errmsg = 'WARNING: premature termination by ' + str(iterfunct)
1102
+ return
1103
+
1104
+ # If parameters were changed (grrr..) then re-tie
1105
+ if numpy.max(numpy.abs(xnew0-self.params)) > 0:
1106
+ if self.qanytied:
1107
+ self.params = self.tie(self.params, ptied)
1108
+ x = self.params[ifree]
1109
+
1110
+
1111
+ # Calculate the jacobian matrix
1112
+ self.status = 2
1113
+ catch_msg = 'calling MPFIT_FDJAC2'
1114
+ fjac = self.fdjac2(fcn, x, fvec, step, qulim, ulim, dside,
1115
+ epsfcn=epsfcn,
1116
+ autoderivative=autoderivative, dstep=dstep,
1117
+ functkw=functkw, ifree=ifree, xall=self.params)
1118
+ if fjac is None:
1119
+ self.errmsg = 'WARNING: premature termination by FDJAC2'
1120
+ return
1121
+
1122
+ # Determine if any of the parameters are pegged at the limits
1123
+ if qanylim:
1124
+ catch_msg = 'zeroing derivatives of pegged parameters'
1125
+ whlpeg = (numpy.nonzero(qllim & (x == llim)))[0]
1126
+ nlpeg = len(whlpeg)
1127
+ whupeg = (numpy.nonzero(qulim & (x == ulim)))[0]
1128
+ nupeg = len(whupeg)
1129
+ # See if any "pegged" values should keep their derivatives
1130
+ if nlpeg > 0:
1131
+ # Total derivative of sum wrt lower pegged parameters
1132
+ for i in range(nlpeg):
1133
+ sum0 = sum(fvec * fjac[:,whlpeg[i]])
1134
+ if sum0 > 0:
1135
+ fjac[:,whlpeg[i]] = 0
1136
+ if nupeg > 0:
1137
+ # Total derivative of sum wrt upper pegged parameters
1138
+ for i in range(nupeg):
1139
+ sum0 = sum(fvec * fjac[:,whupeg[i]])
1140
+ if sum0 < 0:
1141
+ fjac[:,whupeg[i]] = 0
1142
+
1143
+ # Compute the QR factorization of the jacobian
1144
+ [fjac, ipvt, wa1, wa2] = self.qrfac(fjac, pivot=1)
1145
+
1146
+ # On the first iteration if "diag" is unspecified, scale
1147
+ # according to the norms of the columns of the initial jacobian
1148
+ catch_msg = 'rescaling diagonal elements'
1149
+ if self.niter == 1:
1150
+ if (rescale==0) or (len(diag) < n):
1151
+ diag = wa2.copy()
1152
+ diag[diag == 0] = 1.
1153
+
1154
+ # On the first iteration, calculate the norm of the scaled x
1155
+ # and initialize the step bound delta
1156
+ wa3 = diag * x
1157
+ xnorm = self.enorm(wa3)
1158
+ delta = factor*xnorm
1159
+ if delta == 0.:
1160
+ delta = factor
1161
+
1162
+ # Form (q transpose)*fvec and store the first n components in qtf
1163
+ catch_msg = 'forming (q transpose)*fvec'
1164
+ wa4 = fvec.copy()
1165
+ for j in range(n):
1166
+ lj = ipvt[j]
1167
+ temp3 = fjac[j,lj]
1168
+ if temp3 != 0:
1169
+ fj = fjac[j:,lj]
1170
+ wj = wa4[j:]
1171
+ # *** optimization wa4(j:*)
1172
+ wa4[j:] = wj - fj * sum(fj*wj) / temp3
1173
+ fjac[j,lj] = wa1[j]
1174
+ qtf[j] = wa4[j]
1175
+ # From this point on, only the square matrix, consisting of the
1176
+ # triangle of R, is needed.
1177
+ fjac = fjac[0:n, 0:n]
1178
+ fjac = fjac.reshape(n, n)
1179
+ temp = fjac.copy()
1180
+ for i in range(n):
1181
+ temp[:,i] = fjac[:, ipvt[i]]
1182
+ fjac = temp.copy()
1183
+
1184
+ # Check for overflow. This should be a cheap test here since FJAC
1185
+ # has been reduced to a (small) square matrix, and the test is
1186
+ # O(N^2).
1187
+ #wh = where(finite(fjac) EQ 0, ct)
1188
+ #if ct GT 0 then goto, FAIL_OVERFLOW
1189
+
1190
+ # Compute the norm of the scaled gradient
1191
+ catch_msg = 'computing the scaled gradient'
1192
+ gnorm = 0.
1193
+ if self.fnorm != 0:
1194
+ for j in range(n):
1195
+ l = ipvt[j]
1196
+ if wa2[l] != 0:
1197
+ sum0 = sum(fjac[0:j+1,j]*qtf[0:j+1])/self.fnorm
1198
+ gnorm = numpy.max([gnorm,numpy.abs(sum0/wa2[l])])
1199
+
1200
+ # Test for convergence of the gradient norm
1201
+ if gnorm <= gtol:
1202
+ self.status = 4
1203
+ break
1204
+ if maxiter == 0:
1205
+ self.status = 5
1206
+ break
1207
+
1208
+ # Rescale if necessary
1209
+ if rescale == 0:
1210
+ diag = numpy.choose(diag>wa2, (wa2, diag))
1211
+
1212
+ # Beginning of the inner loop
1213
+ while(1):
1214
+
1215
+ # Determine the levenberg-marquardt parameter
1216
+ catch_msg = 'calculating LM parameter (MPFIT_)'
1217
+ [fjac, par, wa1, wa2] = self.lmpar(fjac, ipvt, diag, qtf,
1218
+ delta, wa1, wa2, par=par)
1219
+ # Store the direction p and x+p. Calculate the norm of p
1220
+ wa1 = -wa1
1221
+
1222
+ if (qanylim == 0) and (qminmax == 0):
1223
+ # No parameter limits, so just move to new position WA2
1224
+ alpha = 1.
1225
+ wa2 = x + wa1
1226
+
1227
+ else:
1228
+
1229
+ # Respect the limits. If a step were to go out of bounds, then
1230
+ # we should take a step in the same direction but shorter distance.
1231
+ # The step should take us right to the limit in that case.
1232
+ alpha = 1.
1233
+
1234
+ if qanylim:
1235
+ # Do not allow any steps out of bounds
1236
+ catch_msg = 'checking for a step out of bounds'
1237
+ if nlpeg > 0:
1238
+ wa1[whlpeg] = numpy.clip( wa1[whlpeg], 0., numpy.max(wa1))
1239
+ if nupeg > 0:
1240
+ wa1[whupeg] = numpy.clip(wa1[whupeg], numpy.min(wa1), 0.)
1241
+
1242
+ dwa1 = numpy.abs(wa1) > machep
1243
+ whl = (numpy.nonzero(((dwa1!=0.) & qllim) & ((x + wa1) < llim)))[0]
1244
+ if len(whl) > 0:
1245
+ t = ((llim[whl] - x[whl]) /
1246
+ wa1[whl])
1247
+ alpha = numpy.min([alpha, numpy.min(t)])
1248
+ whu = (numpy.nonzero(((dwa1!=0.) & qulim) & ((x + wa1) > ulim)))[0]
1249
+ if len(whu) > 0:
1250
+ t = ((ulim[whu] - x[whu]) /
1251
+ wa1[whu])
1252
+ alpha = numpy.min([alpha, numpy.min(t)])
1253
+
1254
+ # Obey any max step values.
1255
+ if qminmax:
1256
+ nwa1 = wa1 * alpha
1257
+ whmax = (numpy.nonzero((qmax[ifree] != 0.) & (maxstep[ifree] > 0)))[0]
1258
+ if len(whmax) > 0:
1259
+ mrat = numpy.max(numpy.abs(nwa1[whmax]) /
1260
+ numpy.abs(maxstep[ifree[whmax]]))
1261
+ if mrat > 1:
1262
+ alpha = alpha / mrat
1263
+
1264
+ # Scale the resulting vector
1265
+ wa1 = wa1 * alpha
1266
+ wa2 = x + wa1
1267
+
1268
+ # Adjust the final output values. If the step put us exactly
1269
+ # on a boundary, make sure it is exact.
1270
+ sgnu = (ulim >= 0) * 2. - 1.
1271
+ sgnl = (llim >= 0) * 2. - 1.
1272
+ # Handles case of
1273
+ # ... nonzero *LIM ... ...zero * LIM
1274
+ ulim1 = ulim * (1 - sgnu * machep) - (ulim == 0) * machep
1275
+ llim1 = llim * (1 + sgnl * machep) + (llim == 0) * machep
1276
+ wh = (numpy.nonzero((qulim!=0) & (wa2 >= ulim1)))[0]
1277
+ if len(wh) > 0:
1278
+ wa2[wh] = ulim[wh]
1279
+ wh = (numpy.nonzero((qllim!=0.) & (wa2 <= llim1)))[0]
1280
+ if len(wh) > 0:
1281
+ wa2[wh] = llim[wh]
1282
+ # endelse
1283
+ wa3 = diag * wa1
1284
+ pnorm = self.enorm(wa3)
1285
+
1286
+ # On the first iteration, adjust the initial step bound
1287
+ if self.niter == 1:
1288
+ delta = numpy.min([delta,pnorm])
1289
+
1290
+ self.params[ifree] = wa2
1291
+
1292
+ # Evaluate the function at x+p and calculate its norm
1293
+ mperr = 0
1294
+ catch_msg = 'calling '+str(fcn)
1295
+ [self.status, wa4] = self.call(fcn, self.params, functkw)
1296
+ if self.status < 0:
1297
+ self.errmsg = 'WARNING: premature termination by "'+fcn+'"'
1298
+ return
1299
+ fnorm1 = self.enorm(wa4)
1300
+
1301
+ # Compute the scaled actual reduction
1302
+ catch_msg = 'computing convergence criteria'
1303
+ actred = -1.
1304
+ if (0.1 * fnorm1) < self.fnorm:
1305
+ actred = - (fnorm1/self.fnorm)**2 + 1.
1306
+
1307
+ # Compute the scaled predicted reduction and the scaled directional
1308
+ # derivative
1309
+ for j in range(n):
1310
+ wa3[j] = 0
1311
+ wa3[0:j+1] = wa3[0:j+1] + fjac[0:j+1,j]*wa1[ipvt[j]]
1312
+
1313
+ # Remember, alpha is the fraction of the full LM step actually
1314
+ # taken
1315
+ temp1 = self.enorm(alpha*wa3)/self.fnorm
1316
+ temp2 = (numpy.sqrt(alpha*par)*pnorm)/self.fnorm
1317
+ prered = temp1*temp1 + (temp2*temp2)/0.5
1318
+ dirder = -(temp1*temp1 + temp2*temp2)
1319
+
1320
+ # Compute the ratio of the actual to the predicted reduction.
1321
+ ratio = 0.
1322
+ if prered != 0:
1323
+ ratio = actred/prered
1324
+
1325
+ # Update the step bound
1326
+ if ratio <= 0.25:
1327
+ if actred >= 0:
1328
+ temp = .5
1329
+ else:
1330
+ temp = .5*dirder/(dirder + .5*actred)
1331
+ if ((0.1*fnorm1) >= self.fnorm) or (temp < 0.1):
1332
+ temp = 0.1
1333
+ delta = temp*numpy.min([delta,pnorm/0.1])
1334
+ par = par/temp
1335
+ else:
1336
+ if (par == 0) or (ratio >= 0.75):
1337
+ delta = pnorm/.5
1338
+ par = .5*par
1339
+
1340
+ # Test for successful iteration
1341
+ if ratio >= 0.0001:
1342
+ # Successful iteration. Update x, fvec, and their norms
1343
+ x = wa2
1344
+ wa2 = diag * x
1345
+ fvec = wa4
1346
+ xnorm = self.enorm(wa2)
1347
+ self.fnorm = fnorm1
1348
+ self.niter = self.niter + 1
1349
+
1350
+ # Tests for convergence
1351
+ if (numpy.abs(actred) <= ftol) and (prered <= ftol) \
1352
+ and (0.5 * ratio <= 1):
1353
+ self.status = 1
1354
+ if delta <= xtol*xnorm:
1355
+ self.status = 2
1356
+ if (numpy.abs(actred) <= ftol) and (prered <= ftol) \
1357
+ and (0.5 * ratio <= 1) and (self.status == 2):
1358
+ self.status = 3
1359
+ if self.status != 0:
1360
+ break
1361
+
1362
+ # Tests for termination and stringent tolerances
1363
+ if self.niter >= maxiter:
1364
+ self.status = 5
1365
+ if (numpy.abs(actred) <= machep) and (prered <= machep) \
1366
+ and (0.5*ratio <= 1):
1367
+ self.status = 6
1368
+ if delta <= machep*xnorm:
1369
+ self.status = 7
1370
+ if gnorm <= machep:
1371
+ self.status = 8
1372
+ if self.status != 0:
1373
+ break
1374
+
1375
+ # End of inner loop. Repeat if iteration unsuccessful
1376
+ if ratio >= 0.0001:
1377
+ break
1378
+
1379
+ # Check for over/underflow
1380
+ if ~numpy.all(numpy.isfinite(wa1) & numpy.isfinite(wa2) & \
1381
+ numpy.isfinite(x)) or ~numpy.isfinite(ratio):
1382
+ errmsg = ('''ERROR: parameter or function value(s) have become
1383
+ 'infinite; check model function for over- 'and underflow''')
1384
+ self.status = -16
1385
+ break
1386
+ #wh = where(finite(wa1) EQ 0 OR finite(wa2) EQ 0 OR finite(x) EQ 0, ct)
1387
+ #if ct GT 0 OR finite(ratio) EQ 0 then begin
1388
+
1389
+ if self.status != 0:
1390
+ break;
1391
+ # End of outer loop.
1392
+
1393
+ catch_msg = 'in the termination phase'
1394
+ # Termination, either normal or user imposed.
1395
+ if len(self.params) == 0:
1396
+ return
1397
+ if nfree == 0:
1398
+ self.params = xall.copy()
1399
+ else:
1400
+ self.params[ifree] = x
1401
+ if (nprint > 0) and (self.status > 0):
1402
+ catch_msg = 'calling ' + str(fcn)
1403
+ [status, fvec] = self.call(fcn, self.params, functkw)
1404
+ catch_msg = 'in the termination phase'
1405
+ self.fnorm = self.enorm(fvec)
1406
+
1407
+ if (self.fnorm is not None) and (fnorm1 is not None):
1408
+ self.fnorm = numpy.max([self.fnorm, fnorm1])
1409
+ self.fnorm = self.fnorm**2.
1410
+
1411
+ self.covar = None
1412
+ self.perror = None
1413
+ # (very carefully) set the covariance matrix COVAR
1414
+ if (self.status > 0) and (nocovar==0) and (n is not None) \
1415
+ and (fjac is not None) and (ipvt is not None):
1416
+ sz = fjac.shape
1417
+ if (n > 0) and (sz[0] >= n) and (sz[1] >= n) \
1418
+ and (len(ipvt) >= n):
1419
+
1420
+ catch_msg = 'computing the covariance matrix'
1421
+ cv = self.calc_covar(fjac[0:n,0:n], ipvt[0:n])
1422
+ cv = cv.reshape(n, n)
1423
+ nn = len(xall)
1424
+
1425
+ # Fill in actual covariance matrix, accounting for fixed
1426
+ # parameters.
1427
+ self.covar = numpy.zeros([nn, nn], dtype=float)
1428
+ for i in range(n):
1429
+ self.covar[ifree,ifree[i]] = cv[:,i]
1430
+
1431
+ # Compute errors in parameters
1432
+ catch_msg = 'computing parameter errors'
1433
+ self.perror = numpy.zeros(nn, dtype=float)
1434
+ d = numpy.diagonal(self.covar)
1435
+ wh = (numpy.nonzero(d >= 0))[0]
1436
+ if len(wh) > 0:
1437
+ self.perror[wh] = numpy.sqrt(d[wh])
1438
+ return
1439
+
1440
+
1441
+ def __str__(self):
1442
+ return {'params': self.params,
1443
+ 'niter': self.niter,
1444
+ 'params': self.params,
1445
+ 'covar': self.covar,
1446
+ 'perror': self.perror,
1447
+ 'status': self.status,
1448
+ 'debug': self.debug,
1449
+ 'errmsg': self.errmsg,
1450
+ 'nfev': self.nfev,
1451
+ 'damp': self.damp
1452
+ #,'machar':self.machar
1453
+ }.__str__()
1454
+
1455
+ # Default procedure to be called every iteration. It simply prints
1456
+ # the parameter values.
1457
+ def defiter(self, fcn, x, iter, fnorm=None, functkw=None,
1458
+ quiet=0, iterstop=None, parinfo=None,
1459
+ format=None, pformat='%.10g', dof=1):
1460
+
1461
+ if self.debug:
1462
+ print ('Entering defiter...')
1463
+ if quiet:
1464
+ return
1465
+ if fnorm is None:
1466
+ [status, fvec] = self.call(fcn, x, functkw)
1467
+ fnorm = self.enorm(fvec)**2
1468
+
1469
+ # Determine which parameters to print
1470
+ nprint = len(x)
1471
+ print ("Iter ", ('%6i' % iter)," CHI-SQUARE = ",('%.10g' % fnorm)," DOF = ", ('%i' % dof))
1472
+ for i in range(nprint):
1473
+ if (parinfo is not None) and ('parname' in parinfo[i]):
1474
+ p = ' ' + parinfo[i]['parname'] + ' = '
1475
+ else:
1476
+ p = ' P' + str(i) + ' = '
1477
+ if (parinfo is not None) and ('mpprint' in parinfo[i]):
1478
+ iprint = parinfo[i]['mpprint']
1479
+ else:
1480
+ iprint = 1
1481
+ if iprint:
1482
+ print (p + (pformat % x[i]) + ' ')
1483
+ return 0
1484
+
1485
+ # DO_ITERSTOP:
1486
+ # if keyword_set(iterstop) then begin
1487
+ # k = get_kbrd(0)
1488
+ # if k EQ string(byte(7)) then begin
1489
+ # message, 'WARNING: minimization not complete', /info
1490
+ # print, 'Do you want to terminate this procedure? (y/n)', $
1491
+ # format='(A,$)'
1492
+ # k = ''
1493
+ # read, k
1494
+ # if strupcase(strmid(k,0,1)) EQ 'Y' then begin
1495
+ # message, 'WARNING: Procedure is terminating.', /info
1496
+ # mperr = -1
1497
+ # endif
1498
+ # endif
1499
+ # endif
1500
+
1501
+
1502
+ # Procedure to parse the parameter values in PARINFO, which is a list of dictionaries
1503
+ def parinfo(self, parinfo=None, key='a', default=None, n=0):
1504
+ if self.debug:
1505
+ print ('Entering parinfo...')
1506
+ if (n == 0) and (parinfo is not None):
1507
+ n = len(parinfo)
1508
+ if n == 0:
1509
+ values = default
1510
+
1511
+ return values
1512
+ values = []
1513
+ for i in range(n):
1514
+ if (parinfo is not None) and (key in parinfo[i]):
1515
+ values.append(parinfo[i][key])
1516
+ else:
1517
+ values.append(default)
1518
+
1519
+ # Convert to numeric arrays if possible
1520
+ test = default
1521
+ if type(default) is list:
1522
+ test=default[0]
1523
+ values = numpy.asarray(values)
1524
+ return values
1525
+
1526
+ # Call user function or procedure, with _EXTRA or not, with
1527
+ # derivatives or not.
1528
+ def call(self, fcn, x, functkw, fjac=None):
1529
+ if self.debug:
1530
+ print ('Entering call...')
1531
+ if self.qanytied:
1532
+ x = self.tie(x, self.ptied)
1533
+ self.nfev = self.nfev + 1
1534
+ if fjac is None:
1535
+ [status, f] = fcn(x, fjac=fjac, **functkw)
1536
+ if self.damp > 0:
1537
+ # Apply the damping if requested. This replaces the residuals
1538
+ # with their hyperbolic tangent. Thus residuals larger than
1539
+ # DAMP are essentially clipped.
1540
+ f = numpy.tanh(f/self.damp)
1541
+ return [status, f]
1542
+ else:
1543
+ return fcn(x, fjac=fjac, **functkw)
1544
+
1545
+
1546
+ def enorm(self, vec):
1547
+ ans = self.blas_enorm(vec)
1548
+ return ans
1549
+
1550
+
1551
+ def fdjac2(self, fcn, x, fvec, step=None, ulimited=None, ulimit=None, dside=None,
1552
+ epsfcn=None, autoderivative=1,
1553
+ functkw=None, xall=None, ifree=None, dstep=None):
1554
+
1555
+ if self.debug:
1556
+ print ('Entering fdjac2...')
1557
+ machep = self.machar.machep
1558
+ if epsfcn is None:
1559
+ epsfcn = machep
1560
+ if xall is None:
1561
+ xall = x
1562
+ if ifree is None:
1563
+ ifree = numpy.arange(len(xall))
1564
+ if step is None:
1565
+ step = x * 0.
1566
+ nall = len(xall)
1567
+
1568
+ eps = numpy.sqrt(numpy.max([epsfcn, machep]))
1569
+ m = len(fvec)
1570
+ n = len(x)
1571
+
1572
+ # Compute analytical derivative if requested
1573
+ if autoderivative == 0:
1574
+ mperr = 0
1575
+ fjac = numpy.zeros(nall, dtype=float)
1576
+ fjac[ifree] = 1.0 # Specify which parameters need derivatives
1577
+ [status, fp] = self.call(fcn, xall, functkw, fjac=fjac)
1578
+
1579
+ if len(fjac) != m*nall:
1580
+ print ('ERROR: Derivative matrix was not computed properly.')
1581
+ return None
1582
+
1583
+ # This definition is consistent with CURVEFIT
1584
+ # Sign error found (thanks Jesus Fernandez <fernande@irm.chu-caen.fr>)
1585
+ fjac = fjac.reshape(m, nall)
1586
+ fjac = -fjac
1587
+
1588
+ # Select only the free parameters
1589
+ if len(ifree) < nall:
1590
+ fjac = fjac[:,ifree]
1591
+ fjac = fjac.reshape(m, n)
1592
+ return fjac
1593
+
1594
+ fjac = numpy.zeros([m, n], dtype=float)
1595
+
1596
+ h = eps * numpy.abs(x)
1597
+
1598
+ # if STEP is given, use that
1599
+ # STEP includes the fixed parameters
1600
+ if step is not None:
1601
+ stepi = step[ifree]
1602
+ wh = (numpy.nonzero(stepi > 0))[0]
1603
+ if len(wh) > 0:
1604
+ h[wh] = stepi[wh]
1605
+
1606
+ # if relative step is given, use that
1607
+ # DSTEP includes the fixed parameters
1608
+ if len(dstep) > 0:
1609
+ dstepi = dstep[ifree]
1610
+ wh = (numpy.nonzero(dstepi > 0))[0]
1611
+ if len(wh) > 0:
1612
+ h[wh] = numpy.abs(dstepi[wh]*x[wh])
1613
+
1614
+ # In case any of the step values are zero
1615
+ h[h == 0] = eps
1616
+
1617
+ # Reverse the sign of the step if we are up against the parameter
1618
+ # limit, or if the user requested it.
1619
+ # DSIDE includes the fixed parameters (ULIMITED/ULIMIT have only
1620
+ # varying ones)
1621
+ mask = dside[ifree] == -1
1622
+ if len(ulimited) > 0 and len(ulimit) > 0:
1623
+ mask = (mask | ((ulimited!=0) & (x > ulimit-h)))
1624
+ wh = (numpy.nonzero(mask))[0]
1625
+ if len(wh) > 0:
1626
+ h[wh] = - h[wh]
1627
+ # Loop through parameters, computing the derivative for each
1628
+ for j in range(n):
1629
+ xp = xall.copy()
1630
+ xp[ifree[j]] = xp[ifree[j]] + h[j]
1631
+ [status, fp] = self.call(fcn, xp, functkw)
1632
+ if status < 0:
1633
+ return None
1634
+
1635
+ if numpy.abs(dside[ifree[j]]) <= 1:
1636
+ # COMPUTE THE ONE-SIDED DERIVATIVE
1637
+ # Note optimization fjac(0:*,j)
1638
+ fjac[0:,j] = (fp-fvec)/h[j]
1639
+
1640
+ else:
1641
+ # COMPUTE THE TWO-SIDED DERIVATIVE
1642
+ xp[ifree[j]] = xall[ifree[j]] - h[j]
1643
+
1644
+ mperr = 0
1645
+ [status, fm] = self.call(fcn, xp, functkw)
1646
+ if status < 0:
1647
+ return None
1648
+
1649
+ # Note optimization fjac(0:*,j)
1650
+ fjac[0:,j] = (fp-fm)/(2*h[j])
1651
+ return fjac
1652
+
1653
+
1654
+
1655
+ # Original FORTRAN documentation
1656
+ # **********
1657
+ #
1658
+ # subroutine qrfac
1659
+ #
1660
+ # this subroutine uses householder transformations with column
1661
+ # pivoting (optional) to compute a qr factorization of the
1662
+ # m by n matrix a. that is, qrfac determines an orthogonal
1663
+ # matrix q, a permutation matrix p, and an upper trapezoidal
1664
+ # matrix r with diagonal elements of nonincreasing magnitude,
1665
+ # such that a*p = q*r. the householder transformation for
1666
+ # column k, k = 1,2,...,min(m,n), is of the form
1667
+ #
1668
+ # t
1669
+ # i - (1/u(k))*u*u
1670
+ #
1671
+ # where u has zeros in the first k-1 positions. the form of
1672
+ # this transformation and the method of pivoting first
1673
+ # appeared in the corresponding linpack subroutine.
1674
+ #
1675
+ # the subroutine statement is
1676
+ #
1677
+ # subroutine qrfac(m,n,a,lda,pivot,ipvt,lipvt,rdiag,acnorm,wa)
1678
+ #
1679
+ # where
1680
+ #
1681
+ # m is a positive integer input variable set to the number
1682
+ # of rows of a.
1683
+ #
1684
+ # n is a positive integer input variable set to the number
1685
+ # of columns of a.
1686
+ #
1687
+ # a is an m by n array. on input a contains the matrix for
1688
+ # which the qr factorization is to be computed. on output
1689
+ # the strict upper trapezoidal part of a contains the strict
1690
+ # upper trapezoidal part of r, and the lower trapezoidal
1691
+ # part of a contains a factored form of q (the non-trivial
1692
+ # elements of the u vectors described above).
1693
+ #
1694
+ # lda is a positive integer input variable not less than m
1695
+ # which specifies the leading dimension of the array a.
1696
+ #
1697
+ # pivot is a logical input variable. if pivot is set true,
1698
+ # then column pivoting is enforced. if pivot is set false,
1699
+ # then no column pivoting is done.
1700
+ #
1701
+ # ipvt is an integer output array of length lipvt. ipvt
1702
+ # defines the permutation matrix p such that a*p = q*r.
1703
+ # column j of p is column ipvt(j) of the identity matrix.
1704
+ # if pivot is false, ipvt is not referenced.
1705
+ #
1706
+ # lipvt is a positive integer input variable. if pivot is false,
1707
+ # then lipvt may be as small as 1. if pivot is true, then
1708
+ # lipvt must be at least n.
1709
+ #
1710
+ # rdiag is an output array of length n which contains the
1711
+ # diagonal elements of r.
1712
+ #
1713
+ # acnorm is an output array of length n which contains the
1714
+ # norms of the corresponding columns of the input matrix a.
1715
+ # if this information is not needed, then acnorm can coincide
1716
+ # with rdiag.
1717
+ #
1718
+ # wa is a work array of length n. if pivot is false, then wa
1719
+ # can coincide with rdiag.
1720
+ #
1721
+ # subprograms called
1722
+ #
1723
+ # minpack-supplied ... dpmpar,enorm
1724
+ #
1725
+ # fortran-supplied ... dmax1,dsqrt,min0
1726
+ #
1727
+ # argonne national laboratory. minpack project. march 1980.
1728
+ # burton s. garbow, kenneth e. hillstrom, jorge j. more
1729
+ #
1730
+ # **********
1731
+ #
1732
+ # PIVOTING / PERMUTING:
1733
+ #
1734
+ # Upon return, A(*,*) is in standard parameter order, A(*,IPVT) is in
1735
+ # permuted order.
1736
+ #
1737
+ # RDIAG is in permuted order.
1738
+ # ACNORM is in standard parameter order.
1739
+ #
1740
+ #
1741
+ # NOTE: in IDL the factors appear slightly differently than described
1742
+ # above. The matrix A is still m x n where m >= n.
1743
+ #
1744
+ # The "upper" triangular matrix R is actually stored in the strict
1745
+ # lower left triangle of A under the standard notation of IDL.
1746
+ #
1747
+ # The reflectors that generate Q are in the upper trapezoid of A upon
1748
+ # output.
1749
+ #
1750
+ # EXAMPLE: decompose the matrix [[9.,2.,6.],[4.,8.,7.]]
1751
+ # aa = [[9.,2.,6.],[4.,8.,7.]]
1752
+ # mpfit_qrfac, aa, aapvt, rdiag, aanorm
1753
+ # IDL> print, aa
1754
+ # 1.81818* 0.181818* 0.545455*
1755
+ # -8.54545+ 1.90160* 0.432573*
1756
+ # IDL> print, rdiag
1757
+ # -11.0000+ -7.48166+
1758
+ #
1759
+ # The components marked with a * are the components of the
1760
+ # reflectors, and those marked with a + are components of R.
1761
+ #
1762
+ # To reconstruct Q and R we proceed as follows. First R.
1763
+ # r = fltarr(m, n)
1764
+ # for i = 0, n-1 do r(0:i,i) = aa(0:i,i) # fill in lower diag
1765
+ # r(lindgen(n)*(m+1)) = rdiag
1766
+ #
1767
+ # Next, Q, which are composed from the reflectors. Each reflector v
1768
+ # is taken from the upper trapezoid of aa, and converted to a matrix
1769
+ # via (I - 2 vT . v / (v . vT)).
1770
+ #
1771
+ # hh = ident # identity matrix
1772
+ # for i = 0, n-1 do begin
1773
+ # v = aa(*,i) & if i GT 0 then v(0:i-1) = 0 # extract reflector
1774
+ # hh = hh # (ident - 2*(v # v)/total(v * v)) # generate matrix
1775
+ # endfor
1776
+ #
1777
+ # Test the result:
1778
+ # IDL> print, hh # transpose(r)
1779
+ # 9.00000 4.00000
1780
+ # 2.00000 8.00000
1781
+ # 6.00000 7.00000
1782
+ #
1783
+ # Note that it is usually never necessary to form the Q matrix
1784
+ # explicitly, and MPFIT does not.
1785
+
1786
+
1787
+ def qrfac(self, a, pivot=0):
1788
+
1789
+ if self.debug: print ('Entering qrfac...')
1790
+ machep = self.machar.machep
1791
+ sz = a.shape
1792
+ m = sz[0]
1793
+ n = sz[1]
1794
+
1795
+ # Compute the initial column norms and initialize arrays
1796
+ acnorm = numpy.zeros(n, dtype=float)
1797
+ for j in range(n):
1798
+ acnorm[j] = self.enorm(a[:,j])
1799
+ rdiag = acnorm.copy()
1800
+ wa = rdiag.copy()
1801
+ ipvt = numpy.arange(n)
1802
+
1803
+ # Reduce a to r with householder transformations
1804
+ minmn = numpy.min([m,n])
1805
+ for j in range(minmn):
1806
+ if pivot != 0:
1807
+ # Bring the column of largest norm into the pivot position
1808
+ rmax = numpy.max(rdiag[j:])
1809
+ kmax = (numpy.nonzero(rdiag[j:] == rmax))[0]
1810
+ ct = len(kmax)
1811
+ kmax = kmax + j
1812
+ if ct > 0:
1813
+ kmax = kmax[0]
1814
+
1815
+ # Exchange rows via the pivot only. Avoid actually exchanging
1816
+ # the rows, in case there is lots of memory transfer. The
1817
+ # exchange occurs later, within the body of MPFIT, after the
1818
+ # extraneous columns of the matrix have been shed.
1819
+ if kmax != j:
1820
+ temp = ipvt[j] ; ipvt[j] = ipvt[kmax] ; ipvt[kmax] = temp
1821
+ rdiag[kmax] = rdiag[j]
1822
+ wa[kmax] = wa[j]
1823
+
1824
+ # Compute the householder transformation to reduce the jth
1825
+ # column of A to a multiple of the jth unit vector
1826
+ lj = ipvt[j]
1827
+ ajj = a[j:,lj]
1828
+ ajnorm = self.enorm(ajj)
1829
+ if ajnorm == 0:
1830
+ break
1831
+ if a[j,lj] < 0:
1832
+ ajnorm = -ajnorm
1833
+
1834
+ ajj = ajj / ajnorm
1835
+ ajj[0] = ajj[0] + 1
1836
+ # *** Note optimization a(j:*,j)
1837
+ a[j:,lj] = ajj
1838
+
1839
+ # Apply the transformation to the remaining columns
1840
+ # and update the norms
1841
+
1842
+ # NOTE to SELF: tried to optimize this by removing the loop,
1843
+ # but it actually got slower. Reverted to "for" loop to keep
1844
+ # it simple.
1845
+ if j+1 < n:
1846
+ for k in range(j+1, n):
1847
+ lk = ipvt[k]
1848
+ ajk = a[j:,lk]
1849
+ # *** Note optimization a(j:*,lk)
1850
+ # (corrected 20 Jul 2000)
1851
+ if a[j,lj] != 0:
1852
+ a[j:,lk] = ajk - ajj * sum(ajk*ajj)/a[j,lj]
1853
+ if (pivot != 0) and (rdiag[k] != 0):
1854
+ temp = a[j,lk]/rdiag[k]
1855
+ rdiag[k] = rdiag[k] * numpy.sqrt(numpy.max([(1.-temp**2), 0.]))
1856
+ temp = rdiag[k]/wa[k]
1857
+ if (0.05*temp*temp) <= machep:
1858
+ rdiag[k] = self.enorm(a[j+1:,lk])
1859
+ wa[k] = rdiag[k]
1860
+ rdiag[j] = -ajnorm
1861
+ return [a, ipvt, rdiag, acnorm]
1862
+
1863
+
1864
+ # Original FORTRAN documentation
1865
+ # **********
1866
+ #
1867
+ # subroutine qrsolv
1868
+ #
1869
+ # given an m by n matrix a, an n by n diagonal matrix d,
1870
+ # and an m-vector b, the problem is to determine an x which
1871
+ # solves the system
1872
+ #
1873
+ # a*x = b , d*x = 0 ,
1874
+ #
1875
+ # in the least squares sense.
1876
+ #
1877
+ # this subroutine completes the solution of the problem
1878
+ # if it is provided with the necessary information from the
1879
+ # factorization, with column pivoting, of a. that is, if
1880
+ # a*p = q*r, where p is a permutation matrix, q has orthogonal
1881
+ # columns, and r is an upper triangular matrix with diagonal
1882
+ # elements of nonincreasing magnitude, then qrsolv expects
1883
+ # the full upper triangle of r, the permutation matrix p,
1884
+ # and the first n components of (q transpose)*b. the system
1885
+ # a*x = b, d*x = 0, is then equivalent to
1886
+ #
1887
+ # t t
1888
+ # r*z = q *b , p *d*p*z = 0 ,
1889
+ #
1890
+ # where x = p*z. if this system does not have full rank,
1891
+ # then a least squares solution is obtained. on output qrsolv
1892
+ # also provides an upper triangular matrix s such that
1893
+ #
1894
+ # t t t
1895
+ # p *(a *a + d*d)*p = s *s .
1896
+ #
1897
+ # s is computed within qrsolv and may be of separate interest.
1898
+ #
1899
+ # the subroutine statement is
1900
+ #
1901
+ # subroutine qrsolv(n,r,ldr,ipvt,diag,qtb,x,sdiag,wa)
1902
+ #
1903
+ # where
1904
+ #
1905
+ # n is a positive integer input variable set to the order of r.
1906
+ #
1907
+ # r is an n by n array. on input the full upper triangle
1908
+ # must contain the full upper triangle of the matrix r.
1909
+ # on output the full upper triangle is unaltered, and the
1910
+ # strict lower triangle contains the strict upper triangle
1911
+ # (transposed) of the upper triangular matrix s.
1912
+ #
1913
+ # ldr is a positive integer input variable not less than n
1914
+ # which specifies the leading dimension of the array r.
1915
+ #
1916
+ # ipvt is an integer input array of length n which defines the
1917
+ # permutation matrix p such that a*p = q*r. column j of p
1918
+ # is column ipvt(j) of the identity matrix.
1919
+ #
1920
+ # diag is an input array of length n which must contain the
1921
+ # diagonal elements of the matrix d.
1922
+ #
1923
+ # qtb is an input array of length n which must contain the first
1924
+ # n elements of the vector (q transpose)*b.
1925
+ #
1926
+ # x is an output array of length n which contains the least
1927
+ # squares solution of the system a*x = b, d*x = 0.
1928
+ #
1929
+ # sdiag is an output array of length n which contains the
1930
+ # diagonal elements of the upper triangular matrix s.
1931
+ #
1932
+ # wa is a work array of length n.
1933
+ #
1934
+ # subprograms called
1935
+ #
1936
+ # fortran-supplied ... dabs,dsqrt
1937
+ #
1938
+ # argonne national laboratory. minpack project. march 1980.
1939
+ # burton s. garbow, kenneth e. hillstrom, jorge j. more
1940
+ #
1941
+
1942
+ def qrsolv(self, r, ipvt, diag, qtb, sdiag):
1943
+ if self.debug:
1944
+ print ('Entering qrsolv...')
1945
+ sz = r.shape
1946
+ m = sz[0]
1947
+ n = sz[1]
1948
+
1949
+ # copy r and (q transpose)*b to preserve input and initialize s.
1950
+ # in particular, save the diagonal elements of r in x.
1951
+
1952
+ for j in range(n):
1953
+ r[j:n,j] = r[j,j:n]
1954
+ x = numpy.diagonal(r).copy()
1955
+ wa = qtb.copy()
1956
+
1957
+ # Eliminate the diagonal matrix d using a givens rotation
1958
+ for j in range(n):
1959
+ l = ipvt[j]
1960
+ if diag[l] == 0:
1961
+ break
1962
+ sdiag[j:] = 0
1963
+ sdiag[j] = diag[l]
1964
+
1965
+ # The transformations to eliminate the row of d modify only a
1966
+ # single element of (q transpose)*b beyond the first n, which
1967
+ # is initially zero.
1968
+
1969
+ qtbpj = 0.
1970
+ for k in range(j,n):
1971
+ if sdiag[k] == 0:
1972
+ break
1973
+ if numpy.abs(r[k,k]) < numpy.abs(sdiag[k]):
1974
+ cotan = r[k,k]/sdiag[k]
1975
+ sine = 0.5/numpy.sqrt(.25 + .25*cotan*cotan)
1976
+ cosine = sine*cotan
1977
+ else:
1978
+ tang = sdiag[k]/r[k,k]
1979
+ cosine = 0.5/numpy.sqrt(.25 + .25*tang*tang)
1980
+ sine = cosine*tang
1981
+
1982
+ # Compute the modified diagonal element of r and the
1983
+ # modified element of ((q transpose)*b,0).
1984
+ r[k,k] = cosine*r[k,k] + sine*sdiag[k]
1985
+ temp = cosine*wa[k] + sine*qtbpj
1986
+ qtbpj = -sine*wa[k] + cosine*qtbpj
1987
+ wa[k] = temp
1988
+
1989
+ # Accumulate the transformation in the row of s
1990
+ if n > k+1:
1991
+ temp = cosine*r[k+1:n,k] + sine*sdiag[k+1:n]
1992
+ sdiag[k+1:n] = -sine*r[k+1:n,k] + cosine*sdiag[k+1:n]
1993
+ r[k+1:n,k] = temp
1994
+ sdiag[j] = r[j,j]
1995
+ r[j,j] = x[j]
1996
+
1997
+ # Solve the triangular system for z. If the system is singular
1998
+ # then obtain a least squares solution
1999
+ nsing = n
2000
+ wh = (numpy.nonzero(sdiag == 0))[0]
2001
+ if len(wh) > 0:
2002
+ nsing = wh[0]
2003
+ wa[nsing:] = 0
2004
+
2005
+ if nsing >= 1:
2006
+ wa[nsing-1] = wa[nsing-1]/sdiag[nsing-1] # Degenerate case
2007
+ # *** Reverse loop ***
2008
+ for j in range(nsing-2,-1,-1):
2009
+ sum0 = sum(r[j+1:nsing,j]*wa[j+1:nsing])
2010
+ wa[j] = (wa[j]-sum0)/sdiag[j]
2011
+
2012
+ # Permute the components of z back to components of x
2013
+ x[ipvt] = wa
2014
+ return (r, x, sdiag)
2015
+
2016
+
2017
+
2018
+
2019
+ # Original FORTRAN documentation
2020
+ #
2021
+ # subroutine lmpar
2022
+ #
2023
+ # given an m by n matrix a, an n by n nonsingular diagonal
2024
+ # matrix d, an m-vector b, and a positive number delta,
2025
+ # the problem is to determine a value for the parameter
2026
+ # par such that if x solves the system
2027
+ #
2028
+ # a*x = b , sqrt(par)*d*x = 0 ,
2029
+ #
2030
+ # in the least squares sense, and dxnorm is the euclidean
2031
+ # norm of d*x, then either par is zero and
2032
+ #
2033
+ # (dxnorm-delta) .le. 0.1*delta ,
2034
+ #
2035
+ # or par is positive and
2036
+ #
2037
+ # abs(dxnorm-delta) .le. 0.1*delta .
2038
+ #
2039
+ # this subroutine completes the solution of the problem
2040
+ # if it is provided with the necessary information from the
2041
+ # qr factorization, with column pivoting, of a. that is, if
2042
+ # a*p = q*r, where p is a permutation matrix, q has orthogonal
2043
+ # columns, and r is an upper triangular matrix with diagonal
2044
+ # elements of nonincreasing magnitude, then lmpar expects
2045
+ # the full upper triangle of r, the permutation matrix p,
2046
+ # and the first n components of (q transpose)*b. on output
2047
+ # lmpar also provides an upper triangular matrix s such that
2048
+ #
2049
+ # t t t
2050
+ # p *(a *a + par*d*d)*p = s *s .
2051
+ #
2052
+ # s is employed within lmpar and may be of separate interest.
2053
+ #
2054
+ # only a few iterations are generally needed for convergence
2055
+ # of the algorithm. if, however, the limit of 10 iterations
2056
+ # is reached, then the output par will contain the best
2057
+ # value obtained so far.
2058
+ #
2059
+ # the subroutine statement is
2060
+ #
2061
+ # subroutine lmpar(n,r,ldr,ipvt,diag,qtb,delta,par,x,sdiag,
2062
+ # wa1,wa2)
2063
+ #
2064
+ # where
2065
+ #
2066
+ # n is a positive integer input variable set to the order of r.
2067
+ #
2068
+ # r is an n by n array. on input the full upper triangle
2069
+ # must contain the full upper triangle of the matrix r.
2070
+ # on output the full upper triangle is unaltered, and the
2071
+ # strict lower triangle contains the strict upper triangle
2072
+ # (transposed) of the upper triangular matrix s.
2073
+ #
2074
+ # ldr is a positive integer input variable not less than n
2075
+ # which specifies the leading dimension of the array r.
2076
+ #
2077
+ # ipvt is an integer input array of length n which defines the
2078
+ # permutation matrix p such that a*p = q*r. column j of p
2079
+ # is column ipvt(j) of the identity matrix.
2080
+ #
2081
+ # diag is an input array of length n which must contain the
2082
+ # diagonal elements of the matrix d.
2083
+ #
2084
+ # qtb is an input array of length n which must contain the first
2085
+ # n elements of the vector (q transpose)*b.
2086
+ #
2087
+ # delta is a positive input variable which specifies an upper
2088
+ # bound on the euclidean norm of d*x.
2089
+ #
2090
+ # par is a nonnegative variable. on input par contains an
2091
+ # initial estimate of the levenberg-marquardt parameter.
2092
+ # on output par contains the final estimate.
2093
+ #
2094
+ # x is an output array of length n which contains the least
2095
+ # squares solution of the system a*x = b, sqrt(par)*d*x = 0,
2096
+ # for the output par.
2097
+ #
2098
+ # sdiag is an output array of length n which contains the
2099
+ # diagonal elements of the upper triangular matrix s.
2100
+ #
2101
+ # wa1 and wa2 are work arrays of length n.
2102
+ #
2103
+ # subprograms called
2104
+ #
2105
+ # minpack-supplied ... dpmpar,enorm,qrsolv
2106
+ #
2107
+ # fortran-supplied ... dabs,dmax1,dmin1,dsqrt
2108
+ #
2109
+ # argonne national laboratory. minpack project. march 1980.
2110
+ # burton s. garbow, kenneth e. hillstrom, jorge j. more
2111
+ #
2112
+
2113
+ def lmpar(self, r, ipvt, diag, qtb, delta, x, sdiag, par=None):
2114
+
2115
+ if self.debug:
2116
+ print ('Entering lmpar...')
2117
+ dwarf = self.machar.minnum
2118
+ machep = self.machar.machep
2119
+ sz = r.shape
2120
+ m = sz[0]
2121
+ n = sz[1]
2122
+
2123
+ # Compute and store in x the gauss-newton direction. If the
2124
+ # jacobian is rank-deficient, obtain a least-squares solution
2125
+ nsing = n
2126
+ wa1 = qtb.copy()
2127
+ rthresh = numpy.max(numpy.abs(numpy.diagonal(r))) * machep
2128
+ wh = (numpy.nonzero(numpy.abs(numpy.diagonal(r)) < rthresh))[0]
2129
+ if len(wh) > 0:
2130
+ nsing = wh[0]
2131
+ wa1[wh[0]:] = 0
2132
+ if nsing >= 1:
2133
+ # *** Reverse loop ***
2134
+ for j in range(nsing-1,-1,-1):
2135
+ wa1[j] = wa1[j]/r[j,j]
2136
+ if j-1 >= 0:
2137
+ wa1[0:j] = wa1[0:j] - r[0:j,j]*wa1[j]
2138
+
2139
+ # Note: ipvt here is a permutation array
2140
+ x[ipvt] = wa1
2141
+
2142
+ # Initialize the iteration counter. Evaluate the function at the
2143
+ # origin, and test for acceptance of the gauss-newton direction
2144
+ iter = 0
2145
+ wa2 = diag * x
2146
+ dxnorm = self.enorm(wa2)
2147
+ fp = dxnorm - delta
2148
+ if fp <= 0.1*delta:
2149
+ return [r, 0., x, sdiag]
2150
+
2151
+ # If the jacobian is not rank deficient, the newton step provides a
2152
+ # lower bound, parl, for the zero of the function. Otherwise set
2153
+ # this bound to zero.
2154
+
2155
+ parl = 0.
2156
+ if nsing >= n:
2157
+ wa1 = diag[ipvt] * wa2[ipvt] / dxnorm
2158
+ wa1[0] = wa1[0] / r[0,0] # Degenerate case
2159
+ for j in range(1,n): # Note "1" here, not zero
2160
+ sum0 = sum(r[0:j,j]*wa1[0:j])
2161
+ wa1[j] = (wa1[j] - sum0)/r[j,j]
2162
+
2163
+ temp = self.enorm(wa1)
2164
+ parl = ((fp/delta)/temp)/temp
2165
+
2166
+ # Calculate an upper bound, paru, for the zero of the function
2167
+ for j in range(n):
2168
+ sum0 = sum(r[0:j+1,j]*qtb[0:j+1])
2169
+ wa1[j] = sum0/diag[ipvt[j]]
2170
+ gnorm = self.enorm(wa1)
2171
+ paru = gnorm/delta
2172
+ if paru == 0:
2173
+ paru = dwarf/numpy.min([delta,0.1])
2174
+
2175
+ # If the input par lies outside of the interval (parl,paru), set
2176
+ # par to the closer endpoint
2177
+
2178
+ par = numpy.max([par,parl])
2179
+ par = numpy.min([par,paru])
2180
+ if par == 0:
2181
+ par = gnorm/dxnorm
2182
+
2183
+ # Beginning of an interation
2184
+ while(1):
2185
+ iter = iter + 1
2186
+
2187
+ # Evaluate the function at the current value of par
2188
+ if par == 0:
2189
+ par = numpy.max([dwarf, paru*0.001])
2190
+ temp = numpy.sqrt(par)
2191
+ wa1 = temp * diag
2192
+ [r, x, sdiag] = self.qrsolv(r, ipvt, wa1, qtb, sdiag)
2193
+ wa2 = diag*x
2194
+ dxnorm = self.enorm(wa2)
2195
+ temp = fp
2196
+ fp = dxnorm - delta
2197
+
2198
+ if (numpy.abs(fp) <= 0.1*delta) or \
2199
+ ((parl == 0) and (fp <= temp) and (temp < 0)) or \
2200
+ (iter == 10):
2201
+ break;
2202
+
2203
+ # Compute the newton correction
2204
+ wa1 = diag[ipvt] * wa2[ipvt] / dxnorm
2205
+
2206
+ for j in range(n-1):
2207
+ wa1[j] = wa1[j]/sdiag[j]
2208
+ wa1[j+1:n] = wa1[j+1:n] - r[j+1:n,j]*wa1[j]
2209
+ wa1[n-1] = wa1[n-1]/sdiag[n-1] # Degenerate case
2210
+
2211
+ temp = self.enorm(wa1)
2212
+ parc = ((fp/delta)/temp)/temp
2213
+
2214
+ # Depending on the sign of the function, update parl or paru
2215
+ if fp > 0:
2216
+ parl = numpy.max([parl,par])
2217
+ if fp < 0:
2218
+ paru = numpy.min([paru,par])
2219
+
2220
+ # Compute an improved estimate for par
2221
+ par = numpy.max([parl, par+parc])
2222
+
2223
+ # End of an iteration
2224
+
2225
+ # Termination
2226
+ return [r, par, x, sdiag]
2227
+
2228
+
2229
+ # Procedure to tie one parameter to another.
2230
+ def tie(self, p, ptied=None):
2231
+ if self.debug:
2232
+ print ('Entering tie...')
2233
+ if ptied is None:
2234
+ return
2235
+ for i in range(len(ptied)):
2236
+ if ptied[i] == '':
2237
+ continue
2238
+ cmd = 'p[' + str(i) + '] = ' + ptied[i]
2239
+ exec(cmd)
2240
+ return p
2241
+
2242
+
2243
+ # Original FORTRAN documentation
2244
+ # **********
2245
+ #
2246
+ # subroutine covar
2247
+ #
2248
+ # given an m by n matrix a, the problem is to determine
2249
+ # the covariance matrix corresponding to a, defined as
2250
+ #
2251
+ # t
2252
+ # inverse(a *a) .
2253
+ #
2254
+ # this subroutine completes the solution of the problem
2255
+ # if it is provided with the necessary information from the
2256
+ # qr factorization, with column pivoting, of a. that is, if
2257
+ # a*p = q*r, where p is a permutation matrix, q has orthogonal
2258
+ # columns, and r is an upper triangular matrix with diagonal
2259
+ # elements of nonincreasing magnitude, then covar expects
2260
+ # the full upper triangle of r and the permutation matrix p.
2261
+ # the covariance matrix is then computed as
2262
+ #
2263
+ # t t
2264
+ # p*inverse(r *r)*p .
2265
+ #
2266
+ # if a is nearly rank deficient, it may be desirable to compute
2267
+ # the covariance matrix corresponding to the linearly independent
2268
+ # columns of a. to define the numerical rank of a, covar uses
2269
+ # the tolerance tol. if l is the largest integer such that
2270
+ #
2271
+ # abs(r(l,l)) .gt. tol*abs(r(1,1)) ,
2272
+ #
2273
+ # then covar computes the covariance matrix corresponding to
2274
+ # the first l columns of r. for k greater than l, column
2275
+ # and row ipvt(k) of the covariance matrix are set to zero.
2276
+ #
2277
+ # the subroutine statement is
2278
+ #
2279
+ # subroutine covar(n,r,ldr,ipvt,tol,wa)
2280
+ #
2281
+ # where
2282
+ #
2283
+ # n is a positive integer input variable set to the order of r.
2284
+ #
2285
+ # r is an n by n array. on input the full upper triangle must
2286
+ # contain the full upper triangle of the matrix r. on output
2287
+ # r contains the square symmetric covariance matrix.
2288
+ #
2289
+ # ldr is a positive integer input variable not less than n
2290
+ # which specifies the leading dimension of the array r.
2291
+ #
2292
+ # ipvt is an integer input array of length n which defines the
2293
+ # permutation matrix p such that a*p = q*r. column j of p
2294
+ # is column ipvt(j) of the identity matrix.
2295
+ #
2296
+ # tol is a nonnegative input variable used to define the
2297
+ # numerical rank of a in the manner described above.
2298
+ #
2299
+ # wa is a work array of length n.
2300
+ #
2301
+ # subprograms called
2302
+ #
2303
+ # fortran-supplied ... dabs
2304
+ #
2305
+ # argonne national laboratory. minpack project. august 1980.
2306
+ # burton s. garbow, kenneth e. hillstrom, jorge j. more
2307
+ #
2308
+ # **********
2309
+
2310
+ def calc_covar(self, rr, ipvt=None, tol=1.e-14):
2311
+
2312
+ if self.debug:
2313
+ print ('Entering calc_covar...')
2314
+ if numpy.ndim(rr) != 2:
2315
+ print ('ERROR: r must be a two-dimensional matrix')
2316
+ return -1
2317
+ s = rr.shape
2318
+ n = s[0]
2319
+ if s[0] != s[1]:
2320
+ print ('ERROR: r must be a square matrix')
2321
+ return -1
2322
+
2323
+ if ipvt is None:
2324
+ ipvt = numpy.arange(n)
2325
+ r = rr.copy()
2326
+ r = r.reshape(n, n)
2327
+
2328
+ # For the inverse of r in the full upper triangle of r
2329
+ l = -1
2330
+ tolr = tol * numpy.abs(r[0,0])
2331
+ for k in range(n):
2332
+ if numpy.abs(r[k,k]) <= tolr:
2333
+ break
2334
+ r[k,k] = 1./r[k,k]
2335
+ for j in range(k):
2336
+ temp = r[k,k] * r[j,k]
2337
+ r[j,k] = 0.
2338
+ r[0:j+1,k] = r[0:j+1,k] - temp*r[0:j+1,j]
2339
+ l = k
2340
+
2341
+ # Form the full upper triangle of the inverse of (r transpose)*r
2342
+ # in the full upper triangle of r
2343
+ if l >= 0:
2344
+ for k in range(l+1):
2345
+ for j in range(k):
2346
+ temp = r[j,k]
2347
+ r[0:j+1,j] = r[0:j+1,j] + temp*r[0:j+1,k]
2348
+ temp = r[k,k]
2349
+ r[0:k+1,k] = temp * r[0:k+1,k]
2350
+
2351
+ # For the full lower triangle of the covariance matrix
2352
+ # in the strict lower triangle or and in wa
2353
+ wa = numpy.repeat([r[0,0]], n)
2354
+ for j in range(n):
2355
+ jj = ipvt[j]
2356
+ sing = j > l
2357
+ for i in range(j+1):
2358
+ if sing:
2359
+ r[i,j] = 0.
2360
+ ii = ipvt[i]
2361
+ if ii > jj:
2362
+ r[ii,jj] = r[i,j]
2363
+ if ii < jj:
2364
+ r[jj,ii] = r[i,j]
2365
+ wa[jj] = r[j,j]
2366
+
2367
+ # Symmetrize the covariance matrix in r
2368
+ for j in range(n):
2369
+ r[0:j+1,j] = r[j,0:j+1]
2370
+ r[j,j] = wa[j]
2371
+
2372
+ return r
2373
+
2374
+ class machar:
2375
+ def __init__(self, double=1):
2376
+ if double == 0:
2377
+ info = numpy.finfo(numpy.float32)
2378
+ else:
2379
+ info = numpy.finfo(numpy.float64)
2380
+
2381
+ self.machep = info.eps
2382
+ self.maxnum = info.max
2383
+ self.minnum = info.tiny
2384
+
2385
+ self.maxlog = numpy.log(self.maxnum)
2386
+ self.minlog = numpy.log(self.minnum)
2387
+ self.rdwarf = numpy.sqrt(self.minnum*1.5) * 10
2388
+ self.rgiant = numpy.sqrt(self.maxnum) * 0.1