Coverage for C:\src\imod-python\imod\msw\meteo_mapping.py: 100%

52 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-08 14:15 +0200

1import numpy as np 

2import pandas as pd 

3import xarray as xr 

4 

5from imod.msw.fixed_format import VariableMetaData 

6from imod.msw.pkgbase import MetaSwapPackage 

7from imod.prepare import common 

8 

9 

10class MeteoMapping(MetaSwapPackage): 

11 """ 

12 This class provides common methods for creating mappings between 

13 meteorological data and MetaSWAP grids. It should not be instantiated 

14 by the user but rather be inherited from within imod-python to create 

15 new packages. 

16 """ 

17 

18 def __init__(self): 

19 super().__init__() 

20 

21 def _render(self, file, index, svat): 

22 data_dict = {"svat": svat.values.ravel()[index]} 

23 

24 row, column = self.grid_mapping(svat, self.meteo) 

25 

26 data_dict["row"] = row[index] 

27 data_dict["column"] = column[index] 

28 

29 dataframe = pd.DataFrame( 

30 data=data_dict, columns=list(self._metadata_dict.keys()) 

31 ) 

32 

33 self._check_range(dataframe) 

34 

35 return self.write_dataframe_fixed_width(file, dataframe) 

36 

37 @staticmethod 

38 def grid_mapping(svat: xr.DataArray, meteo_grid: xr.DataArray) -> pd.DataFrame: 

39 flip_meteo_x = meteo_grid.indexes["x"].is_monotonic_decreasing 

40 flip_meteo_y = meteo_grid.indexes["y"].is_monotonic_decreasing 

41 nrow = meteo_grid["y"].size 

42 ncol = meteo_grid["x"].size 

43 

44 # Convert to cell boundaries for the meteo grid 

45 # Method always returns monotonic increasing edges 

46 meteo_x = common._coord(meteo_grid, "x") 

47 meteo_y = common._coord(meteo_grid, "y") 

48 

49 # Create the SVAT grid 

50 svat_grid_y, svat_grid_x = np.meshgrid(svat.y, svat.x, indexing="ij") 

51 svat_grid_y = svat_grid_y.ravel() 

52 svat_grid_x = svat_grid_x.ravel() 

53 

54 # Determine where the svats fit in within the cell boundaries of the meteo grid 

55 row = np.searchsorted(meteo_y, svat_grid_y) 

56 column = np.searchsorted(meteo_x, svat_grid_x) 

57 

58 # Find out of bounds members 

59 if (column == 0).any() or (column > ncol).any(): 

60 raise ValueError("Some values are out of bounds for column") 

61 if (row == 0).any() or (row > nrow).any(): 

62 raise ValueError("Some values are out of bounds for row") 

63 

64 # Flip axis when meteofile bound are flipped, relative to the coords 

65 if flip_meteo_y: 

66 row = (nrow + 1) - row 

67 if flip_meteo_x: 

68 column = (ncol + 1) - column 

69 

70 n_subunit = svat["subunit"].size 

71 

72 return np.tile(row, n_subunit), np.tile(column, n_subunit) 

73 

74 

75class PrecipitationMapping(MeteoMapping): 

76 """ 

77 This contains the data to connect precipitation grid cells to MetaSWAP 

78 svats. The precipitation grid does not have to be equal to the metaswap 

79 grid: connections between the precipitation cells to svats will be 

80 established using a nearest neighbour lookup. 

81 

82 This class is responsible for the file `svat2precgrid.inp`. 

83 

84 Parameters 

85 ---------- 

86 precipitation: array of floats (xr.DataArray) 

87 Describes the precipitation data. The extend of the grid must be larger 

88 than the MetaSvap grid. The data must also be coarser than the MetaSvap 

89 grid. 

90 """ 

91 

92 _file_name = "svat2precgrid.inp" 

93 _metadata_dict = { 

94 "svat": VariableMetaData(10, None, None, int), 

95 "row": VariableMetaData(10, None, None, int), 

96 "column": VariableMetaData(10, None, None, int), 

97 } 

98 

99 def __init__( 

100 self, 

101 precipitation: xr.DataArray, 

102 ): 

103 super().__init__() 

104 self.meteo = precipitation 

105 

106 

107class EvapotranspirationMapping(MeteoMapping): 

108 """ 

109 This contains the data to connect evapotranspiration grid cells to MetaSWAP 

110 svats. The evapotranspiration grid does not have to be equal to the metaswap 

111 grid: connections between the evapotranspiration cells to svats will be 

112 established using a nearest neighbour lookup. 

113 

114 This class is responsible for the file `svat2etrefgrid.inp`. 

115 

116 Parameters 

117 ---------- 

118 evapotransporation: array of floats (xr.DataArray) 

119 Describes the evapotransporation data. The extend of the grid must be 

120 larger than the MetaSvap grid. The data must also be coarser than the 

121 MetaSvap grid. 

122 """ 

123 

124 _file_name = "svat2etrefgrid.inp" 

125 _metadata_dict = { 

126 "svat": VariableMetaData(10, None, None, int), 

127 "row": VariableMetaData(10, None, None, int), 

128 "column": VariableMetaData(10, None, None, int), 

129 } 

130 

131 def __init__( 

132 self, 

133 evapotranspiration: xr.DataArray, 

134 ): 

135 super().__init__() 

136 self.meteo = evapotranspiration