Esempio n. 1
0
def test_add_all_components():
    # models_by_category = defaultdict(list)
    # for k, c_type in Component.component_types.items():
    #     print(k, c_type)
    #     models_by_category[c_type.category].append(c_type)
    comps = [x() for x in Component.component_types.values()]
    tm = TimingModel(name="test_manual", components=comps)
    tm.setup()  # This should not have any parameter check.
    assert len(tm.components) == len(comps)
def test_timing_model():
    ac = AllComponents()
    timing_model = TimingModel(
        name="Test",
        components=[
            ac.components["AstrometryEquatorial"],
            ac.components["Spindown"],
            ac.components["DispersionDMX"],
            ac.components["PhaseJump"],
            ac.components["ScaleToaError"],
        ],
    )
    return timing_model
Esempio n. 3
0
def test_simple_manual():
    tm = TimingModel(
        name="test_manual", components=[AstrometryEquatorial(), Spindown()]
    )
    tm.setup()
    assert "F0" in tm.phase_deriv_funcs.keys()
    assert "F1" in tm.phase_deriv_funcs.keys()
    assert "RAJ" in tm.delay_deriv_funcs.keys()
    assert "DECJ" in tm.delay_deriv_funcs.keys()

    with pytest.raises(MissingParameter):  # No RA and DEC input
        tm.validate()

    tm.RAJ.value = "19:59:48"
    tm.DECJ.value = "20:48:36"
    tm.F0.value = 622.122030511927 * u.Hz
    tm.validate()  # This should work.
Esempio n. 4
0
def test_simple_manual():
    tm = TimingModel(
        name="test_manual", components=[AstrometryEquatorial(), Spindown()]
    )
    tm.setup()
    assert "F0" in tm.phase_deriv_funcs.keys()
    assert "RAJ" in tm.delay_deriv_funcs.keys()
    assert "DECJ" in tm.delay_deriv_funcs.keys()

    with pytest.raises(MissingParameter):  # No RA and DEC input
        tm.validate()

    tm.RAJ.value = "19:59:48"
    tm.DECJ.value = "20:48:36"
    tm.F0.quantity = 622.122030511927 * u.Hz
    tm.PEPOCH.value = 48196.0
    tm.validate()  # This should work.

    # When there is no POSEPOCH set, it should just be unset
    assert tm.POSEPOCH.value is None
Esempio n. 5
0
    def __call__(self, parfile, allow_name_mixing=False):
        """Callable object for making a timing model from .par file.

        Parameter
        ---------
        parfile: str or file-like object
            Input .par file name or string contents

        allow_name_mixing : bool, optional
            Flag for allowing the input to have mixing aliases names for the
            same parameter. For example, if this flag is true, one can have
            T2EFAC and EFAC, both of them maps to PINT parameter EFAC, present
            in the parfile at the same time.

        Return
        ------
        pint.models.timing_model.TimingModel
            The result timing model based on the input .parfile or file object.
        """
        pint_param_dict, original_name, unknown_param = self._pintify_parfile(
            parfile, allow_name_mixing)
        selected, conflict, param_not_in_pint = self.choose_model(
            pint_param_dict)
        selected.update(set(self.default_components))
        # Report conflict
        if len(conflict) != 0:
            self._report_conflict(conflict)
        # Make timing model
        cps = [self.all_components.components[c] for c in selected]
        tm = TimingModel(components=cps)
        self._setup_model(tm,
                          pint_param_dict,
                          original_name,
                          setup=True,
                          validate=True)
        # Report unknown line
        for k, v in unknown_param.items():
            p_line = " ".join([k] + v)
            warnings.warn(f"Unrecognized parfile line '{p_line}'", UserWarning)
            # log.warning(f"Unrecognized parfile line '{p_line}'")
        return tm
Esempio n. 6
0
def choose_model(parfile,
                 category_order=None,
                 name=None,
                 check_for_missing_parameters=False):
    """Determine which model components are appropriate for parfile."""
    if name is None:
        if isinstance(parfile, str):
            name = os.path.basename(parfile)
        else:
            name = ""
    if category_order is None:
        category_order = DEFAULT_ORDER

    models_by_category = defaultdict(list)
    for k, c_type in Component.component_types.items():
        models_by_category[c_type.category].append(c_type)

    par_dict = {}
    par_lines = []
    multi_tags = set([
        "JUMP",
        "ECORR",
        "T2EFAC",
        "T2EQUAD",
        "EQUAD",
        "EFAC",
        "DMJUMP",
        "DMEFAC",
        "DMEQUAD",
    ])
    multi_line = Counter()
    for l in interesting_lines(lines_of(parfile), comments=("#", "C ")):
        ll = l.split()
        k = ll[0]
        if k in multi_tags:
            multi_line[k] += 1
            k = k + str(multi_line[k])
        if k in par_dict:
            # FIXME: what happens with JUMPs?
            log.info("Lines with duplicate keys in par file: {} and {}".format(
                [k] + par_dict[k], ll))
        par_dict[k] = ll[1:]
        par_lines.append(l)

    models_to_use = {}
    for category, models in models_by_category.items():
        acceptable = []
        for m_type in models:
            m = m_type()
            if m.is_in_parfile(par_dict):
                acceptable.append(m)
        if len(acceptable) > 1:
            raise ValueError(
                "Multiple models are compatible with this par file: {}".format(
                    acceptable))
        if acceptable:
            models_to_use[category] = acceptable[0]

    if "BINARY" in par_dict:
        vals = par_dict["BINARY"]
        if len(vals) != 1:
            raise ValueError("Mal-formed binary model selection: {}".format(
                repr(" ".join(["BINARY"] + vals))))
        (bm, ) = vals
        if "pulsar_system" not in models_to_use:
            # Either we're missing parameters or the model is bogus
            # FIXME: distinguish
            raise UnknownBinaryModel(
                "Unknown binary model requested in par file: {}".format(bm))
        # FIXME: consistency check - the componens actually chosen should know the name bm

    models_in_order = []
    for category in category_order:
        try:
            models_in_order.append(models_to_use.pop(category))
        except KeyError:
            pass
    models_in_order.extend(v for k, v in sorted(models_to_use.items()))
    tm = TimingModel(name, models_in_order)

    # FIXME: this should go in TimingModel for when you try to
    # add conflicting components
    alias_map = {}
    for prefix_type in ["prefixParameter", "maskParameter"]:
        for pn in tm.get_params_of_type_top(prefix_type):
            par = getattr(tm, pn)
            for a in [par.prefix] + par.prefix_aliases:
                if a in alias_map:
                    raise ValueError(
                        "Two prefix/mask parameters have the same "
                        "alias {}: {} and {}".format(a, alias_map[a], par))
                alias_map[a] = par

    leftover_params = par_dict.copy()
    for k in tm.get_params_mapping():
        leftover_params.pop(k, None)
        for a in getattr(tm, k).aliases:
            leftover_params.pop(a, None)

    for p in leftover_params:
        try:
            pre, idxstr, idxV = split_prefixed_name(p)
            try:
                par = alias_map[pre]
            except KeyError:
                if pre in ignore_prefix:
                    # log.warning("Ignoring unhandled prefix {}".format(pre))
                    continue
                else:
                    raise ValueError(
                        "Mystery parameter {}, prefix {} with number {}".
                        format(p, pre, idxV))
            component = tm.get_params_mapping()[par.name]
            new_parameter = par.new_param(idxV)
            if hasattr(tm, new_parameter.name):
                raise ValueError("Received duplicate parameter {}".format(
                    new_parameter.name))
            tm.add_param_from_top(new_parameter, component)
            # print("added", new_parameter)
        except PrefixError:
            pass

    return tm
Esempio n. 7
0
class ModelBuilder:
    """A class for model construction interface.

    Parameters
    ----------
    name : str
        Name for the model.
    parfile : str optional
        The .par file input for select components. If the parfile is
        provided the self.model_instance will be put model instance
        with .par file read in. If it is not provided, self.model_instance
        will return as None.

    Returns
    -------
    A class contains the result model instance if parfile is provided and
    method to build the model.
    """
    def __init__(self, parfile=None, name=""):
        self.timing_model = None
        self.name = name
        self.param_inparF = None
        self.param_unrecognized = {}
        self.param_inModel = []
        self.param_prefix = {}

        self.select_comp = {}
        self.control_params = ["EPHEM", "CLK"]
        if parfile is not None:
            self.parfile = parfile
            self.build_model(self.parfile, self.name)

    def __str__(self):
        result = "Model name : " + self.name + "\n"
        result += "Components in the model : \n"
        for c in self.select_comp:
            result += "    " + str(c) + "\n"
        if self.model_instance is not None:
            result += "Read parameters from : " + self.parfile + "\n"
            result += "The model instance is :\n" + str(self.model_instance)

        return result

    def preprocess_parfile(self, parfile):
        """Preprocess the par file.

        Return
        ------
        A dictionary with all the parfile parameters with values in string

        """
        param = {}
        repeat_par = {}
        pfile = open(parfile, "r")
        for l in [pl.strip() for pl in pfile.readlines()]:
            # Skip blank lines
            if not l:
                continue
                # Skip commented lines
            if l.startswith("#") or l[:2] == "C ":
                continue
            k = l.split()
            if (k[0] in param.keys()
                ):  # repeat parameter TODO: add JUMP1 even there is only one
                if k[0] in repeat_par.keys():
                    repeat_par[k[0]] += 1
                else:
                    repeat_par[k[0]] = 2
                param[k[0] + str(repeat_par[k[0]])] = k[1:]
            else:
                param[k[0]] = k[1:]
        self.param_inparF = param
        for key in repeat_par.keys():
            self.param_inparF[key + str(1)] = self.param_inparF.pop(key)
        pfile.close()
        return self.param_inparF

    def get_all_categories(self, ):
        """Obtain a dictionary from category to a list of instances."""
        comp_category = defaultdict(list)
        for k, cp in Component.component_types.items():
            comp_category[cp.category].append(cp())
        return dict(comp_category)

    def get_comp_from_parfile(self, parfile):
        """Right now we only have one component on each category."""
        params_inpar = self.preprocess_parfile(parfile)
        for cat, cmps in self.get_all_categories().items():
            selected_c = None
            for cpi in cmps:
                if cpi.component_special_params:
                    if any(par in params_inpar
                           for par in cpi.component_special_params):
                        selected_c = cpi
                        # Once have match, stop searching
                        break
                    else:
                        continue
                else:
                    if cpi.is_in_parfile(params_inpar):
                        selected_c = cpi
            if selected_c is not None:
                self.select_comp[cat] = selected_c

    def sort_components(self, category_order=DEFAULT_ORDER):
        """Sort the components into order.

        Parameters
        ----------
        category_order: list, optional
           The order for the order sensitive component categories.

        Note
        ----
        If a category is not listed in the category_order, it will be treated
        as order non-sensitive category and put in the end of sorted order list.

        """
        sorted_components = []
        for cat in self.get_all_categories():
            # FIXME, I am not sure adding orders here is a good idea.
            if cat not in category_order:
                category_order.append(cat)
        for co in category_order:
            if co not in self.select_comp:
                continue
            cp = self.select_comp[co]
            sorted_components.append(cp)
        return sorted_components

    def search_prefix_param(self, paramList, model, prefix_type):
        """Check if the Unrecognized parameter has prefix parameter"""
        prefixs = {}
        prefix_inModel = model.get_params_of_type_top(prefix_type)
        for pn in prefix_inModel:
            par = getattr(model, pn)
            prefixs[par.prefix] = []
            for p in paramList:
                try:
                    pre, idxstr, idxV = split_prefixed_name(p)
                    if pre in [par.prefix] + par.prefix_aliases:
                        prefixs[par.prefix].append(p)
                except ValueError:  # FIXME: is this meant to catch KeyErrors?
                    continue

        return prefixs

    def build_model(self, parfile=None, name=""):
        """Read parfile using the model_instance attribute. Throws error if
           mismatched coordinate systems detected.
        Parameters
        ---------
        name: str, optional
            The name for the timing model
        parfile : str optional
            The parfile name
        """
        if parfile is not None:
            self.get_comp_from_parfile(parfile)
            # ensure coordinate systems match for POS and PM
            if "RAJ" in self.preprocess_parfile(parfile).keys():
                if "PMELONG" in self.preprocess_parfile(parfile):
                    raise AttributeError(
                        "Cannot have Ecliptic proper motion parameters (PMELONG/PMELAT) with Equatorial position parameters (RAJ/DECJ) in par file."
                    )
                elif "PMELAT" in self.preprocess_parfile(parfile):
                    raise AttributeError(
                        "Cannot have Ecliptic proper motion parameters (PMELONG/PMELAT) with Equatorial position parameters (RAJ/DECJ) in par file."
                    )
            elif "ELONG" in self.preprocess_parfile(parfile).keys():
                if "PMRA" in self.preprocess_parfile(parfile):
                    raise AttributeError(
                        "Cannot have Equatorial proper motion parameters (PMRA/PMDEC) with Ecliptic position parameters (ELONG/ELAT) in par file."
                    )
                elif "PMDEC" in self.preprocess_parfile(parfile):
                    raise AttributeError(
                        "Cannot have Equatorial proper motion parameters (PMRA/PMDEC) with Ecliptic position parameters (ELONG/ELAT) in par file."
                    )
        sorted_comps = self.sort_components()
        self.timing_model = TimingModel(name, sorted_comps)
        param_inModel = self.timing_model.get_params_mapping()
        # Find unrecognised parameters in par file.

        if self.param_inparF is not None:
            parName = []
            # add aliases
            for p in list(param_inModel.keys()):
                parName += getattr(self.timing_model, p).aliases

            parName += param_inModel.keys()

            for pp in self.param_inparF.keys():
                if pp not in parName:
                    self.param_unrecognized[pp] = self.param_inparF[pp]

            for ptype in ["prefixParameter", "maskParameter"]:
                prefix_param = self.search_prefix_param(
                    self.param_unrecognized, self.timing_model, ptype)
                prefix_in_model = self.timing_model.get_params_of_type_top(
                    ptype)
                for key in prefix_param:
                    ppnames = [x for x in prefix_in_model if x.startswith(key)]
                    for ppn in ppnames:
                        pfx, idxs, idxv = split_prefixed_name(ppn)
                        if pfx == key:
                            exm_par = getattr(self.timing_model, ppn)
                        else:
                            continue
                    exm_par_comp = param_inModel[exm_par.name]
                    for parname in prefix_param[key]:
                        pre, idstr, idx = split_prefixed_name(parname)
                        if idx == exm_par.index:
                            continue
                        if hasattr(exm_par, "new_param"):
                            new_par = exm_par.new_param(idx)
                            self.timing_model.add_param_from_top(
                                new_par, exm_par_comp)
            if "BINARY" in self.param_inparF:
                vals = self.param_inparF["BINARY"]
                if len(vals) != 1:
                    raise ValueError(
                        "Mal-formed binary model selection: {}".format(
                            repr(" ".join(["BINARY"] + vals))))
                (bm, ) = vals
                cats = self.timing_model.get_components_by_category()
                if "pulsar_system" not in cats:
                    raise UnknownBinaryModel(
                        "Unknown binary model requested in par file: {}".
                        format(bm))
                # FIXME: consistency check - the componens actually chosen should know the name bm
        for p in self.timing_model.params:
            if isinstance(self.timing_model[p], maskParameter):
                # maskParameters need a bogus alias for parfile parsing
                # remove this bogus alias
                try:
                    ix = self.timing_model[p].aliases.index(
                        self.timing_model[p].prefix)
                except ValueError:
                    pass
                else:
                    del self.timing_model[p].aliases[ix]
        if parfile is not None:
            self.timing_model.read_parfile(parfile)

    def get_control_info(self):
        info = {}
        if not self.param_unrecognized == {}:
            for ctrlp in self.control_params:
                if ctrlp in self.param_unrecognized:
                    info[ctrlp] = self.param_unrecognized[ctrlp]
                else:
                    # Check if the prefix match
                    for p in self.control_params.keys():
                        if p.startswith(ctrlp):
                            info[ctrlp] = self.param_unrecognized[ctrlp]
        return info
Esempio n. 8
0
    def build_model(self, parfile=None, name=""):
        """Read parfile using the model_instance attribute. Throws error if
           mismatched coordinate systems detected.
        Parameters
        ---------
        name: str, optional
            The name for the timing model
        parfile : str optional
            The parfile name
        """
        if parfile is not None:
            self.get_comp_from_parfile(parfile)
            # ensure coordinate systems match for POS and PM
            if "RAJ" in self.preprocess_parfile(parfile).keys():
                if "PMELONG" in self.preprocess_parfile(parfile):
                    raise AttributeError(
                        "Cannot have Ecliptic proper motion parameters (PMELONG/PMELAT) with Equatorial position parameters (RAJ/DECJ) in par file."
                    )
                elif "PMELAT" in self.preprocess_parfile(parfile):
                    raise AttributeError(
                        "Cannot have Ecliptic proper motion parameters (PMELONG/PMELAT) with Equatorial position parameters (RAJ/DECJ) in par file."
                    )
            elif "ELONG" in self.preprocess_parfile(parfile).keys():
                if "PMRA" in self.preprocess_parfile(parfile):
                    raise AttributeError(
                        "Cannot have Equatorial proper motion parameters (PMRA/PMDEC) with Ecliptic position parameters (ELONG/ELAT) in par file."
                    )
                elif "PMDEC" in self.preprocess_parfile(parfile):
                    raise AttributeError(
                        "Cannot have Equatorial proper motion parameters (PMRA/PMDEC) with Ecliptic position parameters (ELONG/ELAT) in par file."
                    )
        sorted_comps = self.sort_components()
        self.timing_model = TimingModel(name, sorted_comps)
        param_inModel = self.timing_model.get_params_mapping()
        # Find unrecognised parameters in par file.

        if self.param_inparF is not None:
            parName = []
            # add aliases
            for p in list(param_inModel.keys()):
                parName += getattr(self.timing_model, p).aliases

            parName += param_inModel.keys()

            for pp in self.param_inparF.keys():
                if pp not in parName:
                    self.param_unrecognized[pp] = self.param_inparF[pp]

            for ptype in ["prefixParameter", "maskParameter"]:
                prefix_param = self.search_prefix_param(
                    self.param_unrecognized, self.timing_model, ptype)
                prefix_in_model = self.timing_model.get_params_of_type_top(
                    ptype)
                for key in prefix_param:
                    ppnames = [x for x in prefix_in_model if x.startswith(key)]
                    for ppn in ppnames:
                        pfx, idxs, idxv = split_prefixed_name(ppn)
                        if pfx == key:
                            exm_par = getattr(self.timing_model, ppn)
                        else:
                            continue
                    exm_par_comp = param_inModel[exm_par.name]
                    for parname in prefix_param[key]:
                        pre, idstr, idx = split_prefixed_name(parname)
                        if idx == exm_par.index:
                            continue
                        if hasattr(exm_par, "new_param"):
                            new_par = exm_par.new_param(idx)
                            self.timing_model.add_param_from_top(
                                new_par, exm_par_comp)
            if "BINARY" in self.param_inparF:
                vals = self.param_inparF["BINARY"]
                if len(vals) != 1:
                    raise ValueError(
                        "Mal-formed binary model selection: {}".format(
                            repr(" ".join(["BINARY"] + vals))))
                (bm, ) = vals
                cats = self.timing_model.get_components_by_category()
                if "pulsar_system" not in cats:
                    raise UnknownBinaryModel(
                        "Unknown binary model requested in par file: {}".
                        format(bm))
                # FIXME: consistency check - the componens actually chosen should know the name bm
        for p in self.timing_model.params:
            if isinstance(self.timing_model[p], maskParameter):
                # maskParameters need a bogus alias for parfile parsing
                # remove this bogus alias
                try:
                    ix = self.timing_model[p].aliases.index(
                        self.timing_model[p].prefix)
                except ValueError:
                    pass
                else:
                    del self.timing_model[p].aliases[ix]
        if parfile is not None:
            self.timing_model.read_parfile(parfile)
component_instances = []

# Initiate the component instances
for cp_name in selected_components:
    component_class = all_components[cp_name]  # Get the component class
    component_instance = component_class()  # Instantiate a component object
    component_instances.append(component_instance)

# %% [markdown]
# ### Construct timing model (i.e., `TimingModel` instance)
#
# `TimingModel` class provides the storage and interface for the components. It also manages the components internally.

# %%
# Construct timing model instance, given a name and a list of components to include (that we just created above)
tm = TimingModel("NGC6400E", component_instances)

# %% [markdown]
# ### View the components in the timing model instance
#
# To view all the components in `TimingModel` instance, we can use the property `.components`, which returns a dictionary (name as the key, component instance as the value).
#
# Internally, the components are stored in a list(ordered list, you will see why this is important below) according to their types. All the delay type of components (subclasses of `DelayComponent` class) are stored in the `DelayComponent_list`, and the phase type of components (subclasses of `PhaseComponent` class) in the `PhaseComponent_list`.

# %%
# print the components in the timing model
for (cp_name, cp_instance) in tm.components.items():
    print(cp_name, cp_instance)

# %% [markdown]
# ### Useful methods of `TimingModel`
Esempio n. 10
0
    def build_model(self, parfile=None, name=""):
        """Read parfile using the model_instance attribute.
        Parameters
        ---------
        name: str, optional
            The name for the timing model
        parfile : str optional
            The parfile name
        """
        if parfile is not None:
            self.get_comp_from_parfile(parfile)
        sorted_comps = self.sort_components()
        self.timing_model = TimingModel(name, sorted_comps)
        param_inModel = self.timing_model.get_params_mapping()
        # Find unrecognised parameters in par file.

        if self.param_inparF is not None:
            parName = []
            # add aliases
            for p in list(param_inModel.keys()):
                parName += getattr(self.timing_model, p).aliases

            parName += param_inModel.keys()

            for pp in self.param_inparF.keys():
                if pp not in parName:
                    self.param_unrecognized[pp] = self.param_inparF[pp]

            for ptype in ["prefixParameter", "maskParameter"]:
                prefix_param = self.search_prefix_param(
                    self.param_unrecognized, self.timing_model, ptype)
                prefix_in_model = self.timing_model.get_params_of_type(ptype)
                for key in prefix_param:
                    ppnames = [x for x in prefix_in_model if x.startswith(key)]
                    for ppn in ppnames:
                        pfx, idxs, idxv = split_prefixed_name(ppn)
                        if pfx == key:
                            exm_par = getattr(self.timing_model, ppn)
                        else:
                            continue
                    exm_par_comp = param_inModel[exm_par.name]
                    for parname in prefix_param[key]:
                        pre, idstr, idx = split_prefixed_name(parname)
                        if idx == exm_par.index:
                            continue
                        if hasattr(exm_par, "new_param"):
                            new_par = exm_par.new_param(idx)
                            self.timing_model.add_param_from_top(
                                new_par, exm_par_comp)
            if "BINARY" in self.param_inparF:
                vals = self.param_inparF["BINARY"]
                if len(vals) != 1:
                    raise ValueError(
                        "Mal-formed binary model selection: {}".format(
                            repr(" ".join(["BINARY"] + vals))))
                (bm, ) = vals
                cats = self.timing_model.get_component_of_category()
                if "pulsar_system" not in cats:
                    raise UnknownBinaryModel(
                        "Unknown binary model requested in par file: {}".
                        format(bm))
                # FIXME: consistency check - the componens actually chosen should know the name bm

        if parfile is not None:
            self.timing_model.read_parfile(parfile)
Esempio n. 11
0
from pint.models.binary_dd import BinaryDD
from pint.models.binary_ddk import BinaryDDK
from pint.models.binary_ell1 import BinaryELL1, BinaryELL1H
from pint.models.dispersion_model import DispersionDM, DispersionDMX
from pint.models.frequency_dependent import FD
from pint.models.glitch import Glitch
from pint.models.jump import DelayJump, PhaseJump
from pint.models.model_builder import get_model
from pint.models.noise_model import EcorrNoise, PLRedNoise, ScaleToaError
from pint.models.solar_system_shapiro import SolarSystemShapiro
from pint.models.solar_wind_dispersion import SolarWindDispersion
from pint.models.spindown import Spindown

# Import the main timing model classes
from pint.models.timing_model import TimingModel, DEFAULT_ORDER
from pint.models.wave import Wave
from pint.models.ifunc import IFunc

# Define a standard basic model
StandardTimingModel = TimingModel(
    "StandardTimingModel",
    [AstrometryEquatorial(),
     Spindown(),
     DispersionDM(),
     SolarSystemShapiro()],
)
# BTTimingModel = generate_timing_model("BTTimingModel",
#         (Astrometry, Spindown, Dispersion, SolarSystemShapiro, BT))
# DDTimingModel = generate_timing_model("DDTimingModel",
#         (Astrometry, Spindown, Dispersion, SolarSystemShapiro, DD))
Esempio n. 12
0
def model():
    """Make a simple model."""
    return TimingModel(
        components=[AstrometryEquatorial(), DispersionDM(), DispersionDMX()]
    )
Esempio n. 13
0
def test_forgot_name():
    """Check argument validation in case 'name' is forgotten."""
    with pytest.raises(ValueError):
        TimingModel(AstrometryEquatorial())
    with pytest.raises(ValueError):
        TimingModel([AstrometryEquatorial(), DispersionDM()])