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

Make the driver optional and provide entry points for composing ClimaAtmos simulations in Julia scripts Part I: AtmosGrids #2147

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

Sbozzolo
Copy link
Member

@Sbozzolo Sbozzolo commented Sep 22, 2023

This PR provides a user(/developer)-facing entry point to the computational grids used in ClimaAtmos.

When working on ClimaAtmos, it happens often that a user(/developer) wants to quickly build the computational grid where a simulation is run. For instance, I had to do this all the time when developing and testing the diagnostics.
Unfortunately, the primitives defined by ClimaCore are too low level to be directly helpful. On the other hand, there is no easy way to obtain the center/face spaces for the commonly used spaces in ClimaAtmos. In ClimaAtmos there is the function get_spaces for building the space. get_spaces takes in parsed_args, params, comms_ctx and returns a NamedTuple with the center and face spaces (among the other things). This function requires defining a parsed_args dictionary and fill it with the correct values, where "correct values" is a combination of values relevant for the configuration that one wants to build + other values (e.g., one always needs to pass dz_bottom even if we are working with uniform columns). Moreover, the function takes params (only to use the Earth's radius), which is a very complex object that cannot be easily created.

So, at the end, the easiest way I found to create the various spaces is to run get_integrator with some of the various configurations, and get the space from one of the fields in the integrator. However, this is non ideal because it is much more expensive and opaque that it needs to be and also because the method doesn't work when I am actively working on the code and get_integrator fails.

With this PR, one can directly create all the spaces commonly used in ClimaAtmos. For instance, to define a CubedSphere with DCMIP200 topography

import ClimaAtmos.Grids as CA
sphere = CA.Grid.Sphere(;
            nh_poly = 3,
            h_elem = 6,
            z_elem = 10,
            radius = 6_200_000,
            z_max = 30000,
            dz_bottom = 500,
            dz_top = 1000,
            float_type = Float64,
            enable_bubble = true,
            topography = CA.topography_dcmip200,
        )
println(summary(sphere))
# Grid type: SphereGrid
# Number of vertical elements: 10
# Height: 30000.0 meters
# Vertical grid stretching: GeneralizedExponentialStretching
#   with: dz_bottom: 500.0
#   with: dz_top: 5000.0
# Radius: 100.0 meters
# Horizontal elements per edge: 6
#   with: 3-degree polynomials
#   with: bubble correction
#   with: topography_dcmpi200 topography

sphere contains center_space and face_space (sphere.center_space, sphere_face_space).

This PR addresses a second issue: the computational grid is a key object in any numerical simulation, but I think the ClimaCore Spaces are not the right level of abstraction for the higher-level interfaces of ClimaAtmos. For instance, to find what is the height of my simulated columns, one needs to do something like

center_space.vertical_topology.mesh.domain.coord_max.z

It also is not easy to know what configuration is being simulated and one needs to know the details of Meshes and Domain. An example of this problem is manifested by the fact that we have a model_config field in the AtmosModel. model_config is just sphere, box, plane, or column, an information that should already be readily available. This PR defines the physically-relevant abstraction that most scientists will care about.

In summary, this PR

  • is non-breaking and perfectly compatible with current ClimaAtmos (as tested in the unit and integration tests),
  • ensures that only the parameters that are needed for a given configuration are required in parsed_args in get_spaces,
  • decouples the generation of spaces relevant to ClimaAtmos from processing arguments and parameters, providing a way to build and work with important spaces, and improves the entangled logic in get_spaces,
  • provides a physically-relevant abstraction for the computational grid,
  • is a step in the direction of making the driver optional.

@Sbozzolo Sbozzolo added enhancement New feature or request WIP do-not-merge-yet Block from bors API Interface labels Sep 22, 2023
@szy21 szy21 removed WIP labels Sep 22, 2023
@Sbozzolo Sbozzolo force-pushed the gb/interface_script_ready branch from 9531190 to 327b1d1 Compare October 3, 2023 15:47
@Sbozzolo Sbozzolo force-pushed the gb/interface_script_ready branch from 327b1d1 to 447b36b Compare October 3, 2023 17:52
@Sbozzolo Sbozzolo force-pushed the gb/interface_script_ready branch from 447b36b to 5ab4b9d Compare October 3, 2023 22:59
@Sbozzolo Sbozzolo changed the title Make the driver optional and provide entry points for composing ClimaAtmos simulations in Julia scripts Make the driver optional and provide entry points for composing ClimaAtmos simulations in Julia scripts Part I: AtmosGrids Oct 3, 2023
@@ -0,0 +1,701 @@
# This file contains the definitions of common AbstractAtmosGrids.
Copy link
Member

Choose a reason for hiding this comment

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

In terms of scope, these functions are just wrappers around ClimaCore objects, which leads me to think: should we just define these helper functions in ClimaCore? (otherwise we may end up repeating these patterns in the land) cc @simonbyrne

Keyword arguments
=================

- `nh_poly`: Horizontal polynomial degree.
Copy link
Member

Choose a reason for hiding this comment

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

Should we give this a better name? (put degree in it somewhere?)


- `nh_poly`: Horizontal polynomial degree.
- `radius`: Radius of the sphere (in meters).
- `h_elem`: Number of spectral elements per edge.
Copy link
Member

Choose a reason for hiding this comment

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

a more descriptive name? it's defined as the "number of elements across each panel of the cubed sphere"

Comment on lines +408 to +411
- `x_elem`: Number of spectral elements on the x direction.
- `x_max`: Length of the box (in meters) (`x_min` is 0).
- `y_elem`: Number of spectral elements on the y direction.
- `y_max`: Depth of the box (in meters) (`y_min` is 0).
Copy link
Member

Choose a reason for hiding this comment

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

these don't apply to the cubed sphere.

Comment on lines +412 to +415
- `z_elem`: Number of spectral elements on the vertical direction.
- `dz_bottom`: Resolution at the lower end of the column (in meters).
- `dz_top`: Resolution at the top end of the column (in meters).
- `z_max`: Height of the column (in meters).
Copy link
Member

Choose a reason for hiding this comment

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

How about we provide two options:

  1. a simple z_grid which takes in the column grid object,
  2. pass any other arguments to the column grid constructor
  • If we just provide z_elem and z_max, it should be a uniform grid.
  • if we provide the dz_X args, it should give a stretched grid

Comment on lines +416 to +417
- `topography`: Define the surface elevation profile. Provided as a warp function (or nothing).
- `topo_smoothing`: Whether to order-2 smoothing on the LGL mesh.
Copy link
Member

Choose a reason for hiding this comment

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

First thing to figure out is what topography we want to support. Currently we have

@assert topography in ("NoWarp", "DCMIP200", "Earth", "Agnesi", "Schar")

  • no topography

  • analytic cases

    • box/plane: Schar, Agnesi
    • sphere: DCMIP200, mountain from shallow water case (not in ClimaAtmos)
  • from data file

    • is preprocessed, with initial filtering applied to the data on the file lat/long grid ("smoothing_order")
      • elseif topography == "Earth"
        data_path = joinpath(topo_elev_dataset_path(), "ETOPO1_coarse.nc")
        earth_spline = NCDatasets.NCDataset(data_path) do data
        zlevels = Array(data["elevation"])
        lon = Array(data["longitude"])
        lat = Array(data["latitude"])
        # Apply Smoothing
        smooth_degree = Int(parsed_args["smoothing_order"])
        esmth = imfilter(zlevels, Kernel.gaussian(smooth_degree))
        linear_interpolation(
        (lon, lat),
        esmth,
        extrapolation_bc = (Periodic(), Flat()),
        )
        end
        @info "Generated interpolation stencil"
        warp_function = generate_topography_warp(earth_spline)
    • interpolated to cubed sphere, with additional smoothing applied after via"topo_smoothing"

@Sbozzolo
Copy link
Member Author

Closed in favor of CliMA/ClimaCore.jl#1848

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API do-not-merge-yet Block from bors enhancement New feature or request Interface
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants