Пример #1
0
 def add_state(self, state):
     # Add mean clock rate
     xml.parameter(state,
                   text=self.initial_mean,
                   id=self.mean_rate_id,
                   upper="1000.0",
                   name="stateNode")
Пример #2
0
 def _add_prior(self, prior, name):
     alpha_prior = xml.prior(prior,
                             id="covarion_alpha_prior.s:%s" % name,
                             name="distribution",
                             x="@covarion_alpha.s:%s" % name)
     xml.Uniform(alpha_prior,
                 id="CovAlphaUniform:%s" % name,
                 name="distr",
                 upper="Infinity")
     switch_prior = xml.prior(prior,
                              id="covarion_s_prior.s:%s" % name,
                              name="distribution",
                              x="@covarion_s.s:%s" % name)
     gamma = xml.Gamma(switch_prior, id="Gamma.0:%s" % name, name="distr")
     xml.parameter(gamma,
                   text="0.05",
                   id="covarion_switch_gamma_param1:%s" % name,
                   name="alpha",
                   lower="0.0",
                   upper="0.0")
     xml.parameter(gamma,
                   text="10.0",
                   id="covarion_switch_gamma_param2:%s" % name,
                   name="beta",
                   lower="0.0",
                   upper="0.0")
Пример #3
0
    def add_operators(self, beastxml):
        if beastxml.config.languages.sample_branch_lengths:
            updown = xml.operator(
                beastxml.run,
                attrib={
                    "id": "UpDown",
                    "spec": "UpDownOperator",
                    "scaleFactor": "0.5",
                    "weight": "3.0"})
            xml.tree(updown, idref="Tree.t:beastlingTree", name="up")
            xml.parameter(updown, idref="birthRate.t:beastlingTree", name="down")
            ### Include clock rates in up/down only if calibrations are given
            if beastxml.config.calibrations:
                for clock in beastxml.config.clocks:
                    if clock.estimate_rate:
                        xml.parameter(updown, idref=clock.mean_rate_id, name="down")

        # Birth rate scaler
        # Birth rate is *always* scaled.
        xml.operator(
            beastxml.run,
            attrib={"id": "YuleBirthRateScaler.t:beastlingTree",
                    "spec": "ScaleOperator",
                    "parameter": "@birthRate.t:beastlingTree",
                    "scaleFactor": "0.5",
                    "weight": "3.0"})
Пример #4
0
 def add_state(self, state):
     BaseModel.add_state(self, state)
     if self.gamma_categories > 0:
         xml.parameter(state,
                       text="1.0",
                       id="gammaShape.s:%s" % self.name,
                       name="stateNode")
Пример #5
0
 def add_state(self, state):
     RelaxedClock.add_state(self, state)
     # Standard deviation for lognormal dist
     xml.parameter(state,
                   text=self.initial_variance,
                   id="ucldSdev.c:%s" % self.name,
                   lower="0.0",
                   upper="10.0",
                   name="stateNode")
Пример #6
0
 def add_frequency_state(self, state):
     for fname in self.parameter_identifiers():
         xml.parameter(
             state,
             text="0.94 0.05 0.01",
             id="%s:visiblefrequencies.s" % fname,
             name="stateNode",
             dimension="3",
             lower="0.0",
             upper="1.0")
Пример #7
0
 def add_state(self, state):
     RelaxedClock.add_state(self, state)
     xml.parameter(state,
                   text="2.0",
                   id="clockRateGammaShape:%s" % self.name,
                   lower="0.0",
                   name="stateNode")
     xml.parameter(state,
                   text="0.5",
                   id="clockRateGammaScale:%s" % self.name,
                   lower="0.0",
                   name="stateNode")
Пример #8
0
 def add_state(self, state):
     xml.parameter(state,
                   text="100.0",
                   id="sphericalPrecision",
                   lower="0.0",
                   name="stateNode")
     xml.stateNode(state,
                   id="location.geo",
                   spec="sphericalGeo.LocationParameter",
                   minordimension="2",
                   estimate="true",
                   value="0.0 0.0",
                   lower="0.0")
Пример #9
0
 def add_prior(self, beastxml):
     """Add a Yule tree prior."""
     coalescent = xml.distribution(beastxml.prior,
                                   id="Coalescent.t:beastlingTree",
                                   spec="Coalescent")
     popmod = xml.populationModel(coalescent,
                                  id="ConstantPopulation:beastlingTree",
                                  spec="ConstantPopulation")
     xml.parameter(popmod, idref="popSize.t:beastlingTree", name="popSize")
     xml.treeIntervals(coalescent,
                       id="TreeIntervals",
                       spec="TreeIntervals",
                       tree="@Tree.t:beastlingTree")
Пример #10
0
 def add_operators(self, run):
     RelaxedClock.add_operators(self, run)
     updown = xml.operator(run,
                           id="relaxedClockGammaUpDown:%s" % self.name,
                           spec="UpDownOperator",
                           scaleFactor="0.5",
                           weight="3.0")
     xml.parameter(updown,
                   idref="clockRateGammaShape:%s" % self.name,
                   name="up")
     xml.parameter(updown,
                   idref="clockRateGammaScale:%s" % self.name,
                   name="down")
Пример #11
0
    def _add_substmodel(self, sitemodel, feature, name):
        if self.share_params:
            name = self.name
            self.subst_model_id = "%s:pdcovarion.s" % name
        subst_model_id = "%s:pdcovarion.s" % name
        substmodel = xml.substModel(
            sitemodel,
            id=subst_model_id,
            spec="BirthDeathCovarion2",
            deathprob="@{:}:pdcovarion_death.s".format(name),
            originLength="@{:s}:pdcovarion_origin.s".format(name),
            switchRate="@{:}:pdcovarion_s.s".format(name))

        # Numerical instability is an issue with this model, so we give the
        # option of using a more robust method of computing eigenvectors.
        if self.use_robust_eigensystem: # pragma: no cover
            raise ValueError(
                "Currently, Beast's pseudo-Dollo covarion model does not "
                "support robust eigensystems.")
            substmodel.set("eigenSystem", "beast.evolution.substitutionmodel.RobustEigenSystem")

        # The "vfrequencies" parameter here is the frequencies
        # of the *visible* states (present/absent) and should
        # be based on the data (if we are doing an empirical
        # analysis)
        if self.frequencies == "estimate":
            substmodel.set("vfrequencies","@%s:visiblefrequencies.s" % name)
        else:
            vfreq = xml.vfrequencies(
                substmodel,
                id="%s:visiblefrequencies.s" % name,
                dimension="3",
                spec="parameter.RealParameter")
            if self.frequencies == "empirical": # pragma: no cover
                raise ValueError("Dollo model {:} cannot derive empirical "
                                 "frequencies from data".format(self.name))
            else:
                vfreq.text="0.94 0.05 0.01"

        # These are the frequencies of the *hidden* states
        # (fast / slow), and are just set to 50: 50.  They could be estimated,
        # in principle, but this seems to lead to serious instability problems
        # so we don't expose that possibility to the user.
        xml.parameter(
            substmodel,
            text="0.5 0.5",
            id="%s: hiddenfrequencies.s" % name,
            dimension="2",
            name="hfrequencies",
            lower="0.0",
            upper="1.0")
Пример #12
0
 def add_state(self, state):
     BinaryModel.add_state(self, state)
     # Each feature gets a param
     for fname in self.parameter_identifiers():
         xml.parameter(state,
                       text="0.5",
                       id="covarion_alpha.s:%s" % fname,
                       lower="1.0E-4",
                       name="stateNode",
                       upper="1.0")
         xml.parameter(state,
                       text="0.5",
                       id="covarion_s.s:%s" % fname,
                       lower="1.0E-4",
                       name="stateNode",
                       upper="Infinity")
Пример #13
0
    def add_substmodel(self, sitemodel, feature, fname):
        # If we're sharing one substmodel across all features and have already
        # created it, just reference it and that's it
        if self.subst_model_id:
            sitemodel.set("substModel", "@%s" % self.subst_model_id)
            return

        # Otherwise, create a substmodel
        name = self.name if self.share_params else fname
        subst_model_id = "binaryCTMC.s:%s" % name
        if self.share_params:
            self.subst_model_id = subst_model_id
        substmodel = xml.substModel(sitemodel,
                                    id=subst_model_id,
                                    spec="GeneralSubstitutionModel")
        xml.parameter(substmodel,
                      text="1.0 1.0",
                      id="rates.s:%s" % name,
                      dimension=2,
                      estimate="false",
                      name="rates")

        if self.frequencies == "estimate":
            xml.frequencies(substmodel,
                            id="estimatedFrequencies.s:%s" % name,
                            spec="Frequencies",
                            frequencies="@freqs_param.s:%s" % name)
        elif self.frequencies == "empirical":
            attribs = {
                "id": "empiricalFrequencies.s:%s" % name,
                "spec": "Frequencies"
            }
            if self.share_params:
                if self.single_sitemodel:
                    attribs["data"] = "@filtered_data_%s" % name
                else:
                    attribs["frequencies"] = self.build_freq_str()
            else:
                attribs["data"] = "@feature_data_%s" % name
            xml.frequencies(substmodel, attrib=attribs)
        elif self.frequencies == "uniform":
            xml.frequencies(substmodel,
                            text="0.5 0.5",
                            id="frequencies.s:%s" % name,
                            dimension="2",
                            spec="parameter.RealParameter")
Пример #14
0
 def add_substmodel(self, sitemodel, feature, fname):
     attribs = {
         "id": "svs.s:%s"%fname,
         "rateIndicator": "@rateIndicator.s:%s" % fname,
         "rates": "@relativeGeoRates.s:%s" % fname,
         "spec": "SVSGeneralSubstitutionModel"}
     if not self.symmetric:
         attribs['symmetric'] = 'false'
     if self.use_robust_eigensystem:
         attribs["eigenSystem"] = "beast.evolution.substitutionmodel.RobustEigenSystem"
     substmodel = xml.substModel(sitemodel, **attribs)
     attribs = {
         "id": "feature_freqs.s:%s"%fname,
         "spec": "Frequencies",
     }
     freq_string=None
     if self.frequencies == "estimate":
         attribs["frequencies"] = "@feature_freqs_param.s:%s"%fname
     elif self.frequencies == "uniform":
         freq_string = str(1.0/self.valuecounts[feature])
     elif self.frequencies == "empirical":
         #TODO: Do this in the BEAStly way
         freqs = [
             self.counts[feature].get(
                 self.unique_values[feature][v], 0)
             for v in range(self.valuecounts[feature])]
         norm = float(sum(freqs))
         freqs = [f/norm for f in freqs]
         # Sometimes, due to WALS oddities, there's a zero frequency, and that makes BEAST sad.  So do some smoothing in these cases:
         if 0 in freqs:
             freqs = [0.1/self.valuecounts[feature] + 0.9*f for f in freqs]
         norm = float(sum(freqs))
         freq_string = " ".join([str(c/norm) for c in freqs])
     else:
         raise ValueError(
             "Model BSVS does not recognize frequencies %r, "
             "should be 'uniform' or 'empirical'." % self.frequencies)
     freq = xml.frequencies(substmodel, **attribs)
     if self.frequencies != "estimate":
         xml.parameter(
             freq,
             text=freq_string,
             dimension=self.valuecounts[feature],
             id="feature_frequencies.s:%s" % fname,
             name="frequencies")
Пример #15
0
    def add_state_nodes(self, beastxml):
        """
        Add tree-related <state> sub-elements.
        """
        state = beastxml.state
        self.tree = xml.tree(state, id=self.tree_id, name="stateNode")
        xml.taxonset(self.tree, idref="taxa")
        if self.type in ["yule", "birthdeath"]:
            param = xml.parameter(state,
                                  id="birthRate.t:beastlingTree",
                                  name="stateNode")
            if self.birthrate_estimate is not None:
                param.text = str(self.birthrate_estimate)
            else:
                param.text = "1.0"
            if self.type in ["birthdeath"]:
                xml.parameter(beastxml.state,
                              text="0.5",
                              id="deathRate.t:beastlingTree",
                              name="stateNode")
                xml.parameter(beastxml.state,
                              text="0.2",
                              id="sampling.t:beastlingTree",
                              name="stateNode")

        elif self.type == "coalescent":
            xml.parameter(beastxml.state,
                          text="1.0",
                          id="popSize.t:beastlingTree",
                          name="stateNode")
        if beastxml.config.tip_calibrations:
            self.add_tip_heights(beastxml.config.tip_calibrations)
Пример #16
0
    def add_prior(self, prior):
        BaseClock.add_prior(self, prior)

        # Gamma prior over rates
        sub_prior = xml.prior(prior,
                              id="RandomRatesPrior.c:%s" % self.name,
                              name="distribution",
                              x="@clockrates.c:%s" % self.name)
        xml.Gamma(sub_prior,
                  id="RandomRatesPrior:%s" % self.name,
                  name="distr",
                  alpha="@%s" % self.shape_id,
                  beta="@%s" % self.scale_id)

        # Exponential prior over Gamma scale parameter
        # (mean param copied from rate heterogeneity implementation in BaseModel)
        if self.estimate_variance:
            sub_prior = xml.prior(prior,
                                  id="randomClockGammaScalePrior.s:%s" %
                                  self.name,
                                  name="distribution",
                                  x="@%s" % self.shape_id)
            xml.Exponential(sub_prior,
                            id="randomClockGammaScalePriorExponential.s:%s" %
                            self.name,
                            mean="0.23",
                            name="distr")

        # Poisson prior over number of rate changes
        sub_prior = xml.prior(prior,
                              id="RandomRateChangesPrior.c:%s" % self.name,
                              name="distribution")
        xml.x(sub_prior,
              id="RandomRateChangesCount:%s" % self.name,
              spec="util.Sum",
              arg="@Indicators.c:%s" % self.name)
        poisson = xml.distr(sub_prior,
                            id="RandomRatechangesPoisson.c:%s" % self.name,
                            spec="beast.math.distributions.Poisson")
        xml.parameter(poisson,
                      text="0.6931471805599453",
                      id="RandomRateChangesPoissonLambda:%s" % self.name,
                      estimate=False,
                      name="lambda")
Пример #17
0
 def add_operators(self):
     """
     Add all <operator> elements.
     """
     self.add_tree_operators()
     for clock in self.config.clocks:
         clock.add_operators(self.run)
     for model in self.config.all_models:
         model.add_operators(self.run)
     # Add one DeltaExchangeOperator for feature rates per clock
     for clock in self.config.clocks:
         clock_models = [
             m for m in self.config.models
             if m.rate_variation and m.clock == clock
         ]
         if not clock_models:
             continue
         # Add one big DeltaExchangeOperator which operates on all
         # feature clock rates from all models
         delta = xml.operator(self.run,
                              id="featureClockRateDeltaExchanger:%s" %
                              clock.name,
                              spec="DeltaExchangeOperator",
                              weight="3.0")
         for model in clock_models:
             xml.parameter(xml.plate(delta,
                                     var="rate",
                                     range=model.all_rates),
                           idref="featureClockRate:%s:$(rate)" % model.name)
         # Add weight vector if there has been any binarisation
         if any([
                 w != 1 for w in itertools.chain(
                     *[m.weights for m in clock_models])
         ]):
             xml.weightvector(
                 delta,
                 text=" ".join(
                     itertools.chain(
                         *[map(str, m.weights) for m in clock_models])),
                 id="featureClockRateWeightParameter:%s" % clock.name,
                 spec="parameter.IntegerParameter",
                 dimension=str(sum([len(m.weights) for m in clock_models])),
                 estimate="false")
Пример #18
0
 def add_state_nodes(self, beastxml):
     """
     Add tree-related <state> sub-elements.
     """
     super().add_state_nodes(beastxml)
     state = beastxml.state
     param = xml.parameter(state, id="birthRate.t:beastlingTree", name="stateNode")
     if self.birthrate_estimate is not None:
         param.text=str(self.birthrate_estimate)
     else:
         param.text="1.0"
Пример #19
0
 def _add_prior(self, prior, name):
     switch_prior = xml.prior(
         prior,
         id="%s:pdcovarion_s_prior.s" % name,
         name="distribution",
         x="@%s:pdcovarion_s.s" % name)
     gamma = xml.Gamma(switch_prior, id="%s: Gamma.0" % name, name="distr")
     xml.parameter(
         gamma,
         text="0.05",
         id="%s:pdcovarion_switch_gamma_param1" % name,
         name="alpha",
         lower="0.0",
         upper="0.0")
     xml.parameter(
         gamma,
         text="10.0",
         id="%s:pdcovarion_switch_gamma_param2" % name,
         name="beta",
         lower="0.0",
         upper="0.0")
     origin_prior = xml.prior(
         prior,
         id="%s:pdcovarion_origin_prior.s" % name,
         name="distribution",
         x="@%s:pdcovarion_origin.s" % name)
     xml.Uniform(
         origin_prior,
         id="%s:PDCovOriginUniform" % name,
         name="distr",
         upper="Infinity")
     death_prior = xml.prior(
         prior,
         id="%s:pdcovarion_death_prior.s" % name,
         name="distribution",
         x="@{:}:pdcovarion_death.s".format(name))
     xml.Exponential(
         death_prior,
         id="%s:PDCovDeathExp" % name,
         name="distr",
         mean="1.0")
Пример #20
0
 def add_prior(self, prior):
     RelaxedClock.add_prior(self, prior)
     if self.estimate_variance:
         # Gamma prior on the standard deviation for lognormal dist
         sub_prior = xml.prior(prior,
                               id="ucldSdev:%s" % self.name,
                               name="distribution",
                               x="@ucldSdev.c:%s" % self.name)
         gamma = xml.Gamma(sub_prior,
                           id="uclSdevPrior:%s" % self.name,
                           name="distr")
         xml.parameter(gamma,
                       text="0.5396",
                       id="uclSdevPriorAlpha:%s" % self.name,
                       estimate="false",
                       name="alpha")
         xml.parameter(gamma,
                       text="0.3819",
                       id="uclSdevPriorBeta:%s" % self.name,
                       estimate="false",
                       name="beta")
Пример #21
0
    def add_state(self, state):
        BinaryModel.add_state(self, state)

        for fname in self.parameter_identifiers():
            # One param for all features
            xml.parameter(
                state,
                text="0.5 0.5",
                id="%s:pdcovarion_s.s" % fname,
                lower="1.0E-4",
                name="stateNode",
                dimension="2",
                upper="Infinity")
            xml.parameter(
                state,
                text="10",
                id="%s:pdcovarion_origin.s" % fname,
                lower="1",
                name="stateNode",
                upper="Infinity")
            xml.parameter(
                state,
                text="1.0 0.1",
                id="%s:pdcovarion_death.s" % fname,
                lower="1.0E-4",
                name="stateNode",
                dimension="2",
                upper="1.0")
Пример #22
0
 def add_data(self, distribution):
     """
     Add <data> element corresponding to the indicated feature, descending
     from the indicated likelihood distribution.
     """
     data = xml.data(distribution,
                     id="locationData",
                     spec="sphericalGeo.AlignmentFromTraitMap")
     traitmap = xml.traitMap(data,
                             id="geographyTraitmap",
                             spec="sphericalGeo.TreeTraitMap",
                             initByMean="true",
                             randomizelower="-90 -180",
                             randomizeupper="90 180",
                             traitName="location",
                             tree="@Tree.t:beastlingTree")
     xml.parameter(traitmap,
                   text="0.0 0.0",
                   id="locationParameter",
                   spec="sphericalGeo.LocationParameter",
                   dimension=2 *
                   (2 * len(self.config.languages.languages) - 1),
                   minordimension="2")
     loc_data_text_bits = []
     for lang in self.config.languages.languages:
         lat, lon = self.config.locations.get(lang, ("?", "?"))
         if "?" in (lat, lon):
             if lang not in self.sampling_points:
                 self.sampling_points.append(lang)
                 log.info(
                     "Location of language %s will be sampled.  You may wish to add a prior."
                     % lang,
                     model=self)
         else:
             bit = "%s=%.2f %.2f" % (lang, lat, lon)
             loc_data_text_bits.append(bit)
     traitmap.text = ",\n".join(loc_data_text_bits)
     xml.userDataType(data,
                      id="LocationDataType",
                      spec="sphericalGeo.LocationDataType")
Пример #23
0
 def add_operators(self, run):
     """
     Add <operators> for individual feature substitution rates if rate
     variation is configured.
     """
     if self.frequencies == "estimate":
         self.add_frequency_operators(run)
     if self.rate_variation:
         # UpDownOperator to scale the Gamma distribution for this model's
         # feature rates
         updown = xml.operator(run,
                               id="featureClockRateGammaUpDown:%s" %
                               self.name,
                               spec="UpDownOperator",
                               scaleFactor="0.5",
                               weight="0.3")
         xml.parameter(updown,
                       idref="featureClockRateGammaShape:%s" % self.name,
                       name="up")
         xml.parameter(updown,
                       idref="featureClockRateGammaScale:%s" % self.name,
                       name="down")
Пример #24
0
 def add_state(self, state):
     BaseClock.add_state(self, state)
     xml.stateNode(state,
                   text=False,
                   id="Indicators.c:%s" % self.name,
                   spec="parameter.BooleanParameter",
                   dimension=42)
     xml.stateNode(state,
                   text="0.1",
                   id="clockrates.c:%s" % self.name,
                   spec="parameter.RealParameter",
                   dimension=42)
     self.shape_id = "randomClockGammaShape:%s" % self.name
     # Domain and initial values for Gamma params copied from rate heterogeneity
     # implementation in BaseModel
     xml.parameter(state,
                   text="5.0",
                   id=self.shape_id,
                   name="stateNode",
                   lower="1.1",
                   upper="1000.0")
     self.scale_id = "randomClockGammaScale:%s" % self.name
     xml.parameter(state, text="0.2", id=self.scale_id, name="stateNode")
Пример #25
0
    def add_state(self, state):
        """Construct the model's state nodes.

        Add parameters for Gamma-distributed rate heterogenetiy, if
        configured.

        """

        if self.frequencies == "estimate":
            self.add_frequency_state(state)

        if self.rate_variation:
            if self.feature_rates:
                # If user specified rates have been provided for either
                # features or partitions, we need to list each rate
                # individually
                for rate in self.all_rates:
                    xml.parameter(state,
                                  text=self.feature_rates.get(rate, 1.0),
                                  id="featureClockRate:%s:%s" %
                                  (self.name, rate),
                                  name="stateNode")
            else:
                # If not, and everything is initialised to the same
                # value, we can just whack 'em all in a big plate
                plate = xml.plate(state, var="rate", range=self.all_rates)
                xml.parameter(plate,
                              text="1.0",
                              id="featureClockRate:%s:$(rate)" % self.name,
                              name="stateNode")

            # Give Gamma shape parameter a finite domain
            # Must be > 1.0 for the distribution to be bell-shaped,
            # rather than L-shaped.  The domain [1.1,1000] limits feature
            # rate variation to the realms of vague plausibity
            xml.parameter(state,
                          text="5.0",
                          id="featureClockRateGammaShape:%s" % self.name,
                          lower="1.1",
                          upper="100.0",
                          name="stateNode")
            # Gamma scale parameter's domain is defined *implicilty*
            # by the fact that the operators maintain shape*scale = 1.0
            xml.parameter(state,
                          text="0.2",
                          id="featureClockRateGammaScale:%s" % self.name,
                          name="stateNode")
Пример #26
0
 def add_operators(self, run):
     BaseClock.add_operators(self, run)
     # Operate on indicators
     xml.operator(run,
                  id="IndicatorsBitFlip.c:%s" % self.name,
                  spec="BitFlipOperator",
                  parameter="@Indicators.c:%s" % self.name,
                  weight="15.0")
     # Operate on branch rates
     xml.operator(run,
                  id="ClockRateScaler.c:%s" % self.name,
                  spec="ScaleOperator",
                  parameter="@clockrates.c:%s" % self.name,
                  scaleFactor="0.5",
                  weight="15.0")
     # Up/down for Gamma params
     if self.estimate_variance:
         updown = xml.operator(run,
                               id="randomClockGammaUpDown:%s" % self.name,
                               spec="UpDownOperator",
                               scaleFactor="0.5",
                               weight="1.0")
         xml.parameter(updown, idref=self.shape_id, name="up")
         xml.parameter(updown, idref=self.scale_id, name="down")
Пример #27
0
    def add_state(self, state):

        BaseModel.add_state(self, state)
        for f in self.features:
            fname = "%s:%s" % (self.name, f)

            N = self.valuecounts[f]
            dimension = N*(N-1)
            if self.symmetric:
                dimension = int(dimension/2)

            xml.stateNode(
                state,
                text="true",
                id="rateIndicator.s:%s" % fname,
                spec="parameter.BooleanParameter",
                dimension=dimension)

            xml.parameter(
                state,
                text="1.0",
                id="relativeGeoRates.s:%s" % fname,
                name="stateNode",
                dimension=dimension)
Пример #28
0
    def add_substmodel(self, sitemodel, feature, fname):
        # If we're sharing one substmodel across all features and have already
        # created it, just reference it and that's it
        if self.share_params and self.subst_model_id:
            sitemodel.set("substModel", "@%s" % self.subst_model_id)
            return

        # Otherwise, create a substmodel
        name = self.name if self.share_params else fname
        subst_model_id = "covarion.s:%s" % name
        if self.share_params:
            self.subst_model_id = subst_model_id
        substmodel = xml.substModel(sitemodel,
                                    id=subst_model_id,
                                    spec="BinaryCovarion",
                                    alpha="@covarion_alpha.s:%s" % name,
                                    switchRate="@covarion_s.s:%s" % name)

        # Numerical instability is an issue with this model, so we give the
        # option of using a more robust method of computing eigenvectors.
        if self.use_robust_eigensystem:
            substmodel.set(
                "eigenSystem",
                "beast.evolution.substitutionmodel.RobustEigenSystem")

        # The "vfrequencies" parameter here is the frequencies
        # of the *visible* states (present/absent) and should
        # be based on the data (if we are doing an empirical
        # analysis)
        if self.frequencies == "estimate":
            substmodel.set("vfrequencies", "@freqs_param.s:%s" % name)
        else:
            vfreq = xml.vfrequencies(substmodel,
                                     id="%s:visiblefrequencies.s" % name,
                                     dimension="2",
                                     spec="parameter.RealParameter")
            if self.frequencies == "empirical":
                if self.share_params:
                    vfreq.text = self.build_freq_str()
                else:
                    vfreq.text = self.build_freq_str(feature)
            else:
                vfreq.text = "0.5 0.5"

        # These are the frequencies of the *hidden* states
        # (fast / slow), and are just set to 50:50.  They could be estimated,
        # in principle, but this seems to lead to serious instability problems
        # so we don't expose that possibility to the user.
        xml.parameter(substmodel,
                      text="0.5 0.5",
                      id="%s:hiddenfrequencies.s" % name,
                      dimension="2",
                      lower="0.0",
                      name="hfrequencies",
                      upper="1.0")

        # Dummy frequencies - these do nothing and are required
        # to stop the BinaryCovarion model complaining that the
        # "frequencies" input is not specified, which is
        # inherited behaviour from GeneralSubstitutionModel
        # which probably should have been overridden...
        xml.frequencies(substmodel,
                        id="%s:dummyfrequences.s" % name,
                        spec="Frequencies",
                        frequencies="0.5 0.5")
Пример #29
0
 def add_state_nodes(self, beastxml):
     super().add_state_nodes(beastxml)
     xml.parameter(beastxml.state,
                   text="1.0",
                   id="popSize.t:beastlingTree",
                   name="stateNode")
Пример #30
0
    def add_operators(self, beastxml):
        """
        Add all <operator>s which act on the tree topology and branch lengths.
        """
        """
        Add all <operator>s which act on the tree topology and branch lengths.
        """
        # Tree operators
        # Operators which affect the tree must respect the sample_topology and
        # sample_branch_length options.
        if beastxml.config.languages.sample_topology:
            ## Tree topology operators
            xml.operator(beastxml.run,
                         attrib={
                             "id": "SubtreeSlide.t:beastlingTree",
                             "spec": "SubtreeSlide",
                             "tree": "@Tree.t:beastlingTree",
                             "markclades": "true",
                             "weight": "15.0"
                         })
            xml.operator(beastxml.run,
                         attrib={
                             "id": "narrow.t:beastlingTree",
                             "spec": "Exchange",
                             "tree": "@Tree.t:beastlingTree",
                             "markclades": "true",
                             "weight": "15.0"
                         })
            xml.operator(beastxml.run,
                         attrib={
                             "id": "wide.t:beastlingTree",
                             "isNarrow": "false",
                             "spec": "Exchange",
                             "tree": "@Tree.t:beastlingTree",
                             "markclades": "true",
                             "weight": "3.0"
                         })
            xml.operator(beastxml.run,
                         attrib={
                             "id": "WilsonBalding.t:beastlingTree",
                             "spec": "WilsonBalding",
                             "tree": "@Tree.t:beastlingTree",
                             "markclades": "true",
                             "weight": "3.0"
                         })
        if beastxml.config.languages.sample_branch_lengths:
            ## Branch length operators
            xml.operator(beastxml.run,
                         attrib={
                             "id": "UniformOperator.t:beastlingTree",
                             "spec": "Uniform",
                             "tree": "@Tree.t:beastlingTree",
                             "weight": "30.0"
                         })
            xml.operator(beastxml.run,
                         attrib={
                             "id": "treeScaler.t:beastlingTree",
                             "scaleFactor": "0.5",
                             "spec": "ScaleOperator",
                             "tree": "@Tree.t:beastlingTree",
                             "weight": "3.0"
                         })
            xml.operator(beastxml.run,
                         attrib={
                             "id": "treeRootScaler.t:beastlingTree",
                             "scaleFactor": "0.5",
                             "spec": "ScaleOperator",
                             "tree": "@Tree.t:beastlingTree",
                             "rootOnly": "true",
                             "weight": "3.0"
                         })
            ## Up/down operator which scales tree height
            if self.type in ["yule", "birthdeath"]:
                updown = xml.operator(beastxml.run,
                                      attrib={
                                          "id": "UpDown",
                                          "spec": "UpDownOperator",
                                          "scaleFactor": "0.5",
                                          "weight": "3.0"
                                      })
                xml.tree(updown, idref="Tree.t:beastlingTree", name="up")
                xml.parameter(updown,
                              idref="birthRate.t:beastlingTree",
                              name="down")
                ### Include clock rates in up/down only if calibrations are given
                if beastxml.config.calibrations:
                    for clock in beastxml.config.clocks:
                        if clock.estimate_rate:
                            xml.parameter(updown,
                                          idref=clock.mean_rate_id,
                                          name="down")

        if self.type in ["yule", "birthdeath"]:
            # Birth rate scaler
            # Birth rate is *always* scaled.
            xml.operator(beastxml.run,
                         attrib={
                             "id": "YuleBirthRateScaler.t:beastlingTree",
                             "spec": "ScaleOperator",
                             "parameter": "@birthRate.t:beastlingTree",
                             "scaleFactor": "0.5",
                             "weight": "3.0"
                         })
        elif self.type == "coalescent":
            xml.operator(beastxml.run,
                         attrib={
                             "id": "PopulationSizeScaler.t:beastlingTree",
                             "spec": "ScaleOperator",
                             "parameter": "@popSize.t:beastlingTree",
                             "scaleFactor": "0.5",
                             "weight": "3.0"
                         })

        if self.type in ["birthdeath"]:
            xml.operator(beastxml.run,
                         attrib={
                             "id": "SamplingScaler.t:beastlingTree",
                             "spec": "ScaleOperator",
                             "parameter": "@sampling.t:beastlingTree",
                             "scaleFactor": "0.8",
                             "weight": "1.0"
                         })
            xml.operator(beastxml.run,
                         attrib={
                             "id": "DeathRateScaler.t:beastlingTree",
                             "spec": "ScaleOperator",
                             "parameter": "@deathRate.t:beastlingTree",
                             "scaleFactor": "0.5",
                             "weight": "3.0"
                         })

        # Add a Tip Date scaling operator if required
        if beastxml.config.tip_calibrations and beastxml.config.languages.sample_branch_lengths:
            # Get a list of taxa with non-point tip cals
            tip_taxa = [
                next(cal.langs.__iter__())
                for cal in beastxml.config.tip_calibrations.values()
                if cal.dist != "point"
            ]
            for taxon in tip_taxa:
                tiprandomwalker = xml.operator(beastxml.run,
                                               attrib={
                                                   "id":
                                                   "TipDatesandomWalker:%s" %
                                                   taxon,
                                                   "spec":
                                                   "TipDatesRandomWalker",
                                                   "windowSize":
                                                   "1",
                                                   "tree":
                                                   "@Tree.t:beastlingTree",
                                                   "weight":
                                                   "3.0",
                                               })
                beastxml.add_taxon_set(tiprandomwalker, taxon, (taxon, ))