mc3 3.3.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.
mc3/__init__.py ADDED
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2015-2026 Patricio Cubillos and contributors.
2
+ # mc3 is open-source software under the MIT license (see LICENSE).
3
+
4
+ from .sampler_driver import *
5
+ from .fit_driver import *
6
+ from . import plots
7
+ from . import utils
8
+ from . import stats
9
+ from .version import __version__
10
+
11
+
12
+ __all__ = (
13
+ sampler_driver.__all__
14
+ + fit_driver.__all__
15
+ + ['plots', 'utils', 'stats']
16
+ )
17
+
18
+
19
+ # Clean up top-level namespace--delete everything that isn't in __all__
20
+ # or is a magic attribute, and that isn't a submodule of this package
21
+ for varname in dir():
22
+ if not ((varname.startswith('__') and varname.endswith('__')) or
23
+ varname in __all__):
24
+ del locals()[varname]
25
+ del(varname)
mc3/__main__.py ADDED
@@ -0,0 +1,240 @@
1
+ # Copyright (c) 2015-2026 Patricio Cubillos and contributors.
2
+ # mc3 is open-source software under the MIT license (see LICENSE).
3
+
4
+ import sys
5
+ import os
6
+ import warnings
7
+ import argparse
8
+ import configparser
9
+
10
+ import matplotlib
11
+ import matplotlib.pyplot as plt
12
+
13
+ import mc3
14
+ import mc3.utils as mu
15
+
16
+
17
+ def main():
18
+ """
19
+ Multi-Core Markov-chain Monte Carlo (mc3) wrapper for the command line
20
+
21
+ Notes
22
+ -----
23
+ To display the full list of arguments, run from the prompt:
24
+ mc3 -h
25
+
26
+ Command-line arguments overwrite the config-file arguments if the
27
+ argument is defined twice.
28
+ """
29
+ parser = parse()
30
+
31
+ # Parse command-line args (right now, just interested in the config file):
32
+ args, unknown = parser.parse_known_args()
33
+
34
+ # Parse configuration file to a dictionary:
35
+ if args.cfile is not None and not os.path.isfile(args.cfile):
36
+ print(f"Configuration file: '{args.cfile}' not found.")
37
+ sys.exit(0)
38
+ if args.cfile:
39
+ config = configparser.ConfigParser()
40
+ config.read([args.cfile])
41
+ defaults = dict(config.items("MCMC"))
42
+ else:
43
+ defaults = {}
44
+ # Set defaults from the configuration-file values:
45
+ parser.set_defaults(**defaults)
46
+ # Overwrite defaults with the command-line arguments:
47
+ args, unknown = parser.parse_known_args()
48
+ delattr(args, 'cfile')
49
+ # Call MCMC driver:
50
+ mc3.sample(**vars(args))
51
+
52
+
53
+ def parse():
54
+ """mc3 command-line argument parser"""
55
+ # Parse the config file from the command line:
56
+ parser = argparse.ArgumentParser(
57
+ description=__doc__,
58
+ formatter_class=argparse.RawDescriptionHelpFormatter)
59
+
60
+ # Configuration-file option:
61
+ parser.add_argument(
62
+ "-c", "--cfile", help="Configuration file.", metavar="FILE")
63
+ parser.add_argument(
64
+ "-v", "--version", action="version",
65
+ help="Display mc3's version.",
66
+ version=f'mc3 version {mc3.__version__}.')
67
+ # MCMC Options:
68
+ group = parser.add_argument_group("MCMC General Options")
69
+ group.add_argument(
70
+ "--nsamples", dest="nsamples", action="store", type=eval, default=None,
71
+ help="Number of MCMC samples.")
72
+ group.add_argument(
73
+ "--nchains", dest="nchains", action="store", type=int, default=7,
74
+ help="Number of chains [default: %(default)s]")
75
+ group.add_argument(
76
+ "--ncpu", dest="ncpu", action="store", type=int, default=None,
77
+ help="Number of CPUs for the chains [default: nchains+1]")
78
+ group.add_argument(
79
+ "--sampler", dest="sampler", action="store", type=str, default=None,
80
+ help="Sampler algorithm, select from: ['mrw', 'demc', 'snooker'].")
81
+ group.add_argument(
82
+ "--wlike", dest="wlike", action="store", type=eval, default=False,
83
+ help="Calculate the likelihood in a wavelet base "
84
+ "[default: %(default)s]")
85
+ group.add_argument(
86
+ "--leastsq", dest="leastsq", action="store", type=eval, default=None,
87
+ help="If not None, perform a least-squares optimiztion before the "
88
+ "MCMC run. Select from: 'lm': Levenberg-Marquardt (most "
89
+ "efficient, but does not obey bounds); 'trf': Trust Region "
90
+ "Reflective [default: %(default)s].")
91
+ group.add_argument(
92
+ "--chisqscale", dest="chisqscale", action="store",
93
+ type=eval, default=False,
94
+ help="Scale the data uncertainties such that the reduced "
95
+ "chi-squared = 1. [default: %(default)s]")
96
+ group.add_argument(
97
+ "--grtest", dest="grtest", action="store", type=eval, default=False,
98
+ help="Run Gelman-Rubin test [default: %(default)s]")
99
+ group.add_argument(
100
+ "--grbreak", dest="grbreak", action="store", type=float, default=0.0,
101
+ help="Gelman-Rubin convergence threshold to stop the MCMC. I'd "
102
+ "suggest grbreak ~ 1.001 -- 1.005. Do not break if "
103
+ "grbreak=0.0 (default).")
104
+ group.add_argument(
105
+ "--grnmin", dest="grnmin", action="store", type=eval, default=0.5,
106
+ help="Minimum number of valid samples required for grbreak. If grnmin "
107
+ "is integer, require at least grnmin samples to break out of the "
108
+ "MCMC. If grnmin is a float (in the range 0.0--1.0), require at "
109
+ "least grnmin * maximum number of samples to break out of the "
110
+ "MCMC [default: %(default)s]")
111
+ group.add_argument(
112
+ "--burnin", dest="burnin", action="store", type=eval, default=0,
113
+ help="Number of burn-in iterations (per chain) [default: %(default)s]")
114
+ group.add_argument(
115
+ "--thinning", dest="thinning", action="store", type=int, default=1,
116
+ help="Chains thinning factor (use every thinning-th iteration) for GR "
117
+ "test and plots [default: %(default)s]")
118
+ group.add_argument(
119
+ "--fgamma", dest="fgamma", action="store", type=float, default=1.0,
120
+ help="Scaling factor for DEMC's gamma [default: %(default)s]")
121
+ group.add_argument(
122
+ "--fepsilon", dest="fepsilon", action="store", type=float, default=0.0,
123
+ help="Scaling factor for DEMC's support distribution "
124
+ "[default: %(default)s]")
125
+ group.add_argument(
126
+ "--hsize", dest="hsize", action="store", type=int, default=10,
127
+ help="Number of initial samples per chain [default: %(default)s]")
128
+ group.add_argument(
129
+ "--kickoff", dest="kickoff", action="store", type=str, default="normal",
130
+ help="Chain's starter mode, select between: ['normal', 'uniform']. "
131
+ "[default: %(default)s]")
132
+ group.add_argument(
133
+ "--plots", dest="plots", action="store", type=eval, default=False,
134
+ help="If True, generate output figures. [default: %(default)s]")
135
+ group.add_argument(
136
+ "--theme", dest="theme", action="store", type=str, default='blue',
137
+ help="Color theme for plots, can be any color format recognized "
138
+ "by matplotlib. [default: %(default)s]")
139
+ group.add_argument(
140
+ "--statistics", dest="statistics", action="store", type=str,
141
+ default='med_central',
142
+ help="Which statistics to adopt for the plots, select between: "
143
+ "'med_central' (default, median and central quantile statistics), "
144
+ "'max_like' (mode and HPD statistics), or 'global_max_like' "
145
+ "(best-fit and HPD statistics).")
146
+ group.add_argument(
147
+ "--ioff", dest="ioff", action="store", type=eval, default=False,
148
+ help="If True, set plt.ioff(), i.e., do not display figures on screen "
149
+ "[default: %(default)s]")
150
+ group.add_argument(
151
+ "--showbp", dest="showbp", action="store", type=eval, default=True,
152
+ help="If True, show best-fitting values in histogram and pairwise "
153
+ "plots [default: %(default)s]")
154
+ group.add_argument(
155
+ "--savefile", dest="savefile", action="store", type=str, default=None,
156
+ help="Output npz filename to store the parameter posterior "
157
+ "distributions [default: %(default)s]")
158
+ group.add_argument(
159
+ "-r", "--resume", dest="resume", action="store_true", default=False,
160
+ help="If set, resume a previous run (load output).")
161
+ group.add_argument(
162
+ "--rms", dest="rms", action="store", type=eval, default=False,
163
+ help="If True, calculate RMS-vs-binsize of data--bestmodel residuals "
164
+ "[default: %(default)s]")
165
+ group.add_argument(
166
+ "--log", dest="log", action="store", type=str, default=None,
167
+ help="Output log filename.")
168
+ group.add_argument(
169
+ "--pnames", dest="pnames", action="store", type=mu.parray, default=None,
170
+ help="List of parameter names for screen output (and figures if "
171
+ "texnames is not defined). If pnames is not defined, default "
172
+ "to texnames.")
173
+ group.add_argument(
174
+ "--texnames", dest="texnames", action="store", type=mu.parray,
175
+ default=None,
176
+ help="List of parameter names for figures (may use latex syntax). "
177
+ "[default: None]")
178
+ # Fitting-parameter Options:
179
+ group = parser.add_argument_group("Fitting-function Options")
180
+ group.add_argument(
181
+ "--func", dest="func", action="store", type=mu.parray, default=None,
182
+ help="List of strings with the function name, module "
183
+ "name, and path-to-module [required]")
184
+ group.add_argument(
185
+ "--params", dest="params", action="store", type=mu.parray, default=None,
186
+ help="Filename or list of initial-guess model-fitting "
187
+ "parameter [required]")
188
+ group.add_argument(
189
+ "--pmin", dest="pmin", action="store", type=mu.parray, default=None,
190
+ help="Filename or list of parameter lower boundaries "
191
+ "[default: -inf for each parameter]")
192
+ group.add_argument(
193
+ "--pmax", dest="pmax", action="store", type=mu.parray, default=None,
194
+ help="Filename or list of parameter upper boundaries "
195
+ "[default: +inf for each parameter]")
196
+ group.add_argument(
197
+ "--pstep", dest="pstep", action="store", type=mu.parray, default=None,
198
+ help="Parameter stepping [required]. Additionally, parameters with "
199
+ "pstep=0 are fixed, parameters with negative pstep are "
200
+ "shared (see documentation).")
201
+ group.add_argument(
202
+ "--indparams", dest="indparams", action="store",
203
+ type=mu.parray, default=[],
204
+ help="Filename or list with independent parameters for func "
205
+ "[default: None]")
206
+ group.add_argument(
207
+ "--indparams_dict", dest="indparams_dict", action="store",
208
+ type=dict, default={},
209
+ help="Dictionary with independent keyword parameters for func "
210
+ "[default: {}]")
211
+ # Data Options:
212
+ group = parser.add_argument_group("Data Options")
213
+ group.add_argument(
214
+ "--data", dest="data", action="store", type=mu.parray, default=None,
215
+ help="Filename or array of the data being fitted [required]")
216
+ group.add_argument(
217
+ "--uncert", dest="uncert", action="store", type=mu.parray, default=None,
218
+ help="Filemane or array with the data uncertainties [required]")
219
+ group.add_argument(
220
+ "--prior", dest="prior", action="store", type=mu.parray, default=None,
221
+ help="Filename or array with parameter prior estimates "
222
+ "[default: %(default)s]")
223
+ group.add_argument(
224
+ "--priorlow", dest="priorlow", action="store", type=mu.parray,
225
+ default=None,
226
+ help="Filename or array with prior lower uncertainties "
227
+ "[default: %(default)s]")
228
+ group.add_argument(
229
+ "--priorup", dest="priorup", action="store", type=mu.parray,
230
+ default=None,
231
+ help="Filename or array with prior upper uncertainties "
232
+ "[default: %(default)s]")
233
+ return parser
234
+
235
+
236
+ if __name__ == "__main__":
237
+ matplotlib.use('Agg')
238
+ plt.ioff()
239
+ warnings.simplefilter("ignore", RuntimeWarning)
240
+ main()
mc3/chain.py ADDED
@@ -0,0 +1,340 @@
1
+ # Copyright (c) 2015-2026 Patricio Cubillos and contributors.
2
+ # mc3 is open-source software under the MIT license (see LICENSE).
3
+
4
+ import sys
5
+ import warnings
6
+ import random
7
+ import multiprocessing as mp
8
+
9
+ import numpy as np
10
+
11
+ from . import stats as ms
12
+
13
+
14
+ # Ingnore RuntimeWarnings:
15
+ warnings.simplefilter("ignore", RuntimeWarning)
16
+
17
+
18
+ class Chain(mp.get_context('fork').Process):
19
+ """
20
+ Background process. This guy evaluates the model and calculates chisq.
21
+ """
22
+ def __init__(self, func, args, kwargs, pipe, data, uncert,
23
+ params, freepars, pstep, pmin, pmax,
24
+ sampler, wlike, prior, priorlow, priorup, thinning,
25
+ fgamma, fepsilon, Z, zsize, log_post, zchain, M0,
26
+ numaccept, outbounds, ncpp,
27
+ chainsize, bestp, best_log_post, ID, ncpu, **kwds):
28
+ """
29
+ Chain class initializer.
30
+
31
+ Parameters
32
+ ----------
33
+ func: Callable
34
+ Model fitting function.
35
+ args: List
36
+ Additional arguments for func (besides the fitting parameters).
37
+ kwargs: Dict
38
+ Additional keyword arguments for func (if needed).
39
+ pipe: multiprocessing.Pipe object
40
+ Pipe to communicate with mcmc.
41
+ data: 1D shared-ctypes float ndarray
42
+ Dependent data fitted by func.
43
+ uncert: 1D Shared ctypes float ndarray
44
+ Uncertainty of data.
45
+ params: 1D float array
46
+ Array of model parameters (including fixed and shared).
47
+ freepars: 2D shared-ctypes float ndarray
48
+ Current state of fitting parameters (X, as in Braak & Vrugt 2008).
49
+ pstep: 1D float ndarray
50
+ Proposal jump scale.
51
+ pmin: 1D float ndarray
52
+ Lower boundaries of the posteriors.
53
+ pmax: 1D float ndarray
54
+ Upper boundaries of the posteriors.
55
+ sampler: String
56
+ Flag to indicate wich MCMC algorithm to use [mrw, demc, snooker].
57
+ wlike: Boolean
58
+ Flag to use a wavelet-based likelihood function (True) or not (False).
59
+ prior: 1D float ndarray
60
+ Parameter prior.
61
+ priorlow: 1D float ndarray
62
+ Prior lower uncertainties.
63
+ priorup: 1D float ndarray
64
+ Prior uppper uncertainties.
65
+ thinning: Integer
66
+ Thinning factor of the chains.
67
+ fgamma: Float
68
+ Proposals jump scale factor for DEMC's gamma.
69
+ The code computes: gamma = fgamma * 2.38 / sqrt(2*Nfree)
70
+ fepsilon: Float
71
+ Jump scale factor for DEMC's support distribution.
72
+ The code computes: e = fepsilon * Normal(0, pstep)
73
+ Z: 2D shared-ctype float ndarray
74
+ MCMC parameters history (Z, as in Braak & Vrugt 2008).
75
+ zsize: Shared ctypes integer
76
+ Current number of samples in the Z array.
77
+ log_post: Float multiprocessing.Array
78
+ log(posterior) values for the samples in Z.
79
+ zchain: multiprocessing.Array integer
80
+ Chain ID for the given state in the Z array.
81
+ M0: Integer
82
+ Initial number of samples in the Z array.
83
+ numaccept: multiprocessing.Value integer
84
+ Number of accepted MCMC proposals
85
+ outbounds: 1D shared multiprocessing integer Array
86
+ Number of out-of-bound proposals per free parameter.
87
+ ncpp: Integer
88
+ Number of chains for this process.
89
+ chainsize: multiprocessing.Array integer
90
+ The current length of this chain.
91
+ bestp: Shared ctypes float array
92
+ The array with the current best-fitting parameter.
93
+ best_log_post: Float multiprocessing.Value
94
+ The log(posterior) value for bestp.
95
+ ID: Integer
96
+ Identification serial number for this chain.
97
+ ncpu: Integer
98
+ The number of processes running chains.
99
+ """
100
+ # Multiprocessing setup:
101
+ mp.Process.__init__(self, **kwds)
102
+ self.daemon = True
103
+ self.ID = ID
104
+ self.ncpp = ncpp
105
+ self.ncpu = ncpu
106
+ # MCMC setup:
107
+ self.sampler = sampler
108
+ self.thinning = thinning
109
+ self.fgamma = fgamma
110
+ self.fepsilon = fepsilon
111
+ self.Z = Z
112
+ self.zsize = zsize
113
+ self.log_post = log_post
114
+ self.zchain = zchain
115
+ self.chainsize = chainsize
116
+ self.M0 = M0
117
+ self.numaccept = numaccept
118
+ self.outbounds = outbounds
119
+ # Best values:
120
+ self.bestp = bestp
121
+ self.best_log_post = best_log_post
122
+ # Modeling function:
123
+ self.func = func
124
+ self.args = args
125
+ self.kwargs = kwargs
126
+ # Model, fitting, and shared parameters:
127
+ self.params = params
128
+ self.freepars = freepars
129
+ self.pstep = pstep
130
+ self.pmin = pmin
131
+ self.pmax = pmax
132
+ # Input/output Pipe:
133
+ self.pipe = pipe
134
+ # Data:
135
+ self.data = data
136
+ self.uncert = uncert
137
+ # Chisq function:
138
+ self.wlike = wlike
139
+
140
+ # Index of parameters:
141
+ self.ishare = np.where(self.pstep < 0)[0]
142
+ self.ifree = np.where(self.pstep > 0)[0]
143
+
144
+ # Keep only the priors that count:
145
+ self.prior = prior
146
+ self.priorlow = priorlow
147
+ self.priorup = priorup
148
+
149
+ # Size of variables:
150
+ self.nfree = np.sum(self.pstep > 0) # Number of free parameters
151
+ self.nchains = np.shape(self.freepars)[0]
152
+ self.Zlen = np.shape(Z)[0]
153
+
154
+ # Length of mrw/demc chains:
155
+ self.chainlen = int((self.Zlen) / self.nchains)
156
+
157
+
158
+ def run(self):
159
+ """
160
+ Process the requests queue until terminated.
161
+ """
162
+ # Indices in Z-array to start this chains:
163
+ IDs = np.arange(self.ID, self.nchains, self.ncpu)
164
+ self.index = self.M0 + IDs
165
+ for j in range(self.ncpp):
166
+ if np.any(self.zchain==self.ID): # (i.e., resume=True)
167
+ # Set ID to the last iteration for this chain:
168
+ IDs[j] = self.index[j] = np.where(self.zchain==IDs[j])[0][-1]
169
+ self.freepars[self.ID + j*self.ncpu] = np.copy(self.Z[IDs[j]])
170
+ chisq = -2*self.log_post[IDs]
171
+
172
+ nextp = np.copy(self.params) # Array for proposed sample
173
+ nextchisq = 0.0 # Chi-square of nextp
174
+ njump = 0 # Number of jumps since last Z-update
175
+ gamma = self.fgamma * 2.38 / np.sqrt(2*self.nfree)
176
+
177
+ # The numpy random system must have its seed reinitialized in
178
+ # each sub-processes to avoid identical 'random' steps.
179
+ # random.randomint is process- and thread-safe.
180
+ np.random.seed(random.randint(0, 100000))
181
+
182
+ # Run until completing the Z array:
183
+ while True:
184
+ njump += 1
185
+ normal = np.random.normal(0, self.pstep[self.ifree], self.nfree)
186
+
187
+ if self.sampler == "demc":
188
+ b = self.pipe.recv() # Synchronization flag
189
+
190
+ for j in range(self.ncpp):
191
+ ID = self.ID + j*self.ncpu
192
+ mrfactor = 1.0
193
+
194
+ # Algorithm-specific proposals jumps:
195
+ if self.sampler == "snooker":
196
+ # Sampling without replacement (0 <= iR1 != iR2 < zsize):
197
+ iR1 = np.random.randint(0, self.zsize.value)
198
+ iR2 = np.random.randint(1, self.zsize.value)
199
+ if iR2 == iR1:
200
+ iR2 = 0
201
+ sjump = np.random.uniform() < 0.1
202
+ if sjump: # Snooker update:
203
+ iz = np.random.randint(self.zsize.value)
204
+ z = self.Z[iz] # Not to confuse with Z!
205
+ if np.all(z == self.freepars[ID]): # Do not project:
206
+ jump = np.random.uniform(1.2, 2.2) \
207
+ * (self.Z[iR2]-self.Z[iR1])
208
+ else:
209
+ dz = self.freepars[ID] - z
210
+ zp1 = np.dot(self.Z[iR1], dz)
211
+ zp2 = np.dot(self.Z[iR2], dz)
212
+ jump = np.random.uniform(1.2, 2.2) * (zp1-zp2) \
213
+ * dz/np.dot(dz,dz)
214
+ else: # Z update:
215
+ jump = \
216
+ gamma*(self.Z[iR1] - self.Z[iR2]) \
217
+ + self.fepsilon*normal
218
+
219
+ elif self.sampler == "mrw":
220
+ jump = normal
221
+ elif self.sampler == "demc":
222
+ # Select r1, r2 such that: r1 != r2 != ID:
223
+ r1 = np.random.randint(1, self.nchains)
224
+ if r1 == ID:
225
+ r1 = 0
226
+ # Pick r2 without replacement:
227
+ r2 = (r1 + np.random.randint(2, self.nchains))%self.nchains
228
+ if r2 == ID:
229
+ r2 = (r1 + 1) % self.nchains
230
+ jump = \
231
+ gamma*(self.freepars[r1] - self.freepars[r2]) \
232
+ + self.fepsilon*normal
233
+
234
+ # Propose next point:
235
+ nextp[self.ifree] = np.copy(self.freepars[ID]) + jump
236
+
237
+ # Check boundaries:
238
+ outpars = np.asarray(
239
+ ((nextp < self.pmin) | (nextp > self.pmax))[self.ifree])
240
+ # If any parameter lied out of bounds, skip model evaluation:
241
+ if np.any(outpars):
242
+ with self.outbounds.get_lock():
243
+ self.outbounds[:] += outpars
244
+ else:
245
+ # Update shared parameters:
246
+ for s in self.ishare:
247
+ nextp[s] = nextp[-int(self.pstep[s])-1]
248
+ # Evaluate model:
249
+ nextchisq = self.eval_model(nextp, ret="chisq")
250
+ # Additional factor in Metropolis ratio for Snooker jump:
251
+ if self.sampler == "snooker" and sjump:
252
+ # squared norm of current and next:
253
+ cnorm = np.dot(self.freepars[ID]-z, self.freepars[ID]-z)
254
+ nnorm = np.dot(nextp[self.ifree]-z, nextp[self.ifree]-z)
255
+ mrfactor = (nnorm/cnorm)**(0.5*(self.nfree-1))
256
+ # Evaluate the Metropolis ratio:
257
+ metro = (
258
+ np.exp(0.5*(chisq[j]-nextchisq)) * mrfactor
259
+ > np.random.uniform()
260
+ )
261
+ if metro:
262
+ # Update freepars[ID]:
263
+ self.freepars[ID] = np.copy(nextp[self.ifree])
264
+ chisq[j] = nextchisq
265
+ with self.numaccept.get_lock():
266
+ self.numaccept.value += 1
267
+ # Check lowest chi-square:
268
+ with self.best_log_post.get_lock():
269
+ if chisq[j] < -2*self.best_log_post.value:
270
+ self.bestp[self.ifree] = self.freepars[ID]
271
+ for s in self.ishare:
272
+ k = -int(self.pstep[s]) - 1
273
+ self.bestp[s] = self.bestp[k]
274
+ self.best_log_post.value = -0.5*chisq[j]
275
+ # Update Z if necessary:
276
+ if njump == self.thinning:
277
+ with self.zsize.get_lock():
278
+ # Stop when we fill Z:
279
+ if self.zsize.value == self.Zlen:
280
+ return
281
+ if self.sampler == "snooker":
282
+ self.index[j] = self.zsize.value
283
+ self.zsize.value += 1
284
+ # Update values:
285
+ self.zchain[self.index[j]] = ID
286
+ self.Z[self.index[j]] = np.copy(self.freepars[ID])
287
+ self.log_post[self.index[j]] = -0.5*chisq[j]
288
+ self.index[j] += self.nchains
289
+ self.chainsize[ID] += 1
290
+
291
+ if njump == self.thinning:
292
+ njump = 0 # Reset njump
293
+
294
+ if self.sampler == "demc":
295
+ self.pipe.send(chisq[j])
296
+ # Stop when the chain is complete:
297
+ if self.sampler in ["mrw", "demc"] \
298
+ and self.chainsize[0]==self.chainlen:
299
+ return
300
+
301
+
302
+ def eval_model(self, params, ret="model"):
303
+ """
304
+ Evaluate the model for the requested set of parameters.
305
+
306
+ Parameters
307
+ ----------
308
+ params: 1D float ndarray
309
+ The set of model fitting parameters.
310
+ ret: String
311
+ Flag to indicate what to return. Valid options:
312
+ - 'model' Return the evaluated model.
313
+ - 'chisq' Return chi-square.
314
+ - 'both' Return a list with the model and chisq.
315
+ """
316
+ if self.wlike:
317
+ model = self.func(params[0:-3], *self.args, **self.kwargs)
318
+ else:
319
+ model = self.func(params, *self.args, **self.kwargs)
320
+
321
+ # Reject proposed iteration if any model value is infinite:
322
+ if np.any(model == np.inf):
323
+ chisq = np.inf
324
+ else:
325
+ # Calculate chisq:
326
+ if self.wlike:
327
+ chisq = ms.dwt_chisq(
328
+ model, self.data, params,
329
+ self.prior, self.priorlow, self.priorup)
330
+ else:
331
+ chisq = ms.chisq(
332
+ model, self.data, self.uncert, params,
333
+ self.prior, self.priorlow, self.priorup)
334
+
335
+ if ret == "both":
336
+ return [model, chisq]
337
+ elif ret == "chisq":
338
+ return chisq
339
+ else: # ret == "model"
340
+ return model