Beispiel #1
0
    def _getAddedMeshValues(self, other, resolution=1e-2):
        """Calculate the parameters to define a concatenation of `other` with `self`

        Parameters
        ----------
        other : ~fipy.meshes.mesh.Mesh
             The `Mesh` to concatenate with `self`
        resolution : float
            How close vertices have to be (relative to the smallest
            cell-to-cell distance in either mesh) to be considered the same

        Returns
        -------
        dict
            (`vertexCoords`, `faceVertexIDs`, `cellFaceIDs`) for the new mesh.
        """

        selfc = self._concatenableMesh
        otherc = other._concatenableMesh

        selfNumFaces = selfc.faceVertexIDs.shape[-1]
        selfNumVertices = selfc.vertexCoords.shape[-1]
        otherNumFaces = otherc.faceVertexIDs.shape[-1]
        otherNumVertices = otherc.vertexCoords.shape[-1]
        ## check dimensions
        if(selfc.vertexCoords.shape[0] != otherc.vertexCoords.shape[0]):
            raise MeshAdditionError("Dimensions do not match")

        ## compute vertex correlates

#         from fipy.tools.debug import PRINT
#         PRINT("selfNumFaces", selfNumFaces)
#         PRINT("otherNumFaces", otherNumVertices)
#         PRINT("selfNumVertices", selfNumVertices)
#         PRINT("otherNumVertices", otherNumVertices)
# 
#         from fipy.tools.debug import PRINT
#         from fipy.tools.debug import PRINT
#         PRINT("otherExt", otherc.exteriorFaces.value)
#         raw_input()
#         PRINT("selfExt", selfc.exteriorFaces.value)
# 
#         PRINT("self filled", selfc.faceVertexIDs.filled())
#         PRINT("othe filled", otherc.faceVertexIDs.filled())
#         raw_input()
# 
#         PRINT("selfc.faceVertexIDs.filled()\n",selfc.faceVertexIDs.filled())
#         PRINT("flat\n",selfc.faceVertexIDs.filled()[...,
#             selfc.exteriorFaces.value].flatten())
#         PRINT("selfc.exteriorFaces.value\n",selfc.exteriorFaces.value)
#         PRINT("extfaces type", type(selfc.exteriorFaces))
#         PRINT("extfaces mesh", selfc.exteriorFaces.mesh)

        ## only try to match along the operation manifold
        if hasattr(self, "opManifold"):
            self_faces = self.opManifold(selfc)
        else:
            self_faces = selfc.exteriorFaces.value
        if hasattr(other, "opManifold"):
            other_faces = other.opManifold(otherc)
        else:
            other_faces = otherc.exteriorFaces.value

        ## only try to match exterior (X) vertices
        self_Xvertices = numerix.unique(selfc.faceVertexIDs.filled()[...,
            self_faces].flatten())
        other_Xvertices = numerix.unique(otherc.faceVertexIDs.filled()[...,
            other_faces].flatten())

        self_XvertexCoords = selfc.vertexCoords[..., self_Xvertices]
        other_XvertexCoords = otherc.vertexCoords[..., other_Xvertices]

        closest = numerix.nearest(self_XvertexCoords, other_XvertexCoords)

        # just because they're closest, doesn't mean they're close
        tmp = self_XvertexCoords[..., closest] - other_XvertexCoords
        distance = numerix.sqrtDot(tmp, tmp)
        # only want vertex pairs that are 100x closer than the smallest
        # cell-to-cell distance
        close = distance < resolution * min(selfc._cellToCellDistances.min(),
                                            otherc._cellToCellDistances.min())
        vertexCorrelates = numerix.array((self_Xvertices[closest[close]],
                                          other_Xvertices[close]))

        # warn if meshes don't touch, but allow it
        if (selfc._numberOfVertices > 0
            and otherc._numberOfVertices > 0
            and vertexCorrelates.shape[-1] == 0):
            import warnings
            warnings.warn("Vertices are not aligned", UserWarning, stacklevel=4)

        ## compute face correlates

        # ensure that both sets of faceVertexIDs have the same maximum number of (masked) elements
        self_faceVertexIDs = selfc.faceVertexIDs
        other_faceVertexIDs = otherc.faceVertexIDs

        diff = self_faceVertexIDs.shape[0] - other_faceVertexIDs.shape[0]
        if diff > 0:
            other_faceVertexIDs = numerix.append(other_faceVertexIDs,
                                                 -1 * numerix.ones((diff,)
                                                                   + other_faceVertexIDs.shape[1:], 'l'),
                                                 axis=0)
            other_faceVertexIDs = MA.masked_values(other_faceVertexIDs, -1)
        elif diff < 0:
            self_faceVertexIDs = numerix.append(self_faceVertexIDs,
                                                -1 * numerix.ones((-diff,)
                                                                  + self_faceVertexIDs.shape[1:], 'l'),
                                                axis=0)
            self_faceVertexIDs = MA.masked_values(self_faceVertexIDs, -1)

        # want self's Faces for which all faceVertexIDs are in vertexCorrelates
        self_matchingFaces = numerix.in1d(self_faceVertexIDs,
                                          vertexCorrelates[0]).reshape(self_faceVertexIDs.shape).all(axis=0).nonzero()[0]

        # want other's Faces for which all faceVertexIDs are in vertexCorrelates
        other_matchingFaces = numerix.in1d(other_faceVertexIDs,
                                           vertexCorrelates[1]).reshape(other_faceVertexIDs.shape).all(axis=0).nonzero()[0]

        # map other's Vertex IDs to new Vertex IDs,
        # accounting for overlaps with self's Vertex IDs
        vertex_map = numerix.empty(otherNumVertices, dtype=numerix.INT_DTYPE)
        verticesToAdd = numerix.delete(numerix.arange(otherNumVertices), vertexCorrelates[1])
        vertex_map[verticesToAdd] = numerix.arange(otherNumVertices - len(vertexCorrelates[1])) + selfNumVertices
        vertex_map[vertexCorrelates[1]] = vertexCorrelates[0]

        # calculate hashes of faceVertexIDs for comparing Faces

        if self_matchingFaces.shape[-1] == 0:
            self_faceHash = numerix.empty(self_matchingFaces.shape[:-1] + (0,), dtype="str")
        else:
            # sort each of self's Face's vertexIDs for canonical comparison
            self_faceHash = numerix.sort(self_faceVertexIDs[..., self_matchingFaces], axis=0)
            # then hash the Faces for comparison (NumPy set operations are only for 1D arrays)
            self_faceHash = numerix.apply_along_axis(str, axis=0, arr=self_faceHash)

        face_sort = numerix.argsort(self_faceHash)
        self_faceHash = self_faceHash[face_sort]
        self_matchingFaces = self_matchingFaces[face_sort]

        if other_matchingFaces.shape[-1] == 0:
            other_faceHash = numerix.empty(other_matchingFaces.shape[:-1] + (0,), dtype="str")
        else:
            # convert each of other's Face's vertexIDs to new IDs
            other_faceHash = vertex_map[other_faceVertexIDs[..., other_matchingFaces]]
            # sort each of other's Face's vertexIDs for canonical comparison
            other_faceHash = numerix.sort(other_faceHash, axis=0)
            # then hash the Faces for comparison (NumPy set operations are only for 1D arrays)
            other_faceHash = numerix.apply_along_axis(str, axis=0, arr=other_faceHash)

        face_sort = numerix.argsort(other_faceHash)
        other_faceHash = other_faceHash[face_sort]
        other_matchingFaces = other_matchingFaces[face_sort]

        self_matchingFaces = self_matchingFaces[numerix.in1d(self_faceHash,
                                                             other_faceHash)]
        other_matchingFaces = other_matchingFaces[numerix.in1d(other_faceHash,
                                                               self_faceHash)]

        faceCorrelates = numerix.array((self_matchingFaces,
                                        other_matchingFaces))

        # warn if meshes don't touch, but allow it
        if (selfc.numberOfFaces > 0
            and otherc.numberOfFaces > 0
            and faceCorrelates.shape[-1] == 0):
            import warnings
            warnings.warn("Faces are not aligned", UserWarning, stacklevel=4)

        # map other's Face IDs to new Face IDs,
        # accounting for overlaps with self's Face IDs
        face_map = numerix.empty(otherNumFaces, dtype=numerix.INT_DTYPE)
        facesToAdd = numerix.delete(numerix.arange(otherNumFaces), faceCorrelates[1])
        face_map[facesToAdd] = numerix.arange(otherNumFaces - len(faceCorrelates[1])) + selfNumFaces
        face_map[faceCorrelates[1]] = faceCorrelates[0]

        other_faceVertexIDs = vertex_map[otherc.faceVertexIDs[..., facesToAdd]]

        # ensure that both sets of cellFaceIDs have the same maximum number of (masked) elements
        self_cellFaceIDs = selfc.cellFaceIDs
        other_cellFaceIDs = face_map[otherc.cellFaceIDs]
        diff = self_cellFaceIDs.shape[0] - other_cellFaceIDs.shape[0]
        if diff > 0:
            other_cellFaceIDs = numerix.append(other_cellFaceIDs,
                                               -1 * numerix.ones((diff,)
                                                                 + other_cellFaceIDs.shape[1:], 'l'),
                                               axis=0)
            other_cellFaceIDs = MA.masked_values(other_cellFaceIDs, -1)
        elif diff < 0:
            self_cellFaceIDs = numerix.append(self_cellFaceIDs,
                                              -1 * numerix.ones((-diff,)
                                                                + self_cellFaceIDs.shape[1:], 'l'),
                                              axis=0)
            self_cellFaceIDs = MA.masked_values(self_cellFaceIDs, -1)

        # concatenate everything and return
        return {
            'vertexCoords': numerix.concatenate((selfc.vertexCoords,
                                                 otherc.vertexCoords[..., verticesToAdd]), axis=1),
            'faceVertexIDs': numerix.concatenate((self_faceVertexIDs,
                                                  other_faceVertexIDs), axis=1),
            'cellFaceIDs': MA.concatenate((self_cellFaceIDs,
                                           other_cellFaceIDs), axis=1)
            }
 
     ####
     #
     # phloem
     #
     ####
     
     phl.mp2mesh(segs) #creates grid
     phl.cellsID = [phl.new2oldNodeID[xi] - 1 for xi in phl.mesh.cellFaceIDs[1] ]
     
     if(len(phl.phi.value) > len(phiOld)): #place according to index ID
     
         CphiOld = phiOld * cellVolumeOld
         orderedCPhi = np.concatenate((np.array([x for _,x in sorted(zip(cellsIDOld, CphiOld))]), np.full(len(phl.phi.value)-len(phiOld),0.)))        
         orderedCPhiNew = np.take(orderedCPhi, phl.cellsID)/phl.mesh.cellVolumes
         growthSteps = np.append(growthSteps, [step])
         phl.phi = CellVariablemod(mesh = phl.mesh, value= orderedCPhiNew , hasOld =True)
         
         phl.phi.updateOld()
         
         orderedcumulOut = np.concatenate((np.array([x for _,x in sorted(zip(cellsIDOld, cumulOutOld))]), np.full(len(phl.phi.value)-len(phiOld),0.)))        
         orderedcumulOutNew = np.take(orderedcumulOut, phl.cellsID)        
         cumulOut = CellVariable(mesh = phl.mesh, value= orderedcumulOutNew)
         
         orderedcumulGr = np.concatenate((np.array([x for _,x in sorted(zip(cellsIDOld, cumulGrOld))]), np.full(len(phl.phi.value)-len(phiOld),0.)))        
         orderedcumulGrNew = np.take(orderedcumulGr, phl.cellsID)                
         cumulGr = CellVariable(mesh = phl.mesh, value= orderedcumulGrNew)
         
         orderedcumulRm = np.concatenate((np.array([x for _,x in sorted(zip(cellsIDOld, cumulRmOld))]), np.full(len(phl.phi.value)-len(phiOld),0.)))        
         orderedcumulRmNew = np.take(orderedcumulRm, phl.cellsID)                
         cumulRm = CellVariable(mesh = phl.mesh, value= orderedcumulRmNew)
    rho_sorted_acc_to_theta = index_sorted(
        xvar, yvar)  # calling the index_sorted function
    rho_sorted_acc_to_theta = np.reshape(
        rho_sorted_acc_to_theta,
        (1, len(rho_sorted_acc_to_theta)))  # reshaping into a single array

    theta_sorted = np.sort(theta_at_index)  # theta value sorted
    theta_sorted = theta_sorted[
        0, :]  # converting from 1Xn matrix to row array of n elements

    phi_new = phi_value * numerix.ones(len(theta_sorted))

    m_cell_modified_sph_pol = numerix.append(
        numerix.asarray(r_at_index),
        [numerix.asarray(theta_sorted),
         numerix.asarray(phi_new)],
        axis=0)

    #print(numerix.shape(m_cell_modified_sph_pol))
    m_cell_sph = numerix.append(
        m_cell_sph, (m_cell_modified_sph_pol),
        axis=1)  #Appending the m values in spherical polar coordinate

    theta_sz = np.shape(theta_sorted)
    size = theta_sz[0]
    total_size = total_size + size  # calculate total number of cells being covered during calculation

    phi_value = phi_value + delta  # phi is increased by delta at end of each loop

print('Total number of cells covered = ' + str(total_size))
Beispiel #4
0
    def _getAddedMeshValues(self, other, resolution=1e-2):
        """Calculate the parameters to define a concatenation of `other` with `self`
        
        :Parameters:
          - `other`: The :class:`~fipy.meshes.numMesh.Mesh` to concatenate with `self`
          - `resolution`: How close vertices have to be (relative to the smallest 
            cell-to-cell distance in either mesh) to be considered the same

        :Returns:
          A `dict` with 3 elements: the new mesh vertexCoords, faceVertexIDs, and cellFaceIDs.
        """
        
        selfc = self._getConcatenableMesh()
        other = other._getConcatenableMesh()

        selfNumFaces = selfc.faceVertexIDs.shape[-1]
        selfNumVertices = selfc.vertexCoords.shape[-1]
        otherNumFaces = other.faceVertexIDs.shape[-1]
        otherNumVertices = other.vertexCoords.shape[-1]
        ## check dimensions
        if(selfc.vertexCoords.shape[0] != other.vertexCoords.shape[0]):
            raise MeshAdditionError, "Dimensions do not match"
            
        ## compute vertex correlates

        ## only try to match exterior (X) vertices
        self_Xvertices = numerix.unique(selfc._getFaceVertexIDs().filled()[..., selfc.getExteriorFaces().getValue()].flatten())
        other_Xvertices = numerix.unique(other._getFaceVertexIDs().filled()[..., other.getExteriorFaces().getValue()].flatten())

        self_XvertexCoords = selfc.vertexCoords[..., self_Xvertices]
        other_XvertexCoords = other.vertexCoords[..., other_Xvertices]
        
        # lifted from Mesh._getNearestCellID()
        other_vertexCoordMap = numerix.resize(other_XvertexCoords, 
                                              (self_XvertexCoords.shape[-1], 
                                               other_XvertexCoords.shape[0], 
                                               other_XvertexCoords.shape[-1])).swapaxes(0,1)
        tmp = self_XvertexCoords[..., numerix.newaxis] - other_vertexCoordMap
        closest = numerix.argmin(numerix.dot(tmp, tmp), axis=0)
        
        # just because they're closest, doesn't mean they're close
        tmp = self_XvertexCoords[..., closest] - other_XvertexCoords
        distance = numerix.sqrtDot(tmp, tmp)
        # only want vertex pairs that are 100x closer than the smallest 
        # cell-to-cell distance
        close = distance < resolution * min(selfc._getCellToCellDistances().min(), 
                                            other._getCellToCellDistances().min())
        vertexCorrelates = numerix.array((self_Xvertices[closest[close]],
                                          other_Xvertices[close]))
        
        # warn if meshes don't touch, but allow it
        if (selfc._getNumberOfVertices() > 0 
            and other._getNumberOfVertices() > 0 
            and vertexCorrelates.shape[-1] == 0):
            import warnings
            warnings.warn("Vertices are not aligned", UserWarning, stacklevel=4)

        ## compute face correlates

        # ensure that both sets of faceVertexIDs have the same maximum number of (masked) elements
        self_faceVertexIDs = selfc.faceVertexIDs
        other_faceVertexIDs = other.faceVertexIDs

        diff = self_faceVertexIDs.shape[0] - other_faceVertexIDs.shape[0]
        if diff > 0:
            other_faceVertexIDs = numerix.append(other_faceVertexIDs, 
                                                 -1 * numerix.ones((diff,) 
                                                                   + other_faceVertexIDs.shape[1:]),
                                                 axis=0)
            other_faceVertexIDs = MA.masked_values(other_faceVertexIDs, -1)
        elif diff < 0:
            self_faceVertexIDs = numerix.append(self_faceVertexIDs, 
                                                -1 * numerix.ones((-diff,) 
                                                                  + self_faceVertexIDs.shape[1:]),
                                                axis=0)
            self_faceVertexIDs = MA.masked_values(self_faceVertexIDs, -1)

        # want self's Faces for which all faceVertexIDs are in vertexCorrelates
        self_matchingFaces = numerix.in1d(self_faceVertexIDs, 
                                          vertexCorrelates[0]).reshape(self_faceVertexIDs.shape).all(axis=0).nonzero()[0]

        # want other's Faces for which all faceVertexIDs are in vertexCorrelates
        other_matchingFaces = numerix.in1d(other_faceVertexIDs, 
                                           vertexCorrelates[1]).reshape(other_faceVertexIDs.shape).all(axis=0).nonzero()[0]
                                           
        # map other's Vertex IDs to new Vertex IDs, 
        # accounting for overlaps with self's Vertex IDs
        vertex_map = numerix.empty(otherNumVertices, dtype=int)
        verticesToAdd = numerix.delete(numerix.arange(otherNumVertices), vertexCorrelates[1])
        vertex_map[verticesToAdd] = numerix.arange(otherNumVertices - len(vertexCorrelates[1])) + selfNumVertices
        vertex_map[vertexCorrelates[1]] = vertexCorrelates[0]

        # calculate hashes of faceVertexIDs for comparing Faces
        
        if self_matchingFaces.shape[-1] == 0:
            self_faceHash = numerix.empty(self_matchingFaces.shape[:-1] + (0,), dtype="str")
        else:
            # sort each of self's Face's vertexIDs for canonical comparison
            self_faceHash = numerix.sort(self_faceVertexIDs[..., self_matchingFaces], axis=0)
            # then hash the Faces for comparison (NumPy set operations are only for 1D arrays)
            self_faceHash = numerix.apply_along_axis(str, axis=0, arr=self_faceHash)
            
        face_sort = numerix.argsort(self_faceHash)
        self_faceHash = self_faceHash[face_sort]
        self_matchingFaces = self_matchingFaces[face_sort]

        if other_matchingFaces.shape[-1] == 0:
            other_faceHash = numerix.empty(other_matchingFaces.shape[:-1] + (0,), dtype="str")
        else:
            # convert each of other's Face's vertexIDs to new IDs
            other_faceHash = vertex_map[other_faceVertexIDs[..., other_matchingFaces]]
            # sort each of other's Face's vertexIDs for canonical comparison
            other_faceHash = numerix.sort(other_faceHash, axis=0)
            # then hash the Faces for comparison (NumPy set operations are only for 1D arrays)
            other_faceHash = numerix.apply_along_axis(str, axis=0, arr=other_faceHash)

        face_sort = numerix.argsort(other_faceHash)
        other_faceHash = other_faceHash[face_sort]
        other_matchingFaces = other_matchingFaces[face_sort]

        self_matchingFaces = self_matchingFaces[numerix.in1d(self_faceHash, 
                                                             other_faceHash)]
        other_matchingFaces = other_matchingFaces[numerix.in1d(other_faceHash, 
                                                               self_faceHash)]
        
        faceCorrelates = numerix.array((self_matchingFaces,
                                        other_matchingFaces))

        # warn if meshes don't touch, but allow it
        if (selfc._getNumberOfFaces() > 0 
            and other._getNumberOfFaces() > 0 
            and faceCorrelates.shape[-1] == 0):
            import warnings
            warnings.warn("Faces are not aligned", UserWarning, stacklevel=4)

        # map other's Face IDs to new Face IDs, 
        # accounting for overlaps with self's Face IDs
        face_map = numerix.empty(otherNumFaces, dtype=int)
        facesToAdd = numerix.delete(numerix.arange(otherNumFaces), faceCorrelates[1])
        face_map[facesToAdd] = numerix.arange(otherNumFaces - len(faceCorrelates[1])) + selfNumFaces
        face_map[faceCorrelates[1]] = faceCorrelates[0]
        
        other_faceVertexIDs = vertex_map[other.faceVertexIDs[..., facesToAdd]]
        
        # ensure that both sets of cellFaceIDs have the same maximum number of (masked) elements
        self_cellFaceIDs = selfc.cellFaceIDs
        other_cellFaceIDs = face_map[other.cellFaceIDs]
        diff = self_cellFaceIDs.shape[0] - other_cellFaceIDs.shape[0]
        if diff > 0:
            other_cellFaceIDs = numerix.append(other_cellFaceIDs, 
                                               -1 * numerix.ones((diff,) 
                                                                 + other_cellFaceIDs.shape[1:]),
                                               axis=0)
            other_cellFaceIDs = MA.masked_values(other_cellFaceIDs, -1)
        elif diff < 0:
            self_cellFaceIDs = numerix.append(self_cellFaceIDs, 
                                              -1 * numerix.ones((-diff,) 
                                                                + self_cellFaceIDs.shape[1:]),
                                              axis=0)
            self_cellFaceIDs = MA.masked_values(self_cellFaceIDs, -1)

        # concatenate everything and return
        return {
            'vertexCoords': numerix.concatenate((selfc.vertexCoords, 
                                                 other.vertexCoords[..., verticesToAdd]), axis=1), 
            'faceVertexIDs': numerix.concatenate((self_faceVertexIDs, 
                                                  other_faceVertexIDs), axis=1), 
            'cellFaceIDs': MA.concatenate((self_cellFaceIDs, 
                                           other_cellFaceIDs), axis=1)
            }
issue = []
issueRes = []
issueLoop = []
for _ in range(steps):
    res = 1e+10
    resOld = 2e+10
    loop = 0
    print('step ', _)
    while res > max(1e-10,
                    1e-5 * max(phl.phi)) and loop < 1000 and resOld != res:
        resOld = res
        res = eq1.sweep(dt=dt)
        loop += 1
    if res > max(1e-10, 1e-5 * max(phl.phi)):
        print('no convergence! res: ', res)
        issue = np.append(issue, [_])
        issueRes = np.append(issueRes, [res])
        issueLoop = np.append(issueLoop, [loop])

    phl.phi.updateOld()
    cumulRm.setValue(cumulRm.value + phl.Rm.value * dt * phl.mesh.cellVolumes)
    cumulAn.setValue(cumulAn.value +
                     phl.Source.value * dt * phl.mesh.cellVolumes)
    cumulGr.setValue(cumulGr.value +
                     phl.GrSink.value * dt * phl.mesh.cellVolumes)

    loop = 0
    resOld = 2e+10
    res = 1e+10
    while res > max(1e-10,
                    1e-5 * max(phl.phi)) and loop < 1000 and resOld != res:
Beispiel #6
0
    def update_artists(self, tidx):
        """
        Update the data of the line artists for time point

        Args:
            tidx (int): The time index

        """
        self.logger.info(
            'Updating artist_paths for time step #{}'.format(tidx))

        clocktime = self.model.times[tidx]
        dt = int(np.ceil((clocktime - self._clock).numericValue))
        H, M, S = [int(s.value) for s in clocktime.inUnitsOf('h', 'min', 's')]
        hmstr = self.clockstr.format(H, M, S, dt)
        self._clock = clocktime

        self.clock_artist.set_text(hmstr)
        self.logger.debug('Time: {}'.format(hmstr))

        # self.axes_all
        # all_depth_axes = itertools.chain(self.axes_depth, self.axes_depth_linked.values())
        # all_time_axes = itertools.chain(self.axes_time, self.axes_time_linked.values())

        for artist, dpath in self.artist_paths.items():

            ax = artist.axes
            self.logger.info('Updating {} artist {} from {}'.format(
                ax.name, artist, dpath))

            # get the data
            data = self.model.get_data(dpath, tidx=tidx)
            data_unit = data.unit.name()
            self.logger.debug('Got data {} {} of unit: {!r}'.format(
                data.__class__.__name__, data.shape, data_unit))

            # cast to units
            if not getattr(ax, 'data_unit_', None):
                ax.data_unit_ = data.unit.name()
                self.logger.debug('Set axes {} to unit: {}'.format(
                    ax.name, ax.data_unit_))
                # if ax in all_time_axes:
                #     ax.set_ylabel(ax.data_unit_)
            ax_unit = ax.data_unit_

            try:
                D = data.inUnitsOf(ax_unit).value
                self.logger.debug('Got data {} dtype {} --> {}'.format(
                    D.dtype, D.min(), D.max()))

            except TypeError:
                self.logger.error(
                    "Error casting {} units from {} to {}".format(
                        dpath, data_unit, ax_unit))
                # raise
                D = data.value

            # now data D is a numpy array

            label_base = self._get_label(dpath)

            # normalize if necessary
            data_normed = getattr(ax, 'data_normed_', False)

            if data_normed:
                Dabs = abs(D)
                Dabsmax = float(Dabs.max())
                Dabsmin = float(Dabs.min())
                Drange = Dabsmax - Dabsmin
                if Drange <= 1e-15:
                    self.logger.debug('abs(data) max = min = {:.2g}'.format(
                        Dabsmax, Dabsmin))
                    if Dabsmax == 0.0:
                        Drange = 1.0
                        self.logger.debug(
                            'all data is zero, normalizing by 1.0')
                    else:
                        Drange = Dabsmax
                        self.logger.debug(
                            'normalizing by abs(data).max = {:.2g}'.format(
                                Dabsmax))
                else:
                    self.logger.debug(
                        'abs(data) range {:.2g} --> {:.2g}'.format(
                            Dabsmin, Dabsmax))
                    Drange = Dabsmax

                D = D / Drange

                self.logger.info(
                    'Normalized {} data by {:.3g}: {:.3g} --> {:.3g}'.format(
                        label_base, Drange, D.min(), D.max()))

                label = label_base + flabel(Drange)

                if D.max() > 1.01:
                    self.logger.error('data max {} is not <=1.01'.format(
                        D.max()))
                    self.logger.warning(D)
                    self.logger.warning('Drange: {}'.format(Drange))
                    self.logger.warning('Original data: {}'.format(
                        data.inUnitsOf(ax_unit).value))
                    raise RuntimeError(
                        'Data normalization of {} failed!'.format(dpath))

            else:
                label = label_base

            # now ready to set data and label
            if ax in self.axes_depth_all:
                artist.set_xdata(D)
                artist.set_label(label)

            elif ax in self.axes_time_all:
                xdata, ydata = artist.get_data()
                t = self.model.get_data('/time', tidx=tidx)
                artist.set_xdata(np.append(xdata, t.inUnitsOf('h').value))
                artist.set_ydata(np.append(ydata, D))
                artist.set_label(label + ' {}'.format(ax.data_unit_))

            self.logger.debug('{} updated'.format(artist))

        self.update_legends()

        for ax in self.axes_depth + self.axes_time:
            ax.relim()
            ax.autoscale_view(scalex=True, scaley=True)