• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

California-Planet-Search / radvel / #503

14 Sep 2023 05:47PM UTC coverage: 90.035%. Remained the same
#503

push

coveralls-python

web-flow
Merge pull request #382 from California-Planet-Search/next-release

Version 1.4.11

10 of 10 new or added lines in 3 files covered. (100.0%)

3298 of 3663 relevant lines covered (90.04%)

0.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.0
/radvel/driver.py
1
"""
2
Driver functions for the radvel pipeline.\
3
These functions are meant to be used only with\
4
the `cli.py` command line interface.
5
"""
6
from __future__ import print_function
1✔
7

8
import radvel
1✔
9
from radvel.likelihood import GPLikelihood
1✔
10
from radvel.plot import orbit_plots, mcmc_plots
1✔
11
from radvel.mcmc import statevars
1✔
12

13
import os
1✔
14
import sys
1✔
15
import copy
1✔
16
import collections
1✔
17
from collections import OrderedDict
1✔
18

19
import pandas as pd
1✔
20
import numpy as np
1✔
21
from numpy import inf
1✔
22
from astropy import constants as c
1✔
23

24
if sys.version_info[0] < 3:
1✔
25
    import ConfigParser as configparser
×
26
else:
27
    import configparser
1✔
28
    from configparser import NoSectionError
1✔
29

30

31
def plots(args):
1✔
32
    """
33
    Generate plots
34

35
    Args:
36
        args (ArgumentParser): command line arguments
37
    """
38

39
    config_file = args.setupfn
1✔
40
    conf_base = os.path.basename(config_file).split('.')[0]
1✔
41
    statfile = os.path.join(
1✔
42
        args.outputdir, "{}_radvel.stat".format(conf_base)
43
    )
44

45
    status = load_status(statfile)
1✔
46

47
    P, post = radvel.utils.initialize_posterior(config_file,
1✔
48
                                                decorr=args.decorr)
49

50
    assert status.getboolean('fit', 'run'), \
1✔
51
        "Must perform max-liklihood fit before plotting"
52
    post = radvel.posterior.load(status.get('fit', 'postfile'))
1✔
53

54
    for ptype in args.type:
1✔
55
        print("Creating {} plot for {}".format(ptype, conf_base))
1✔
56

57
        if ptype == 'rv':
1✔
58
            args.plotkw['uparams'] = post.uparams
1✔
59
            args.plotkw['status'] = status
1✔
60
            if 'saveplot' not in args.plotkw:
1✔
61
                saveto = os.path.join(
1✔
62
                    args.outputdir, conf_base+'_rv_multipanel.pdf'
63
                )
64
            else:
65
                saveto = args.plotkw['saveplot']
×
66
                args.plotkw.pop('saveplot')
×
67
            P, _ = radvel.utils.initialize_posterior(config_file)
1✔
68
            if hasattr(P, 'bjd0'):
1✔
69
                args.plotkw['epoch'] = P.bjd0
1✔
70

71
            if args.gp or isinstance(post.likelihood, GPLikelihood):
1✔
72
                GPPlot = orbit_plots.GPMultipanelPlot(
1✔
73
                    post, saveplot=saveto, **args.plotkw
74
                )
75
                GPPlot.plot_multipanel()
1✔
76
            else:
77
                RVPlot = orbit_plots.MultipanelPlot(
1✔
78
                    post, saveplot=saveto, **args.plotkw
79
                )
80
                RVPlot.plot_multipanel()
1✔
81

82
                # check to make sure that Posterior is not GP, print warning if it is
83
                if isinstance(post.likelihood, radvel.likelihood.CompositeLikelihood):
1✔
84
                    like_list = post.likelihood.like_list
1✔
85
                else:
86
                    like_list = [post.likelihood]
×
87
                for like in like_list:
1✔
88
                    if isinstance(like, radvel.likelihood.GPLikelihood):
1✔
89
                        print("WARNING: GP Likelihood(s) detected. \
×
90
You may want to use the '--gp' flag when making these plots.")
91
                        break
×
92

93
        if ptype == 'corner' or ptype == 'auto' or ptype == 'trend':
1✔
94
            assert status.getboolean('mcmc', 'run'), \
1✔
95
                "Must run MCMC before making corner, auto, or trend plots"
96

97
            chains = pd.read_csv(status.get('mcmc', 'chainfile'))
1✔
98
            autocorr = pd.read_csv(status.get('mcmc', 'autocorrfile'))
1✔
99

100
        if ptype == 'auto':
1✔
101
            saveto = os.path.join(args.outputdir, conf_base+'_auto.pdf')
1✔
102
            Auto = mcmc_plots.AutoPlot(autocorr, saveplot=saveto)
1✔
103
            Auto.plot()
1✔
104

105
        if ptype == 'corner':
1✔
106
            saveto = os.path.join(args.outputdir, conf_base+'_corner.pdf')
1✔
107
            Corner = mcmc_plots.CornerPlot(post, chains, saveplot=saveto)
1✔
108
            Corner.plot()
1✔
109

110
        if ptype == 'trend':
1✔
111
            nwalkers = status.getint('mcmc', 'nwalkers')
1✔
112
            nensembles = status.getint('mcmc', 'nensembles')
1✔
113

114
            saveto = os.path.join(args.outputdir, conf_base+'_trends.pdf')
1✔
115
            Trend = mcmc_plots.TrendPlot(post, chains, nwalkers, nensembles, saveto)
1✔
116
            Trend.plot()
1✔
117

118
        if ptype == 'derived':
1✔
119
            assert status.has_section('derive'), \
1✔
120
                "Must run `radvel derive` before plotting derived parameters"
121

122
            P, _ = radvel.utils.initialize_posterior(config_file)
1✔
123
            chains = pd.read_csv(status.get('derive', 'chainfile'))
1✔
124
            saveto = os.path.join(
1✔
125
                args.outputdir, conf_base+'_corner_derived_pars.pdf'
126
            )
127

128
            Derived = mcmc_plots.DerivedPlot(chains, P, saveplot=saveto)
1✔
129
            Derived.plot()
1✔
130

131
        savestate = {'{}_plot'.format(ptype): os.path.relpath(saveto)}
1✔
132
        save_status(statfile, 'plot', savestate)
1✔
133

134

135
def fit(args):
1✔
136
    """Perform maximum a posteriori fit
137

138
    Args:
139
        args (ArgumentParser): command line arguments
140
    """
141

142
    config_file = args.setupfn
1✔
143
    conf_base = os.path.basename(config_file).split('.')[0]
1✔
144
    print("Performing maximum a posteriori fitting for {}".format(conf_base))
1✔
145

146
    P, post = radvel.utils.initialize_posterior(config_file, decorr=args.decorr)
1✔
147

148
    post = radvel.fitting.maxlike_fitting(post, verbose=True)
1✔
149

150
    postfile = os.path.join(args.outputdir,
1✔
151
                            '{}_post_obj.pkl'.format(conf_base))
152
    post.writeto(postfile)
1✔
153

154
    savestate = {'run': True,
1✔
155
                 'postfile': os.path.relpath(postfile)}
156
    save_status(os.path.join(args.outputdir,
1✔
157
                '{}_radvel.stat'.format(conf_base)),
158
                'fit', savestate)
159

160

161
def mcmc(args):
1✔
162
    """Perform MCMC error analysis
163

164
    Args:
165
        args (ArgumentParser): command line arguments
166
    """
167

168
    config_file = args.setupfn
1✔
169
    conf_base = os.path.basename(config_file).split('.')[0]
1✔
170
    statfile = os.path.join(args.outputdir,
1✔
171
                            "{}_radvel.stat".format(conf_base))
172

173
    if args.save or args.proceed:
1✔
174
        backend_loc = os.path.join(args.outputdir, conf_base+'_rawchain.h5')
1✔
175
    else:
176
        backend_loc = None
×
177

178
    status = load_status(statfile)
1✔
179
    P, post = radvel.utils.initialize_posterior(config_file,
1✔
180
                                                decorr=args.decorr)
181

182
    if status.getboolean('fit', 'run'):
1✔
183
        print("Loading starting positions from previous MAP fit")
1✔
184

185
        post = radvel.posterior.load(status.get('fit', 'postfile'))
1✔
186

187
    msg1 = (
1✔
188
            "Running MCMC for {}, N_walkers = {}, N_steps = {}, N_ensembles = {}, Min Auto Factor = {}, "
189
            ).format(conf_base, args.nwalkers, args.nsteps, args.ensembles, args.minAfactor)
190

191
    msg2 = (
1✔
192
            "Max Auto Relative-Change = {}, Max G-R = {}, Min Tz = {} ..."
193
            ).format(args.maxArchange, args.maxGR, args.minTz)
194

195
    print(msg1 + '\n' + msg2)
1✔
196

197
    chains = radvel.mcmc(post, nwalkers=args.nwalkers, nrun=args.nsteps, ensembles=args.ensembles,
1✔
198
                         minAfactor=args.minAfactor, maxArchange=args.maxArchange, burnAfactor=args.burnAfactor,
199
                         burnGR=args.burnGR, maxGR=args.maxGR, minTz=args.minTz, minsteps=args.minsteps,
200
                         minpercent=args.minpercent, thin=args.thin, serial=args.serial, save=args.save,
201
                         savename=backend_loc, proceed=args.proceed, proceedname=backend_loc, headless=args.headless)
202

203
    mintz = statevars.mintz
1✔
204
    maxgr = statevars.maxgr
1✔
205
    minafactor = statevars.minafactor
1✔
206
    maxarchange = statevars.maxarchange
1✔
207

208
    # Convert chains into synth basis
209
    synthchains = chains.copy()
1✔
210
    for par in post.params.keys():
1✔
211
        if not post.vector.vector[post.vector.indices[par]][1]:
1✔
212
            synthchains[par] = post.vector.vector[post.vector.indices[par]][0]
1✔
213

214
    synthchains = post.params.basis.to_synth(synthchains)
1✔
215
    synth_quantile = synthchains.quantile([0.159, 0.5, 0.841])
1✔
216

217
    # Get quantiles and update posterior object to median
218
    # values returned by MCMC chains
219
    post_summary = chains.quantile([0.159, 0.5, 0.841])
1✔
220

221
    for k in chains.columns:
1✔
222
        if k in post.params.keys():
1✔
223
            post.vector.vector[post.vector.indices[k]][0] = post_summary[k][0.5]
1✔
224

225
    post.vector.vector_to_dict()
1✔
226

227
    print("Performing post-MCMC maximum likelihood fit...")
1✔
228
    post = radvel.fitting.maxlike_fitting(post, verbose=False)
1✔
229

230
    final_logprob = post.logprob()
1✔
231
    final_residuals = post.likelihood.residuals().std()
1✔
232
    final_chisq = np.sum(post.likelihood.residuals()**2 / (post.likelihood.errorbars()**2))
1✔
233
    deg_of_freedom = len(post.likelihood.y) - len(post.likelihood.get_vary_params())
1✔
234
    final_chisq_reduced = final_chisq / deg_of_freedom
1✔
235
    post.vector.vector_to_dict()
1✔
236
    synthparams = post.params.basis.to_synth(post.params)
1✔
237

238
    print("Calculating uncertainties...")
1✔
239
    post.uparams = {}
1✔
240
    post.medparams = {}
1✔
241
    post.maxparams = {}
1✔
242
    for par in synthparams.keys():
1✔
243
        maxlike = synthparams[par].value
1✔
244
        med = synth_quantile[par][0.5]
1✔
245
        high = synth_quantile[par][0.841] - med
1✔
246
        low = med - synth_quantile[par][0.159]
1✔
247
        err = np.mean([high, low])
1✔
248
        if maxlike == -np.inf and med == -np.inf and np.isnan(low) and np.isnan(high):
1✔
249
            err = 0.0
×
250
        else:
251
            err = radvel.utils.round_sig(err)
1✔
252
        if err > 0.0:
1✔
253
            med, err, errhigh = radvel.utils.sigfig(med, err)
1✔
254
            maxlike, err, errhigh = radvel.utils.sigfig(maxlike, err)
1✔
255
        post.uparams[par] = err
1✔
256
        post.medparams[par] = med
1✔
257
        post.maxparams[par] = maxlike
1✔
258

259
    print("Final loglikelihood = %f" % final_logprob)
1✔
260
    print("Final RMS = %f" % final_residuals)
1✔
261
    print("Final reduced chi-square = {}".format(final_chisq_reduced))
1✔
262
    print("Best-fit parameters:")
1✔
263
    print(post)
1✔
264

265
    print("Saving output files...")
1✔
266
    saveto = os.path.join(args.outputdir, conf_base+'_post_summary.csv')
1✔
267
    post_summary.to_csv(saveto, sep=',')
1✔
268

269
    postfile = os.path.join(args.outputdir,
1✔
270
                            '{}_post_obj.pkl'.format(conf_base))
271
    post.writeto(postfile)
1✔
272

273
    csvfn = os.path.join(args.outputdir, conf_base+'_chains.csv.bz2')
1✔
274
    chains.to_csv(csvfn, compression='bz2')
1✔
275

276
    auto = pd.DataFrame()
1✔
277
    auto['autosamples'] = statevars.autosamples
1✔
278
    auto['automin'] = statevars.automin
1✔
279
    auto['automean'] = statevars.automean
1✔
280
    auto['automax'] = statevars.automax
1✔
281
    auto['factor'] = statevars.factor
1✔
282
    autocorr = os.path.join(args.outputdir, conf_base+'_autocorr.csv')
1✔
283
    auto.to_csv(autocorr, sep=',')
1✔
284

285
    savestate = {'run': True,
1✔
286
                 'postfile': os.path.relpath(postfile),
287
                 'chainfile': os.path.relpath(csvfn),
288
                 'autocorrfile': os.path.relpath(autocorr),
289
                 'summaryfile': os.path.relpath(saveto),
290
                 'nwalkers': statevars.nwalkers,
291
                 'nensembles': args.ensembles,
292
                 'maxsteps': args.nsteps*statevars.nwalkers*args.ensembles,
293
                 'nsteps': statevars.ncomplete,
294
                 'nburn': statevars.nburn,
295
                 'minafactor': minafactor,
296
                 'maxarchange': maxarchange,
297
                 'minTz': mintz,
298
                 'maxGR': maxgr}
299
    save_status(statfile, 'mcmc', savestate)
1✔
300

301
    statevars.reset()
1✔
302

303

304
def ic_compare(args):
1✔
305
    """Compare different models and comparative statistics including
306
          AIC and BIC statistics.
307

308
    Args:
309
        args (ArgumentParser): command line arguments
310
    """
311

312
    config_file = args.setupfn
1✔
313
    conf_base = os.path.basename(config_file).split('.')[0]
1✔
314
    statfile = os.path.join(args.outputdir,
1✔
315
                            "{}_radvel.stat".format(conf_base))
316

317
    status = load_status(statfile)
1✔
318

319
    P, post = radvel.utils.initialize_posterior(config_file,
1✔
320
                                                decorr=args.decorr)
321

322
    assert status.getboolean('fit', 'run'), \
1✔
323
        "Must perform max-liklihood fit before running Information Criteria comparisons"
324
    post = radvel.posterior.load(status.get('fit', 'postfile'))
1✔
325

326
    choices = ['nplanets', 'e', 'trend', 'jit', 'gp']
1✔
327
    statsdictlist = []
1✔
328
    paramlist = []
1✔
329
    compareparams = args.type
1✔
330

331
    ipost = copy.deepcopy(post)
1✔
332

333
    if args.simple:
1✔
334
        statsdictlist += radvel.fitting.model_comp(ipost, params=[], verbose=args.verbose)
1✔
335
    else:
336
        if hasattr(args, 'fixjitter') and args.fixjitter:
1✔
337
            for param in ipost.params:
×
338
                if len(param) >= 3 and param[0:3] == 'jit':
×
339
                    ipost.params[param].vary = False
×
340

341
        for compareparam in compareparams:
1✔
342
            assert compareparam in choices, \
1✔
343
                "Valid parameter choices for 'ic -t' are combinations of: "\
344
                + " ".join(choices)
345
            paramlist.append(compareparam)
1✔
346
            if hasattr(args, 'mixed') and not args.mixed:
1✔
347
                statsdictlist += radvel.fitting.model_comp(ipost, params=[compareparam], verbose=args.verbose)
×
348
        if hasattr(args, 'mixed') and not args.mixed:
1✔
349
            new_statsdictlist = []
×
350
            for dicti in statsdictlist:
×
351
                anymatch = False
×
352
                for seendict in new_statsdictlist:
×
353
                    if collections.Counter(dicti['Free Params'][0]) == \
×
354
                            collections.Counter(seendict['Free Params'][0]):
355
                        anymatch = True
×
356
                        continue
×
357
                if not anymatch:
×
358
                    new_statsdictlist.append(dicti)
×
359
            statsdictlist = new_statsdictlist
×
360

361
        if not hasattr(args, 'mixed') or (hasattr(args, 'mixed') and args.mixed):
1✔
362
            statsdictlist += radvel.fitting.model_comp(ipost, params=paramlist, verbose=args.verbose)
1✔
363

364
    savestate = {'ic': statsdictlist}
1✔
365
    save_status(statfile, 'ic_compare', savestate)
1✔
366

367

368
def tables(args):
1✔
369
    """Generate TeX code for tables in summary report
370

371
    Args:
372
        args (ArgumentParser): command line arguments
373
    """
374

375
    config_file = args.setupfn
1✔
376
    conf_base = os.path.basename(config_file).split('.')[0]
1✔
377
    statfile = os.path.join(args.outputdir,
1✔
378
                            "{}_radvel.stat".format(conf_base))
379
    status = load_status(statfile)
1✔
380

381
    assert status.getboolean('mcmc', 'run'), \
1✔
382
        "Must run MCMC before making tables"
383

384
    P, post = radvel.utils.initialize_posterior(config_file)
1✔
385
    post = radvel.posterior.load(status.get('fit', 'postfile'))
1✔
386
    chains = pd.read_csv(status.get('mcmc', 'chainfile'))
1✔
387
    minafactor = status.get('mcmc', 'minafactor')
1✔
388
    maxarchange = status.get('mcmc', 'maxarchange')
1✔
389
    maxgr = status.get('mcmc', 'maxgr')
1✔
390
    mintz = status.get('mcmc', 'mintz')
1✔
391
    if 'derive' in status.sections() and status.getboolean('derive', 'run'):
1✔
392
        dchains = pd.read_csv(status.get('derive', 'chainfile'))
1✔
393
        chains = chains.join(dchains, rsuffix='_derived')
1✔
394
        derived = True
1✔
395
    else:
396
        derived = False
×
397
    report = radvel.report.RadvelReport(P, post, chains, minafactor, maxarchange, maxgr, mintz, derived=derived)
1✔
398
    tabletex = radvel.report.TexTable(report)
1✔
399
    attrdict = {'priors': 'tab_prior_summary', 'rv': 'tab_rv',
1✔
400
                'params': 'tab_params', 'derived': 'tab_derived',
401
                'crit': 'tab_crit'}
402
    for tabtype in args.type:
1✔
403
        print("Generating LaTeX code for {} table".format(tabtype))
1✔
404

405
        if tabtype == 'ic_compare':
1✔
406
            assert status.has_option('ic_compare', 'ic'), \
1✔
407
                "Must run Information Criteria comparison before making comparison tables"
408

409
            compstats = eval(status.get('ic_compare', 'ic'))
1✔
410
            report = radvel.report.RadvelReport(
1✔
411
                P, post, chains, minafactor, maxarchange, maxgr, mintz, compstats=compstats
412
            )
413
            tabletex = radvel.report.TexTable(report)
1✔
414
            tex = tabletex.tab_comparison()
1✔
415
        elif tabtype == 'rv':
1✔
416
            tex = getattr(tabletex, attrdict[tabtype])(name_in_title=args.name_in_title, max_lines=None)
1✔
417
        elif tabtype == 'crit':
1✔
418
            tex = getattr(tabletex, attrdict[tabtype])(name_in_title=args.name_in_title)
1✔
419
        else:
420
            if tabtype == 'derived':
1✔
421
                assert status.has_option('derive', 'run'), \
1✔
422
                    "Must run `radvel derive` before making derived parameter table"
423
            assert tabtype in attrdict, 'Invalid Table Type %s ' % tabtype
1✔
424
            tex = getattr(tabletex, attrdict[tabtype])(name_in_title=args.name_in_title)
1✔
425

426
        saveto = os.path.join(
1✔
427
            args.outputdir, '{}_{}.tex'.format(conf_base, tabtype)
428
        )
429
        with open(saveto, 'w+') as f:
1✔
430
            f.write(tex)
1✔
431

432
        savestate = {'{}_tex'.format(tabtype): os.path.relpath(saveto)}
1✔
433
        save_status(statfile, 'table', savestate)
1✔
434

435

436
def derive(args):
1✔
437
    """Derive physical parameters from posterior samples
438

439
    Args:
440
        args (ArgumentParser): command line arguments
441
    """
442

443
    config_file = args.setupfn
1✔
444
    conf_base = os.path.basename(config_file).split('.')[0]
1✔
445
    statfile = os.path.join(args.outputdir,
1✔
446
                            "{}_radvel.stat".format(conf_base))
447
    status = load_status(statfile)
1✔
448

449
    msg = "Multiplying mcmc chains by physical parameters for {}".format(
1✔
450
        conf_base
451
    )
452
    print(msg)
1✔
453

454
    assert status.getboolean('mcmc', 'run'), "Must run MCMC before making tables"
1✔
455

456
    P, post = radvel.utils.initialize_posterior(config_file)
1✔
457
    post = radvel.posterior.load(status.get('fit', 'postfile'))
1✔
458
    chains = pd.read_csv(status.get('mcmc', 'chainfile'))
1✔
459

460
    try:
1✔
461
        mstar = np.random.normal(
1✔
462
            loc=P.stellar['mstar'], scale=P.stellar['mstar_err'],
463
            size=len(chains)
464
            )
465
    except AttributeError:
×
466
        print("Unable to calculate derived parameters, stellar parameters not defined the config file.")
×
467
        return
×
468

469
    if (mstar <= 0.0).any():
1✔
470
        num_nan = np.sum(mstar <= 0.0)
×
471
        nan_perc = float(num_nan) / len(chains)
×
472
        mstar[mstar <= 0] = np.abs(mstar[mstar <= 0])
×
473
        print("WARNING: {} ({:.2f} %) of Msini samples are NaN. The stellar mass posterior may contain negative \
×
474
values. Interpret posterior with caution.".format(num_nan, nan_perc))
475

476
    # Convert chains into synth basis
477
    synthchains = chains.copy()
1✔
478
    for par in post.params.keys():
1✔
479
        if not post.params[par].vary:
1✔
480
            synthchains[par] = post.params[par].value
1✔
481

482
    synthchains = post.params.basis.to_synth(synthchains)
1✔
483

484
    savestate = {'run': True}
1✔
485
    outcols = []
1✔
486
    for i in np.arange(1, P.nplanets + 1, 1):
1✔
487
        # Grab parameters from the chain
488
        def _has_col(key):
1✔
489
            cols = list(synthchains.columns)
1✔
490
            return cols.count('{}{}'.format(key, i)) == 1
1✔
491

492
        def _get_param(key):
1✔
493
            if _has_col(key):
1✔
494
                return synthchains['{}{}'.format(key, i)]
1✔
495
            else:
496
                return P.params['{}{}'.format(key, i)].value
×
497

498
        def _set_param(key, value):
1✔
499
            chains['{}{}'.format(key, i)] = value
1✔
500

501
        def _get_colname(key):
1✔
502
            return '{}{}'.format(key, i)
1✔
503

504
        per = _get_param('per')
1✔
505
        k = _get_param('k')
1✔
506
        e = _get_param('e')
1✔
507

508
        mpsini = radvel.utils.Msini(k, per, mstar, e, Msini_units='earth')
1✔
509
        _set_param('mpsini', mpsini)
1✔
510
        outcols.append(_get_colname('mpsini'))
1✔
511

512
        mtotal = mstar + (mpsini * c.M_earth.value) / c.M_sun.value      # get total star plus planet mass
1✔
513
        a = radvel.utils.semi_major_axis(per, mtotal)               # changed from mstar to mtotal
1✔
514
        
515
        _set_param('a', a)
1✔
516
        outcols.append(_get_colname('a'))
1✔
517

518
        musini = (mpsini * c.M_earth) / (mstar * c.M_sun)
1✔
519
        _set_param('musini', musini)
1✔
520
        outcols.append(_get_colname('musini'))
1✔
521

522
        try:
1✔
523
            rp = np.random.normal(
1✔
524
                loc=P.planet['rp{}'.format(i)],
525
                scale=P.planet['rp_err{}'.format(i)],
526
                size=len(chains)
527
            )
528

529
            _set_param('rp', rp)
1✔
530
            _set_param('rhop', radvel.utils.density(mpsini, rp))
1✔
531

532
            outcols.append(_get_colname('rhop'))
1✔
533
        except (AttributeError, KeyError):
×
534
            pass
×
535

536
    # Get quantiles and update posterior object to median
537
    # values returned by MCMC chains
538
    quantiles = chains.quantile([0.159, 0.5, 0.841])
1✔
539
    csvfn = os.path.join(args.outputdir, conf_base+'_derived_quantiles.csv')
1✔
540
    quantiles.to_csv(csvfn, columns=outcols)
1✔
541

542
    # saved derived paramters to posterior file
543
    postfile = os.path.join(args.outputdir,
1✔
544
                            '{}_post_obj.pkl'.format(conf_base))
545
    post.derived = quantiles[outcols]
1✔
546
    post.writeto(postfile)
1✔
547
    savestate['quantfile'] = os.path.relpath(csvfn)
1✔
548

549
    csvfn = os.path.join(args.outputdir, conf_base+'_derived.csv.bz2')
1✔
550
    chains.to_csv(csvfn, columns=outcols, compression='bz2')
1✔
551
    savestate['chainfile'] = os.path.relpath(csvfn)
1✔
552

553
    print("Derived parameters:", outcols)
1✔
554

555
    save_status(statfile, 'derive', savestate)
1✔
556

557

558
def report(args):
1✔
559
    """Generate summary report
560

561
    Args:
562
        args (ArgumentParser): command line arguments
563
    """
564

565
    config_file = args.setupfn
1✔
566
    conf_base = os.path.basename(config_file).split('.')[0]
1✔
567
    print("Assembling report for {}".format(conf_base))
1✔
568

569
    statfile = os.path.join(args.outputdir,
1✔
570
                            "{}_radvel.stat".format(conf_base))
571

572
    status = load_status(statfile)
1✔
573
    if 'ic_compare' in status.keys():
1✔
574
        status['ic_compare']['ic'] = status['ic_compare']['ic'].replace('-inf', '-np.inf')
1✔
575

576
    P, post = radvel.utils.initialize_posterior(config_file)
1✔
577
    post = radvel.posterior.load(status.get('fit', 'postfile'))
1✔
578
    chains = pd.read_csv(status.get('mcmc', 'chainfile'))
1✔
579
    minafactor = status.get('mcmc', 'minafactor')
1✔
580
    maxarchange = status.get('mcmc', 'maxarchange')
1✔
581
    maxgr = status.get('mcmc', 'maxgr')
1✔
582
    mintz = status.get('mcmc', 'mintz')
1✔
583
    if 'derive' in status.sections() and status.getboolean('derive', 'run'):
1✔
584
        dchains = pd.read_csv(status.get('derive', 'chainfile'))
1✔
585
        chains = chains.join(dchains, rsuffix='_derived')
1✔
586
        derived = True
1✔
587
    else:
588
        derived = False
×
589
    try:
1✔
590
        compstats = eval(status.get('ic_compare', 'ic'))
1✔
591
    except (KeyError, NoSectionError):
×
592
        print("WARNING: Could not find {} model comparison \
×
593
in {}.\nPlease make sure that you have run `radvel ic -t {}` (or, e.g., `radvel \
594
ic -t nplanets e trend jit gp`)\
595
\nif you would like to include the model comparison table in the \
596
report.".format(args.comptype,
597
                statfile,
598
                args.comptype))
599
        compstats = None
×
600

601
    report = radvel.report.RadvelReport(P, post, chains, minafactor, maxarchange, maxgr, mintz, compstats=compstats,
1✔
602
                                        derived=derived)
603
    report.runname = conf_base
1✔
604

605
    report_depfiles = []
1✔
606
    for ptype, pfile in status.items('plot'):
1✔
607
        report_depfiles.append(pfile)
1✔
608

609
    with radvel.utils.working_directory(args.outputdir):
1✔
610
        rfile = os.path.join(conf_base+"_results.pdf")
1✔
611
        report_depfiles = [os.path.basename(p) for p in report_depfiles]
1✔
612
        report.compile(
1✔
613
            rfile, depfiles=report_depfiles, latex_compiler=args.latex_compiler
614
        )
615

616

617
def save_status(statfile, section, statevars):
1✔
618
    """Save pipeline status
619

620
    Args:
621
        statfile (string): name of output file
622
        section (string): name of section to write
623
        statevars (dict): dictionary of all options to populate
624
           the specified section
625
    """
626

627
    config = configparser.RawConfigParser()
1✔
628

629
    if os.path.isfile(statfile):
1✔
630
        config.read(statfile)
1✔
631

632
    if not config.has_section(section):
1✔
633
        config.add_section(section)
1✔
634

635
    for key, val in statevars.items():
1✔
636
        config.set(section, key, val)
1✔
637

638
    with open(statfile, 'w') as f:
1✔
639
        config.write(f)
1✔
640

641

642
def load_status(statfile):
1✔
643
    """Load pipeline status
644

645
    Args:
646
        statfile (string): name of configparser file
647

648
    Returns:
649
        configparser.RawConfigParser
650
    """
651

652
    config = configparser.RawConfigParser()
1✔
653
    gl = config.read(statfile)
1✔
654

655
    return config
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc