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

54 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-08 10:26 +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_svat_x = svat.indexes["x"].is_monotonic_decreasing 

40 flip_svat_y = svat.indexes["y"].is_monotonic_decreasing 

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

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

43 nrow = meteo_grid["y"].size 

44 ncol = meteo_grid["x"].size 

45 

46 # Convert to cell boundaries for the meteo grid 

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

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

49 

50 # Create the SVAT grid 

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

52 svat_grid_y = svat_grid_y.ravel() 

53 svat_grid_x = svat_grid_x.ravel() 

54 

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

56 row = np.searchsorted(meteo_y, svat_grid_y) 

57 column = np.searchsorted(meteo_x, svat_grid_x) 

58 

59 # Find out of bounds members 

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

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

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

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

64 

65 # Flip axis if necessary 

66 if flip_meteo_y ^ flip_svat_y: 

67 row = (nrow + 1) - row 

68 if flip_meteo_x ^ flip_svat_x: 

69 column = (ncol + 1) - column 

70 

71 n_subunit = svat["subunit"].size 

72 

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

74 

75 

76class PrecipitationMapping(MeteoMapping): 

77 """ 

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

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

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

81 established using a nearest neighbour lookup. 

82 

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

84 

85 Parameters 

86 ---------- 

87 precipitation: array of floats (xr.DataArray) 

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

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

90 grid. 

91 """ 

92 

93 _file_name = "svat2precgrid.inp" 

94 _metadata_dict = { 

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

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

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

98 } 

99 

100 def __init__( 

101 self, 

102 precipitation: xr.DataArray, 

103 ): 

104 super().__init__() 

105 self.meteo = precipitation 

106 

107 

108class EvapotranspirationMapping(MeteoMapping): 

109 """ 

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

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

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

113 established using a nearest neighbour lookup. 

114 

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

116 

117 Parameters 

118 ---------- 

119 evapotransporation: array of floats (xr.DataArray) 

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

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

122 MetaSvap grid. 

123 """ 

124 

125 _file_name = "svat2etrefgrid.inp" 

126 _metadata_dict = { 

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

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

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

130 } 

131 

132 def __init__( 

133 self, 

134 evapotranspiration: xr.DataArray, 

135 ): 

136 super().__init__() 

137 self.meteo = evapotranspiration