Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(mfdatastorage): use appropriate fill_value for data type #1689

Merged
merged 1 commit into from
Feb 13, 2023

Conversation

mwtoews
Copy link
Contributor

@mwtoews mwtoews commented Jan 21, 2023

This resolves a RuntieWarning from flopy doing something like this:

# test_this.py
import flopy

def test_this():
    sim = flopy.mf6.MFSimulation()
    _ = flopy.mf6.ModflowTdis(sim)
    gwf = flopy.mf6.ModflowGwf(sim)
    _ = flopy.mf6.ModflowIms(sim)
    _ = flopy.mf6.ModflowGwfdis(gwf, idomain=1)
    _ = flopy.mf6.ModflowGwfoc(gwf, saverecord=[("HEAD", "ALL")])

which shows a warning summary:

$ pytest test_this.py
...
=============================== warnings summary ===============================
test_this.py::test_this
  <__array_function__ internals>:200: RuntimeWarning: invalid value encountered in cast

and looking at a big trace shows where/how it was raised:

pytest trace
$ pytest -W error::RuntimeWarning test_this.py 
============================= test session starts ==============================
platform linux -- Python 3.8.10, pytest-7.2.1, pluggy-1.0.0
benchmark: 4.0.0 (defaults: timer=time.perf_counter disable_gc=False min_rounds=5 min_time=0.000005 max_time=1.0 calibration_precision=10 warmup=False warmup_iterations=100000)
rootdir: /tmp
plugins: cases-3.6.13, anyio-3.6.2, benchmark-4.0.0, cov-4.0.0, xdist-3.1.0, dotenv-0.5.2, flaky-3.7.0
collected 1 item                                                               

test_this.py F                                                           [100%]

=================================== FAILURES ===================================
__________________________________ test_this ___________________________________

self = {constant 1}
, layer = None, apply_mult = True, kwargs = {'array': True}
storage = {constant 1}
, type_ = <class 'RuntimeWarning'>
value_ = RuntimeWarning('invalid value encountered in cast')
traceback_ = <traceback object at 0x7f6698da7ac0>

    def _get_data(self, layer=None, apply_mult=False, **kwargs):
        if self._get_storage_obj() is None:
            self._data_storage = self._new_storage(False)
        if isinstance(layer, int):
            layer = (layer,)
        storage = self._get_storage_obj()
        if storage is not None:
            try:
>               data = storage.get_data(layer, apply_mult)

/data/mtoews/src/flopy/flopy/mf6/data/mfdataarray.py:730: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {constant 1}
, layer = None, apply_mult = True, block_exists = False

    def get_data(self, layer=None, apply_mult=True, block_exists=False):
>       data = self._access_data(layer, True, apply_mult=apply_mult)

/data/mtoews/src/flopy/flopy/mf6/data/mfdatastorage.py:668: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {constant 1}
, layer = None, return_data = True, apply_mult = True

    def _access_data(self, layer, return_data=False, apply_mult=True):
        layer_check = self._resolve_layer(layer)
        if (
            self.layer_storage[layer_check].internal_data is None
            and self.layer_storage[layer_check].data_storage_type
            == DataStorageType.internal_array
        ) or (
            self.layer_storage[layer_check].data_const_value is None
            and self.layer_storage[layer_check].data_storage_type
            == DataStorageType.internal_constant
        ):
            return None
        if (
            layer is None
            and (
                self.data_structure_type == DataStructureType.ndarray
                or self.data_structure_type == DataStructureType.scalar
            )
            and return_data
        ):
            # return data from all layers
>           data = self._build_full_data(apply_mult)

/data/mtoews/src/flopy/flopy/mf6/data/mfdatastorage.py:695: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {constant 1}
, apply_multiplier = True

    def _build_full_data(self, apply_multiplier=False):
        if self.data_structure_type == DataStructureType.scalar:
            return self.layer_storage.first_item().internal_data
        dimensions = self.get_data_dimensions(None)
        if dimensions[0] < 0:
            # dimensions can not be determined from dfn file, use
            # the size of the data provided as the dimensions
            dimensions = [self.layer_storage.get_total_size()]
        all_none = True
        np_data_type = self.data_dimensions.structure.get_datum_type()
>       full_data = np.full(
            dimensions,
            np.nan,
            self.data_dimensions.structure.get_datum_type(True),
        )

/data/mtoews/src/flopy/flopy/mf6/data/mfdatastorage.py:2436: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

shape = [1, 2, 2], fill_value = nan, dtype = <class 'numpy.int32'>, order = 'C'

    @set_array_function_like_doc
    @set_module('numpy')
    def full(shape, fill_value, dtype=None, order='C', *, like=None):
        """
        Return a new array of given shape and type, filled with `fill_value`.
    
        Parameters
        ----------
        shape : int or sequence of ints
            Shape of the new array, e.g., ``(2, 3)`` or ``2``.
        fill_value : scalar or array_like
            Fill value.
        dtype : data-type, optional
            The desired data-type for the array  The default, None, means
             ``np.array(fill_value).dtype``.
        order : {'C', 'F'}, optional
            Whether to store multidimensional data in C- or Fortran-contiguous
            (row- or column-wise) order in memory.
        ${ARRAY_FUNCTION_LIKE}
    
            .. versionadded:: 1.20.0
    
        Returns
        -------
        out : ndarray
            Array of `fill_value` with the given shape, dtype, and order.
    
        See Also
        --------
        full_like : Return a new array with shape of input filled with value.
        empty : Return a new uninitialized array.
        ones : Return a new array setting values to one.
        zeros : Return a new array setting values to zero.
    
        Examples
        --------
        >>> np.full((2, 2), np.inf)
        array([[inf, inf],
               [inf, inf]])
        >>> np.full((2, 2), 10)
        array([[10, 10],
               [10, 10]])
    
        >>> np.full((2, 2), [1, 2])
        array([[1, 2],
               [1, 2]])
    
        """
        if like is not None:
            return _full_with_like(shape, fill_value, dtype=dtype, order=order, like=like)
    
        if dtype is None:
            fill_value = asarray(fill_value)
            dtype = fill_value.dtype
        a = empty(shape, dtype, order)
>       multiarray.copyto(a, fill_value, casting='unsafe')

py38/lib/python3.8/site-packages/numpy/core/numeric.py:345: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

args = (array([[[         0, 2146959360],
        [         0, 2146959360]]], dtype=int32), nan)
kwargs = {'casting': 'unsafe'}
relevant_args = (array([[[         0, 2146959360],
        [         0, 2146959360]]], dtype=int32), nan, None)

>   ???
E   RuntimeWarning: invalid value encountered in cast

<__array_function__ internals>:200: RuntimeWarning

During handling of the above exception, another exception occurred:

self = 
dataset_struct = <flopy.mf6.data.mfstructure.MFDataStructure object at 0x7f6698f7c9a0>
data = [('HEAD', 'ALL')], var_path = ('model', 'oc', 'period', 'saverecord')

    def add_dataset(self, dataset_struct, data, var_path):
        """Add data to this block."""
        try:
>           self.datasets[var_path[-1]] = self.data_factory(
                self._simulation_data,
                self._model_or_sim,
                dataset_struct,
                True,
                var_path,
                self._dimensions,
                data,
                self._container_package,
            )

/data/mtoews/src/flopy/flopy/mf6/mfpackage.py:585: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = 
sim_data = <flopy.mf6.modflow.mfsimulation.MFSimulationData object at 0x7f6699118f10>
model_or_sim = name = model
model_type = gwf6
version = mf6
model_relative_path = .

###################
Package dis
################...####

package_name = oc
filename = model.oc
package_type = oc
model_or_simulation_package = model
model_name = model



structure = <flopy.mf6.data.mfstructure.MFDataStructure object at 0x7f6698f7c9a0>
enable = True, path = ('model', 'oc', 'period', 'saverecord')
dimensions = <flopy.mf6.coordinates.modeldimensions.PackageDimensions object at 0x7f6698fd4f70>
data = [('HEAD', 'ALL')]
package = package_name = oc
filename = model.oc
package_type = oc
model_or_simulation_package = model
model_name = model



    def data_factory(
        self,
        sim_data,
        model_or_sim,
        structure,
        enable,
        path,
        dimensions,
        data=None,
        package=None,
    ):
        """Creates the appropriate data child object derived from MFData."""
        data_type = structure.get_datatype()
        # examine the data structure and determine the data type
        if (
            data_type == mfstructure.DataType.scalar_keyword
            or data_type == mfstructure.DataType.scalar
        ):
            return mfdatascalar.MFScalar(
                sim_data,
                model_or_sim,
                structure,
                data,
                enable,
                path,
                dimensions,
            )
        elif (
            data_type == mfstructure.DataType.scalar_keyword_transient
            or data_type == mfstructure.DataType.scalar_transient
        ):
            trans_scalar = mfdatascalar.MFScalarTransient(
                sim_data, model_or_sim, structure, enable, path, dimensions
            )
            if data is not None:
                trans_scalar.set_data(data, key=0)
            return trans_scalar
        elif data_type == mfstructure.DataType.array:
            return mfdataarray.MFArray(
                sim_data,
                model_or_sim,
                structure,
                data,
                enable,
                path,
                dimensions,
                self,
            )
        elif data_type == mfstructure.DataType.array_transient:
            trans_array = mfdataarray.MFTransientArray(
                sim_data,
                model_or_sim,
                structure,
                enable,
                path,
                dimensions,
                self,
            )
            if data is not None:
                trans_array.set_data(data, key=0)
            return trans_array
        elif data_type == mfstructure.DataType.list:
            return mfdatalist.MFList(
                sim_data,
                model_or_sim,
                structure,
                data,
                enable,
                path,
                dimensions,
                package,
                self,
            )
        elif data_type == mfstructure.DataType.list_transient:
            trans_list = mfdatalist.MFTransientList(
                sim_data,
                model_or_sim,
                structure,
                enable,
                path,
                dimensions,
                package,
                self,
            )
            if data is not None:
>               trans_list.set_data(data, key=0, autofill=True)

/data/mtoews/src/flopy/flopy/mf6/mfpackage.py:492: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {internal}
(rec.array([('HEAD', 'ALL', None)],
          dtype=[('rtype', 'O'), ('ocsetting', 'O'), ('ocsetting_data', 'O')]))

data = [('HEAD', 'ALL')], key = 0, autofill = True

    def set_data(self, data, key=None, autofill=False):
        """Sets the contents of the data at time `key` to `data`.
    
        Parameters
        ----------
        data : dict, recarray, list
            Data being set.  Data can be a dictionary with keys as
            zero-based stress periods and values as the data.  If data is
            a recarray or list of tuples, it will be assigned to the
            stress period specified in `key`.  If any is set to None, that
            stress period of data will be removed.
        key : int
            Zero based stress period to assign data too.  Does not apply
            if `data` is a dictionary.
        autofill : bool
            Automatically correct data.
        """
>       self._set_data_record(data, key, autofill)

/data/mtoews/src/flopy/flopy/mf6/data/mfdatalist.py:1828: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {internal}
(rec.array([('HEAD', 'ALL', None)],
          dtype=[('rtype', 'O'), ('ocsetting', 'O'), ('ocsetting_data', 'O')]))

data = [('HEAD', 'ALL')], key = 0, autofill = True, check_data = False
is_record = False

    def _set_data_record(
        self, data, key=None, autofill=False, check_data=False, is_record=False
    ):
        self._cache_model_grid = True
        if isinstance(data, dict):
            if "filename" not in data and "data" not in data:
                # each item in the dictionary is a list for one stress period
                # the dictionary key is the stress period the list is for
                del_keys = []
                for key, list_item in data.items():
                    if list_item is None:
                        self.remove_transient_key(key)
                        del_keys.append(key)
                        self.empty_keys[key] = False
                    elif isinstance(list_item, list) and len(list_item) == 0:
                        self.empty_keys[key] = True
                    else:
                        self.empty_keys[key] = False
                        if (
                            isinstance(list_item, dict)
                            and "check" in list_item
                        ):
                            check = list_item["check"]
                        else:
                            check = True
                        self._set_data_prep(list_item, key)
                        if is_record:
                            super().set_record(list_item, autofill, check_data)
                        else:
                            super().set_data(
                                list_item, autofill=autofill, check_data=check
                            )
                for key in del_keys:
                    del data[key]
            else:
                self.empty_keys[key] = False
                self._set_data_prep(data["data"], key)
                super().set_data(data, autofill)
        else:
            if is_record:
                comment = (
                    "Set record method requires that data_record is a "
                    "dictionary."
                )
                type_, value_, traceback_ = sys.exc_info()
                raise MFDataException(
                    self.structure.get_model(),
                    self.structure.get_package(),
                    self._path,
                    "setting data record",
                    self.structure.name,
                    inspect.stack()[0][3],
                    type_,
                    value_,
                    traceback_,
                    comment,
                    self._simulation_data.debug,
                )
            if key is None:
                # search for a key
                new_key_index = self.structure.first_non_keyword_index()
                if new_key_index is not None and len(data) > new_key_index:
                    key = data[new_key_index]
                else:
                    key = 0
            if isinstance(data, list) and len(data) == 0:
                self.empty_keys[key] = True
            else:
                check = True
                if (
                    isinstance(data, list)
                    and len(data) > 0
                    and data[0] == "no_check"
                ):
                    # not checking data
                    check = False
                    data = data[1:]
                self.empty_keys[key] = False
                if data is None:
                    self.remove_transient_key(key)
                else:
                    self._set_data_prep(data, key)
>                   super().set_data(data, autofill, check_data=check)

/data/mtoews/src/flopy/flopy/mf6/data/mfdatalist.py:1912: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {internal}
(rec.array([('HEAD', 'ALL', None)],
          dtype=[('rtype', 'O'), ('ocsetting', 'O'), ('ocsetting_data', 'O')]))

data = [('HEAD', 'ALL')], autofill = True, check_data = True

    def set_data(self, data, autofill=False, check_data=True):
        """Sets the contents of the data to "data".  Data can have the
        following formats:
            1) recarray - recarray containing the datalist
            2) [(line_one), (line_two), ...] - list where each line of the
               datalist is a tuple within the list
        If the data is transient, a dictionary can be used to specify each
        stress period where the dictionary key is <stress period> - 1 and
        the dictionary value is the datalist data defined above:
        {0:ndarray, 1:[(line_one), (line_two), ...], 2:{'filename':filename})
    
        Parameters
        ----------
            data : ndarray/list/dict
                Data to set
            autofill : bool
                Automatically correct data
            check_data : bool
                Whether to verify the data
    
        """
>       self._set_data(data, autofill, check_data=check_data)

/data/mtoews/src/flopy/flopy/mf6/data/mfdatalist.py:597: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {internal}
(rec.array([('HEAD', 'ALL', None)],
          dtype=[('rtype', 'O'), ('ocsetting', 'O'), ('ocsetting_data', 'O')]))

data = [('HEAD', 'ALL')], autofill = True, check_data = True
preserve_record = True

    def _set_data(
        self, data, autofill=False, check_data=True, preserve_record=True
    ):
        # set data
        self._resync()
        try:
            if self._get_storage_obj() is None:
                self._data_storage = self._new_storage()
            # store data
            self._get_storage_obj().set_data(
                data,
                autofill=autofill,
                check_data=check_data,
                preserve_record=preserve_record,
            )
        except Exception as ex:
            type_, value_, traceback_ = sys.exc_info()
            raise MFDataException(
                self.structure.get_model(),
                self.structure.get_package(),
                self._path,
                "setting data",
                self.structure.name,
                inspect.stack()[0][3],
                type_,
                value_,
                traceback_,
                None,
                self._simulation_data.debug,
                ex,
            )
        if check_data and self._simulation_data.verify_data:
            # verify cellids
>           self._check_valid_cellids()

/data/mtoews/src/flopy/flopy/mf6/data/mfdatalist.py:476: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {internal}
(rec.array([('HEAD', 'ALL', None)],
          dtype=[('rtype', 'O'), ('ocsetting', 'O'), ('ocsetting_data', 'O')]))


    def _check_valid_cellids(self):
        # only check packages that are a part of a model
>       if isinstance(self._model_or_sim, ModelInterface) and hasattr(
            self._model_or_sim, "modelgrid"
        ):

/data/mtoews/src/flopy/flopy/mf6/data/mfdatalist.py:480: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = name = model
model_type = gwf6
version = mf6
model_relative_path = .

###################
Package dis
################...####

package_name = oc
filename = model.oc
package_type = oc
model_or_simulation_package = model
model_name = model




    @property
    def modelgrid(self):
        """Model spatial discretization information.
    
        Returns
        -------
        model grid : Grid subclass
            FloPy object containing spatial discretization information for the
            model.
    
        """
    
        if not self._mg_resync:
            return self._modelgrid
        if self.get_grid_type() == DiscretizationType.DIS:
            dis = self.get_package("dis")
            if not hasattr(dis, "_init_complete"):
                if not hasattr(dis, "delr"):
                    # dis package has not yet been initialized
                    return self._modelgrid
                else:
                    # dis package has been partially initialized
                    self._modelgrid = StructuredGrid(
                        delc=dis.delc.array,
                        delr=dis.delr.array,
                        top=None,
                        botm=None,
                        idomain=None,
                        lenuni=None,
                        proj4=self._modelgrid.proj4,
                        epsg=self._modelgrid.epsg,
                        xoff=self._modelgrid.xoffset,
                        yoff=self._modelgrid.yoffset,
                        angrot=self._modelgrid.angrot,
                    )
            else:
                self._modelgrid = StructuredGrid(
                    delc=dis.delc.array,
                    delr=dis.delr.array,
                    top=dis.top.array,
                    botm=dis.botm.array,
>                   idomain=dis.idomain.array,
                    lenuni=dis.length_units.array,
                    proj4=self._modelgrid.proj4,
                    epsg=self._modelgrid.epsg,
                    xoff=self._modelgrid.xoffset,
                    yoff=self._modelgrid.yoffset,
                    angrot=self._modelgrid.angrot,

/data/mtoews/src/flopy/flopy/mf6/mfmodel.py:362: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {constant 1}


    @property
    def array(self):
        kwargs = {"array": True}
>       return self.get_data(apply_mult=True, **kwargs)

/data/mtoews/src/flopy/flopy/mf6/data/mfdata.py:286: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {constant 1}
, layer = None, apply_mult = True, kwargs = {'array': True}

    def get_data(self, layer=None, apply_mult=False, **kwargs):
        """Returns the data associated with layer "layer".  If "layer"
        is None, returns all data.
    
        Parameters
        ----------
            layer : int
    
        Returns
        -------
             data : ndarray
                Array data in an ndarray
    
        """
>       return self._get_data(layer, apply_mult, **kwargs)

/data/mtoews/src/flopy/flopy/mf6/data/mfdataarray.py:720: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = {constant 1}
, layer = None, apply_mult = True, kwargs = {'array': True}
storage = {constant 1}
, type_ = <class 'RuntimeWarning'>
value_ = RuntimeWarning('invalid value encountered in cast')
traceback_ = <traceback object at 0x7f6698da7ac0>

    def _get_data(self, layer=None, apply_mult=False, **kwargs):
        if self._get_storage_obj() is None:
            self._data_storage = self._new_storage(False)
        if isinstance(layer, int):
            layer = (layer,)
        storage = self._get_storage_obj()
        if storage is not None:
            try:
                data = storage.get_data(layer, apply_mult)
                if (
                    "array" in kwargs
                    and kwargs["array"]
                    and isinstance(self, MFTransientArray)
                    and data is not []
                ):
                    data = np.expand_dims(data, 0)
                return data
            except Exception as ex:
                type_, value_, traceback_ = sys.exc_info()
>               raise MFDataException(
                    self.structure.get_model(),
                    self.structure.get_package(),
                    self._path,
                    "getting data",
                    self.structure.name,
                    inspect.stack()[0][3],
                    type_,
                    value_,
                    traceback_,
                    None,
                    self._simulation_data.debug,
                    ex,
                )
E               flopy.mf6.mfbase.MFDataException: An error occurred in data element "idomain" model "gwf6" package "dis". The error occurred while getting data in the "_get_data" method.

/data/mtoews/src/flopy/flopy/mf6/data/mfdataarray.py:741: MFDataException

During handling of the above exception, another exception occurred:

    def test_this():
        sim = flopy.mf6.MFSimulation()
        _ = flopy.mf6.ModflowTdis(sim)
        gwf = flopy.mf6.ModflowGwf(sim)
        _ = flopy.mf6.ModflowIms(sim)
        _ = flopy.mf6.ModflowGwfdis(gwf, idomain=1)
>       _ = flopy.mf6.ModflowGwfoc(gwf, saverecord=[("HEAD", "ALL")])

test_this.py:9: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/data/mtoews/src/flopy/flopy/mf6/modflow/mfgwfoc.py:430: in __init__
    self.saverecord = self.build_mfdata("saverecord", saverecord)
/data/mtoews/src/flopy/flopy/mf6/mfpackage.py:2542: in build_mfdata
    ds = self.blocks[block.name].add_dataset(
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = 
dataset_struct = <flopy.mf6.data.mfstructure.MFDataStructure object at 0x7f6698f7c9a0>
data = [('HEAD', 'ALL')], var_path = ('model', 'oc', 'period', 'saverecord')

    def add_dataset(self, dataset_struct, data, var_path):
        """Add data to this block."""
        try:
            self.datasets[var_path[-1]] = self.data_factory(
                self._simulation_data,
                self._model_or_sim,
                dataset_struct,
                True,
                var_path,
                self._dimensions,
                data,
                self._container_package,
            )
        except MFDataException as mfde:
>           raise MFDataException(
                mfdata_except=mfde,
                model=self._container_package.model_name,
                package=self._container_package._get_pname(),
                message="Error occurred while adding"
                ' dataset "{}" to block '
                '"{}"'.format(dataset_struct.name, self.structure.name),
            )
E           flopy.mf6.mfbase.MFDataException: An error occurred in data element "idomain" model "model" package "oc". The error occurred while getting data in the "_get_data" method.
E           Additional Information:
E           (1) Error occurred while adding dataset "saverecord" to block "period"

/data/mtoews/src/flopy/flopy/mf6/mfpackage.py:596: MFDataException
=========================== short test summary info ============================
FAILED test_this.py::test_this - flopy.mf6.mfbase.MFDataException: An error occurred in data element "idomai...
============================== 1 failed in 1.08s ===============================

which shows that np.full has an int32 type with a fill value NaN, which is not possible. This PR evaluates the numpy data type, and chooses an appropriate fill value. I'm not 100% sure what these should be, so I've chosen 0 for integer, False for boolean, and None for other types.

@codecov
Copy link

codecov bot commented Jan 21, 2023

Codecov Report

Merging #1689 (7b202b8) into develop (2e6a7e1) will increase coverage by 0.0%.
The diff coverage is 66.6%.

@@           Coverage Diff           @@
##           develop   #1689   +/-   ##
=======================================
  Coverage     71.8%   71.9%           
=======================================
  Files          253     253           
  Lines        55881   55892   +11     
=======================================
+ Hits         40176   40188   +12     
+ Misses       15705   15704    -1     
Impacted Files Coverage Δ
flopy/mf6/data/mfdatastorage.py 70.5% <66.6%> (-0.1%) ⬇️
flopy/modflow/mfgmg.py 10.3% <0.0%> (-0.3%) ⬇️
flopy/modpath/mp7.py 85.0% <0.0%> (+<0.1%) ⬆️
flopy/utils/get_modflow.py 65.3% <0.0%> (+1.4%) ⬆️

@mwtoews
Copy link
Contributor Author

mwtoews commented Feb 13, 2023

Any feedback @spaulins-usgs ? This should be a quick one to review.

Copy link
Contributor

@spaulins-usgs spaulins-usgs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

@spaulins-usgs spaulins-usgs merged commit 940e690 into modflowpy:develop Feb 13, 2023
@mwtoews mwtoews deleted the numpy-full-fill-value branch February 14, 2023 07:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants