def __init__(self,
                 config_file,
                 random_seed):

        # Fix the seed for the random number generator
        np.random.seed(random_seed)

        # Read in the configuration file using a WorkflowConfigParser.
        # Note that the argument `configFiles` has to be a list here,
        # so we need to wrap the `config_file` argument accordingly...
        config_file = WorkflowConfigParser(configFiles=[config_file])

        # Extract variable arguments and constraints
        # We don't need the static_args here, hence they do not get amended.
        self.var_args, _ = read_params_from_config(config_file)
        self.constraints = read_constraints_from_config(config_file)

        # Extract distributions
        dist = read_distributions_from_config(config_file)

        # Extract transformations
        self.trans = read_transforms_from_config(config_file)

        # Set up a joint distribution to sample from
        self.pval = JointDistribution(self.var_args,
                                      *dist,
                                      **{'constraints': self.constraints})
Пример #2
0
    def from_config(cls, cp, variable_params):
        """Gets sampling transforms specified in a config file.

        Sampling parameters and the parameters they replace are read from the
        ``sampling_params`` section, if it exists. Sampling transforms are
        read from the ``sampling_transforms`` section(s), using
        ``transforms.read_transforms_from_config``.

        An ``AssertionError`` is raised if no ``sampling_params`` section
        exists in the config file.

        Parameters
        ----------
        cp : WorkflowConfigParser
            Config file parser to read.
        variable_params : list
            List of parameter names of the original variable params.

        Returns
        -------
        SamplingTransforms
            A sampling transforms class.
        """
        if not cp.has_section('sampling_params'):
            raise ValueError("no sampling_params section found in config file")
        # get sampling transformations
        sampling_params, replace_parameters = \
            read_sampling_params_from_config(cp)
        sampling_transforms = transforms.read_transforms_from_config(
            cp, 'sampling_transforms')
        logging.info("Sampling in {} in place of {}".format(
            ', '.join(sampling_params), ', '.join(replace_parameters)))
        return cls(variable_params, sampling_params, replace_parameters,
                   sampling_transforms)
Пример #3
0
    def __init__(
        self,
        config_files: Union[List[Union[str, os.PathLike]], Union[str,
                                                                 os.PathLike]],
        seed: Optional[int] = None,
    ):
        """Class to generate gravitational waveform parameters using PyCBC workflow and distribution packages.
        """
        if seed is not None:
            raise NotImplementedError(
                "Reproducible random seed not yet implemented.")

        self.config_files = config_files if isinstance(
            config_files, list) else [config_files]
        self.config_parser = WorkflowConfigParser(
            configFiles=self.config_files)

        self.parameters, self.static_args = read_params_from_config(
            self.config_parser)
        self.constraints = read_constraints_from_config(self.config_parser)
        self.transforms = read_transforms_from_config(self.config_parser)
        self.distribution = JointDistribution(
            self.parameters,
            *read_distributions_from_config(self.config_parser),
            **{'constraints': self.constraints})

        # ensure statistics match output of self.parameters
        self.statistics = compute_parameter_statistics({
            parameter: self.distribution.bounds[parameter]
            for parameter in self.parameters
        })
Пример #4
0
    def from_config(cls, cp, variable_params):
        """Gets sampling transforms specified in a config file.

        Sampling parameters and the parameters they replace are read from the
        ``sampling_params`` section, if it exists. Sampling transforms are
        read from the ``sampling_transforms`` section(s), using
        ``transforms.read_transforms_from_config``.

        An ``AssertionError`` is raised if no ``sampling_params`` section
        exists in the config file.

        Parameters
        ----------
        cp : WorkflowConfigParser
            Config file parser to read.
        variable_params : list
            List of parameter names of the original variable params.

        Returns
        -------
        SamplingTransforms
            A sampling transforms class.
        """
        if not cp.has_section('sampling_params'):
            raise ValueError("no sampling_params section found in config file")
        # get sampling transformations
        sampling_params, replace_parameters = \
            read_sampling_params_from_config(cp)
        sampling_transforms = transforms.read_transforms_from_config(
            cp, 'sampling_transforms')
        logging.info("Sampling in {} in place of {}".format(
            ', '.join(sampling_params), ', '.join(replace_parameters)))
        return cls(variable_params, sampling_params,
                   replace_parameters, sampling_transforms)
Пример #5
0
def draw_samples_from_config(path, num=1, seed=150914):
    r""" Generate sampling points from a standalone .ini file.

    Parameters
    ----------
    path : str
        The path to the .ini file.
    num : int
        The number of samples.
    seed: int
        The random seed for sampling.

    Returns
    --------
    samples : pycbc.io.record.FieldArray
        The parameter values and names of sample(s).

    Examples
    --------
    Draw a sample from the distribution defined in the .ini file:

    >>> import numpy as np
    >>> from pycbc.distributions.utils import draw_samples_from_config

    >>> # A path to the .ini file.
    >>> CONFIG_PATH = "./pycbc_bbh_prior.ini"
    >>> random_seed = np.random.randint(low=0, high=2**32-1)
    >>> sample = draw_samples_from_config(
    >>>          path=CONFIG_PATH, num=1, seed=random_seed)

    >>> # Print all parameters.
    >>> print(sample.fieldnames)
    >>> print(sample)
    >>> # Print a certain parameter, for example 'mass1'.
    >>> print(sample[0]['mass1'])
    """

    np.random.seed(seed)

    # Initialise InterpolatingConfigParser class.
    config_parser = InterpolatingConfigParser()
    # Read the file
    file = open(path, 'r')
    config_parser.read_file(file)
    file.close()

    # Construct class that will draw the samples.
    prior_dists = prior_from_config(cp=config_parser)
    # Draw samples from prior distribution.
    samples = prior_dists.rvs(size=int(num))

    # Apply parameter transformation.
    if any(config_parser.get_subsections('waveform_transforms')):
        waveform_transforms = transforms.read_transforms_from_config(
            config_parser, 'waveform_transforms')
        samples = transforms.apply_transforms(samples, waveform_transforms)

    return samples
Пример #6
0
    def _init_args_from_config(cls, cp):
        """Helper function for loading parameters.

        This retrieves the prior, variable parameters, static parameterss,
        constraints, sampling transforms, and waveform transforms
        (if provided).

        Parameters
        ----------
        cp : ConfigParser
            Config parser to read.

        Returns
        -------
        dict :
            Dictionary of the arguments. Has keys ``variable_params``,
            ``static_params``, ``prior``, and ``sampling_transforms``. If
            waveform transforms are in the config file, will also have
            ``waveform_transforms``.
        """
        section = "model"
        prior_section = "prior"
        vparams_section = 'variable_params'
        sparams_section = 'static_params'
        constraint_section = 'constraint'
        # check that the name exists and matches
        name = cp.get(section, 'name')
        if name != cls.name:
            raise ValueError("section's {} name does not match mine {}".format(
                name, cls.name))
        # get model parameters
        variable_params, static_params = distributions.read_params_from_config(
            cp,
            prior_section=prior_section,
            vargs_section=vparams_section,
            sargs_section=sparams_section)
        # get prior
        prior = cls.prior_from_config(cp, variable_params, prior_section,
                                      constraint_section)
        args = {
            'variable_params': variable_params,
            'static_params': static_params,
            'prior': prior
        }
        # try to load sampling transforms
        try:
            sampling_transforms = SamplingTransforms.from_config(
                cp, variable_params)
        except NoSectionError:
            sampling_transforms = None
        args['sampling_transforms'] = sampling_transforms
        # get any waveform transforms
        if any(cp.get_subsections('waveform_transforms')):
            logging.info("Loading waveform transforms")
            args['waveform_transforms'] = \
                transforms.read_transforms_from_config(
                    cp, 'waveform_transforms')
        return args
Пример #7
0
    def __init__(self, config_file, seed=0):
        numpy.random.seed(seed)
        config_file = WorkflowConfigParser(config_file, None)
        var_args, self.static, constraints = read_args_from_config(config_file)
        dist = read_distributions_from_config(config_file)

        self.trans = read_transforms_from_config(config_file)
        self.pval = JointDistribution(var_args, *dist, 
                                **{"constraints": constraints})   
Пример #8
0
    def _init_args_from_config(cls, cp):
        """Helper function for loading parameters.

        This retrieves the prior, variable parameters, static parameterss,
        constraints, sampling transforms, and waveform transforms
        (if provided).

        Parameters
        ----------
        cp : ConfigParser
            Config parser to read.

        Returns
        -------
        dict :
            Dictionary of the arguments. Has keys ``variable_params``,
            ``static_params``, ``prior``, and ``sampling_transforms``. If
            waveform transforms are in the config file, will also have
            ``waveform_transforms``.
        """
        section = "model"
        prior_section = "prior"
        vparams_section = 'variable_params'
        sparams_section = 'static_params'
        constraint_section = 'constraint'
        # check that the name exists and matches
        name = cp.get(section, 'name')
        if name != cls.name:
            raise ValueError("section's {} name does not match mine {}".format(
                             name, cls.name))
        # get model parameters
        variable_params, static_params = distributions.read_params_from_config(
            cp, prior_section=prior_section, vargs_section=vparams_section,
            sargs_section=sparams_section)
        # get prior
        prior = cls.prior_from_config(cp, variable_params, prior_section,
                                      constraint_section)
        args = {'variable_params': variable_params,
                'static_params': static_params,
                'prior': prior}
        # try to load sampling transforms
        try:
            sampling_transforms = SamplingTransforms.from_config(
                cp, variable_params)
        except ValueError:
            sampling_transforms = None
        args['sampling_transforms'] = sampling_transforms
        # get any waveform transforms
        if any(cp.get_subsections('waveform_transforms')):
            logging.info("Loading waveform transforms")
            args['waveform_transforms'] = \
                transforms.read_transforms_from_config(
                    cp, 'waveform_transforms')
        return args
Пример #9
0
    def _init_args_from_config(cls, cp):
        """Adds loading waveform_transforms to parent function.

        For details on parameters, see ``from_config``.
        """
        args = super(BaseDataModel, cls)._init_args_from_config(cp)
        # add waveform transforms to the arguments
        if any(cp.get_subsections('waveform_transforms')):
            logging.info("Loading waveform transforms")
            args['waveform_transforms'] = \
                transforms.read_transforms_from_config(
                    cp, 'waveform_transforms')
        return args
Пример #10
0
    def from_config(cls, cp, section, tag):
        """ Return instance based on config file

        Return a new instance based on the config file. This will draw from
        a single distribution section provided in the config file and
        apply a single transformation section if desired. If a transformation
        is applied, an inverse mapping is also provided for use in the config
        file.
        """
        from pycbc.distributions import read_distributions_from_config
        from pycbc.transforms import (read_transforms_from_config,
                                      apply_transforms, BaseTransform)
        from pycbc.transforms import transforms as global_transforms

        params = tag.split(VARARGS_DELIM)
        subname = cp.get_opt_tag(section, 'subname', tag)
        size = cp.get_opt_tag(section, 'sample-size', tag)

        distsec = '{}_sample'.format(subname)
        dist = read_distributions_from_config(cp, section=distsec)
        if len(dist) > 1:
            raise ValueError("Fixed sample distrubtion only supports a single"
                             " distribution to sample from.")

        logging.info('Drawing samples for fixed sample distribution:%s', params)
        samples = dist[0].rvs(size=int(float(size)))
        samples = {p: samples[p] for p in samples.dtype.names}

        transec = '{}_transform'.format(subname)
        trans = read_transforms_from_config(cp, section=transec)
        if len(trans) > 0:
            trans = trans[0]
            samples = apply_transforms(samples, [trans])
            p1 = samples[params[0]]

            # We have transformed parameters, so automatically provide the
            # inverse transform for use in passing to waveform approximants
            class Thook(BaseTransform):
                name = subname
                _inputs = trans.outputs
                _outputs = trans.inputs
                p1name = params[0]
                sort = p1.argsort()
                p1sorted = p1[sort]
                def transform(self, maps):
                    idx = numpy.searchsorted(self.p1sorted, maps[self.p1name])
                    out = {p: samples[p][self.sort[idx]] for p in self.outputs}
                    return self.format_output(maps, out)
            global_transforms[Thook.name] = Thook
        return cls(params, samples)
Пример #11
0
def prior_from_config(cp, prior_section='prior'):
    """Loads a prior distribution from the given config file.

    Parameters
    ----------
    cp : pycbc.workflow.WorkflowConfigParser
        The config file to read.
    sections : list of str, optional
        The sections to retrieve the prior from. If ``None`` (the default),
        will look in sections starting with 'prior'.

    Returns
    -------
    distributions.JointDistribution
        The prior distribution.
    """

    # Read variable and static parameters from the config file
    variable_params, static_params = distributions.read_params_from_config(
        cp,
        prior_section=prior_section,
        vargs_section='variable_params',
        sargs_section='static_params')

    # Read waveform_transforms to apply to priors from the config file
    if any(cp.get_subsections('waveform_transforms')):
        waveform_transforms = transforms.read_transforms_from_config(
            cp, 'waveform_transforms')
    else:
        waveform_transforms = None

    # Read constraints to apply to priors from the config file
    constraints = distributions.read_constraints_from_config(
        cp, transforms=waveform_transforms, static_args=static_params)

    # Get PyCBC distribution instances for each variable parameter in the
    # config file
    dists = distributions.read_distributions_from_config(cp, prior_section)

    # construct class that will return draws from the prior
    return distributions.JointDistribution(variable_params, *dists,
                                           **{"constraints": constraints})
Пример #12
0
    def from_config(cls, cp, variable_params):
        """Gets sampling transforms specified in a config file.

        Sampling parameters and the parameters they replace are read from the
        ``sampling_params`` section, if it exists. Sampling transforms are
        read from the ``sampling_transforms`` section(s), using
        ``transforms.read_transforms_from_config``.

        An ``AssertionError`` is raised if no ``sampling_params`` section
        exists in the config file.

        Parameters
        ----------
        cp : WorkflowConfigParser
            Config file parser to read.
        variable_params : list
            List of parameter names of the original variable params.

        Returns
        -------
        SamplingTransforms
            A sampling transforms class.
        """
        # Check if a sampling_params section is provided
        try:
            sampling_params, replace_parameters = \
                read_sampling_params_from_config(cp)
        except NoSectionError as e:
            logging.warning("No sampling_params section read from config file")
            raise e
        # get sampling transformations
        sampling_transforms = transforms.read_transforms_from_config(
            cp, 'sampling_transforms')
        logging.info("Sampling in {} in place of {}".format(
            ', '.join(sampling_params), ', '.join(replace_parameters)))
        return cls(variable_params, sampling_params, replace_parameters,
                   sampling_transforms)
Пример #13
0
    def from_config(cls, cp, **kwargs):
        r"""Initializes an instance of this class from the given config file.

        Sub-models are initialized before initializing this class. The model
        section must have a ``submodels`` argument that lists the names of all
        the submodels to generate as a space-separated list. Each sub-model
        should have its own ``[{label}__model]`` section that sets up the
        model for that sub-model. For example:

        .. code-block:: ini

            [model]
            name = hiearchical
            submodels = event1 event2

            [event1__model]
            <event1 model options>

            [event2__model]
            <event2 model options>

        Similarly, all other sections that are specific to a model should start
        with the model's label. All sections starting with a model's label will
        be passed to that model's ``from_config`` method with the label removed
        from the section name. For example, if a sub-model requires a data
        section to be specified, it should be titled ``[{label}__data]``. Upon
        initialization, the ``{label}__`` will be stripped from the section
        header and passed to the model.

        No model labels should preceed the ``variable_params``,
        ``static_params``, ``waveform_transforms``, or ``sampling_transforms``
        sections.  Instead, the parameters specified in these sections should
        follow the naming conventions described in :py:class:`HierachicalParam`
        to determine which sub-model(s) they belong to. (Sampling parameters
        can follow any naming convention, as they are only handled by the
        hierarchical model.) This is because the hierarchical model handles
        all transforms, communication with the sampler, file IO, and prior
        calculation. Only sub-model's loglikelihood functions are called.

        Metadata for each sub-model is written to the output hdf file under
        groups given by the sub-model label. For example, if we have two
        submodels labelled ``event1`` and ``event2``, there will be groups
        with the same names in the top level of the output that contain that
        model's subdata. For instance, if event1 used the ``gaussian_noise``
        model, the GW data and PSDs will be found in ``event1/data`` and the
        low frequency cutoff used for that model will be in the ``attrs`` of
        the ``event1`` group.

        Parameters
        ----------
        cp : WorkflowConfigParser
            Config file parser to read.
        \**kwargs :
            All additional keyword arguments are passed to the class. Any
            provided keyword will override what is in the config file.
        """
        # we need the read from config function from the init; to prevent
        # circular imports, we import it here
        from pycbc.inference.models import read_from_config
        # get the submodels
        submodel_lbls = shlex.split(cp.get('model', 'submodels'))
        # sort parameters by model
        vparam_map = map_params(
            hpiter(cp.options('variable_params'), submodel_lbls))
        sparam_map = map_params(
            hpiter(cp.options('static_params'), submodel_lbls))

        # we'll need any waveform transforms for the initializing sub-models,
        # as the underlying models will receive the output of those transforms
        if any(cp.get_subsections('waveform_transforms')):
            waveform_transforms = transforms.read_transforms_from_config(
                cp, 'waveform_transforms')
            wfoutputs = set.union(*[t.outputs for t in waveform_transforms])
            wfparam_map = map_params(hpiter(wfoutputs, submodel_lbls))
        else:
            wfparam_map = {lbl: [] for lbl in submodel_lbls}
        # initialize the models
        submodels = {}
        logging.info("Loading submodels")
        for lbl in submodel_lbls:
            logging.info("============= %s =============", lbl)
            # create a config parser to pass to the model
            subcp = WorkflowConfigParser()
            # copy sections over that start with the model label (this should
            # include the [model] section for that model)
            copy_sections = [
                HierarchicalParam(sec, submodel_lbls)
                for sec in cp.sections() if lbl in sec.split('-')[0].split(
                    HierarchicalParam.delim, 1)[0]
            ]
            for sec in copy_sections:
                # check that the user isn't trying to set variable or static
                # params for the model (we won't worry about waveform or
                # sampling transforms here, since that is checked for in the
                # __init__)
                if sec.subname in ['variable_params', 'static_params']:
                    raise ValueError("Section {} found in the config file; "
                                     "[variable_params] and [static_params] "
                                     "sections should not include model "
                                     "labels. To specify parameters unique to "
                                     "one or more sub-models, prepend the "
                                     "individual parameter names with the "
                                     "model label. See HierarchicalParam for "
                                     "details.".format(sec))
                subcp.add_section(sec.subname)
                for opt, val in cp.items(sec):
                    subcp.set(sec.subname, opt, val)
            # set the static params
            subcp.add_section('static_params')
            for param in sparam_map[lbl]:
                subcp.set('static_params', param.subname,
                          cp.get('static_params', param.fullname))
            # set the variable params: for now we'll just set all the
            # variable params as static params
            # so that the model doesn't raise an error looking for
            # prior sections. We'll then manually set the variable
            # params after the model is initialized

            subcp.add_section('variable_params')
            for param in vparam_map[lbl]:
                subcp.set('static_params', param.subname, 'REPLACE')
            # add the outputs from the waveform transforms
            for param in wfparam_map[lbl]:
                subcp.set('static_params', param.subname, 'REPLACE')

            # initialize
            submodel = read_from_config(subcp)
            # move the static params back to variable
            for p in vparam_map[lbl]:
                submodel.static_params.pop(p.subname)
            submodel.variable_params = tuple(p.subname
                                             for p in vparam_map[lbl])
            # remove the waveform transform parameters
            for p in wfparam_map[lbl]:
                submodel.static_params.pop(p.subname)
            # store
            submodels[lbl] = submodel
            logging.info("")
        # now load the model
        logging.info("Loading hierarchical model")
        return super().from_config(cp, submodels=submodels)