|
25 | 25 | ep2ap, |
26 | 26 | rotate, |
27 | 27 | find_files_by_pattern, |
| 28 | + try_pint_convert, |
28 | 29 | ) |
29 | 30 |
|
30 | | - |
31 | 31 | warnings.filterwarnings("ignore") |
32 | 32 |
|
33 | 33 | __all__ = [ |
|
39 | 39 | "get_glorys_data", |
40 | 40 | ] |
41 | 41 |
|
| 42 | +# If the array is pint possible, ensure we have the right units for main fields (eta, u, v, temp), |
| 43 | +# salinity and bgc tracers are a bit more abstract and should be already in the correct units, a TODO: would be to add functionality to convert these tracers |
| 44 | +main_field_target_units = { |
| 45 | + "eta": "m", |
| 46 | + "u": "m/s", |
| 47 | + "v": "m/s", |
| 48 | + "temp": "degC", |
| 49 | +} |
42 | 50 |
|
43 | 51 | ## Mapping Functions |
44 | 52 |
|
@@ -135,7 +143,6 @@ def longitude_slicer(data, longitude_extent, longitude_coords): |
135 | 143 |
|
136 | 144 | for i in range(-1, 2, 1): |
137 | 145 | if data[lon][0] <= central_longitude + 360 * i <= data[lon][-1]: |
138 | | - |
139 | 146 | ## Shifted version of target midpoint; e.g., could be -90 vs 270 |
140 | 147 | ## integer i keeps track of what how many multiples of 360 we need to shift entire |
141 | 148 | ## grid by to match central_longitude |
@@ -231,11 +238,9 @@ def get_glorys_data( |
231 | 238 |
|
232 | 239 | file = open(Path(path / "get_glorys_data.sh"), "w") |
233 | 240 |
|
234 | | - lines.append( |
235 | | - f""" |
| 241 | + lines.append(f""" |
236 | 242 | copernicusmarine subset --dataset-id cmems_mod_glo_phy_my_0.083deg_P1D-m --variable so --variable thetao --variable uo --variable vo --variable zos --start-datetime {str(timerange[0]).replace(" ","T")} --end-datetime {str(timerange[1]).replace(" ","T")} --minimum-longitude {longitude_extent[0] - buffer} --maximum-longitude {longitude_extent[1] + buffer} --minimum-latitude {latitude_extent[0] - buffer} --maximum-latitude {latitude_extent[1] + buffer} --minimum-depth 0 --maximum-depth 6000 -o {str(path)} -f {segment_name}.nc\n |
237 | | -""" |
238 | | - ) |
| 243 | +""") |
239 | 244 | file.writelines(lines) |
240 | 245 | file.close() |
241 | 246 | return Path(path / "get_glorys_data.sh") |
@@ -607,7 +612,6 @@ def __init__( |
607 | 612 | regridding_method="bilinear", |
608 | 613 | fill_method=rgd.fill_missing_data, |
609 | 614 | ): |
610 | | - |
611 | 615 | # Creates an empty experiment object for testing and experienced user manipulation. |
612 | 616 | if create_empty: |
613 | 617 | return |
@@ -830,7 +834,6 @@ def bathymetry_path(self): |
830 | 834 | return "Not Found" |
831 | 835 |
|
832 | 836 | def __getattr__(self, name): |
833 | | - |
834 | 837 | ## First, check whether the attribute is an input file |
835 | 838 | if "segment" in name: |
836 | 839 | try: |
@@ -904,7 +907,6 @@ def _make_hgrid(self): |
904 | 907 | ), "only even_spacing grid type is implemented" |
905 | 908 |
|
906 | 909 | if self.hgrid_type == "even_spacing": |
907 | | - |
908 | 910 | # longitudes are evenly spaced based on resolution and bounds |
909 | 911 | nx = int( |
910 | 912 | (self.longitude_extent[1] - self.longitude_extent[0]) |
@@ -1023,6 +1025,22 @@ def setup_initial_condition( |
1023 | 1025 | if type(reprocessed_var_map["depth_coord"]) == list: |
1024 | 1026 | reprocessed_var_map["depth_coord"] = reprocessed_var_map["depth_coord"][0] |
1025 | 1027 |
|
| 1028 | + # Convert zdim if possible & needed |
| 1029 | + ic_raw[reprocessed_var_map["depth_coord"]] = try_pint_convert( |
| 1030 | + ic_raw[reprocessed_var_map["depth_coord"]], |
| 1031 | + "m", |
| 1032 | + reprocessed_var_map["depth_coord"], |
| 1033 | + ) |
| 1034 | + |
| 1035 | + # Convert values |
| 1036 | + for var in main_field_target_units: |
| 1037 | + if var == "temp" or var == "salt": |
| 1038 | + value_name = reprocessed_var_map["tracer_var_names"][var] |
| 1039 | + else: |
| 1040 | + value_name = reprocessed_var_map[var + "_var_name"] |
| 1041 | + ic_raw[value_name] = try_pint_convert( |
| 1042 | + ic_raw[value_name], main_field_target_units[var], var |
| 1043 | + ) |
1026 | 1044 | # Remove time dimension if present in the IC. |
1027 | 1045 | # Assume that the first time dim is the intended one if more than one is present |
1028 | 1046 |
|
@@ -1060,6 +1078,8 @@ def setup_initial_condition( |
1060 | 1078 |
|
1061 | 1079 | ## if min(temperature) > 100 then assume that units must be degrees K |
1062 | 1080 | ## (otherwise we can't be on Earth) and convert to degrees C |
| 1081 | + ## Although we now attempt a pint convert, we're leaving this manual conversion in for now |
| 1082 | + ## just in case, as K->C is absolutely necessary, and for some inputs pint may fail where this won't. |
1063 | 1083 | if np.nanmin(ic_raw[reprocessed_var_map["tracer_var_names"]["temp"]]) > 100: |
1064 | 1084 | ic_raw[reprocessed_var_map["tracer_var_names"]["temp"]] -= 273.15 |
1065 | 1085 | ic_raw[reprocessed_var_map["tracer_var_names"]["temp"]].attrs[ |
@@ -2377,7 +2397,6 @@ def setup_run_directory( |
2377 | 2397 | ) |
2378 | 2398 | # Tides OBC adjustments |
2379 | 2399 | if with_tides: |
2380 | | - |
2381 | 2400 | # Include internal tide forcing |
2382 | 2401 | MOM_override_dict["TIDES"]["value"] = "True" |
2383 | 2402 |
|
@@ -2655,6 +2674,14 @@ def regrid_velocity_tracers( |
2655 | 2674 |
|
2656 | 2675 | coords = rgd.coords(self.hgrid, self.orientation, self.segment_name) |
2657 | 2676 |
|
| 2677 | + # Convert z coordinates to meters if pint-enabled |
| 2678 | + if type(reprocessed_var_map["depth_coord"]) != list: |
| 2679 | + dc_list = [reprocessed_var_map["depth_coord"]] |
| 2680 | + else: |
| 2681 | + dc_list = reprocessed_var_map["depth_coord"] |
| 2682 | + for dc in dc_list: |
| 2683 | + rawseg[dc] = try_pint_convert(rawseg[dc], "m", dc) |
| 2684 | + |
2658 | 2685 | regridders = create_vt_regridders( |
2659 | 2686 | reprocessed_var_map, |
2660 | 2687 | rawseg, |
@@ -2789,6 +2816,17 @@ def regrid_velocity_tracers( |
2789 | 2816 | ## Rename each variable in dataset |
2790 | 2817 | segment_out = segment_out.rename({allfields[var]: v}) |
2791 | 2818 |
|
| 2819 | + # Try Pint Conversion |
| 2820 | + if var in main_field_target_units: |
| 2821 | + # Apply raw data units if they exist |
| 2822 | + units = rawseg[allfields[var]].attrs.get("units") |
| 2823 | + if units is not None: |
| 2824 | + segment_out[v].attrs["units"] = units |
| 2825 | + |
| 2826 | + segment_out[v] = try_pint_convert( |
| 2827 | + segment_out[v], main_field_target_units[var], var |
| 2828 | + ) |
| 2829 | + |
2792 | 2830 | # Find out if the tracer has depth, and if so, what is it's z dimension (z dimension being a list is an edge case for MARBL BGC) |
2793 | 2831 | variable_has_depth = False |
2794 | 2832 | depth_coord = None |
@@ -3093,7 +3131,6 @@ def encode_tidal_files_and_output(self, ds, filename): |
3093 | 3131 | ## Expand Tidal Dimensions ## |
3094 | 3132 |
|
3095 | 3133 | for var in ds: |
3096 | | - |
3097 | 3134 | ds = rgd.add_secondary_dimension(ds, str(var), coords, self.segment_name) |
3098 | 3135 |
|
3099 | 3136 | ## Rename Tidal Dimensions ## |
|
0 commit comments