Exemplo n.º 1
0
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)
Exemplo n.º 2
0
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 ~~")
Exemplo n.º 3
0
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
Exemplo n.º 4
0
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()
Exemplo n.º 5
0
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()
Exemplo n.º 6
0
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
Exemplo n.º 7
0
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)))