class HasSets(properties.HasProperties): basic = properties.Set('', properties.Integer('')) advanced = properties.Set('', properties.Integer(''), observe_mutations=True) def __init__(self, **kwargs): self._basic_tic = 0 self._advanced_tic = 0 @properties.validator('basic') def _basic_val(self, change): self._basic_tic += 1 @properties.validator('advanced') def _advanced_val(self, change): self._advanced_tic += 1
def test_with_None_and_no_default(self): target = properties.Integer() with self.assertRaises(properties.ValidationError) as e: value = target('Test', None) self.assertIn('Test', e.exception.message)
class HasNestedList(properties.HasProperties): nested_list = properties.List( 'This is not a great idea...', properties.List('', properties.Integer(''), observe_mutations=True), observe_mutations=om, )
class GridInfo(properties.HasProperties): """Internal helper class to store Surfer grid properties and create ``vtkImageData`` objects from them. """ ny = properties.Integer('number of columns', min=2) nx = properties.Integer('number of rows', min=2) xll = properties.Float('x-value of lower-left corner') yll = properties.Float('y-value of lower-left corner') dx = properties.Float('x-axis spacing') dy = properties.Float('y-axis spacing') dmin = properties.Float('minimum data value', required=False) dmax = properties.Float('maximum data value', required=False) data = properties.Array('grid of data values', shape=('*', )) def mask(self): """Mask the no data value""" data = self.data nans = data >= 1.701410009187828e38 if np.any(nans): data = np.ma.masked_where(nans, data) err_msg = "{} of data ({}) doesn't match that set by file ({})." if not np.allclose(self.dmin, np.nanmin(data)): raise _helpers.PVGeoError( err_msg.format('Min', np.nanmin(data), self.dmin)) if not np.allclose(self.dmax, np.nanmax(data)): raise _helpers.PVGeoError( err_msg.format('Max', np.nanmax(data), self.dmax)) self.data = data return def to_vtk(self, output=None, z=0.0, dz=1.0, data_name='Data'): """Convert to a ``vtkImageData`` object""" self.mask() self.validate() if output is None: output = vtk.vtkImageData() # Build the data object output.SetOrigin(self.xll, self.yll, z) output.SetSpacing(self.dx, self.dy, dz) output.SetDimensions(self.nx, self.ny, 1) vtkarr = interface.convert_array(self.data, name=data_name) output.GetPointData().AddArray(vtkarr) return output
class Plot(_BaseSceneComponent): """Object describing the contents of the 3D scene Contains info about how a plot is positioned in the scene, as well as the plot limits. Also contains active elements, slices, and measurements in the plot. """ position = properties.Vector3( 'x,y,z position of the plot center relative to scene origin', default=lambda: [0., 0, 0], ) scale = properties.Vector3( 'x,y,z scale of the plot coordinate system relative to scene ' 'coordinate system', default=lambda: [1., 1, 1], ) rotation = properties.List( 'Quaternion rotation of plot axes relative to scene axes', properties.Float(''), min_length=4, max_length=4, default=lambda: [0., 0, 0, 1], ) lims = properties.List( 'x,y,z limits, defined in plot coordinates', properties.Vector2(''), min_length=3, max_length=3, default=lambda: [[0, 0.00001]] * 3, ) exaggeration = properties.List( 'x,y,z exaggeration of the plot coordinates', properties.Integer('', min=1), default=lambda: [1, 1, 1], ) slice_groups = properties.List( 'Active slice groups; currently only one is supported', SliceGroup, max_length=1, default=lambda: [SliceGroup()], ) measurements = properties.List( 'List of active ruler instances; currently only one is supported', Ruler, max_length=1, default=list, ) views = properties.List( 'List of element views in the plot', properties.Union('', [ view for key, view in _BaseSceneComponent._REGISTRY.items() if key[0] != '_' and issubclass(view, _BaseElementView) ]), max_length=100, default=list, )
class GridSpec(properties.HasProperties): """A ``GridSpec`` object provides the details of a single axis along a grid. If you have a 3D grid then you will have 3 ``GridSpec`` objects. """ n = properties.Integer('The number of components along this dimension.') min = properties.Integer( 'The minimum value along this dimension. The origin.', default=0) sz = properties.Integer('The uniform cell size along this dimension.', default=1) nnodes = properties.Integer( 'The number of grid nodes to consider on either \ side of the origin in the output map', required=False) @properties.validator def _validate_nnodes(self): if self.nnodes is None: self.nnodes = self.n // 2 return True
class ErrorListeners(properties.HasProperties): a = properties.Integer('int a') @properties.observer('a') def _obs(self, change): raise ObserveError() @properties.validator('a') def _val(self, change): raise ValidateError()
class ExponentialSinusoidSimulation(LinearSimulation): """ This is the simulation class for the linear problem consisting of exponentially decaying sinusoids. The rows of the G matrix are .. math:: \\int_x e^{p j_k x} \\cos(\\pi q j_k x) \\quad, j_k \\in [j_0, ..., j_n] """ n_kernels = properties.Integer( "number of kernels defining the linear problem", default=20 ) p = properties.Float("rate of exponential decay of the kernel", default=-0.25) q = properties.Float("rate of oscillation of the kernel", default=0.25) j0 = properties.Float("maximum value for :math:`j_k = j_0`", default=0.0) jn = properties.Float("maximum value for :math:`j_k = j_n`", default=60.0) def __init__(self, **kwargs): super(ExponentialSinusoidSimulation, self).__init__(**kwargs) @property def jk(self): """ Parameters controlling the spread of kernel functions """ if getattr(self, "_jk", None) is None: self._jk = np.linspace(self.j0, self.jn, self.n_kernels) return self._jk def g(self, k): """ Kernel functions for the decaying oscillating exponential functions. """ return np.exp(self.p * self.jk[k] * self.mesh.vectorCCx) * np.cos( np.pi * self.q * self.jk[k] * self.mesh.vectorCCx ) @property def G(self): """ Matrix whose rows are the kernel functions """ if getattr(self, "_G", None) is None: G = np.empty((self.n_kernels, self.mesh.nC)) for i in range(self.n_kernels): G[i, :] = self.g(i) * self.mesh.hx self._G = G return self._G
class DomainConditionInteger(DomainCondition): """This represents an integer query.""" value = properties.Integer( 'Integer Value', required=True, ) def __str__(self): """Return a string usable as a query part in an API request.""" return '%s:%d' % (self.field_name, self.value)
class DispositionTypeParams(BaseModel): allowChangeTimer = properties.Bool( 'Whether the agent can change the redial timer for this disposition.', ) attempts = properties.Integer('Number of redial attempts.', ) timer = properties.Instance( 'Redial timer.', instance_class=Timer, ) useTimer = properties.Bool( 'Whether this disposition uses a redial timer.', )
class Option(BaseModel): """This represents option for a custom field of type ``DROPDOWN``.""" label = properties.String( 'Label of the option.', required=True, ) order = properties.Integer( 'Relative order of the custom field. Can be ``null`` or a number ' 'between ``0`` and ``255``.', min=0, max=255, )
class GeneralOverview(BaseModel): """Object that holds a general overview of other objects. This is the object that is typically returned by the API, which holds the high level information & how to access the actual dataset. """ count = properties.Integer( 'Total amount of reviews for this record.', ) link = properties.String( 'Link to the detailed review information in the Cannabis Reports ' 'API.', )
class SquareLoop(Point): """Square loop receiver Measurements with this type of receiver are the field, integrated over the area of the loop, then multiplied by the number of coils, then normalized by the dipole moment. As a result, the units for fields predicted with this type of receiver are the same as 'h', 'b', 'dhdt' and 'dbdt', respectively. """ width = properties.Float("Square loop width", min=1e-6) nTurns = properties.Integer("Number of loop turns", min=1, default=1) quadOrder = properties.Integer( "Order for numerical quadrature integration over loop", min=1, max=7, default=3 ) def __init__(self, locations, **kwargs): if locations.shape[1] != 3: raise ValueError( "Rx locations (xi,yi,zi) must be np.array(N,3) where N is the number of stations" ) super(SquareLoop, self).__init__(locations, **kwargs)
def test_list_default(self): class HasIntList(properties.HasProperties): intlist = properties.List('list of ints', properties.Integer('')) hil = HasIntList() assert isinstance(hil.intlist, list) assert len(hil.intlist) == 0 assert hil.intlist is not HasIntList().intlist with warnings.catch_warnings(record=True) as w: properties.List('list', properties.Integer('', default=5)) assert len(w) == 1 assert issubclass(w[0].category, RuntimeWarning)
class _BaseFile(_BaseUIDModel): """Base class for File resources The properties defined here apply to any generic file. Note that this file resource does not actually store the binary file itself, only its metadata. """ BASE_TYPE = 'files' _REGISTRY = OrderedDict() content_type = properties.String('Content type of the file') content_length = properties.Integer( 'Content length of the file', min=0, )
class SearchConversation(BaseConversation): """This represents a conversation as returned by search results.""" mailbox_id = properties.Integer( 'The ID of the mailbox this conversation is in.', required=True, ) customer_name = properties.String( 'Name of the customer this conversation is regarding.', required=True, ) customer_email = properties.String( 'Email address of the customer', required=True, ) has_attachments = properties.Bool( '``True`` when the conversation has at least one attachment.', )
class HasDynamicProperty(properties.HasProperties): my_int = properties.Integer('an int') @properties.Integer('a dynamic int') def my_doubled_int(self): if self.my_int is None: raise ValueError('my_doubled_int depends on my_int') return self.my_int * 2 @properties.Vector3('a vector') def my_vector(self): self.validate() if self.my_int is None: raise ValueError('my_vector depends on my_int') val = [ float(val) for val in [self.my_int, self.my_int, self.my_doubled_int] ] return val
class Tag(BaseModel): tag = properties.String( 'The tag value.', required=True, ) slug = properties.String( 'Slugified version of the tag value.', ) count = properties.Integer( 'The number of times the tag is used.', ) color = properties.Color( 'The tag color.', ) created_at = properties.DateTime( 'UTC time when this tag was created.', ) modified_at = properties.DateTime( 'UTC time when this tag was modified.', )
class IO(properties.HasProperties): """""" # Survey survey_layout = properties.StringChoice( "Survey geometry of DC surveys", default="SURFACE", choices=["SURFACE", "BOREHOLE", "GENERAL"], ) survey_type = properties.StringChoice( "DC-IP Survey type", default="dipole-dipole", choices=["dipole-dipole", "pole-dipole", "dipole-pole", "pole-pole"], ) dimension = properties.Integer("Dimension of electrode locations", default=2, required=True) a_locations = properties.Array( "locations of the positive (+) current electrodes", required=True, shape=("*", "*"), # ('*', 3) for 3D or ('*', 2) for 2D dtype=float, # data are floats ) b_locations = properties.Array( "locations of the negative (-) current electrodes", required=True, shape=("*", "*"), # ('*', 3) for 3D or ('*', 2) for 2D dtype=float, # data are floats ) m_locations = properties.Array( "locations of the positive (+) potential electrodes", required=True, shape=("*", "*"), # ('*', 3) for 3D or ('*', 2) for 2D dtype=float, # data are floats ) n_locations = properties.Array( "locations of the negative (-) potential electrodes", required=True, shape=("*", "*"), # ('*', 3) for 3D or ('*', 2) for 2D dtype=float, # data are floats ) electrode_locations = properties.Array( "unique locations of a, b, m, n electrodes", required=True, shape=("*", "*"), # ('*', 3) for 3D or ('*', 2) for 2D dtype=float, # data are floats ) # Data data_dc_type = properties.StringChoice( "Type of DC-IP survey", required=True, default="volt", choices=[ "volt", "apparent_resistivity", "apparent_conductivity", ], ) data_dc = properties.Array( "Measured DC data", shape=("*", ), dtype=float # data are floats ) data_ip_type = properties.StringChoice( "Type of DC-IP survey", required=True, default="volt", choices=[ "volt", "apparent_chargeability", ], ) data_ip = properties.Array( "Measured IP data", shape=("*", ), dtype=float # data are floats ) data_sip_type = properties.StringChoice( "Type of DC-IP survey", required=True, default="volt", choices=[ "volt", "apparent_chargeability", ], ) data_sip = properties.Array( "Measured Spectral IP data", shape=("*", "*"), dtype=float # data are floats ) times_ip = properties.Array( "Time channels of measured Spectral IP voltages (s)", required=True, shape=("*", ), dtype=float, # data are floats ) G = properties.Array( "Geometric factor of DC-IP survey", shape=("*", ), dtype=float # data are floats ) grids = properties.Array( "Spatial grids for plotting pseudo-section", shape=("*", "*"), dtype=float, # data are floats ) space_type = properties.StringChoice( "Assumption to compute apparent resistivity", default="half-space", choices=["half-space", "whole-space"], ) line_inds = properties.Array( "Line indices", required=True, shape=("*", ), dtype=int # data are floats ) sort_inds = properties.Array( "Sorting indices from ABMN", required=True, shape=("*", ), dtype=int, # data are floats ) # Related to Physics and Discretization mesh = properties.Instance("Mesh for discretization", BaseMesh, required=True) dx = properties.Float( "Length of corecell in x-direction", required=True, ) dy = properties.Float("Length of corecell in y-direction", required=True) dz = properties.Float("Length of corecell in z-direction", required=True) npad_x = properties.Integer("The number of padding cells x-direction", required=True, default=5) npad_y = properties.Integer("The number of padding cells y-direction", required=True, default=5) npad_z = properties.Integer("The number of padding cells z-direction", required=True, default=5) pad_rate_x = properties.Float( "Expansion rate of padding cells in x-direction", required=True, default=1.3) pad_rate_y = properties.Float( "Expansion rate of padding cells in y-direction", required=True, default=1.3) pad_rate_z = properties.Float( "Expansion rate of padding cells in z-direction", required=True, default=1.3) ncell_per_dipole = properties.Integer( "The number of cells between dipole electrodes", required=True, default=4) corezlength = properties.Float( "Core depth (m)", required=True, ) # For synthetic surveys x0 = None lineLength = None a = None n_spacing = None n_data = None def __init__(self, **kwargs): super(IO, self).__init__(**kwargs) warnings.warn( "code under construction - API might change in the future") # Properties @property def voltages(self): """ Votages (V) """ if self.data_dc_type.lower() == "volt": return self.data_dc elif self.data_dc_type.lower() == "apparent_resistivity": return self.data_dc * self.G elif self.data_dc_type.lower() == "apparent_conductivity": return self.apparent_conductivity / (self.data_dc * self.G) else: raise NotImplementedError() @property def apparent_resistivity(self): """ Apparent Resistivity (Ohm-m) """ if self.data_dc_type.lower() == "apparent_resistivity": return self.data_dc elif self.data_dc_type.lower() == "volt": return self.data_dc / self.G elif self.data_dc_type.lower() == "apparent_conductivity": return 1.0 / self.data_dc else: print(self.data_dc_type.lower()) raise NotImplementedError() @property def apparent_conductivity(self): """ Apparent Conductivity (S/m) """ if self.data_dc_type.lower() == "apparent_conductivity": return self.data_dc elif self.data_dc_type.lower() == "apparent_resistivity": return 1.0 / self.data_dc elif self.data_dc_type.lower() == "volt": return 1.0 / self.data_dc * self.G # For IP @property def voltages_ip(self): """ IP votages (V) """ if self.data_ip_type.lower() == "volt": return self.data_ip elif self.data_ip_type.lower() == "apparent_chargeability": if self.voltages is None: raise Exception( "DC voltages must be set to compute IP voltages") return self.data_ip * self.voltages else: raise NotImplementedError() # For SIP @property def voltages_sip(self): """ IP votages (V) """ if self.data_sip_type.lower() == "volt": return self.data_sip elif self.data_sip_type.lower() == "apparent_chargeability": if self.voltages is None: raise Exception( "DC voltages must be set to compute IP voltages") return sdiag(self.voltages) * self.data_sip else: raise NotImplementedError() @property def apparent_chargeability(self): """ Apparent Conductivity (S/m) """ if self.data_ip_type.lower() == "apparent_chargeability": return self.data_ip elif self.data_ip_type.lower() == "volt": if self.voltages is None: raise Exception( "DC voltages must be set to compute Apparent Chargeability" ) return self.data_ip / self.voltages else: raise NotImplementedError() # For SIP @property def apparent_chargeability_sip(self): """ Apparent Conductivity (S/m) """ if self.data_sip_type.lower() == "apparent_chargeability": return self.data_sip elif self.data_sip_type.lower() == "volt": if self.voltages is None: raise Exception( "DC voltages must be set to compute Apparent Chargeability" ) return sdiag(1.0 / self.voltages) * self.data_sip else: raise NotImplementedError() def geometric_factor(self, survey): """ Compute geometric factor, G, using locational informaition in survey object """ G = geometric_factor(survey, space_type=self.space_type) return G def from_ambn_locations_to_survey(self, *args, **kwargs): warnings.warn( "from_ambn_locations_to_survey has been renamed to " "from_abmn_locations_to_survey. It will be removed in a future version 0.17.0 of simpeg", DeprecationWarning, ) return self.from_abmn_locations_to_survey(*args, **kwargs) def from_abmn_locations_to_survey( self, a_locations, b_locations, m_locations, n_locations, survey_type=None, data_dc=None, data_ip=None, data_sip=None, data_dc_type="volt", data_ip_type="volt", data_sip_type="volt", fname=None, dimension=2, line_inds=None, times_ip=None, ): """ read A, B, M, N electrode location and data (V or apparent_resistivity) """ self.a_locations = a_locations.copy() self.b_locations = b_locations.copy() self.m_locations = m_locations.copy() self.n_locations = n_locations.copy() self.survey_type = survey_type self.dimension = dimension self.data_dc_type = data_dc_type self.data_ip_type = data_ip_type self.data_sip_type = data_sip_type if times_ip is not None: self.times_ip = times_ip uniqSrc = uniqueRows(np.c_[self.a_locations, self.b_locations]) uniqElec = uniqueRows( np.vstack((self.a_locations, self.b_locations, self.m_locations, self.n_locations))) self.electrode_locations = uniqElec[0] nSrc = uniqSrc[0].shape[0] ndata = self.a_locations.shape[0] if self.survey_layout == "SURFACE": # 2D locations srcLists = [] sort_inds = [] for iSrc in range(nSrc): inds = uniqSrc[2] == iSrc sort_inds.append(np.arange(ndata)[inds]) locsM = self.m_locations[inds, :] locsN = self.n_locations[inds, :] if survey_type in ["dipole-dipole", "pole-dipole"]: rx = Rx.Dipole(locsM, locsN) elif survey_type in ["dipole-pole", "pole-pole"]: rx = Rx.Pole(locsM) else: raise NotImplementedError() if dimension == 2: locA = uniqSrc[0][iSrc, :2] locB = uniqSrc[0][iSrc, 2:] elif dimension == 3: locA = uniqSrc[0][iSrc, :3] locB = uniqSrc[0][iSrc, 3:] if survey_type in ["dipole-dipole", "dipole-pole"]: src = Src.Dipole([rx], locA, locB) elif survey_type in ["pole-dipole", "pole-pole"]: src = Src.Pole([rx], locA) srcLists.append(src) self.sort_inds = np.hstack(sort_inds) if dimension == 2: survey = Survey(srcLists) elif dimension == 3: survey = Survey(srcLists) else: raise NotImplementedError() self.a_locations = self.a_locations[self.sort_inds, :] self.b_locations = self.b_locations[self.sort_inds, :] self.m_locations = self.m_locations[self.sort_inds, :] self.n_locations = self.n_locations[self.sort_inds, :] self.G = self.geometric_factor(survey) if data_dc is not None: self.data_dc = data_dc[self.sort_inds] if data_ip is not None: self.data_ip = data_ip[self.sort_inds] if data_sip is not None: self.data_sip = data_sip[self.sort_inds, :] if line_inds is not None: self.line_inds = line_inds[self.sort_inds] # Here we ignore ... z-locations self.n_data = survey.nD midABx = (self.a_locations[:, 0] + self.b_locations[:, 0]) * 0.5 midMNx = (self.m_locations[:, 0] + self.n_locations[:, 0]) * 0.5 if dimension == 2: z = abs(midABx - midMNx) * 1.0 / 3.0 x = (midABx + midMNx) * 0.5 zmax = z.max() a = abs(np.diff(np.sort(self.electrode_locations[:, 0]))).min() # Consider the case of 1D types of array if np.all(zmax < a): z = abs(self.a_locations[:, 0] - self.b_locations[:, 0]) / 3.0 self.grids = np.c_[x, z] elif dimension == 3: midABy = (self.a_locations[:, 1] + self.b_locations[:, 1]) * 0.5 midMNy = (self.m_locations[:, 1] + self.n_locations[:, 1]) * 0.5 z = np.sqrt((midABx - midMNx)**2 + (midABy - midMNy)**2) * 1.0 / 3.0 x = (midABx + midMNx) * 0.5 y = (midABy + midMNy) * 0.5 self.grids = np.c_[x, y, z] else: raise Exception() else: raise NotImplementedError() return survey def set_mesh( self, topo=None, dx=None, dy=None, dz=None, corezlength=None, npad_x=None, npad_y=None, npad_z=None, pad_rate_x=None, pad_rate_y=None, pad_rate_z=None, ncell_per_dipole=None, mesh_type="TensorMesh", dimension=2, method="nearest", ): """ Set up a mesh for a given DC survey """ # Update properties if npad_x is None: npad_x = self.npad_x self.npad_x = npad_x if npad_z is None: npad_z = self.npad_z self.npad_z = npad_z if pad_rate_x is None: pad_rate_x = self.pad_rate_x self.pad_rate_x = pad_rate_x if pad_rate_z is None: pad_rate_z = self.pad_rate_z self.pad_rate_z = pad_rate_z if ncell_per_dipole is None: ncell_per_dipole = self.ncell_per_dipole self.ncell_per_dipole = ncell_per_dipole # 2D or 3D mesh if dimension not in [2, 3]: raise NotImplementedError( "Set mesh has not been implemented for a 1D system") if dimension == 2: z_ind = 1 else: z_ind = 2 a = abs(np.diff(np.sort(self.electrode_locations[:, 0]))).min() lineLength = abs(self.electrode_locations[:, 0].max() - self.electrode_locations[:, 0].min()) dx_ideal = a / ncell_per_dipole if dx is None: dx = dx_ideal print("dx is set to {} m (samllest electrode spacing ({}) / {})". format(dx, a, ncell_per_dipole)) if dz is None: dz = dx * 0.5 print("dz ({} m) is set to dx ({} m) / {}".format(dz, dx, 2)) if dimension == 3: if dy is None: print("dy is set equal to dx") dy = dx self.dy = dy if npad_y is None: npad_y = self.npad_y self.npad_y = npad_y if pad_rate_y is None: pad_rate_y = self.pad_rate_y self.pad_rate_y = pad_rate_y x0 = self.electrode_locations[:, 0].min() if topo is None: # For 2D mesh if dimension == 2: # sort by x row_idx = np.lexsort((self.electrode_locations[:, 0], )) # For 3D mesh else: # sort by x, then by y row_idx = np.lexsort( (self.electrode_locations[:, 1], self.electrode_locations[:, 0])) locs = self.electrode_locations[row_idx, :] else: # For 2D mesh if dimension == 2: mask = np.isin(self.electrode_locations[:, 0], topo[:, 0]) if np.any(mask): warnings.warn( "Because the x coordinates of some topo and electrodes are the same," " we excluded electrodes with the same coordinates.", RuntimeWarning, ) locs_tmp = np.vstack( (topo, self.electrode_locations[~mask, :])) row_idx = np.lexsort((locs_tmp[:, 0], )) else: dtype = [("x", np.float64), ("y", np.float64)] mask = np.isin( self.electrode_locations[:, [0, 1]].copy().view(dtype), topo[:, [0, 1]].copy().view(dtype), ).flatten() if np.any(mask): warnings.warn( "Because the x and y coordinates of some topo and electrodes are the same," " we excluded electrodes with the same coordinates.", RuntimeWarning, ) locs_tmp = np.vstack( (topo, self.electrode_locations[~mask, :])) row_idx = np.lexsort((locs_tmp[:, 1], locs_tmp[:, 0])) locs = locs_tmp[row_idx, :] if dx > dx_ideal: # warnings.warn( # "Input dx ({}) is greater than expected \n We recommend using {:0.1e} m cells, that is, {} cells per {0.1e} m dipole length".format(dx, dx_ideal, ncell_per_dipole, a) # ) pass # Set mesh properties to class instance self.dx = dx self.dz = dz zmax = locs[:, z_ind].max() zmin = locs[:, z_ind].min() # 3 cells each for buffer corexlength = lineLength + dx * 6 if corezlength is None: dz_topo = locs[:, 1].max() - locs[:, 1].min() corezlength = self.grids[:, z_ind].max() + dz_topo self.corezlength = corezlength if mesh_type == "TensorMesh": ncx = np.round(corexlength / dx) ncz = np.round(corezlength / dz) hx = [(dx, npad_x, -pad_rate_x), (dx, ncx), (dx, npad_x, pad_rate_x)] hz = [(dz, npad_z, -pad_rate_z), (dz, ncz)] x0_mesh = -( (dx * pad_rate_x**(np.arange(npad_x) + 1)).sum() + dx * 3 - x0) z0_mesh = (-( (dz * pad_rate_z**(np.arange(npad_z) + 1)).sum() + dz * ncz) + zmax) # For 2D mesh if dimension == 2: h = [hx, hz] x0_for_mesh = [x0_mesh, z0_mesh] self.xyzlim = np.vstack( (np.r_[x0, x0 + lineLength], np.r_[zmax - corezlength, zmax])) fill_value = "extrapolate" # For 3D mesh else: ylocs = np.unique(self.electrode_locations[:, 1]) ymin, ymax = ylocs.min(), ylocs.max() # 3 cells each for buffer in y-direction coreylength = ymax - ymin + dy * 6 ncy = np.round(coreylength / dy) hy = [(dy, npad_y, -pad_rate_y), (dy, ncy), (dy, npad_y, pad_rate_y)] y0 = ylocs.min() - dy / 2.0 y0_mesh = -((dy * pad_rate_y**(np.arange(npad_y) + 1)).sum() + dy * 3 - y0) h = [hx, hy, hz] x0_for_mesh = [x0_mesh, y0_mesh, z0_mesh] self.xyzlim = np.vstack(( np.r_[x0, x0 + lineLength], np.r_[ymin - dy * 3, ymax + dy * 3], np.r_[zmax - corezlength, zmax], )) mesh = TensorMesh(h, x0=x0_for_mesh) elif mesh_type == "TREE": # Quadtree mesh if dimension == 2: pad_length_x = np.sum(meshTensor([(dx, npad_x, pad_rate_x)])) pad_length_z = np.sum(meshTensor([(dz, npad_z, pad_rate_z)])) dom_width_x = lineLength + 2 * pad_length_x # domain width x dom_width_z = corezlength + pad_length_z # domain width z nbcx = 2**int(np.ceil(np.log(dom_width_x / dx) / np.log(2.0))) # num. base cells x nbcz = 2**int(np.ceil(np.log(dom_width_z / dz) / np.log(2.0))) # num. base cells z length = 0.0 dz_tmp = dz octree_levels = [] while length < corezlength: length += 5 * dz_tmp octree_levels.append(5) dz_tmp *= 2 # Define the base mesh hx = [(dx, nbcx)] hz = [(dz, nbcz)] mesh_width = np.sum(meshTensor(hx)) mesh_height = np.sum(meshTensor(hz)) array_midpoint = 0.5 * (self.electrode_locations[:, 0].min() + self.electrode_locations[:, 0].max()) mesh = TreeMesh( [hx, hz], x0=[array_midpoint - mesh_width / 2, zmax - mesh_height]) # mesh = TreeMesh([hx, hz], x0='CN') # Mesh refinement based on topography mesh = refine_tree_xyz( mesh, self.electrode_locations, octree_levels=octree_levels, method="radial", finalize=False, ) mesh.finalize() self.xyzlim = np.vstack(( np.r_[self.electrode_locations[:, 0].min(), self.electrode_locations[:, 0].max(), ], np.r_[zmax - corezlength, zmax], )) # Octree mesh elif dimension == 3: raise NotImplementedError( "set_mesh has not implemented 3D TreeMesh (yet)") else: raise NotImplementedError( "set_mesh currently generates TensorMesh or TreeMesh") actind = surface2ind_topo(mesh, locs, method=method, fill_value=np.nan) return mesh, actind def plotPseudoSection( self, data_type="apparent_resistivity", data=None, dataloc=True, aspect_ratio=2, scale="log", cmap="viridis", ncontour=10, ax=None, figname=None, clim=None, label=None, iline=0, orientation="vertical", ): """ Plot 2D pseudo-section for DC-IP data """ matplotlib.rcParams["font.size"] = 12 if ax is None: fig = plt.figure(figsize=(10, 5)) ax = plt.subplot(111) if self.dimension == 2: inds = np.ones(self.n_data, dtype=bool) grids = self.grids.copy() elif self.dimension == 3: inds = self.line_inds == iline grids = self.grids[inds, :][:, [0, 2]] else: raise NotImplementedError() if data_type == "apparent_resistivity": if data is None: val = self.apparent_resistivity[inds] else: val = data.copy()[inds] label_tmp = "Apparent Res. ($\Omega$m)" elif data_type == "volt": if data is None: val = self.voltages[inds] else: val = data.copy()[inds] label_tmp = "Voltage (V)" elif data_type == "apparent_conductivity": if data is None: val = self.apparent_conductivity[inds] else: val = data.copy()[inds] label_tmp = "Apparent Cond. (S/m)" elif data_type == "apparent_chargeability": if data is not None: val = data.copy()[inds] else: val = self.apparent_chargeability.copy()[inds] * 1e3 label_tmp = "Apparent Charg. (mV/V)" elif data_type == "volt_ip": if data is not None: val = data.copy()[inds] else: val = self.voltages_ip.copy()[inds] * 1e3 label_tmp = "Secondary voltage. (mV)" else: print(data_type) raise NotImplementedError() if label is None: label = label_tmp out = plot2Ddata( grids, val, contourOpts={"cmap": cmap}, ax=ax, dataloc=dataloc, scale=scale, ncontour=ncontour, clim=clim, ) ax.invert_yaxis() ax.set_xlabel("x (m)") ax.set_yticklabels([]) ax.set_ylabel("n-spacing") if orientation == "vertical": frac = 0.01 elif orientation == "horizontal": frac = 0.03 else: raise ValueError( "Orientation must be either vertical or horizontal, not {}". format(orientation)) cb = plt.colorbar(out[0], format="%.1e", ax=ax, orientation=orientation, fraction=frac) cb.set_label(label) cb.set_ticks(out[0].levels) ax.set_aspect(aspect_ratio) plt.tight_layout() if figname is not None: fig.savefig(figname, dpi=200) def read_ubc_dc2d_obs_file(self, filename, input_type="simple", toponame=None): obsfile = np.genfromtxt(filename, delimiter=" \n", dtype=np.str, comments="!") if input_type == "general": topo = None n_src = 0 n_rxs = [] src_info = [] abmn = [] for obs in obsfile: temp = np.fromstring(obs, dtype=float, sep=" ").T if len(temp) == 5: n_src += 1 src_info = temp[:4] n_rxs.append(int(temp[-1])) else: abmn.append(np.r_[src_info, temp]) abmn = np.vstack(abmn) a = np.c_[abmn[:, 0], -abmn[:, 1]] b = np.c_[abmn[:, 2], -abmn[:, 3]] m = np.c_[abmn[:, 4], -abmn[:, 5]] n = np.c_[abmn[:, 6], -abmn[:, 7]] voltage = abmn[:, 8] standard_deviation = abmn[:, 9] elif input_type == "simple": if toponame is not None: tmp_topo = np.loadtxt(toponame) n_topo = tmp_topo[0, 0] z_ref = tmp_topo[0, 1] topo = tmp_topo[1:, :] if topo.shape[0] != n_topo: print( ">> # of points for the topography is not {0}, but {0}" .format(n_topo, topo.shape[0])) tmp = np.loadtxt(filename, comments="!").astype(float) e = np.zeros(tmp.shape[0], dtype=float) a = np.c_[tmp[:, 0], e] b = np.c_[tmp[:, 1], e] m = np.c_[tmp[:, 2], e] n = np.c_[tmp[:, 3], e] voltage = tmp[:, 4] standard_deviation = tmp[:, 5] if np.all(a == b): if np.all(m == n): survey_type = "pole-pole" else: survey_type = "pole-dipole" else: if np.all(m == n): survey_type = "dipole-pole" else: survey_type = "dipole-dipole" survey = self.from_abmn_locations_to_survey(a, b, m, n, survey_type=survey_type, data_dc=voltage) survey.dobs = voltage[self.sort_inds] survey.std = standard_deviation[self.sort_inds] survey.topo = topo return survey def write_to_csv(self, fname, dobs, standard_deviation=None, **kwargs): uncert = kwargs.pop("uncertainty", None) if uncert is not None: warnings.warn( "The uncertainty option has been deprecated and will be removed" " in SimPEG 0.16.0. Please use standard_deviation.", FutureWarning, ) standard_deviation = uncert if standard_deviation is None: standard_deviation = np.ones(dobs.size) * np.nan data = np.c_[self.a_locations, self.b_locations, self.m_locations, self.n_locations, dobs, standard_deviation, ] df = pd.DataFrame( data=data, columns=[ "Ax", "Az", "Bx", "Bz", "Mx", "Mz", "Nx", "Nz", "Voltage", "Uncertainty", ], ) df.to_csv(fname) def read_dc_data_csv(self, fname, dim=2): df = pd.read_csv(fname) if dim == 2: a_locations = df[["Ax", "Az"]].values b_locations = df[["Bx", "Bz"]].values m_locations = df[["Mx", "Mz"]].values n_locations = df[["Nx", "Nz"]].values dobs = df["Voltage"].values standard_deviation = df["Uncertainty"].values if np.all(a_locations == b_locations): src_type = "pole-" else: src_type = "dipole-" if np.all(m_locations == n_locations): rx_type = "pole" else: rx_type = "dipole" survey_type = src_type + rx_type survey = self.from_abmn_locations_to_survey( a_locations, b_locations, m_locations, n_locations, survey_type, data_dc=dobs, data_dc_type="volt", ) survey.std = standard_deviation[self.sort_inds] survey.dobs = dobs[self.sort_inds] else: raise NotImplementedError() return survey def read_topo_csv(self, fname, dim=2): if dim == 2: df = pd.read_csv(fname) topo = df[["X", "Z"]].values return topo
class HasInt(properties.HasProperties): myint = properties.Integer('my integer')
def _test_dict(self, om): with self.assertRaises(TypeError): properties.Dictionary('bad string set', key_prop=str) with self.assertRaises(TypeError): properties.Dictionary('bad string set', value_prop=str) with self.assertRaises(TypeError): properties.Dictionary('bad observe', properties.Integer(''), observe_mutations=5) class HasPropsDummy(properties.HasProperties): pass mydict = properties.Dictionary('dummy has properties set', key_prop=properties.String(''), value_prop=HasPropsDummy, observe_mutations=om) assert isinstance(mydict.key_prop, properties.String) assert isinstance(mydict.value_prop, properties.Instance) assert mydict.value_prop.instance_class is HasPropsDummy class HasDummyDict(properties.HasProperties): mydict = properties.Dictionary('dummy has properties set', key_prop=properties.String(''), value_prop=HasPropsDummy, observe_mutations=om) assert HasDummyDict()._props['mydict'].name == 'mydict' assert HasDummyDict()._props['mydict'].key_prop.name == 'mydict' assert HasDummyDict()._props['mydict'].value_prop.name == 'mydict' class HasDict(properties.HasProperties): aaa = properties.Dictionary('dictionary', default=dict) li = HasDict() li.aaa = {1: 2} with self.assertRaises(ValueError): li.aaa = (1, 2, 3) li.aaa = {'hi': HasPropsDummy()} with self.assertRaises(ValueError): li.aaa = 4 with self.assertRaises(ValueError): li.aaa = {'a', 'b', 'c'} li1 = HasDict() li2 = HasDict() assert li1.aaa == li2.aaa assert li1.aaa is not li2.aaa class HasInt(properties.HasProperties): myint = properties.Integer('my integer') class HasFunnyDict(properties.HasProperties): mydict = properties.Dictionary('my dict', key_prop=properties.Color(''), value_prop=HasInt, observe_mutations=om) hfd = HasFunnyDict() hfd.mydict = {'red': HasInt(myint=5)} hfd.mydict.update({'green': HasInt(myint=1)}) if om: hfd.validate() else: with self.assertRaises(ValueError): hfd.validate() with self.assertRaises(ValueError): hfd.mydict.update({1: HasInt(myint=1)}) hfd.validate() class HasCoercedDict(properties.HasProperties): my_coerced_dict = properties.Dictionary('my dict', coerce=True) my_uncoerced_dict = properties.Dictionary('my dict') key_val_list = [('a', 1), ('b', 2), ('c', 3)] hcd = HasCoercedDict() with self.assertRaises(ValueError): hcd.my_uncoerced_dict = key_val_list hcd.my_coerced_dict = key_val_list assert hcd.my_coerced_dict == {'a': 1, 'b': 2, 'c': 3} with self.assertRaises(properties.ValidationError): hcd.my_coerced_dict = 'a'
class HasCoercedIntTuple(properties.HasProperties): aaa = properties.Tuple('tuple of ints', properties.Integer(''), coerce=True)
class HasIntTuple(properties.HasProperties): aaa = properties.Tuple('tuple of ints', properties.Integer(''), default=tuple)
class HasIntA(properties.HasProperties): a = properties.Integer('int a', required=True)
class HasConstrianedSet(properties.HasProperties): aaa = properties.Set('set of ints', properties.Integer(''), max_length=2, observe_mutations=om)
class HasCoercedIntSet(properties.HasProperties): aaa = properties.Set('set of ints', properties.Integer(''), observe_mutations=om, coerce=True)
class HasIntSet(properties.HasProperties): aaa = properties.Set('set of ints', properties.Integer(''), observe_mutations=om, default=set)
def _test_set(self, om): with self.assertRaises(TypeError): properties.Set('bad string set', prop=str) with self.assertRaises(TypeError): properties.Set('bad max', properties.Integer(''), max_length=-10) with self.assertRaises(TypeError): properties.Set('bad max', properties.Integer(''), max_length='ten') with self.assertRaises(TypeError): myset = properties.Set('bad max', properties.Integer(''), min_length=20) myset.max_length = 10 with self.assertRaises(TypeError): properties.Set('bad min', properties.Integer(''), min_length=-10) with self.assertRaises(TypeError): properties.Set('bad min', properties.Integer(''), min_length='ten') with self.assertRaises(TypeError): myset = properties.Set('bad min', properties.Integer(''), max_length=10) myset.min_length = 20 with self.assertRaises(TypeError): properties.Set('bad observe', properties.Integer(''), observe_mutations=5) with self.assertRaises(TypeError): properties.Set('bad coerce', properties.Integer(''), coerce=5) class HasPropsDummy(properties.HasProperties): pass myset = properties.Set('dummy has properties set', prop=HasPropsDummy, observe_mutations=om) assert isinstance(myset.prop, properties.Instance) assert myset.prop.instance_class is HasPropsDummy class HasDummySet(properties.HasProperties): myset = properties.Set('dummy has properties set', prop=HasPropsDummy, observe_mutations=om) assert HasDummySet()._props['myset'].name == 'myset' assert HasDummySet()._props['myset'].prop.name == 'myset' class HasIntSet(properties.HasProperties): aaa = properties.Set('set of ints', properties.Integer(''), observe_mutations=om, default=set) li = HasIntSet() li.aaa = {1, 2, 3} with self.assertRaises(ValueError): li.aaa = (1, 2, 3) li.aaa = {1., 2., 3.} with self.assertRaises(ValueError): li.aaa = 4 with self.assertRaises(ValueError): li.aaa = {'a', 'b', 'c'} li1 = HasIntSet() li2 = HasIntSet() assert li1.aaa == li2.aaa assert li1.aaa is not li2.aaa class HasCoercedIntSet(properties.HasProperties): aaa = properties.Set('set of ints', properties.Integer(''), observe_mutations=om, coerce=True) li = HasCoercedIntSet() li.aaa = 1 assert li.aaa == {1} li.aaa = [1, 2, 3] assert li.aaa == {1, 2, 3} li.aaa = (1, 2, 3) assert li.aaa == {1, 2, 3} class HasConstrianedSet(properties.HasProperties): aaa = properties.Set('set of ints', properties.Integer(''), min_length=2, observe_mutations=om) li = HasConstrianedSet() li.aaa = {1, 2, 3} li.validate() li.aaa = {1} with self.assertRaises(ValueError): li.validate() class HasConstrianedSet(properties.HasProperties): aaa = properties.Set('set of ints', properties.Integer(''), max_length=2, observe_mutations=om) li = HasConstrianedSet() li.aaa = {1, 2} li.validate() li.aaa = {1, 2, 3, 4, 5} with self.assertRaises(ValueError): li.validate() class HasColorSet(properties.HasProperties): ccc = properties.Set('set of colors', properties.Color(''), observe_mutations=om) li = HasColorSet() li.ccc = {'red', '#00FF00'} assert li.ccc == {(255, 0, 0), (0, 255, 0)} numset = {1, 2, 3, 4} assert properties.Set.to_json(numset) == list(numset) assert properties.Set.from_json(list(numset)) == numset assert properties.Set.from_json(list(numset)) is not numset class HasIntA(properties.HasProperties): a = properties.Integer('int a', required=True) hia_json = properties.Set.to_json({HasIntA(a=5), HasIntA(a=10)}) assert (hia_json == [{ '__class__': 'HasIntA', 'a': 5 }, { '__class__': 'HasIntA', 'a': 10 }] or hia_json == [{ '__class__': 'HasIntA', 'a': 10 }, { '__class__': 'HasIntA', 'a': 5 }]) li_ser = li.serialize(include_class=False) assert (li_ser == { 'ccc': [[255, 0, 0], [0, 255, 0]] } or li_ser == { 'ccc': [[0, 255, 0], [255, 0, 0]] }) class HasIntASet(properties.HasProperties): myset = properties.Set('set of HasIntA', HasIntA, observe_mutations=om) deser_set = HasIntASet.deserialize({ 'myset': [{ 'a': 0 }, { 'a': 10 }, { 'a': 100 }] }).myset assert isinstance(deser_set, set) assert len(deser_set) == 3 assert all(isinstance(val, HasIntA) for val in deser_set) assert {val.a for val in deser_set} == {0, 10, 100} class HasOptionalSet(properties.HasProperties): myset = properties.Set('', properties.Bool(''), required=False, observe_mutations=om) hol = HasOptionalSet() hol.validate() assert HasIntASet._props['myset'].deserialize(None) is None assert properties.Set('', properties.Instance('', HasIntA), observe_mutations=om).equal( {HasIntA(a=1), HasIntA(a=2)}, {HasIntA(a=1), HasIntA(a=2)}) assert not properties.Set( '', properties.Instance('', HasIntA), observe_mutations=om).equal( {HasIntA(a=1), HasIntA(a=2)}, {HasIntA(a=1), HasIntA(a=2), HasIntA(a=3)}) assert not properties.Set( '', properties.Instance('', HasIntA), observe_mutations=om).equal( {HasIntA(a=1), HasIntA(a=2)}, {HasIntA(a=1), HasIntA(a=3)}) assert not properties.Set( '', properties.Integer(''), observe_mutations=om).equal(5, 5)
class HasConstrianedList(properties.HasProperties): aaa = properties.List('list of ints', properties.Integer(''), min_length=2, observe_mutations=om)
class HasIntList(properties.HasProperties): aaa = properties.List('list of ints', properties.Integer(''), observe_mutations=om, default=list)