Example #1
0
    def test_uid(self):
        class UidModel(properties.HasProperties):
            uid = properties.Uuid('my uuid')

        model = UidModel()
        assert isinstance(model.uid, uuid.UUID)
        with self.assertRaises(AttributeError):
            model.uid = uuid.uuid4()
        assert model.validate()
        model._backend['uid'] = 'hi'
        with self.assertRaises(ValueError):
            model.validate()

        json_uuid = uuid.uuid4()
        json_uuid_str = str(json_uuid)

        assert properties.Uuid.to_json(json_uuid) == json_uuid_str
        assert str(properties.Uuid.from_json(json_uuid_str)) == json_uuid_str

        assert properties.Uuid('').equal(uuid.UUID(int=0), uuid.UUID(int=0))
Example #2
0
 class UidModel(properties.HasProperties):
     uid = properties.Uuid('my uuid')
Example #3
0
class BaseRx(properties.HasProperties):
    """SimPEG Receiver Object"""

    # TODO: write a validator that checks against mesh dimension in the
    # BaseSimulation
    # TODO: location
    locations = RxLocationArray("Locations of the receivers (nRx x nDim)",
                                shape=("*", "*"),
                                required=True)

    # TODO: project_grid?
    projGLoc = properties.StringChoice(
        "Projection grid location, default is CC",
        choices=["CC", "Fx", "Fy", "Fz", "Ex", "Ey", "Ez", "N"],
        default="CC",
    )

    # TODO: store_projections
    storeProjections = properties.Bool(
        "Store calls to getP (organized by mesh)", default=True)

    _uid = properties.Uuid("unique ID for the receiver")

    _Ps = properties.Dictionary("dictonary for storing projections", )

    def __init__(self, locations=None, **kwargs):
        super(BaseRx, self).__init__(**kwargs)
        if locations is not None:
            self.locations = locations
        rxType = kwargs.pop("rxType", None)
        if rxType is not None:
            warnings.warn(
                "BaseRx no longer has an rxType. Each rxType should instead "
                "be a different receiver class.")
        if getattr(self, "_Ps", None) is None:
            self._Ps = {}

    locs = deprecate_property(locations,
                              "locs",
                              new_name="locations",
                              removal_version="0.15.0")

    @property
    def nD(self):
        """Number of data in the receiver."""
        return self.locations.shape[0]

    def getP(self, mesh, projGLoc=None):
        """
            Returns the projection matrices as a
            list for all components collected by
            the receivers.

            .. note::

                Projection matrices are stored as a dictionary listed by meshes.
        """
        if projGLoc is None:
            projGLoc = self.projGLoc

        if (mesh, projGLoc) in self._Ps:
            return self._Ps[(mesh, projGLoc)]

        P = mesh.getInterpolationMat(self.locations, projGLoc)
        if self.storeProjections:
            self._Ps[(mesh, projGLoc)] = P
        return P

    def eval(self, **kwargs):
        raise NotImplementedError(
            "the eval method for {} has not been implemented".format(self))

    def evalDeriv(self, **kwargs):
        raise NotImplementedError(
            "the evalDeriv method for {} has not been implemented".format(
                self))
Example #4
0
class BaseSrc(BaseSimPEG):
    """SimPEG Source Object"""

    location = SourceLocationArray("Location of the source [x, y, z] in 3D",
                                   shape=("*", ),
                                   required=False)

    receiver_list = properties.List("receiver list",
                                    properties.Instance(
                                        "a SimPEG receiver", BaseRx),
                                    default=[])

    _uid = properties.Uuid("unique identifier for the source")

    loc = deprecate_property(location,
                             "loc",
                             new_name="location",
                             removal_version="0.15.0")

    @properties.validator("receiver_list")
    def _receiver_list_validator(self, change):
        value = change["value"]
        assert len(
            set(value)) == len(value), "The receiver_list must be unique"
        self._rxOrder = dict()
        [self._rxOrder.setdefault(rx._uid, ii) for ii, rx in enumerate(value)]

    rxList = deprecate_property(receiver_list,
                                "rxList",
                                new_name="receiver_list",
                                removal_version="0.15.0")

    def getReceiverIndex(self, receiver):
        if not isinstance(receiver, list):
            receiver = [receiver]
        for rx in receiver:
            if getattr(rx, "_uid", None) is None:
                raise KeyError("Source does not have a _uid: {0!s}".format(
                    str(rx)))
        inds = list(map(lambda rx: self._rxOrder.get(rx._uid, None), receiver))
        if None in inds:
            raise KeyError(
                "Some of the receiver specified are not in this survey. "
                "{0!s}".format(str(inds)))
        return inds

    @property
    def nD(self):
        """Number of data"""
        return self.vnD.sum()

    @property
    def vnD(self):
        """Vector number of data"""
        return np.array([rx.nD for rx in self.receiver_list])

    def __init__(self, receiver_list=None, location=None, **kwargs):
        super(BaseSrc, self).__init__(**kwargs)
        if receiver_list is not None:
            self.receiver_list = receiver_list
        if location is not None:
            self.location = location
Example #5
0
class Data(properties.HasProperties):
    """
    Data storage. This class keeps track of observed data, relative error
    of those data and the noise floor.

    .. code:: python

        data = Data(survey, dobs=dobs, relative_error=relative, noise_floor=floor)

    or

    .. code:: python

        data = Data(survey, dobs=dobs, standard_deviation=standard_deviation)
    """

    dobs = properties.Array(
        """
        Vector of the observed data. The data can be set using the survey
        parameters:

        .. code:: python

            data = Data(survey)
            for src in survey.source_list:
                for rx in src.receiver_list:
                    data[src, rx] = datum

        """,
        shape=("*", ),
        required=True,
    )

    relative_error = UncertaintyArray(
        """
        Relative error of the data. This can be set using an array of the
        same size as the data (e.g. if you want to assign a different relative
        error to each datum) or as a scalar if you would like to assign a
        the same relative error to all data.

        The standard_deviation is constructed as follows::

            sqrt( (relative_error * np.abs(dobs))**2 + noise_floor**2 )

        For example, if you set

        .. code:: python

            data = Data(survey, dobs=dobs)
            data.relative_error = 0.05

        then the contribution to the standard_deviation is equal to

        .. code:: python

            data.relative_error * np.abs(data.dobs)

        """,
        shape=("*", ),
    )

    noise_floor = UncertaintyArray(
        """
        Noise floor of the data. This can be set using an array of the
        same size as the data (e.g. if you want to assign a different noise
        floor to each datum) or as a scalar if you would like to assign a
        the same noise floor to all data.

        The standard_deviation is constructed as follows::

            sqrt( (relative_error * np.abs(dobs))**2 + noise_floor**2 )

        For example, if you set

        .. code:: python

            data = Data(survey, dobs=dobs)
            data.noise_floor = 1e-10

        then the contribution to the standard_deviation is equal to

        .. code:: python

            data.noise_floor

        """,
        shape=("*", ),
    )

    survey = properties.Instance("a SimPEG survey object",
                                 BaseSurvey,
                                 required=True)

    _uid = properties.Uuid("unique ID for the data")

    #######################
    # Instantiate the class
    #######################
    def __init__(
        self,
        survey,
        dobs=None,
        relative_error=None,
        noise_floor=None,
        standard_deviation=None,
    ):
        super(Data, self).__init__()
        self.survey = survey

        # Observed data
        if dobs is None:
            dobs = np.nan * np.ones(survey.nD)  # initialize data as nans
        self.dobs = dobs

        if relative_error is not None:
            self.relative_error = relative_error

        if noise_floor is not None:
            self.noise_floor = noise_floor

        if standard_deviation is not None:
            if relative_error is not None or noise_floor is not None:
                warnings.warn("Setting the standard_deviation overwrites the "
                              "relative_error and noise_floor")
            self.standard_deviation = standard_deviation

        if (standard_deviation is None and relative_error is None
                and noise_floor is None):
            self.standard_deviation = 0.0

    #######################
    # Properties
    #######################
    @property
    def standard_deviation(self):
        """
        Data standard deviations. If a relative error and noise floor are
        provided, the standard_deviation is

        .. code:: python

            data.standard_deviation = np.sqrt(
                (data.relative_error*np.abs(data.dobs))**2 +
                data.noise_floor**2
            )

        otherwise, the standard_deviation can be set directly

        .. code:: python

            data.standard_deviation = 0.05 * np.absolute(self.dobs) + 1e-12

        Note that setting the standard_deviation directly will clear the `relative_error`
        and set the value to the `noise_floor` property.

        """
        if self.relative_error is None and self.noise_floor is None:
            raise Exception(
                "The relative_error and / or noise_floor must be set "
                "before asking for uncertainties. Alternatively, the "
                "standard_deviation can be set directly")

        uncert = np.zeros(self.nD)
        if self.relative_error is not None:
            uncert += np.array(self.relative_error * np.absolute(self.dobs))**2
        if self.noise_floor is not None:
            uncert += np.array(self.noise_floor)**2

        return np.sqrt(uncert)

    @standard_deviation.setter
    def standard_deviation(self, value):
        self.relative_error = np.zeros(self.nD)
        self.noise_floor = value

    @property
    def nD(self):
        return len(self.dobs)

    @property
    def shape(self):
        return self.dobs.shape

    ##########################
    # Observers and validators
    ##########################

    @properties.validator("dobs")
    def _dobs_validator(self, change):
        if self.survey.nD != len(change["value"]):
            raise ValueError(
                "{} must have the same length as the number of data. The "
                "provided input has len {}, while the survey expects "
                "survey.nD = {}".format(change["name"], len(change["value"]),
                                        self.survey.nD))

    @properties.validator(["relative_error", "noise_floor"])
    def _standard_deviation_validator(self, change):
        if isinstance(change["value"], float):
            change["value"] = change["value"] * np.ones(self.nD)
        self._dobs_validator(change)

    @property
    def index_dictionary(self):
        """
        Dictionary of data indices by sources and receivers. To set data using
        survey parameters:

        .. code:: python

            data = Data(survey)
            for src in survey.source_list:
                for rx in src.receiver_list:
                    index = data.index_dictionary[src][rx]
                    data.dobs[index] = datum

        """
        if getattr(self, "_index_dictionary", None) is None:
            if self.survey is None:
                raise Exception(
                    "To set or get values by source-receiver pairs, a survey must "
                    "first be set. `data.survey = survey`")

            # create an empty dict
            self._index_dictionary = {}

            # create an empty dict associated with each source
            for src in self.survey.source_list:
                self._index_dictionary[src] = {}

            # loop over sources and find the associated data indices
            indBot, indTop = 0, 0
            for src in self.survey.source_list:
                for rx in src.receiver_list:
                    indTop += rx.nD
                    self._index_dictionary[src][rx] = np.arange(indBot, indTop)
                    indBot += rx.nD

        return self._index_dictionary

    ##########################
    # Methods
    ##########################

    def __setitem__(self, key, value):
        index = self.index_dictionary[key[0]][key[1]]
        self.dobs[index] = mkvc(value)

    def __getitem__(self, key):
        index = self.index_dictionary[key[0]][key[1]]
        return self.dobs[index]

    def tovec(self):
        return self.dobs

    def fromvec(self, v):
        v = mkvc(v)
        self.dobs = v

    ##########################
    # Deprecated
    ##########################
    std = deprecate_property(
        relative_error,
        "std",
        new_name="relative_error",
        removal_version="0.16.0",
        future_warn=True,
    )
    eps = deprecate_property(
        noise_floor,
        "eps",
        new_name="noise_floor",
        removal_version="0.16.0",
        future_warn=True,
    )
Example #6
0
class UidModel(properties.HasProperties):
    """UidModel is a HasProperties object with uid"""
    _REGISTRY = OrderedDict()

    uid = properties.Uuid('Unique identifier',
                          serializer=lambda val, **kwargs: None,
                          deserializer=lambda val, **kwargs: None)
    date_created = properties.GettableProperty(
        'Date project was created',
        default=datetime.datetime.utcnow,
        serializer=properties.DateTime.to_json,
        deserializer=lambda val, **kwargs: None)
    date_modified = properties.GettableProperty(
        'Date project was modified',
        default=datetime.datetime.utcnow,
        serializer=properties.DateTime.to_json,
        deserializer=lambda val, **kwargs: None)

    @properties.observer(properties.everything)
    def _modify(self, _):
        """Update date_modified whenever anything changes"""
        self._backend['date_modified'] = datetime.datetime.utcnow()

    @properties.validator
    def _update_date_modified(self):
        """Update date_modified if any contained UidModel has been modified"""
        for val in self._backend.values():
            if (isinstance(val, UidModel)
                    and val.date_modified > self.date_modified):
                self._backend['date_modified'] = val.date_modified

    def serialize(
            self,
            include_class=True,
            registry=None,  #pylint: disable=arguments-differ
            skip_validation=False,
            **kwargs):
        """Serialize nested UidModels to a flat dictionary with pointers"""
        if registry is None:
            if not skip_validation:
                self.validate()
            registry = dict()
            root = True
        else:
            root = False
        if str(self.uid) not in registry:
            registry.update({
                str(self.uid):
                super(UidModel, self).serialize(include_class,
                                                registry=registry,
                                                **kwargs)
            })
        if root:
            return registry
        return str(self.uid)

    @classmethod
    def deserialize(cls, uid, trusted=True, registry=None, **kwargs):  #pylint: disable=arguments-differ
        """Deserialize nested UidModels from flat pointer dictionary"""
        if registry is None:
            raise ValueError('no registry provided')
        if uid not in registry:
            raise ValueError('uid not found: {}'.format(uid))
        if not isinstance(registry[uid], UidModel):
            date_created = registry[uid]['date_created']
            date_modified = registry[uid]['date_modified']
            kwargs.update({'verbose': False})
            new_model = super(UidModel, cls).deserialize(value=registry[uid],
                                                         registry=registry,
                                                         trusted=trusted,
                                                         **kwargs)
            new_model._backend.update({
                'uid':
                properties.Uuid.from_json(uid),
                'date_created':
                properties.DateTime.from_json(date_created),
                'date_modified':
                properties.DateTime.from_json(date_modified)
            })
            registry.update({uid: new_model})
        return registry[uid]
Example #7
0
 class HasUid(properties.HasProperties):
     uid = properties.Uuid('uid')
Example #8
0
 class UidModel(properties.HasProperties):
     uid = properties.Uuid('unique id')