|
1 | 1 | import Oceananigans as OC |
2 | 2 | import ClimaOcean as CO |
| 3 | +import ClimaAtmos as CA |
3 | 4 | import ClimaCoupler: Checkpointer, FieldExchanger, FluxCalculator, Interfacer, Utilities |
4 | 5 | import ClimaComms |
5 | 6 | import ClimaCore as CC |
@@ -46,6 +47,9 @@ function OceananigansSimulation( |
46 | 47 | output_dir, |
47 | 48 | comms_ctx = ClimaComms.context(), |
48 | 49 | ) |
| 50 | + # using Dates |
| 51 | + # start_date = Dates.DateTime(2008) |
| 52 | + # stop_date = Dates.DateTime(2008, 1, 2) |
49 | 53 | arch = comms_ctx.device isa ClimaComms.CUDADevice ? OC.GPU() : OC.CPU() |
50 | 54 |
|
51 | 55 | # Retrieve EN4 data (monthly) |
@@ -102,13 +106,84 @@ function OceananigansSimulation( |
102 | 106 | OC.set!(ocean.model, T = en4_temperature[1], S = en4_salinity[1]) |
103 | 107 |
|
104 | 108 | # Construct a remapper from the exchange grid to `Center, Center` fields |
105 | | - long_cc = OC.λnodes(grid, OC.Center(), OC.Center(), OC.Center()) |
106 | | - lat_cc = OC.φnodes(grid, OC.Center(), OC.Center(), OC.Center()) |
| 109 | + |
| 110 | + # Tripolar to cubed sphere (fails currently) |
| 111 | + # long_oc = OC.λnodes(grid, OC.Center(), OC.Center(), OC.Center()) |
| 112 | + # lat_oc = OC.φnodes(grid, OC.Center(), OC.Center(), OC.Center()) |
| 113 | + |
| 114 | + T = OC.CenterField(grid) # field on tripolar grid |
| 115 | + OC.set!(T, en4_temperature[1]) |
| 116 | + coords_tripolar, _ = XESMF.extract_xesmf_coordinates_structure(T, T) |
107 | 117 |
|
108 | 118 | # Create a 2D matrix containing each lat/long combination as a LatLongPoint |
109 | 119 | # Note this must be done on CPU since the CC.Remapper module is not GPU-compatible |
110 | | - target_points_cc = Array(CC.Geometry.LatLongPoint.(lat_cc, long_cc)) |
| 120 | + # target_points_oc = Array(CC.Geometry.LatLongPoint.(lat_oc, long_oc)) |
| 121 | + |
| 122 | + # TODO double check these coords are on centers, get lat/lon bounds for each element |
| 123 | + # boundary_space = axes(area_fraction) |
| 124 | + boundary_space = CC.CommonSpaces.CubedSphereSpace( |
| 125 | + Float32; |
| 126 | + radius = 1.0, |
| 127 | + n_quad_points = 2, |
| 128 | + h_elem = 10, |
| 129 | + ) |
| 130 | + boundary_coords = CC.Fields.coordinate_field(boundary_space) |
| 131 | + boundary_lat_arr = CC.Fields.field2array(boundary_coords.lat) |
| 132 | + boundary_long_arr = CC.Fields.field2array(boundary_coords.long) |
| 133 | + coords_cubedsphere = Dict("lat" => boundary_lat_arr, "lon" => boundary_long_arr) |
| 134 | + |
| 135 | + regridder_tripolar_to_cubedsphere = |
| 136 | + XESMF.Regridder(coords_cubedsphere, coords_tripolar; method = "conservative") |
| 137 | + regridder_cubedsphere_to_tripolar = |
| 138 | + XESMF.Regridder(coords_tripolar, coords_cubedsphere; method = "conservative") |
| 139 | + |
| 140 | + # Tripolar to LatLon |
| 141 | + T = OC.CenterField(grid) # field on tripolar grid |
| 142 | + OC.set!(T, en4_temperature[1]) |
| 143 | + |
| 144 | + grid_latlon = OC.LatitudeLongitudeGrid( |
| 145 | + arch; |
| 146 | + size = (Nx, Ny, Nz), |
| 147 | + longitude = (0, 360), |
| 148 | + latitude = (-81, 90), |
| 149 | + z, |
| 150 | + ) |
| 151 | + field_latlon = OC.CenterField(grid_latlon) |
| 152 | + remapper_tripolar_to_latlon = XESMF.Regridder(T, field_latlon; method = "conservative") |
| 153 | + remapper_tripolar_to_latlon( |
| 154 | + vec(OC.interior(field_latlon, :, :, Nz)), |
| 155 | + vec(OC.interior(T, :, :, Nz)), |
| 156 | + ) |
| 157 | + OC.fill_halo_regions!(field_latlon) |
| 158 | + # heatmap(field_latlon) # using GeoMakie, using CairoMakie |
| 159 | + |
| 160 | + # LatLon to cubed sphere |
| 161 | + boundary_space = CC.CommonSpaces.CubedSphereSpace( |
| 162 | + Float32; |
| 163 | + radius = 1.0, |
| 164 | + n_quad_points = 2, |
| 165 | + h_elem = 10, |
| 166 | + ) |
| 167 | + field_cubedsphere = Interfacer.remap(field_latlon, boundary_space) |
| 168 | + # fieldheatmap(field_cubedsphere) # using ClimaCoreMakie |
| 169 | + |
| 170 | + # Cubed sphere to LatLon |
| 171 | + long_oc = OC.λnodes(grid_latlon, OC.Center(), OC.Center(), OC.Center()) |
| 172 | + lat_oc = OC.φnodes(grid_latlon, OC.Center(), OC.Center(), OC.Center()) |
| 173 | + long_oc = reshape(long_oc, length(long_oc), 1) |
| 174 | + lat_oc = reshape(lat_oc, 1, length(lat_oc)) |
| 175 | + target_points_oc = @. CC.Geometry.LatLongPoint(lat_oc, long_oc) |
| 176 | + |
| 177 | + remapper_cubedsphere_to_latlon = CC.Remapping.Remapper(boundary_space, target_points_oc) |
| 178 | + field_cubedsphere = CC.Fields.zeros(boundary_space) |
| 179 | + CC.Remapping.interpolate!( |
| 180 | + field_cubedsphere, |
| 181 | + remapper_cubedsphere_to_latlon, |
| 182 | + field_latlon, |
| 183 | + ) |
| 184 | + |
111 | 185 |
|
| 186 | + # Previous remapper for LatLon |
112 | 187 | if pkgversion(CC) >= v"0.14.34" |
113 | 188 | remapper_cc = CC.Remapping.Remapper(axes(area_fraction), target_points_cc) |
114 | 189 | else |
@@ -194,14 +269,14 @@ Interfacer.step!(sim::OceananigansSimulation, t) = |
194 | 269 |
|
195 | 270 | # We always want the surface, so we always set zero(pt.lat) for z |
196 | 271 | """ |
197 | | - to_node(pt::CA.ClimaCore.Geometry.LatLongPoint) |
| 272 | + to_node(pt::CCGeometry.LatLongPoint) |
198 | 273 |
|
199 | 274 | Transform `LatLongPoint` into a tuple (long, lat, 0), where the 0 is needed because we only |
200 | 275 | care about the surface. |
201 | 276 | """ |
202 | | -@inline to_node(pt::CA.ClimaCore.Geometry.LatLongPoint) = pt.long, pt.lat, zero(pt.lat) |
| 277 | +@inline to_node(pt::CC.Geometry.LatLongPoint) = pt.long, pt.lat, zero(pt.lat) |
203 | 278 | # This next one is needed if we have "LevelGrid" |
204 | | -@inline to_node(pt::CA.ClimaCore.Geometry.LatLongZPoint) = pt.long, pt.lat, zero(pt.lat) |
| 279 | +@inline to_node(pt::CC.Geometry.LatLongZPoint) = pt.long, pt.lat, zero(pt.lat) |
205 | 280 |
|
206 | 281 | """ |
207 | 282 | map_interpolate(points, oc_field::OC.Field) |
|
0 commit comments