def main(comm): """ Wrapper of modeling function for MCMC under MPI protocol. Modification History: --------------------- 2014-04-19 patricio Initial implementation. [email protected] 2014-06-25 patricio Added support for inner-MPI loop. 2014-10-23 patricio Removed inner-MPI loop. """ # Parse arguments: cparser = argparse.ArgumentParser(description=__doc__, add_help=False, formatter_class=argparse.RawDescriptionHelpFormatter) # Add config file option: cparser.add_argument("-c", "--config_file", help="Configuration file", metavar="FILE") # Remaining_argv contains all other command-line-arguments: args, remaining_argv = cparser.parse_known_args() # Get parameters from configuration file: cfile = args.config_file if cfile: config = ConfigParser.SafeConfigParser() config.read([cfile]) defaults = dict(config.items("MCMC")) else: defaults = {} parser = argparse.ArgumentParser(parents=[cparser]) parser.add_argument("-f", "--func", dest="func", type=mu.parray, action="store", default=None) parser.add_argument("-i", "--indparams", dest="indparams", type=mu.parray, action="store", default=[]) parser.set_defaults(**defaults) args2, unknown = parser.parse_known_args(remaining_argv) # Add path to func: if len(args2.func) == 3: sys.path.append(args2.func[2]) exec('from {:s} import {:s} as func'.format(args2.func[1], args2.func[0])) # Get indparams from configuration file: if args2.indparams != [] and os.path.isfile(args2.indparams[0]): indparams = mu.readbin(args2.indparams[0]) # Get the number of parameters and iterations from MPI: array1 = np.zeros(2, np.int) mu.comm_bcast(comm, array1) npars, niter = array1 # Allocate array to receive parameters from MPI: params = np.zeros(npars, np.double) # Main MCMC Loop: while niter >= 0: # Receive parameters from MCMC: mu.comm_scatter(comm, params) # Evaluate model: fargs = [params] + indparams # List of function's arguments model = func(*fargs) # Send resutls: mu.comm_gather(comm, model, MPI.DOUBLE) niter -= 1 # Close communications and disconnect: mu.comm_disconnect(comm)
def main(comm): """ This is a hacked version of MC3's func.py. This function directly call's the modeling function for the BART project. Modification History: --------------------- 2014-04-19 patricio Initial implementation. [email protected] 2014-06-25 patricio Added support for inner-MPI loop. """ # Parse arguments: cparser = argparse.ArgumentParser(description=__doc__, add_help=False, formatter_class=argparse.RawDescriptionHelpFormatter) # Add config file option: cparser.add_argument("-c", "--config_file", help="Configuration file", metavar="FILE") # Remaining_argv contains all other command-line-arguments: args, remaining_argv = cparser.parse_known_args() # Get parameters from configuration file: cfile = args.config_file if cfile: config = ConfigParser.SafeConfigParser() config.optionxform = str config.read([cfile]) defaults = dict(config.items("MCMC")) else: defaults = {} parser = argparse.ArgumentParser(parents=[cparser]) parser.add_argument("--func", dest="func", type=mu.parray, action="store", default=None) parser.add_argument("--indparams", dest="indparams", type=mu.parray, action="store", default=[]) parser.add_argument("--params", dest="params", type=mu.parray, action="store", default=None, help="Model-fitting parameters [default: %(default)s]") parser.add_argument("--molfit", dest="molfit", type=mu.parray, action="store", default=None, help="Molecules fit [default: %(default)s]") parser.add_argument("--Tmin", dest="Tmin", type=float, action="store", default=400.0, help="Lower Temperature boundary [default: %(default)s]") parser.add_argument("--Tmax", dest="Tmax", type=float, action="store", default=3000.0, help="Higher Temperature boundary [default: %(default)s]") parser.add_argument("--quiet", action="store_true", help="Set verbosity level to minimum", dest="quiet") # Input-Converter Options: group = parser.add_argument_group("Input Converter Options") group.add_argument("--atmospheric_file", action="store", help="Atmospheric file [default: %(default)s]", dest="atmfile", type=str, default=None) group.add_argument("--PTtype", action="store", help="PT profile type.", dest="PTtype", type=str, default="none") #choices=('line', 'madhu')) group.add_argument("--tint", action="store", help="Internal temperature of the planet [default: " "%(default)s].", dest="tint", type=float, default=100.0) # transit Options: group = parser.add_argument_group("transit Options") group.add_argument("--config", action="store", help="transit configuration file [default: %(default)s]", dest="config", type=str, default=None) # Output-Converter Options: group = parser.add_argument_group("Output Converter Options") group.add_argument("--filter", action="store", help="Waveband filter name [default: %(default)s]", dest="filter", type=mu.parray, default=None) group.add_argument("--tep_name", action="store", help="A TEP file [default: %(default)s]", dest="tep_name", type=str, default=None) group.add_argument("--kurucz_file", action="store", help="Stellar Kurucz file [default: %(default)s]", dest="kurucz", type=str, default=None) group.add_argument("--solution", action="store", help="Solution geometry [default: %(default)s]", dest="solution", type=str, default="None", choices=('transit', 'eclipse')) parser.set_defaults(**defaults) args2, unknown = parser.parse_known_args(remaining_argv) # Quiet all threads except rank 0: rank = comm.Get_rank() verb = rank == 0 # Get (Broadcast) the number of parameters and iterations from MPI: array1 = np.zeros(2, np.int) mu.comm_bcast(comm, array1) npars, niter = array1 # ::::::: Initialize the Input converter :::::::::::::::::::::::::: atmfile = args2.atmfile molfit = args2.molfit PTtype = args2.PTtype params = args2.params tepfile = args2.tep_name tint = args2.tint Tmin = args2.Tmin Tmax = args2.Tmax solution = args2.solution # Solution type # Extract necessary values from the TEP file: tep = rd.File(tepfile) # Stellar temperature in K: tstar = float(tep.getvalue('Ts')[0]) # Stellar radius (in meters): rstar = float(tep.getvalue('Rs')[0]) * c.Rsun # Semi-major axis (in meters): sma = float(tep.getvalue( 'a')[0]) * sc.au # Planetary radius (in meters): rplanet = float(tep.getvalue('Rp')[0]) * c.Rjup # Planetary mass (in kg): mplanet = float(tep.getvalue('Mp')[0]) * c.Mjup # Number of fitting parameters: nfree = len(params) # Total number of free parameters nmolfit = len(molfit) # Number of molecular free parameters nradfit = int(solution == 'transit') # 1 for transit, 0 for eclipse nPT = nfree - nmolfit - nradfit # Number of PT free parameters # Read atmospheric file to get data arrays: species, pressure, temp, abundances = mat.readatm(atmfile) # Reverse pressure order (for PT to work): pressure = pressure[::-1] nlayers = len(pressure) # Number of atmospheric layers nspecies = len(species) # Number of species in the atmosphere mu.msg(verb, "There are {:d} layers and {:d} species.".format(nlayers, nspecies)) # Find index for Hydrogen and Helium: species = np.asarray(species) iH2 = np.where(species=="H2")[0] iHe = np.where(species=="He")[0] # Get H2/He abundance ratio: ratio = (abundances[:,iH2] / abundances[:,iHe]).squeeze() # Find indices for the metals: imetals = np.where((species != "He") & (species != "H2"))[0] # Index of molecular abundances being modified: imol = np.zeros(nmolfit, dtype='i') for i in np.arange(nmolfit): imol[i] = np.where(np.asarray(species) == molfit[i])[0] # Pressure-Temperature profile: PTargs = [PTtype] if PTtype == "line": # Planetary surface gravity (in cm s-2): gplanet = 100.0 * sc.G * mplanet / rplanet**2 # Additional PT arguments: PTargs += [rstar, tstar, tint, sma, gplanet] # Allocate arrays for receiving and sending data to master: freepars = np.zeros(nfree, dtype='d') profiles = np.zeros((nspecies+1, nlayers), dtype='d') # This are sub-sections of profiles, containing just the temperature and # the abundance profiles, respectively: tprofile = profiles[0, :] aprofiles = profiles[1:,:] # Store abundance profiles: for i in np.arange(nspecies): aprofiles[i] = abundances[:, i] # ::::::: Spawn transit code ::::::::::::::::::::::::::::::::::::: # # transit configuration file: transitcfile = args2.tconfig # FINDME: Find a way to set verb to the transit subprocesses. # Silence all threads except rank 0: # if verb == 0: # rargs = ["--quiet"] # else: # rargs = [] # Initialize the transit python module: transit_args = ["transit", "-c", transitcfile] trm.transit_init(len(transit_args), transit_args) # Get wavenumber array from transit: nwave = trm.get_no_samples() specwn = trm.get_waveno_arr(nwave) # ::::::: Output Converter ::::::::::::::::::::::::::::::::::::::: ffile = args2.filter # Filter files kurucz = args2.kurucz # Kurucz file # Log10(stellar gravity) gstar = float(tep.getvalue('loggstar')[0]) # Planet-to-star radius ratio: rprs = rplanet / rstar mu.msg(verb, "OCON FLAG 10: {}, {}, {}".format(tstar, gstar, rprs)) nfilters = len(ffile) # Number of filters: # FINDME: Separate filter/stellar interpolation? # Get stellar model: starfl, starwn, tmodel, gmodel = w.readkurucz(kurucz, tstar, gstar) # Read and resample the filters: nifilter = [] # Normalized interpolated filter istarfl = [] # interpolated stellar flux wnindices = [] # wavenumber indices used in interpolation for i in np.arange(nfilters): # Read filter: filtwaven, filttransm = w.readfilter(ffile[i]) # Check that filter boundaries lie within the spectrum wn range: if filtwaven[0] < specwn[0] or filtwaven[-1] > specwn[-1]: mu.exit(message="Wavenumber array ({:.2f} - {:.2f} cm-1) does not " "cover the filter[{:d}] wavenumber range ({:.2f} - {:.2f} " "cm-1).".format(specwn[0], specwn[-1], i, filtwaven[0], filtwaven[-1])) # Resample filter and stellar spectrum: nifilt, strfl, wnind = w.resample(specwn, filtwaven, filttransm, starwn, starfl) mu.msg(verb, "OCON FLAG 67: mean star flux: %.3e"%np.mean(strfl)) nifilter.append(nifilt) istarfl.append(strfl) wnindices.append(wnind) # Allocate arrays for receiving and sending data to master: spectrum = np.zeros(nwave, dtype='d') bandflux = np.zeros(nfilters, dtype='d') # Allocate array to receive parameters from MPI: params = np.zeros(npars, np.double) # :::::: Main MCMC Loop :::::::::::::::::::::::::::::::::::::::::: # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: while niter >= 0: niter -= 1 # Receive parameters from MCMC: mu.comm_scatter(comm, params) #mu.msg(verb, "ICON FLAG 71: incon pars: {:s}". # format(str(params).replace("\n", ""))) # Input converter calculate the profiles: try: tprofile[:] = pt.PT_generator(pressure, params[0:nPT], PTargs)[::-1] except ValueError: mu.msg(verb, 'Input parameters give non-physical profile.') # FINDME: what to do here? # If the temperature goes out of bounds: if np.any(tprofile < Tmin) or np.any(tprofile > Tmax): print("Out of bounds") mu.comm_gather(comm, -np.ones(nfilters), MPI.DOUBLE) continue #mu.msg(verb, "T pars: \n{}\n".format(PTargs)) mu.msg(verb-20, "Temperature profile: {}".format(tprofile)) # Scale abundance profiles: for i in np.arange(nmolfit): m = imol[i] # Use variable as the log10: aprofiles[m] = abundances[:, m] * 10.0**params[nPT+nradfit+i] # Update H2, He abundances so sum(abundances) = 1.0 in each layer: q = 1.0 - np.sum(aprofiles[imetals], axis=0) aprofiles[iH2] = ratio * q / (1.0 + ratio) aprofiles[iHe] = q / (1.0 + ratio) # print("qH2O: {}, Qmetals: {}, QH2: {} p: {}".format(params[nPT], # q[50], profiles[iH2+1,50], profiles[:,50])) # Set the 'surface' level: if solution == "transit": trm.set_radius(params[nPT]) if rank == 1: print("Iteration: {:05}".format(niter)) # Let transit calculate the model spectrum: spectrum = trm.run_transit(profiles.flatten(), nwave) # Output converter band-integrate the spectrum: # Calculate the band-integrated intensity per filter: for i in np.arange(nfilters): if solution == "eclipse": fluxrat = (spectrum[wnindices[i]]/istarfl[i]) * rprs*rprs bandflux[i] = w.bandintegrate(fluxrat, specwn, nifilter[i], wnindices[i]) elif solution == "transit": bandflux[i] = w.bandintegrate(spectrum[wnindices[i]], specwn, nifilter[i], wnindices[i]) # Send resutls back to MCMC: #mu.msg(verb, "OCON FLAG 95: Flux band integrated ({})".format(bandflux)) #mu.msg(verb, "{}".format(params[nPT:])) mu.comm_gather(comm, bandflux, MPI.DOUBLE) #mu.msg(verb, "OCON FLAG 97: Sent results back to MCMC") # :::::: End main Loop ::::::::::::::::::::::::::::::::::::::::::: # :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # Close communications and disconnect: mu.comm_disconnect(comm) mu.msg(verb, "FUNC FLAG 99: func out") # Close the transit communicators: trm.free_memory() mu.msg(verb, "FUNC FLAG OUT ~~ 100 ~~")
def main(comm, piargs=None): """ Take arguments from the command line and run MCMC when called from the prompt Parameters: ----------- comm: MPI communicator An MPI intercommunicator piargs: List List of MCMC arguments (sent from mc3.mcmc) from the python interpreter. Modification History: --------------------- 2014-04-19 patricio Initial implementation. [email protected] 2014-05-04 patricio Added piargs argument for Python Interpreter support. """ # Parse the config file from the command line: cparser = argparse.ArgumentParser( description=__doc__, add_help=False, formatter_class=argparse.RawDescriptionHelpFormatter) # Add config file option: cparser.add_argument("-c", "--config_file", type=str, help="Configuration file", metavar="FILE") # Remaining_argv contains all other command-line-arguments: args, remaining_argv = cparser.parse_known_args() # Get configuration file from the python interpreter: if piargs is not None: cfile = piargs['cfile'] else: cfile = args.config_file # Get values from the configuration file: if cfile: config = ConfigParser.SafeConfigParser() config.read([cfile]) defaults = dict(config.items("MCMC")) else: defaults = {} # Now, parser for the MCMC arguments: parser = argparse.ArgumentParser(parents=[cparser]) # MCMC Options: group = parser.add_argument_group("MCMC General Options") group.add_argument("-n", "--numit", dest="numit", help="Number of MCMC samples [default: %(default)s]", type=eval, action="store", default=100) group.add_argument("-x", "--nchains", dest="nchains", help="Number of chains [default: %(default)s]", type=int, action="store", default=10) group.add_argument("-w", "--walk", dest="walk", help="Random walk algorithm [default: %(default)s]", type=str, action="store", default="demc", choices=('demc', 'mrw')) group.add_argument("-g", "--gelman_rubin", dest="grtest", help="Run Gelman-Rubin test [default: %(default)s]", type=eval, action="store", default=False) group.add_argument("-b", "--burnin", help="Number of burn-in iterations (per chain) " "[default: %(default)s]", dest="burnin", type=eval, action="store", default=0) group.add_argument( "-t", "--thinning", dest="thinning", help="Chains thinning factor (use every thinning-th " "iteration) for GR test and plots [default: %(default)s]", type=int, action="store", default=1) group.add_argument( "--plots", dest="plots", help="If True plot parameter traces, pairwise posteriors, " "and marginal posterior histograms [default: %(default)s]", type=eval, action="store", default=False) group.add_argument("-o", "--save_file", dest="savefile", help="Output filename to store the parameter posterior " "distributions [default: %(default)s]", type=str, action="store", default="output.npy") group.add_argument("--mpi", dest="mpi", help="Run under MPI multiprocessing [default: " "%(default)s]", type=eval, action="store", default=False) # Fitting-parameter Options: group = parser.add_argument_group("Fitting-function Options") group.add_argument("-f", "--func", dest="func", help="List of strings with the function name, module " "name, and path-to-module [required]", type=mu.parray, action="store", default=None) group.add_argument("-p", "--params", dest="params", help="Filename or list of initial-guess model-fitting " "parameter [required]", type=mu.parray, action="store", default=None) group.add_argument("-m", "--pmin", dest="pmin", help="Filename or list of parameter lower boundaries " "[default: -inf]", type=mu.parray, action="store", default=None) group.add_argument("-M", "--pmax", dest="pmax", help="Filename or list of parameter upper boundaries " "[default: +inf]", type=mu.parray, action="store", default=None) group.add_argument("-s", "--stepsize", dest="stepsize", help="Filename or list with proposal jump scale " "[default: 0.1*params]", type=mu.parray, action="store", default=None) group.add_argument("-i", "--indparams", dest="indparams", help="Filename or list with independent parameters for " "func [default: None]", type=mu.parray, action="store", default=[]) # Data Options: group = parser.add_argument_group("Data Options") group.add_argument("-d", "--data", dest="data", help="Filename or list of the data being fitted " "[required]", type=mu.parray, action="store", default=None) group.add_argument("-u", "--uncertainties", dest="uncert", help="Filemane or list with the data uncertainties " "[default: ones]", type=mu.parray, action="store", default=None) group.add_argument("--prior", dest="prior", help="Filename or list with parameter prior estimates " "[default: %(default)s]", type=mu.parray, action="store", default=None) group.add_argument("--priorlow", dest="priorlow", help="Filename or list with prior lower uncertainties " "[default: %(default)s]", type=mu.parray, action="store", default=None) group.add_argument("--priorup", dest="priorup", help="Filename or list with prior upper uncertainties " "[default: %(default)s]", type=mu.parray, action="store", default=None) # Set the defaults from the configuration file: parser.set_defaults(**defaults) # Set values from command line: args2, unknown = parser.parse_known_args(remaining_argv) # Unpack configuration-file/command-line arguments: numit = args2.numit nchains = args2.nchains walk = args2.walk grtest = args2.grtest burnin = args2.burnin thinning = args2.thinning plots = args2.plots savefile = args2.savefile mpi = args2.mpi func = args2.func params = args2.params pmin = args2.pmin pmax = args2.pmax stepsize = args2.stepsize indparams = args2.indparams data = args2.data uncert = args2.uncert prior = args2.prior priorup = args2.priorup priorlow = args2.priorlow # Set values from the python interpreter: if piargs is not None: for key in piargs.keys(): exec("%s = piargs['%s']" % (key, key)) # Checks for mpi4py: if mpi: if comm is None: mu.exit( message="Attempted to use MPI, but mpi4py is not installed.") try: commname = comm.Get_name() except: mu.exit(None, message="Invalid communicator. Did you run mcmc.py? " "For MPI run mpmc.py instead.") if not mpi: comm = None # Handle arguments: if params is None: mu.exit(comm, True, "'params' is a required argument.") elif isinstance(params[0], str): # If params is a filename, unpack: if not os.path.isfile(params[0]): mu.exit(comm, True, "'params' file not found.") array = mu.read2array(params[0]) # Array size: ninfo, ndata = np.shape(array) if ninfo == 7: # The priors prior = array[4] priorlow = array[5] priorup = array[6] if ninfo >= 4: # The stepsize stepsize = array[3] if ninfo >= 2: # The boundaries pmin = array[1] pmax = array[2] params = array[0] # The initial guess # Check for pmin and pmax files if not read before: if pmin is not None and isinstance(pmin[0], str): if not os.path.isfile(pmin[0]): mu.exit(comm, True, "'pmin' file not found.") pmin = mu.read2array(pmin[0])[0] if pmax is not None and isinstance(pmax[0], str): if not os.path.isfile(pmax[0]): mu.exit(comm, True, "'pmax' file not found.") pmax = mu.read2array(pmax[0])[0] # Stepsize: if stepsize is not None and isinstance(stepsize[0], str): if not os.path.isfile(stepsize[0]): mu.exit(comm, True, "'stepsize' file not found.") stepsize = mu.read2array(stepsize[0])[0] # Priors: if prior is not None and isinstance(prior[0], str): if not os.path.isfile(prior[0]): mu.exit(comm, True, "'prior' file not found.") prior = mu.read2array(prior[0])[0] if priorlow is not None and isinstance(priorlow[0], str): if not os.path.isfile(priorlow[0]): mu.exit(comm, True, "'priorlow' file not found.") priorlow = mu.read2array(priorlow[0])[0] if priorup is not None and isinstance(priorup[0], str): if not os.path.isfile(priorup[0]): mu.exit(comm, True, "'priorup' file not found.") priorup = mu.read2array(priorup[0])[0] # Process the data and uncertainties: if data is None: mu.exit(comm, True, "'data' is a required argument.") # If params is a filename, unpack: elif isinstance(data[0], str): if not os.path.isfile(data[0]): mu.exit(comm, True, "'data' file not found.") array = mu.read2array(data[0]) # Array size: ninfo, ndata = np.shape(array) data = array[0] if ninfo == 2: uncert = array[1] if uncert is not None and isinstance(uncert[0], str): if not os.path.isfile(uncert[0]): mu.exit(comm, True, "'uncert' file not found.") uncert = mu.read2array(uncert[0])[0] # Process the independent parameters: if indparams != [] and isinstance(indparams[0], str): if not os.path.isfile(indparams[0]): mu.exit(comm, True, "'indparams' file not found.") indparams = mu.read2array(indparams[0], square=False) # Send OK: if mpi: mu.comm_gather(comm, np.array([0]), MPI.INT) # Run the MCMC: allp, bp = mcmc(data, uncert, func, indparams, params, pmin, pmax, stepsize, prior, priorup, priorlow, numit, nchains, walk, grtest, burnin, thinning, plots, savefile, mpi) # Successful exit mu.comm_disconnect(comm) return allp, bp
def main(): """ Multi-Core Markov-Chain Monte Carlo (MC cubed) This code calls MCMC to work under an MPI multiprocessor protocol or single-thread mode. When using MPI it will launch one CPU per MCMC chain to work in parallel. Parameters: ----------- cfile: String Filename of a configuration file. """ # Parse the config file from the command line: cparser = argparse.ArgumentParser(description=__doc__, add_help=False, formatter_class=argparse.RawDescriptionHelpFormatter) # Add config file option: cparser.add_argument("-c", "--config_file", help="Configuration file", metavar="FILE") # Remaining_argv contains all other command-line-arguments: args, remaining_argv = cparser.parse_known_args() # Take configuration file from command-line: cfile = args.config_file # Incorrect configuration file name: if cfile is not None and not os.path.isfile(cfile): mu.error("Configuration file: '{:s}' not found.".format(cfile)) if cfile: config = ConfigParser.SafeConfigParser() config.read([cfile]) defaults = dict(config.items("MCMC")) else: defaults = {} # Parser for the MCMC arguments: parser = argparse.ArgumentParser(parents=[cparser]) # MCMC Options: group = parser.add_argument_group("MCMC General Options") group.add_argument("-n", "--numit", dest="numit", help="Number of MCMC samples [default: %(default)s]", type=eval, action="store", default=100) group.add_argument("-x", "--nchains", dest="nchains", help="Number of chains [default: %(default)s]", type=int, action="store", default=10) group.add_argument("-w", "--walk", dest="walk", help="Random walk algorithm [default: %(default)s]", type=str, action="store", default="demc", choices=('demc', 'mrw')) group.add_argument( "--wlikelihood", dest="wlike", help="Calculate the likelihood in a wavelet base " "[default: %(default)s]", type=eval, action="store", default=False) group.add_argument( "--leastsq", dest="leastsq", help="Perform a least-square minimization before the " "MCMC run [default: %(default)s]", type=eval, action="store", default=False) group.add_argument( "--chisq_scale", dest="chisqscale", help="Scale the data uncertainties such that the reduced " "chi-squared = 1. [default: %(default)s]", type=eval, action="store", default=False) group.add_argument("-g", "--gelman_rubin", dest="grtest", help="Run Gelman-Rubin test [default: %(default)s]", type=eval, action="store", default=False) group.add_argument( "--grexit", dest="grexit", help="Exit the MCMC loop if the MCMC satisfies the GR " "test two consecutive times [default: %(default)s]", type=eval, action="store", default=False) group.add_argument("-b", "--burnin", help="Number of burn-in iterations (per chain) " "[default: %(default)s]", dest="burnin", type=eval, action="store", default=0) group.add_argument("-t", "--thinning", dest="thinning", help="Chains thinning factor (use every thinning-th " "iteration) for GR test and plots [default: %(default)s]", type=int, action="store", default=1) group.add_argument( "--plots", dest="plots", help="If True plot parameter traces, pairwise posteriors, " "and marginal posterior histograms [default: %(default)s]", type=eval, action="store", default=False) group.add_argument("-o", "--save_file", dest="savefile", help="Output filename to store the parameter posterior " "distributions [default: %(default)s]", type=str, action="store", default="output.npy") group.add_argument( "--savemodel", dest="savemodel", help="Output filename to store the evaluated models " "[default: %(default)s]", type=str, action="store", default=None) group.add_argument( "--mpi", dest="mpi", help="Run under MPI multiprocessing [default: " "%(default)s]", type=eval, action="store", default=False) group.add_argument( "--resume", dest="resume", help="If True, resume a previous run (load output) " "[default: %(default)s]", type=eval, action="store", default=False) group.add_argument( "--rms", dest="rms", help="If True, calculate the RMS of (data-bestmodel) " "[default: %(default)s]", type=eval, action="store", default=False) group.add_argument( "--logfile", dest="logfile", help="Log file.", action="store", default=None) group.add_argument("-T", "--tracktime", dest="tractime", action="store_true") # Fitting-parameter Options: group = parser.add_argument_group("Fitting-function Options") group.add_argument("-f", "--func", dest="func", help="List of strings with the function name, module " "name, and path-to-module [required]", type=mu.parray, action="store", default=None) group.add_argument("-p", "--params", dest="params", help="Filename or list of initial-guess model-fitting " "parameter [required]", type=mu.parray, action="store", default=None) group.add_argument("-m", "--pmin", dest="pmin", help="Filename or list of parameter lower boundaries " "[default: -inf]", type=mu.parray, action="store", default=None) group.add_argument("-M", "--pmax", dest="pmax", help="Filename or list of parameter upper boundaries " "[default: +inf]", type=mu.parray, action="store", default=None) group.add_argument("-s", "--stepsize", dest="stepsize", help="Filename or list with proposal jump scale " "[default: 0.1*params]", type=mu.parray, action="store", default=None) group.add_argument("-i", "--indparams", dest="indparams", help="Filename or list with independent parameters for " "func [default: None]", type=mu.parray, action="store", default=[]) # Data Options: group = parser.add_argument_group("Data Options") group.add_argument("-d", "--data", dest="data", help="Filename or list of the data being fitted " "[required]", type=mu.parray, action="store", default=None) group.add_argument("-u", "--uncertainties", dest="uncert", help="Filemane or list with the data uncertainties " "[default: ones]", type=mu.parray, action="store", default=None) group.add_argument( "--prior", dest="prior", help="Filename or list with parameter prior estimates " "[default: %(default)s]", type=mu.parray, action="store", default=None) group.add_argument( "--priorlow", dest="priorlow", help="Filename or list with prior lower uncertainties " "[default: %(default)s]", type=mu.parray, action="store", default=None) group.add_argument( "--priorup", dest="priorup", help="Filename or list with prior upper uncertainties " "[default: %(default)s]", type=mu.parray, action="store", default=None) # Set the defaults from the configuration file: parser.set_defaults(**defaults) # Set values from command line: args2, unknown = parser.parse_known_args(remaining_argv) # Unpack configuration-file/command-line arguments: numit = args2.numit nchains = args2.nchains walk = args2.walk wlike = args2.wlike leastsq = args2.leastsq chisqscale = args2.chisqscale grtest = args2.grtest grexit = args2.grexit burnin = args2.burnin thinning = args2.thinning plots = args2.plots savefile = args2.savefile savemodel = args2.savemodel mpi = args2.mpi resume = args2.resume tracktime = args2.tractime logfile = args2.logfile rms = args2.rms func = args2.func params = args2.params pmin = args2.pmin pmax = args2.pmax stepsize = args2.stepsize indparams = args2.indparams data = args2.data uncert = args2.uncert prior = args2.prior priorup = args2.priorup priorlow = args2.priorlow nprocs = nchains # Open a log FILE if requested: if logfile is not None: log = open(logfile, "w") else: log = None # Handle arguments: if params is None: mu.error("'params' is a required argument.", log) elif isinstance(params[0], str): # If params is a filename, unpack: if not os.path.isfile(params[0]): mu.error("params file '{:s}' not found.".format(params[0]), log) array = mu.loadascii(params[0]) # Array size: ninfo, ndata = np.shape(array) if ninfo == 7: # The priors prior = array[4] priorlow = array[5] priorup = array[6] if ninfo >= 4: # The stepsize stepsize = array[3] if ninfo >= 2: # The boundaries pmin = array[1] pmax = array[2] params = array[0] # The initial guess # Check for pmin and pmax files if not read before: if pmin is not None and isinstance(pmin[0], str): if not os.path.isfile(pmin[0]): mu.error("pmin file '{:s}' not found.".format(pmin[0]), log) pmin = mu.loadascii(pmin[0])[0] if pmax is not None and isinstance(pmax[0], str): if not os.path.isfile(pmax[0]): mu.error("pmax file '{:s}' not found.".format(pmax[0]), log) pmax = mu.loadascii(pmax[0])[0] # Stepsize: if stepsize is not None and isinstance(stepsize[0], str): if not os.path.isfile(stepsize[0]): mu.error("stepsize file '{:s}' not found.".format(stepsize[0]), log) stepsize = mu.loadascii(stepsize[0])[0] # Priors: if prior is not None and isinstance(prior[0], str): if not os.path.isfile(prior[0]): mu.error("prior file '{:s}' not found.".format(prior[0]), log) prior = mu.loadascii(prior [0])[0] if priorlow is not None and isinstance(priorlow[0], str): if not os.path.isfile(priorlow[0]): mu.error("priorlow file '{:s}' not found.".format(priorlow[0]), log) priorlow = mu.loadascii(priorlow[0])[0] if priorup is not None and isinstance(priorup[0], str): if not os.path.isfile(priorup[0]): mu.error("priorup file '{:s}' not found.".format(priorup[0]), log) priorup = mu.loadascii(priorup [0])[0] # Process the data and uncertainties: if data is None: mu.error("'data' is a required argument.", log) # If params is a filename, unpack: elif isinstance(data[0], str): if not os.path.isfile(data[0]): mu.error("data file '{:s}' not found.".format(data[0]), log) array = mu.loadbin(data[0]) data = array[0] if len(array) == 2: uncert = array[1] if uncert is None: mu.error("'uncert' is a required argument.", log) elif isinstance(uncert[0], str): if not os.path.isfile(uncert[0]): mu.error("uncert file '{:s}' not found.".format(uncert[0]), log) uncert = mu.loadbin(uncert[0])[0] # Process the independent parameters: if indparams != [] and isinstance(indparams[0], str): if not os.path.isfile(indparams[0]): mu.error("indparams file '{:s}' not found.".format(indparams[0]), log) indparams = mu.loadbin(indparams[0]) if tracktime: start_mpi = timeit.default_timer() if mpi: # Checks for mpi4py: try: from mpi4py import MPI except: mu.error("Attempted to use MPI, but mpi4py is not installed.", log) # Get source dir: mcfile = mc.__file__ iright = mcfile.rfind('/') if iright == -1: sdir = "." else: sdir = mcfile[:iright] # Hack func here: funccall = sdir + "/func.py" if func[0] == 'hack': funccall = func[2] + "/" + func[1] + ".py" # Call wrapper of model function: args = [funccall, "-c" + cfile] + remaining_argv comm = MPI.COMM_SELF.Spawn(sys.executable, args=args, maxprocs=nprocs) else: comm = None # Use a copy of uncert to avoid overwrite on it. if uncert is not None: unc = np.copy(uncert) else: unc = None if tracktime: start_loop = timeit.default_timer() # Run the MCMC: allp, bp = mc.mcmc(data, unc, func, indparams, params, pmin, pmax, stepsize, prior, priorlow, priorup, numit, nchains, walk, wlike, leastsq, chisqscale, grtest, grexit, burnin, thinning, plots, savefile, savemodel, comm, resume, log, rms) if tracktime: stop = timeit.default_timer() # Close communications and disconnect: if mpi: mu.comm_disconnect(comm) #if bench == True: if tracktime: mu.msg(1, "Total execution time: %10.6f s"%(stop - start), log) if log is not None: log.close()
def main(): """ Multi-Core Markov-Chain Monte Carlo (MC cubed) This code calls MCMC to work under an MPI multiprocessor protocol or single-thread mode. When using MPI it will launch one CPU per MCMC chain to work in parallel. Parameters: ----------- cfile: String Filename of a configuration file. Modification History: --------------------- 2014-04-19 patricio Initial implementation. [email protected] 2014-05-04 patricio Added cfile argument for Interpreter support. 2014-05-26 patricio Re-engineered the MPI support. 2014-06-26 patricio Fixed bug with copy when uncert is None. 2014-09-14 patricio Write/read now binary files. 2014-10-23 patricio Added support for func hack. 2015-02-04 patricio Added resume argument. 2015-05-15 patricio Added logfile argument. """ # Parse the config file from the command line: cparser = argparse.ArgumentParser( description=__doc__, add_help=False, formatter_class=argparse.RawDescriptionHelpFormatter) # Add config file option: cparser.add_argument("-c", "--config_file", help="Configuration file", metavar="FILE") # Remaining_argv contains all other command-line-arguments: args, remaining_argv = cparser.parse_known_args() # Take configuration file from command-line: cfile = args.config_file # Incorrect configuration file name: if cfile is not None and not os.path.isfile(cfile): mu.error("Configuration file: '{:s}' not found.".format(cfile)) if cfile: config = ConfigParser.SafeConfigParser() config.read([cfile]) defaults = dict(config.items("MCMC")) else: defaults = {} # Parser for the MCMC arguments: parser = argparse.ArgumentParser(parents=[cparser]) # MCMC Options: group = parser.add_argument_group("MCMC General Options") group.add_argument("-n", "--numit", dest="numit", help="Number of MCMC samples [default: %(default)s]", type=eval, action="store", default=100) group.add_argument("-x", "--nchains", dest="nchains", help="Number of chains [default: %(default)s]", type=int, action="store", default=10) group.add_argument("-w", "--walk", dest="walk", help="Random walk algorithm [default: %(default)s]", type=str, action="store", default="demc", choices=('demc', 'mrw')) group.add_argument("--wlikelihood", dest="wlike", help="Calculate the likelihood in a wavelet base " "[default: %(default)s]", type=eval, action="store", default=False) group.add_argument("--leastsq", dest="leastsq", help="Perform a least-square minimization before the " "MCMC run [default: %(default)s]", type=eval, action="store", default=False) group.add_argument( "--chisq_scale", dest="chisqscale", help="Scale the data uncertainties such that the reduced " "chi-squared = 1. [default: %(default)s]", type=eval, action="store", default=False) group.add_argument("-g", "--gelman_rubin", dest="grtest", help="Run Gelman-Rubin test [default: %(default)s]", type=eval, action="store", default=False) group.add_argument("-b", "--burnin", help="Number of burn-in iterations (per chain) " "[default: %(default)s]", dest="burnin", type=eval, action="store", default=0) group.add_argument( "-t", "--thinning", dest="thinning", help="Chains thinning factor (use every thinning-th " "iteration) for GR test and plots [default: %(default)s]", type=int, action="store", default=1) group.add_argument( "--plots", dest="plots", help="If True plot parameter traces, pairwise posteriors, " "and marginal posterior histograms [default: %(default)s]", type=eval, action="store", default=False) group.add_argument("-o", "--save_file", dest="savefile", help="Output filename to store the parameter posterior " "distributions [default: %(default)s]", type=str, action="store", default="output.npy") group.add_argument("--savemodel", dest="savemodel", help="Output filename to store the evaluated models " "[default: %(default)s]", type=str, action="store", default=None) group.add_argument("--mpi", dest="mpi", help="Run under MPI multiprocessing [default: " "%(default)s]", type=eval, action="store", default=False) group.add_argument("--resume", dest="resume", help="If True, resume a previous run (load output) " "[default: %(default)s]", type=eval, action="store", default=False) group.add_argument("--rms", dest="rms", help="If True, calculate the RMS of (data-bestmodel) " "[default: %(default)s]", type=eval, action="store", default=False) group.add_argument("--logfile", dest="logfile", help="Log file.", action="store", default=None) group.add_argument("-T", "--tracktime", dest="tractime", action="store_true") # Fitting-parameter Options: group = parser.add_argument_group("Fitting-function Options") group.add_argument("-f", "--func", dest="func", help="List of strings with the function name, module " "name, and path-to-module [required]", type=mu.parray, action="store", default=None) group.add_argument("-p", "--params", dest="params", help="Filename or list of initial-guess model-fitting " "parameter [required]", type=mu.parray, action="store", default=None) group.add_argument("-m", "--pmin", dest="pmin", help="Filename or list of parameter lower boundaries " "[default: -inf]", type=mu.parray, action="store", default=None) group.add_argument("-M", "--pmax", dest="pmax", help="Filename or list of parameter upper boundaries " "[default: +inf]", type=mu.parray, action="store", default=None) group.add_argument("-s", "--stepsize", dest="stepsize", help="Filename or list with proposal jump scale " "[default: 0.1*params]", type=mu.parray, action="store", default=None) group.add_argument("-i", "--indparams", dest="indparams", help="Filename or list with independent parameters for " "func [default: None]", type=mu.parray, action="store", default=[]) # Data Options: group = parser.add_argument_group("Data Options") group.add_argument("-d", "--data", dest="data", help="Filename or list of the data being fitted " "[required]", type=mu.parray, action="store", default=None) group.add_argument("-u", "--uncertainties", dest="uncert", help="Filemane or list with the data uncertainties " "[default: ones]", type=mu.parray, action="store", default=None) group.add_argument("--prior", dest="prior", help="Filename or list with parameter prior estimates " "[default: %(default)s]", type=mu.parray, action="store", default=None) group.add_argument("--priorlow", dest="priorlow", help="Filename or list with prior lower uncertainties " "[default: %(default)s]", type=mu.parray, action="store", default=None) group.add_argument("--priorup", dest="priorup", help="Filename or list with prior upper uncertainties " "[default: %(default)s]", type=mu.parray, action="store", default=None) # Set the defaults from the configuration file: parser.set_defaults(**defaults) # Set values from command line: args2, unknown = parser.parse_known_args(remaining_argv) # Unpack configuration-file/command-line arguments: numit = args2.numit nchains = args2.nchains walk = args2.walk wlike = args2.wlike leastsq = args2.leastsq chisqscale = args2.chisqscale grtest = args2.grtest burnin = args2.burnin thinning = args2.thinning plots = args2.plots savefile = args2.savefile savemodel = args2.savemodel mpi = args2.mpi resume = args2.resume tracktime = args2.tractime logfile = args2.logfile rms = args2.rms func = args2.func params = args2.params pmin = args2.pmin pmax = args2.pmax stepsize = args2.stepsize indparams = args2.indparams data = args2.data uncert = args2.uncert prior = args2.prior priorup = args2.priorup priorlow = args2.priorlow nprocs = nchains # Open a log FILE if requested: if logfile is not None: log = open(logfile, "w") else: log = None # Handle arguments: if params is None: mu.error("'params' is a required argument.", log) elif isinstance(params[0], str): # If params is a filename, unpack: if not os.path.isfile(params[0]): mu.error("'params' file not found.", log) array = mu.read2array(params[0]) # Array size: ninfo, ndata = np.shape(array) if ninfo == 7: # The priors prior = array[4] priorlow = array[5] priorup = array[6] if ninfo >= 4: # The stepsize stepsize = array[3] if ninfo >= 2: # The boundaries pmin = array[1] pmax = array[2] params = array[0] # The initial guess # Check for pmin and pmax files if not read before: if pmin is not None and isinstance(pmin[0], str): if not os.path.isfile(pmin[0]): mu.error("'pmin' file not found.", log) pmin = mu.read2array(pmin[0])[0] if pmax is not None and isinstance(pmax[0], str): if not os.path.isfile(pmax[0]): mu.error("'pmax' file not found.", log) pmax = mu.read2array(pmax[0])[0] # Stepsize: if stepsize is not None and isinstance(stepsize[0], str): if not os.path.isfile(stepsize[0]): mu.error("'stepsize' file not found.", log) stepsize = mu.read2array(stepsize[0])[0] # Priors: if prior is not None and isinstance(prior[0], str): if not os.path.isfile(prior[0]): mu.error("'prior' file not found.", log) prior = mu.read2array(prior[0])[0] if priorlow is not None and isinstance(priorlow[0], str): if not os.path.isfile(priorlow[0]): mu.error("'priorlow' file not found.", log) priorlow = mu.read2array(priorlow[0])[0] if priorup is not None and isinstance(priorup[0], str): if not os.path.isfile(priorup[0]): mu.error("'priorup' file not found.", log) priorup = mu.read2array(priorup[0])[0] # Process the data and uncertainties: if data is None: mu.error("'data' is a required argument.", log) # If params is a filename, unpack: elif isinstance(data[0], str): if not os.path.isfile(data[0]): mu.error("'data' file not found.", log) array = mu.readbin(data[0]) data = array[0] if len(array) == 2: uncert = array[1] if uncert is not None and isinstance(uncert[0], str): if not os.path.isfile(uncert[0]): mu.error("'uncert' file not found.", log) uncert = mu.readbin(uncert[0])[0] # Process the independent parameters: if indparams != [] and isinstance(indparams[0], str): if not os.path.isfile(indparams[0]): mu.error("'indparams' file not found.", log) indparams = mu.readbin(indparams[0]) if tracktime: start_mpi = timeit.default_timer() if mpi: # Checks for mpi4py: try: from mpi4py import MPI except: mu.error("Attempted to use MPI, but mpi4py is not installed.", log) # Get source dir: mcfile = mc.__file__ iright = mcfile.rfind('/') if iright == -1: sdir = "." else: sdir = mcfile[:iright] # Hack func here: funccall = sdir + "/func.py" if func[0] == 'hack': funccall = func[2] + "/" + func[1] + ".py" # Call wrapper of model function: args = [funccall, "-c" + cfile] + remaining_argv comm = MPI.COMM_SELF.Spawn(sys.executable, args=args, maxprocs=nprocs) else: comm = None # Use a copy of uncert to avoid overwrite on it. if uncert is not None: unc = np.copy(uncert) else: unc = None if tracktime: start_loop = timeit.default_timer() # Run the MCMC: allp, bp = mc.mcmc(data, unc, func, indparams, params, pmin, pmax, stepsize, prior, priorlow, priorup, numit, nchains, walk, wlike, leastsq, chisqscale, grtest, burnin, thinning, plots, savefile, savemodel, comm, resume, log, rms) if tracktime: stop = timeit.default_timer() # Close communications and disconnect: if mpi: mu.comm_disconnect(comm) #if bench == True: if tracktime: mu.msg(1, "Total execution time: %10.6f s" % (stop - start), log) if log is not None: log.close()
def main(comm, piargs=None): """ Take arguments from the command line and run MCMC when called from the prompt Parameters: ----------- comm: MPI communicator An MPI intercommunicator piargs: List List of MCMC arguments (sent from mc3.mcmc) from the python interpreter. Modification History: --------------------- 2014-04-19 patricio Initial implementation. [email protected] 2014-05-04 patricio Added piargs argument for Python Interpreter support. """ # Parse the config file from the command line: cparser = argparse.ArgumentParser(description=__doc__, add_help=False, formatter_class=argparse.RawDescriptionHelpFormatter) # Add config file option: cparser.add_argument("-c", "--config_file", type=str, help="Configuration file", metavar="FILE") # Remaining_argv contains all other command-line-arguments: args, remaining_argv = cparser.parse_known_args() # Get configuration file from the python interpreter: if piargs is not None: cfile = piargs['cfile'] else: cfile = args.config_file # Get values from the configuration file: if cfile: config = ConfigParser.SafeConfigParser() config.read([cfile]) defaults = dict(config.items("MCMC")) else: defaults = {} # Now, parser for the MCMC arguments: parser = argparse.ArgumentParser(parents=[cparser]) # MCMC Options: group = parser.add_argument_group("MCMC General Options") group.add_argument("-n", "--numit", dest="numit", help="Number of MCMC samples [default: %(default)s]", type=eval, action="store", default=100) group.add_argument("-x", "--nchains", dest="nchains", help="Number of chains [default: %(default)s]", type=int, action="store", default=10) group.add_argument("-w", "--walk", dest="walk", help="Random walk algorithm [default: %(default)s]", type=str, action="store", default="demc", choices=('demc', 'mrw')) group.add_argument("-g", "--gelman_rubin", dest="grtest", help="Run Gelman-Rubin test [default: %(default)s]", type=eval, action="store", default=False) group.add_argument("-b", "--burnin", help="Number of burn-in iterations (per chain) " "[default: %(default)s]", dest="burnin", type=eval, action="store", default=0) group.add_argument("-t", "--thinning", dest="thinning", help="Chains thinning factor (use every thinning-th " "iteration) for GR test and plots [default: %(default)s]", type=int, action="store", default=1) group.add_argument( "--plots", dest="plots", help="If True plot parameter traces, pairwise posteriors, " "and marginal posterior histograms [default: %(default)s]", type=eval, action="store", default=False) group.add_argument("-o", "--save_file", dest="savefile", help="Output filename to store the parameter posterior " "distributions [default: %(default)s]", type=str, action="store", default="output.npy") group.add_argument( "--mpi", dest="mpi", help="Run under MPI multiprocessing [default: " "%(default)s]", type=eval, action="store", default=False) # Fitting-parameter Options: group = parser.add_argument_group("Fitting-function Options") group.add_argument("-f", "--func", dest="func", help="List of strings with the function name, module " "name, and path-to-module [required]", type=mu.parray, action="store", default=None) group.add_argument("-p", "--params", dest="params", help="Filename or list of initial-guess model-fitting " "parameter [required]", type=mu.parray, action="store", default=None) group.add_argument("-m", "--pmin", dest="pmin", help="Filename or list of parameter lower boundaries " "[default: -inf]", type=mu.parray, action="store", default=None) group.add_argument("-M", "--pmax", dest="pmax", help="Filename or list of parameter upper boundaries " "[default: +inf]", type=mu.parray, action="store", default=None) group.add_argument("-s", "--stepsize", dest="stepsize", help="Filename or list with proposal jump scale " "[default: 0.1*params]", type=mu.parray, action="store", default=None) group.add_argument("-i", "--indparams", dest="indparams", help="Filename or list with independent parameters for " "func [default: None]", type=mu.parray, action="store", default=[]) # Data Options: group = parser.add_argument_group("Data Options") group.add_argument("-d", "--data", dest="data", help="Filename or list of the data being fitted " "[required]", type=mu.parray, action="store", default=None) group.add_argument("-u", "--uncertainties", dest="uncert", help="Filemane or list with the data uncertainties " "[default: ones]", type=mu.parray, action="store", default=None) group.add_argument( "--prior", dest="prior", help="Filename or list with parameter prior estimates " "[default: %(default)s]", type=mu.parray, action="store", default=None) group.add_argument( "--priorlow", dest="priorlow", help="Filename or list with prior lower uncertainties " "[default: %(default)s]", type=mu.parray, action="store", default=None) group.add_argument( "--priorup", dest="priorup", help="Filename or list with prior upper uncertainties " "[default: %(default)s]", type=mu.parray, action="store", default=None) # Set the defaults from the configuration file: parser.set_defaults(**defaults) # Set values from command line: args2, unknown = parser.parse_known_args(remaining_argv) # Unpack configuration-file/command-line arguments: numit = args2.numit nchains = args2.nchains walk = args2.walk grtest = args2.grtest burnin = args2.burnin thinning = args2.thinning plots = args2.plots savefile = args2.savefile mpi = args2.mpi func = args2.func params = args2.params pmin = args2.pmin pmax = args2.pmax stepsize = args2.stepsize indparams = args2.indparams data = args2.data uncert = args2.uncert prior = args2.prior priorup = args2.priorup priorlow = args2.priorlow # Set values from the python interpreter: if piargs is not None: for key in piargs.keys(): exec("%s = piargs['%s']"%(key, key)) # Checks for mpi4py: if mpi: if comm is None: mu.exit(message="Attempted to use MPI, but mpi4py is not installed.") try: commname = comm.Get_name() except: mu.exit(None, message="Invalid communicator. Did you run mcmc.py? " "For MPI run mpmc.py instead.") if not mpi: comm = None # Handle arguments: if params is None: mu.exit(comm, True, "'params' is a required argument.") elif isinstance(params[0], str): # If params is a filename, unpack: if not os.path.isfile(params[0]): mu.exit(comm, True, "'params' file not found.") array = mu.read2array(params[0]) # Array size: ninfo, ndata = np.shape(array) if ninfo == 7: # The priors prior = array[4] priorlow = array[5] priorup = array[6] if ninfo >= 4: # The stepsize stepsize = array[3] if ninfo >= 2: # The boundaries pmin = array[1] pmax = array[2] params = array[0] # The initial guess # Check for pmin and pmax files if not read before: if pmin is not None and isinstance(pmin[0], str): if not os.path.isfile(pmin[0]): mu.exit(comm, True, "'pmin' file not found.") pmin = mu.read2array(pmin[0])[0] if pmax is not None and isinstance(pmax[0], str): if not os.path.isfile(pmax[0]): mu.exit(comm, True, "'pmax' file not found.") pmax = mu.read2array(pmax[0])[0] # Stepsize: if stepsize is not None and isinstance(stepsize[0], str): if not os.path.isfile(stepsize[0]): mu.exit(comm, True, "'stepsize' file not found.") stepsize = mu.read2array(stepsize[0])[0] # Priors: if prior is not None and isinstance(prior[0], str): if not os.path.isfile(prior[0]): mu.exit(comm, True, "'prior' file not found.") prior = mu.read2array(prior [0])[0] if priorlow is not None and isinstance(priorlow[0], str): if not os.path.isfile(priorlow[0]): mu.exit(comm, True, "'priorlow' file not found.") priorlow = mu.read2array(priorlow[0])[0] if priorup is not None and isinstance(priorup[0], str): if not os.path.isfile(priorup[0]): mu.exit(comm, True, "'priorup' file not found.") priorup = mu.read2array(priorup [0])[0] # Process the data and uncertainties: if data is None: mu.exit(comm, True, "'data' is a required argument.") # If params is a filename, unpack: elif isinstance(data[0], str): if not os.path.isfile(data[0]): mu.exit(comm, True, "'data' file not found.") array = mu.read2array(data[0]) # Array size: ninfo, ndata = np.shape(array) data = array[0] if ninfo == 2: uncert = array[1] if uncert is not None and isinstance(uncert[0], str): if not os.path.isfile(uncert[0]): mu.exit(comm, True, "'uncert' file not found.") uncert = mu.read2array(uncert[0])[0] # Process the independent parameters: if indparams != [] and isinstance(indparams[0], str): if not os.path.isfile(indparams[0]): mu.exit(comm, True, "'indparams' file not found.") indparams = mu.read2array(indparams[0], square=False) # Send OK: if mpi: mu.comm_gather(comm, np.array([0]), MPI.INT) # Run the MCMC: allp, bp = mcmc(data, uncert, func, indparams, params, pmin, pmax, stepsize, prior, priorup, priorlow, numit, nchains, walk, grtest, burnin, thinning, plots, savefile, mpi) # Successful exit mu.comm_disconnect(comm) return allp, bp
def main(cfile=None): """ Multi-Processor Markov-Chain Monte Carlo (MPMC) This code calls MCMC to work under an MPI multiprocessor protocol or single-thread mode. When using MPI it will launch one CPU per MCMC chain to work in parallel. Parameters: ----------- cfile: String Filename of a configuration file. Modification History: --------------------- 2014-04-19 patricio Initial implementation. [email protected] 2014-05-04 patricio Added cfile argument for Interpreter support. """ # Parse arguments: cparser = argparse.ArgumentParser(description=__doc__, add_help=False, formatter_class=argparse.RawDescriptionHelpFormatter) # Add config file option: cparser.add_argument("-c", "--config_file", help="Specify config file", metavar="FILE") # Remaining_argv contains all other command-line-arguments: args, remaining_argv = cparser.parse_known_args() # Take configuration file from command-line if not given as an argument: if cfile is None: cfile = args.config_file # Incorrect configuration file name: if cfile is not None and not os.path.isfile(cfile): mu.exit(None, message="Configuration file: '%s' not found."%cfile) if cfile: config = ConfigParser.SafeConfigParser() config.read([cfile]) defaults = dict(config.items("MCMC")) else: defaults = {} parser = argparse.ArgumentParser(parents=[cparser], add_help=False) parser.add_argument("-x", "--nchains", dest="nchains", type=int, action="store", default=10) parser.add_argument( "--mpi", dest="mpi", type=eval, help="Run under MPI multiprocessing [default %(default)s]", action="store", default=False) parser.add_argument("-T", "--tracktime", dest="tractime", action="store_true") parser.add_argument("-h", "--help", dest="help", action="store_true") parser.set_defaults(**defaults) args2, unknown = parser.parse_known_args(remaining_argv) # The number of processors is the number of chains: nprocs = args2.nchains mpi = args2.mpi # Hidden feature to track the execution of the time per loop for MPI: tracktime = args2.tractime # Get source dir: mcfile = mc.__file__ iright = mcfile.rfind('/') if iright == -1: sdir = "." else: sdir = mcfile[:iright] # If asked for help: if args2.help: subprocess.call([sdir + "/mcmc.py --help"], shell=True) sys.exit(0) if not mpi: subprocess.call([sdir+"/mcmc.py " + " ".join(sys.argv[1:])], shell=True) else: if tracktime: start_mpi = timeit.default_timer() # Call MCMC: args = [sdir+"/mcmc.py", "-c"+cfile] + remaining_argv comm1 = MPI.COMM_SELF.Spawn(sys.executable, args=args, maxprocs=1) # Get OK flag from MCMC: abort = np.array([0]) mu.comm_gather(comm1, abort) if abort[0]: mu.exit(comm1) # Call wrapper of model function: args = [sdir+"/func.py", "-c"+cfile] + remaining_argv comm2 = MPI.COMM_SELF.Spawn(sys.executable, args=args, maxprocs=nprocs) # MPI get sizes from MCMC: array1 = np.zeros(3, np.int) mu.comm_gather(comm1, array1) npars, ndata, niter = array1 # MPI Broadcast to workers: mu.comm_bcast(comm2, np.asarray([npars, niter], np.int), MPI.INT) # get npars, ndata from MCMC: mpipars = np.zeros(npars*nprocs, np.double) mpimodels = np.zeros(ndata*nprocs, np.double) if tracktime: start_loop = timeit.default_timer() loop_timer = [] loop_timer2 = [] while niter >= 0: if tracktime: loop_timer.append(timeit.default_timer()) # Gather (receive) parameters from MCMC: mu.comm_gather(comm1, mpipars) # Scatter (send) parameters to funcwrapper: mu.comm_scatter(comm2, mpipars, MPI.DOUBLE) # Gather (receive) models: mu.comm_gather(comm2, mpimodels) # Scatter (send) results to MCMC: mu.comm_scatter(comm1, mpimodels, MPI.DOUBLE) niter -= 1 if tracktime: loop_timer2.append(timeit.default_timer() - loop_timer[-1]) if tracktime: stop = timeit.default_timer() # Close communications and disconnect: if mpi: mu.comm_disconnect(comm1) mu.comm_disconnect(comm2) #if bench == True: if tracktime: print("Total execution time: %10.6f s"%(stop - start)) print("Time to initialize MPI: %10.6f s"%(start_loop - start_mpi)) print("Time to run first loop: %10.6f s"%(loop_timer[1] - loop_timer[0])) print("Time to run last loop: %10.6f s"%(loop_timer[-1]- loop_timer[-2])) print("Time to run avg loop: %10.6f s"%(np.mean(loop_timer2)))