From 55b85b1d452bb38ef335762911e0b0cac5ae11f2 Mon Sep 17 00:00:00 2001 From: sit23 Date: Tue, 14 May 2019 16:15:15 +0100 Subject: [PATCH 01/24] Added code necessary to run shallow water and barotropic vorticity codes to Isca. Downloaded necessary files from ftp://ftp.gfdl.noaa.gov/perm/GFDL_pubrelease/Spectral_Idealized_Atmospheric_Models/spectral_idealized_public_release.tar.gz on 14/05/19. --- src/atmos_spectral_barotropic/atmosphere.F90 | 246 +++++++ src/atmos_spectral_barotropic/atmosphere.html | 174 +++++ src/atmos_spectral_barotropic/barotropic.pdf | Bin 0 -> 80013 bytes .../barotropic_diagnostics.F90 | 152 +++++ .../barotropic_diagnostics.html | 152 +++++ .../barotropic_dynamics.F90 | 573 +++++++++++++++++ .../barotropic_dynamics.html | 371 +++++++++++ .../barotropic_physics.F90 | 173 +++++ .../barotropic_physics.html | 165 +++++ src/atmos_spectral_barotropic/stirring.F90 | 252 ++++++++ src/atmos_spectral_shallow/atmosphere.F90 | 279 ++++++++ src/atmos_spectral_shallow/atmosphere.html | 164 +++++ src/atmos_spectral_shallow/shallow.pdf | Bin 0 -> 62941 bytes .../shallow_diagnostics.F90 | 139 ++++ .../shallow_diagnostics.html | 150 +++++ .../shallow_dynamics.F90 | 607 ++++++++++++++++++ .../shallow_dynamics.html | 370 +++++++++++ .../shallow_physics.F90 | 232 +++++++ .../shallow_physics.html | 210 ++++++ 19 files changed, 4409 insertions(+) create mode 100644 src/atmos_spectral_barotropic/atmosphere.F90 create mode 100644 src/atmos_spectral_barotropic/atmosphere.html create mode 100644 src/atmos_spectral_barotropic/barotropic.pdf create mode 100644 src/atmos_spectral_barotropic/barotropic_diagnostics.F90 create mode 100644 src/atmos_spectral_barotropic/barotropic_diagnostics.html create mode 100644 src/atmos_spectral_barotropic/barotropic_dynamics.F90 create mode 100644 src/atmos_spectral_barotropic/barotropic_dynamics.html create mode 100644 src/atmos_spectral_barotropic/barotropic_physics.F90 create mode 100644 src/atmos_spectral_barotropic/barotropic_physics.html create mode 100644 src/atmos_spectral_barotropic/stirring.F90 create mode 100644 src/atmos_spectral_shallow/atmosphere.F90 create mode 100644 src/atmos_spectral_shallow/atmosphere.html create mode 100644 src/atmos_spectral_shallow/shallow.pdf create mode 100644 src/atmos_spectral_shallow/shallow_diagnostics.F90 create mode 100644 src/atmos_spectral_shallow/shallow_diagnostics.html create mode 100644 src/atmos_spectral_shallow/shallow_dynamics.F90 create mode 100644 src/atmos_spectral_shallow/shallow_dynamics.html create mode 100644 src/atmos_spectral_shallow/shallow_physics.F90 create mode 100644 src/atmos_spectral_shallow/shallow_physics.html diff --git a/src/atmos_spectral_barotropic/atmosphere.F90 b/src/atmos_spectral_barotropic/atmosphere.F90 new file mode 100644 index 000000000..40a01ebb1 --- /dev/null +++ b/src/atmos_spectral_barotropic/atmosphere.F90 @@ -0,0 +1,246 @@ +module atmosphere_mod + +!----------------------------------------------------------------------- +! GNU General Public License +! +! This program is free software; you can redistribute it and/or modify it and +! are expected to follow the terms of the GNU General Public License +! as published by the Free Software Foundation; either version 2 of +! the License, or (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, but WITHOUT +! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +! License for more details. +! +! For the full text of the GNU General Public License, +! write to: Free Software Foundation, Inc., +! 675 Mass Ave, Cambridge, MA 02139, USA. +! or see: http://www.gnu.org/licenses/gpl.html +!----------------------------------------------------------------------- + +use fms_mod, only: open_namelist_file, & + open_restart_file, & + file_exist, & + check_nml_error, & + error_mesg, & + FATAL, WARNING, & + write_version_number, & + mpp_pe, & + mpp_root_pe, & + close_file, & + stdlog, stdout + +use transforms_mod, only: get_deg_lon, & + get_deg_lat, & + get_grid_boundaries, & + get_grid_domain, & + get_spec_domain, & + area_weighted_global_mean, & + atmosphere_domain + +use time_manager_mod, only: time_type, & + set_time, & + get_time, & + interval_alarm, & + operator(+), & + operator(<), & + operator(==) + +use barotropic_dynamics_mod, only: barotropic_dynamics_init, & + barotropic_dynamics, & + barotropic_dynamics_end, & + dynamics_type + +use barotropic_physics_mod, only: barotropic_physics_init, & + barotropic_physics, & + barotropic_physics_end, & + phys_type + +use diag_manager_mod, only: diag_manager_init, & + diag_manager_end + +use barotropic_diagnostics_mod, only: barotropic_diagnostics_init, & + barotropic_diagnostics + +!======================================================================== +implicit none +private +!======================================================================== + +! version information +!======================================================================== +character(len=128) :: version = '$Id: atmosphere.F90,v 17.0 2009/07/21 03:00:15 fms Exp $' +character(len=128) :: tagname = '$Name: siena_201207 $' +!======================================================================== + +public :: atmosphere_init, & + atmosphere, & + atmosphere_end, & + atmosphere_domain + +!======================================================================== + +integer :: unit, seconds, days +integer :: pe, npes, itmp, m, n +integer :: previous, current, future +logical :: root + +integer :: dt_integer +real :: dt_real +type(time_type) :: dt_time_type, Time_init, Time_step + +real :: delta_t ! = 2*dt_real for leapfrog step + +type(phys_type), save :: Phys +type(dynamics_type), save :: Dyn + +integer :: is, ie, js, je, ms, me, ns, ne +integer :: num_lon, num_lat + +logical :: module_is_initialized =.false. + +integer :: print_interval=86400 + +! namelist +!======================================================================== +namelist /atmosphere_nml/ print_interval +!======================================================================== + +contains +!======================================================================= + +subroutine atmosphere_init(Time_init_in, Time, Time_step_in) + +type (time_type), intent(in) :: Time_init_in, Time, Time_step_in + +integer :: i, j, n, nn, ierr, io, unit +integer :: nlon, nlat +integer :: id_lon, id_lat, id_lonb, id_latb + +pe = mpp_pe() +root = (pe == mpp_root_pe()) + +Time_step = Time_step_in +call get_time( Time_step, seconds, days) +dt_integer = 86400*days + seconds +dt_real = float(dt_integer) +dt_time_type = Time_step +Time_init = Time_init_in + +! read the namelist + +if (file_exist('input.nml')) then + unit = open_namelist_file () + ierr=1 + do while (ierr /= 0) + read (unit, nml=atmosphere_nml, iostat=io, end=10) + ierr = check_nml_error (io, 'atmosphere_nml') + enddo + 10 call close_file (unit) +endif +call write_version_number(version, tagname) +if (root) write (stdlog(), nml=atmosphere_nml) + +call barotropic_dynamics_init (Dyn, Time, Time_init, dt_real, id_lon, id_lat, id_lonb, id_latb) + +call get_grid_domain(is,ie,js,je) +call get_spec_domain(ms,me,ns,ne) + +num_lon = Dyn%num_lon +num_lat = Dyn%num_lat + +nlon = ie+1-is ! size of grid on each processor +nlat = je+1-js + +call barotropic_physics_init(Phys) +call barotropic_diagnostics_init(Time, num_lon, num_lat, id_lon, id_lat, id_lonb, id_latb) + +if(Time == Time_init) then + previous = 1 + current = 1 ! starting with a forward step before settling into leapfrog +else + previous = 1 + current = 2 +endif + +module_is_initialized = .true. + +return +end subroutine atmosphere_init + +!===================================================================== + +subroutine atmosphere(Time) + +type (time_type), intent(in) :: Time +integer :: day, second, dt +real :: energy, enstrophy + +if(.not.module_is_initialized) then + call error_mesg('atmosphere', & + 'atmosphere_init has not been called', FATAL) +end if + +call get_time(Time_step, second, day) +dt = second + 86400*day + +Dyn%Tend%u = 0.0 +Dyn%Tend%v = 0.0 +if(Dyn%grid_tracer) Dyn%Tend%tr = 0.0 +if(Dyn%spec_tracer) Dyn%Tend%trs = 0.0 + +if(Time == Time_init) then + delta_t = dt_real + future = 2 +else + delta_t = 2.0*dt_real + future = previous +endif + +call barotropic_physics(Time, & + Dyn%Tend%u, Dyn%Tend%v, & + Dyn%Grid%u, Dyn%Grid%v, & + delta_t, previous, current, & + Phys) + +call barotropic_dynamics(Time, Time_init, & + Dyn, previous, current, future, delta_t) + +previous = current +current = future + +call barotropic_diagnostics (Time+Time_step, Dyn, Phys, current) + +enstrophy = area_weighted_global_mean(Dyn%grid%vor(:,:,current)*Dyn%grid%vor(:,:,previous)) +energy = -area_weighted_global_mean(Dyn%grid%stream*Dyn%grid%vor(:,:,previous)) + +if(root) then + call get_time(Time+Time_step, second, day) + if(mod(second+86400*day, print_interval) < dt) then + write(stdout(),1000) day, second, energy, enstrophy + end if +end if +1000 format(1x, 'day =',i6,2x,'second =', i6,2x,'energy = ',e13.6,3x,'enstrophy = ',e13.6) + +return +end subroutine atmosphere + +!======================================================================================= + +subroutine atmosphere_end + +if(.not.module_is_initialized) then + call error_mesg('atmosphere_end', & + 'atmosphere_init has not been called.', FATAL) +end if + +call barotropic_physics_end (Phys) +call barotropic_dynamics_end (Dyn, previous, current) +module_is_initialized = .false. + +return +end subroutine atmosphere_end + +!======================================================================================= +end module atmosphere_mod diff --git a/src/atmos_spectral_barotropic/atmosphere.html b/src/atmos_spectral_barotropic/atmosphere.html new file mode 100644 index 000000000..7b937f1f1 --- /dev/null +++ b/src/atmos_spectral_barotropic/atmosphere.html @@ -0,0 +1,174 @@ + +module atmosphere_mod + + +
+PUBLIC INTERFACE / +DATA / +ROUTINES / +NAMELIST / +ERRORS + +


+ +

module atmosphere_mod

+ + +
+     Contact: Isaac Held
+     Reviewers: Peter Phillipps
+
+
+ + +
+

OVERVIEW

+ +
+   A spectral transform model for two-dimensional, non-divergent flow on the
+   surface of the sphere.  
+
+
+ + +
+

DESCRIPTION

+ +
+   Integrates the barotropic vorticity equation for nondivergent flow on the
+   sphere using the spectral transform technique.  Also allows for the
+   inclusion of a passive tracer advected by the same spectral advection
+   algorithm as  the vorticity, and a gridpoint tracer advected with a finite
+   volume  algorithm on the transform grid.  The default initial condition 
+   provided as an example is a zonal flow resembling that in the Northern
+   winter,  plus a sinusoidal disurbance localized in midlatitudes.
+
+   For a full description of the model and algorithms used, see barotropic.ps
+
+   The interfaces in this module are the generic intefaces required by the
+   main program that can be used to drive various idealized atmospheric
+   models within FMS. Model resolution and related paramters are set in
+   namelists within the modules barotropic_xxx.
+
+ + + +
+

OTHER MODULES USED

+ +
+     fms_mod
+     constants_mod
+     transforms_mod
+     time_manager_mod
+     diag_manager_mod
+     barotropic_dynamics_mod
+     barotropic_physics_mod
+     barotopic_diagnostics_mod
+
+
+ + +
+

PUBLIC INTERFACE

+ +
+
+  use atmosphere_mod [,only: atmosphere_init,       
+                             atmosphere,
+			     atmosphere_end]
+                                
+
+
+ + +
+

PUBLIC DATA

+ +
+     
+  There are no pubic data types
+ 
+
+
+ + +
+

PUBLIC ROUTINES

+ +
+
+subroutine atmosphere_init. Initializes the model.
+subroutine atmosphere.      Integrates forward one time step
+subroutine atmosphere_end.  Terminates model, cleaning up memory and finalizing diagnostics.
+
+
+
+
+ subroutine atmosphere_init(Time_init, Time, Time_step)
+
+    input:
+ 
+    type(time_type) :: Time_init -- Initial model time
+
+    type(time_type) :: Time      -- Model time
+
+    type(time_type) :: Time_step -- Time step
+       
+    When Time=Time_init, the first time step is a forward
+    step rather than leap frog because a cold start is assumed.
+
+    The FMS main program that runs the solo atmospheric models
+    obtains Time_init from the diag_table and Time from its namelist.
+
+
+
+ + + subroutine atmosphere(Time) + + input: + + type(time_type) :: Time -- Model time + + Integrates forward one time step + + +
+ + subroutine atmosphere_end(Atmos) + + No calling arguments. + + Terminates model, cleaning up memory and finalizing diagnostics + + +
+
+ + +

NAMELIST

+ +
+&atmosphere_nml
+
+   print_interval, integer : time interval in seconds 
+   between prints of global mean energy and enstrophy to standard output
+
+
+ + +
+

ERROR MESSAGES

+ +
+
+  Fatal error message if any public routine is called prior to atmosphere_init
+
+
+
+ + +
+ + diff --git a/src/atmos_spectral_barotropic/barotropic.pdf b/src/atmos_spectral_barotropic/barotropic.pdf new file mode 100644 index 0000000000000000000000000000000000000000..454e56389ee1c928fa8504acd2da98eec8ca41a4 GIT binary patch literal 80013 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 literal 0 HcmV?d00001 diff --git a/src/atmos_spectral_barotropic/barotropic_diagnostics.F90 b/src/atmos_spectral_barotropic/barotropic_diagnostics.F90 new file mode 100644 index 000000000..69cfc096e --- /dev/null +++ b/src/atmos_spectral_barotropic/barotropic_diagnostics.F90 @@ -0,0 +1,152 @@ + +module barotropic_diagnostics_mod + +!----------------------------------------------------------------------- +! GNU General Public License +! +! This program is free software; you can redistribute it and/or modify it and +! are expected to follow the terms of the GNU General Public License +! as published by the Free Software Foundation; either version 2 of +! the License, or (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, but WITHOUT +! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +! License for more details. +! +! For the full text of the GNU General Public License, +! write to: Free Software Foundation, Inc., +! 675 Mass Ave, Cambridge, MA 02139, USA. +! or see: http://www.gnu.org/licenses/gpl.html +!----------------------------------------------------------------------- + +use fms_mod, only: write_version_number, & + mpp_pe, & + mpp_root_pe, & + error_mesg, FATAL + +use transforms_mod, only: get_grid_domain, & + get_spec_domain, & + grid_domain, & + trans_spherical_to_grid + +use diag_manager_mod, only: register_diag_field, & + register_static_field, & + send_data + +use time_manager_mod, only: time_type, & + get_time + +use barotropic_physics_mod, only: phys_type +use barotropic_dynamics_mod, only: grid_type, dynamics_type + +implicit none +private + +public :: barotropic_diagnostics_init, & + barotropic_diagnostics + +character(len=84), parameter :: version = '$Id: barotropic_diagnostics.F90,v 17.0 2009/07/21 03:00:18 fms Exp $' +character(len=84), parameter :: tagname = '$Name: siena_201207 $' + +logical :: module_is_initialized = .false. + +character(len=8) :: axiset = 'barotropic' +character(len=84) :: mod_name = 'barotropic_diagnostics' + +integer :: id_vor, id_stream, id_pv, id_u, id_v, id_trs, id_tr, id_eddy_vor, id_delta_u +integer :: is, ie, js, je, ms, me, ns, ne + +contains + +!----------------------------------------------------------------------------------------------------------------- +subroutine barotropic_diagnostics_init(Time, lon_max, lat_max, id_lon, id_lat, id_lonb, id_latb) + +type(time_type), intent(in) :: Time +integer, intent(in) :: lon_max, lat_max, id_lon, id_lat, id_lonb, id_latb + +integer, dimension(2) :: axis_2d + +integer :: log_unit +integer :: namelist_unit, ierr, io +logical :: used + +call write_version_number(version, tagname) + +call get_grid_domain(is, ie, js, je) +call get_spec_domain(ms, me, ns, ne) + +axis_2d(1) = id_lon +axis_2d(2) = id_lat + +id_u = register_diag_field(mod_name, 'ucomp' , axis_2d, Time, 'u_wind' , 'm/s' ) +id_v = register_diag_field(mod_name, 'vcomp' , axis_2d, Time, 'v_wind' , 'm/s' ) +id_vor = register_diag_field(mod_name, 'vor' , axis_2d, Time, 'relative vorticity', '1/s' ) +id_pv = register_diag_field(mod_name, 'pv' , axis_2d, Time, 'absolute vorticity', '1/s' ) +id_stream = register_diag_field(mod_name, 'stream' , axis_2d, Time, 'streamfunction' , 'm^2/s') +id_trs = register_diag_field(mod_name, 'trs' , axis_2d, Time, 'spectral tracer' , 'none' ) +id_tr = register_diag_field(mod_name, 'tr' , axis_2d, Time, 'grid tracer' , 'none' ) +id_eddy_vor= register_diag_field(mod_name, 'eddy_vor', axis_2d, Time, 'eddy vorticity' , '1/s' ) +id_delta_u = register_diag_field(mod_name, 'delta_u' , axis_2d, Time, 'change in zonal wind','m/s' ) + +module_is_initialized = .true. + +return +end subroutine barotropic_diagnostics_init + +!-------------------------------------------------------------------------------------------- + +subroutine barotropic_diagnostics(Time, Dyn, Phys, time_index) + +type(time_type), intent(in) :: Time +type(phys_type), intent(in) :: Phys +type(dynamics_type), intent(in) :: Dyn +integer, intent(in) :: time_index + +real, dimension(is:ie,js:je) :: grid_tmp +real, dimension(is:ie,js:je) :: delta_zonal_u +complex, dimension(ms:me,ns:ne) :: spec_tmp +logical :: used +integer :: j + +if(.not.module_is_initialized) call error_mesg('barotropic_diagnostics', & + 'barotropic_diagnostics_init has not been called', FATAL) + +if(id_u > 0) used = send_data(id_u , Dyn%Grid%u (:,:,time_index) , time) +if(id_v > 0) used = send_data(id_v , Dyn%Grid%v (:,:,time_index) , time) +if(id_vor > 0) used = send_data(id_vor , Dyn%Grid%vor (:,:,time_index) , time) +if(id_pv > 0) used = send_data(id_pv , Dyn%Grid%pv (:,:) , time) +if(id_stream > 0) used = send_data(id_stream , Dyn%Grid%stream (:,:) , time) +if(id_tr > 0) used = send_data(id_tr , Dyn%Grid%tr (:,:,time_index) , time) +if(id_trs > 0) used = send_data(id_trs , Dyn%Grid%trs (:,:,time_index) , time) +if(id_eddy_vor > 0) then + spec_tmp = Dyn%Spec%vor(:,:,time_index) + if(ms == 0) spec_tmp(0,:) = cmplx(0.0,0.0) + call trans_spherical_to_grid(spec_tmp, grid_tmp) + used = send_data(id_eddy_vor, grid_tmp, time) +endif +if(id_delta_u > 0) then + do j=js,je + delta_zonal_u(:,j) = sum(Dyn%Grid%u(:,j,time_index))/Dyn%num_lon - Dyn%Grid%zonal_u_init(j) + enddo + used = send_data(id_delta_u, delta_zonal_u, time) +endif + +return +end subroutine barotropic_diagnostics +!-------------------------------------------------------------------------------------------- + +subroutine barotropic_diagnostics_end(Time) + +type(time_type), intent(in) :: Time + +if(.not.module_is_initialized) call error_mesg('barotropic_diagnostics_end', & + 'barotropic_diagnostics_init has not been called', FATAL) + +module_is_initialized = .false. + +return +end subroutine barotropic_diagnostics_end +!-------------------------------------------------------------------------------------------- + +end module barotropic_diagnostics_mod diff --git a/src/atmos_spectral_barotropic/barotropic_diagnostics.html b/src/atmos_spectral_barotropic/barotropic_diagnostics.html new file mode 100644 index 000000000..d852a921d --- /dev/null +++ b/src/atmos_spectral_barotropic/barotropic_diagnostics.html @@ -0,0 +1,152 @@ + +module barotropic_diagnostics_mod + + +
+ + +

module barotropic_diagnostics_mod

+ + +
+     Contact: Isaac Held
+     Reviewers: Peter Phillipps
+
+
+
+ + +
+

OVERVIEW

+ +
+
+   The diagnostics module for the model that solves the barotropic vorticity
+   equation on the sphere  
+   
+
+
+ + +
+

DESCRIPTION

+ +
+
+   Using the diagnostics manager, creates output files for the barotropic model.
+   Variables currently available for output are
+       zonal wind 
+       meridional wind 
+       relative vorticity
+       absolute vorticity
+       streamfunction
+       spectral tracer in grid domain
+       grid tracer
+       
+   Whether or not these fields are actually output, the location of the 
+   output, the frequency of output, whether or not the output is averaged
+   in time or an instantaneous snapshot, is controlled by a 
+   diag_table file utilized by the diagnostics manager module
+       
+   One can add other diagnostics by following the (somewhat convoluted)
+       pattern within the program
+
+
+
+
+ + +
+

OTHER MODULES USED

+ +
+
+     diag_manaager_mod
+     transforms_mod
+     time_manager_mod
+     barotropic_dynamics_mod
+     barotropic_physics_mod
+
+
+
+ + +
+

PUBLIC INTERFACE

+ +
+
+  use barotropic_diagnostics_mod [,only: barotropic_diagnostics_init,       
+                                         barotropic_diagnostics]
+                                
+
+
+ + + +
+

PUBLIC ROUTINES

+ +
+
+subroutine  barotropic_diagnostics_init
+subroutine  barotropic_diagnostics
+
+
+
+
+ subroutine barotropic_diagnostics_init(Time, num_lon, num_lat)
+ 
+   type(time_type)    , intent(in)     :: Time
+         current time 
+   integer, intent(in) :: num_lon, num_lat
+      num_lon = number of longitudes in global domain
+      num_lat = number of latitudes in global domain
+         
+
+   Initializes module
+
+
+
+
+ + + + subroutine barotropic_diagnostics (Time, Grid, Phys, time_index) + + type(time_type), intent(in) :: Time + type(phys_type), intent(in) :: Phys + type(grid_type), intent(in) :: Grid + integer, intent(in) :: time_index + + phys_type is defined in barotropic_physics_mod; + Phys is currently empty as there is no information generated in + barotropic_physics_mod to be output; + + grid_type is defined in barotropic_dynamics_mod: + Grid contains all of the fields to be output + + many of the grid fields in grid_type are dimensioned (lon, lat, time_index) + where time_index = 1 or 2 -- the two time levels needed to update the + state of the model using a leapfrog step are toggled between (:,:,1) + and (:,:,2). The input time_index (which must equal either 1 or 2) + determines which of these two fields is output) + + (this is confusing -- the calling program needs to know what has + been placed in which slot -- it would be better to store this + information within the data type) + + + + +
+ + + diff --git a/src/atmos_spectral_barotropic/barotropic_dynamics.F90 b/src/atmos_spectral_barotropic/barotropic_dynamics.F90 new file mode 100644 index 000000000..07922fdbc --- /dev/null +++ b/src/atmos_spectral_barotropic/barotropic_dynamics.F90 @@ -0,0 +1,573 @@ +module barotropic_dynamics_mod + +!----------------------------------------------------------------------- +! GNU General Public License +! +! This program is free software; you can redistribute it and/or modify it and +! are expected to follow the terms of the GNU General Public License +! as published by the Free Software Foundation; either version 2 of +! the License, or (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, but WITHOUT +! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +! License for more details. +! +! For the full text of the GNU General Public License, +! write to: Free Software Foundation, Inc., +! 675 Mass Ave, Cambridge, MA 02139, USA. +! or see: http://www.gnu.org/licenses/gpl.html +!----------------------------------------------------------------------- + +use fms_mod, only: open_namelist_file, & + open_restart_file, & + file_exist, & + check_nml_error, & + error_mesg, & + mpp_error, & + FATAL, WARNING, & + write_version_number, & + mpp_pe, & + mpp_root_pe, & + read_data, & + write_data, & + set_domain, & + close_file, & + stdlog + +use time_manager_mod, only : time_type, & + get_time, & + operator(==), & + operator(-) + +use constants_mod, only: radius, omega + +use transforms_mod, only: transforms_init, transforms_end, & + get_grid_boundaries, & + trans_spherical_to_grid, trans_grid_to_spherical, & + compute_laplacian, & + get_sin_lat, get_cos_lat, & + get_deg_lon, get_deg_lat, & + get_grid_domain, get_spec_domain, & + spectral_domain, grid_domain, & + vor_div_from_uv_grid, uv_grid_from_vor_div, & + horizontal_advection + +use spectral_damping_mod, only: spectral_damping_init, & + compute_spectral_damping + +use leapfrog_mod, only: leapfrog + +use fv_advection_mod, only: fv_advection_init, & + a_grid_horiz_advection + +use stirring_mod, only: stirring_init, stirring, stirring_end + +!=============================================================================================== +implicit none +private +!=============================================================================================== + +public :: barotropic_dynamics_init, & + barotropic_dynamics, & + barotropic_dynamics_end, & + dynamics_type, & + grid_type, & + spectral_type, & + tendency_type + + +! version information +!=================================================================== +character(len=128) :: version = '$Id: barotropic_dynamics.F90,v 17.0 2009/07/21 03:00:21 fms Exp $' +character(len=128) :: tagname = '$Name: siena_201207 $' +!=================================================================== + +type grid_type + real, pointer, dimension(:,:,:) :: u=>NULL(), v=>NULL(), vor=>NULL(), trs=>NULL(), tr=>NULL() + real, pointer, dimension(:,:) :: pv=>NULL(), stream=>NULL() + real, pointer, dimension(:) :: zonal_u_init=>NULL() +end type +type spectral_type + complex, pointer, dimension(:,:,:) :: vor=>NULL(), trs=>NULL() +end type +type tendency_type + real, pointer, dimension(:,:) :: u=>NULL(), v=>NULL(), trs=>NULL(), tr=>NULL() +end type +type dynamics_type + type(grid_type) :: grid + type(spectral_type) :: spec + type(tendency_type) :: tend + integer :: num_lon, num_lat + logical :: grid_tracer, spec_tracer +end type + +integer, parameter :: num_time_levels = 2 + +integer :: is, ie, js, je, ms, me, ns, ne + +logical :: module_is_initialized = .false. + +real, allocatable, dimension(:) :: sin_lat, cos_lat, rad_lat, rad_lon, & + deg_lat, deg_lon, & + coriolis, glon_bnd, glat_bnd + +integer :: pe, npes + +! namelist parameters with default values + +logical :: check_fourier_imag = .false. +logical :: south_to_north = .true. +logical :: triang_trunc = .true. + +real :: robert_coeff = 0.04 +real :: longitude_origin = 0.0 + +character(len=64) :: damping_option = 'resolution_dependent' +integer :: damping_order = 4 +real :: damping_coeff = 1.e-04 +real :: damping_coeff_r = 0.0 + +real :: zeta_0 = 8.e-05 +integer :: m_0 = 4 +real :: eddy_width = 15.0 +real :: eddy_lat = 45.0 + +logical :: spec_tracer = .true. +logical :: grid_tracer = .true. + +integer :: num_lat = 128 +integer :: num_lon = 256 +integer :: num_fourier = 85 +integer :: num_spherical = 86 +integer :: fourier_inc = 1 + +real, dimension(2) :: valid_range_v = (/-1.e3,1.e3/) +character(len=64) :: initial_zonal_wind = 'two_jets' + +namelist /barotropic_dynamics_nml/ check_fourier_imag, south_to_north, & + triang_trunc, & + num_lon, num_lat, num_fourier, & + num_spherical, fourier_inc, & + longitude_origin, damping_option, & + damping_order, damping_coeff, & + damping_coeff_r, robert_coeff, & + spec_tracer, grid_tracer, & + eddy_lat, eddy_width, zeta_0, m_0, & + valid_range_v, initial_zonal_wind + +contains + +!=============================================================================================== + +subroutine barotropic_dynamics_init (Dyn, Time, Time_init, dt_real, id_lon, id_lat, id_lonb, id_latb) + +type(dynamics_type), intent(inout) :: Dyn +type(time_type) , intent(in) :: Time, Time_init +real, intent(in) :: dt_real +integer, intent(out) :: id_lon, id_lat, id_lonb, id_latb + +integer :: i, j + +real, allocatable, dimension(:) :: glon_bnd, glat_bnd +complex, allocatable, dimension(:,:) :: div +real :: xx, yy, dd + +integer :: ierr, io, unit, pe +logical :: root + +! < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > + +call write_version_number (version, tagname) + +pe = mpp_pe() +root = (pe == mpp_root_pe()) + +if (file_exist('input.nml')) then + unit = open_namelist_file () + ierr=1 + do while (ierr /= 0) + read (unit, nml=barotropic_dynamics_nml, iostat=io, end=10) + ierr = check_nml_error (io, 'barotropic_dynamics_nml') + enddo + 10 call close_file (unit) +endif + + +if (root) write (stdlog(), nml=barotropic_dynamics_nml) + +call transforms_init(radius, num_lat, num_lon, num_fourier, fourier_inc, num_spherical, & + south_to_north=south_to_north, & + triang_trunc=triang_trunc, & + longitude_origin=longitude_origin ) + +call get_grid_domain(is,ie,js,je) +call get_spec_domain(ms,me,ns,ne) + +Dyn%num_lon = num_lon +Dyn%num_lat = num_lat +Dyn%spec_tracer = spec_tracer +Dyn%grid_tracer = grid_tracer + +allocate (sin_lat (js:je)) +allocate (cos_lat (js:je)) +allocate (deg_lat (js:je)) +allocate (deg_lon (is:ie)) +allocate (rad_lat (js:je)) +allocate (rad_lon (is:ie)) +allocate (coriolis (js:je)) + +allocate (glon_bnd (num_lon + 1)) +allocate (glat_bnd (num_lat + 1)) + +call get_deg_lon (deg_lon) +call get_deg_lat (deg_lat) +call get_sin_lat (sin_lat) +call get_cos_lat (cos_lat) +call get_grid_boundaries (glon_bnd, glat_bnd, global=.true.) + +coriolis = 2*omega*sin_lat + +rad_lat = deg_lat*atan(1.0)/45.0 +rad_lon = deg_lon*atan(1.0)/45.0 + +call spectral_damping_init(damping_coeff, damping_order, damping_option, num_fourier, num_spherical, 1, 0., 0., 0., & + damping_coeff_r=damping_coeff_r) +call stirring_init(dt_real, Time, id_lon, id_lat, id_lonb, id_latb) + +allocate (Dyn%spec%vor (ms:me, ns:ne, num_time_levels)) +allocate (Dyn%grid%u (is:ie, js:je, num_time_levels)) +allocate (Dyn%grid%v (is:ie, js:je, num_time_levels)) +allocate (Dyn%grid%vor (is:ie, js:je, num_time_levels)) + +allocate (Dyn%tend%u (is:ie, js:je)) +allocate (Dyn%tend%v (is:ie, js:je)) +allocate (Dyn%grid%stream (is:ie, js:je)) +allocate (Dyn%grid%pv (is:ie, js:je)) +allocate (Dyn%grid%zonal_u_init(js:je)) + +allocate (div (ms:me, ns:ne)) + +call fv_advection_init(num_lon, num_lat, glat_bnd, 360./float(fourier_inc)) +if(Dyn%grid_tracer) then + allocate(Dyn%Grid%tr (is:ie, js:je, num_time_levels)) + allocate(Dyn%Tend%tr (is:ie, js:je)) +endif + +if(Dyn%spec_tracer) then + allocate(Dyn%Grid%trs (is:ie, js:je, num_time_levels)) + allocate(Dyn%Tend%trs (is:ie, js:je)) + allocate(Dyn%Spec%trs (ms:me, ns:ne, num_time_levels)) +endif + +if(trim(initial_zonal_wind) == 'zero') then + Dyn%grid%zonal_u_init = 0.0 +else if(trim(initial_zonal_wind) == 'two_jets') then + do j = js, je + Dyn%grid%zonal_u_init(j) = 25.0*cos_lat(j) & + - 30.0*(cos_lat(j)**3) & + + 300.0*(sin_lat(j)**2)*(cos_lat(j)**6) + enddo +else + call error_mesg('barotropic_dynamics_init',trim(initial_zonal_wind)// & + ' is not a valid value of initial_zonal_wind ', FATAL) +endif + +if(Time == Time_init) then + + do j = js, je + Dyn%Grid%u(:,j,1) = Dyn%grid%zonal_u_init(j) + Dyn%Grid%v(:,j,1) = 0.0 + end do + + call vor_div_from_uv_grid(Dyn%Grid%u (:,:,1), Dyn%Grid%v (:,:,1), & + Dyn%Spec%vor(:,:,1), div) + + call trans_spherical_to_grid(Dyn%Spec%vor(:,:,1), Dyn%Grid%vor(:,:,1)) + + do j = js, je + do i = is, ie + yy = (deg_lat(j)- eddy_lat)/eddy_width + Dyn%Grid%vor(i,j,1) = Dyn%Grid%vor(i,j,1) + & + 0.5*zeta_0*cos_lat(j)*exp(-yy*yy)*cos(m_0*rad_lon(i)) + end do + end do + + call trans_grid_to_spherical(Dyn%Grid%vor(:,:,1), Dyn%Spec%vor(:,:,1)) + + div = (0.,0.) + call uv_grid_from_vor_div (Dyn%Spec%vor(:,:,1), div, & + Dyn%Grid%u (:,:,1), Dyn%Grid%v (:,:,1)) + + if(Dyn%grid_tracer) then + Dyn%Grid%tr = 0.0 + do j = js, je + if(deg_lat(j) > 10.0 .and. deg_lat(j) < 20.0) Dyn%Grid%tr(:,j,1) = 1.0 + if(deg_lat(j) > 70.0 ) Dyn%Grid%tr(:,j,1) = -1.0 + end do + endif + + if(Dyn%spec_tracer) then + Dyn%Grid%trs = 0.0 + do j = js, je + if(deg_lat(j) > 10.0 .and. deg_lat(j) < 20.0) Dyn%Grid%trs(:,j,1) = 1.0 + if(deg_lat(j) > 70.0 ) Dyn%Grid%trs(:,j,1) = -1.0 + end do + call trans_grid_to_spherical(Dyn%Grid%trs(:,:,1), Dyn%Spec%trs(:,:,1)) + endif + +else + + call read_restart(Dyn) + +endif + +module_is_initialized = .true. + +return +end subroutine barotropic_dynamics_init + +!=============================================================================================== + +subroutine barotropic_dynamics(Time, Time_init, Dyn, previous, current, future, delta_t) + +type(time_type) , intent(in) :: Time, Time_init +type(dynamics_type), intent(inout) :: Dyn +integer, intent(in ) :: previous, current, future +real, intent(in ) :: delta_t + +! < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > + +complex, dimension(ms:me, ns:ne) :: dt_vors, dt_divs, stream, zeros, spec_diss +real, dimension(is:ie, js:je) :: dt_vorg +integer :: j, seconds, days + +! < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > + +if(.not.module_is_initialized) then + call error_mesg('barotropic_dynamics','dynamics has not been initialized ', FATAL) +endif + +zeros = (0.,0.) + +do j = js, je + Dyn%grid%pv(:,j) = Dyn%grid%vor(:,j,current) + coriolis(j) +end do + +Dyn%Tend%u = Dyn%Tend%u + Dyn%grid%pv*Dyn%Grid%v(:,:,current) +Dyn%Tend%v = Dyn%Tend%v - Dyn%grid%pv*Dyn%Grid%u(:,:,current) + +call vor_div_from_uv_grid (Dyn%Tend%u, Dyn%Tend%v, dt_vors, dt_divs) + +call compute_spectral_damping(Dyn%Spec%vor(:,:,previous), dt_vors, delta_t) + +call stirring(Time, dt_vors) + +call leapfrog(Dyn%Spec%vor , dt_vors , previous, current, future, delta_t, robert_coeff) + +call trans_spherical_to_grid(Dyn%Spec%vor(:,:,future), Dyn%Grid%vor(:,:,future)) + +call uv_grid_from_vor_div (Dyn%Spec%vor (:,:,future), zeros, & + Dyn%Grid%u (:,:,future), Dyn%Grid%v (:,:,future)) + +if(minval(Dyn%Grid%v) < valid_range_v(1) .or. maxval(Dyn%Grid%v) > valid_range_v(2)) then + call get_time (Time, seconds, days) + call mpp_error(FATAL,'barotropic_dynamics: Meridional wind out of valid range. Model time=',days,' days ',seconds,' seconds') +endif + +if(Dyn%spec_tracer) call update_spec_tracer(Dyn%Spec%trs, Dyn%Grid%trs, Dyn%Tend%trs, & + Dyn%Grid%u, Dyn%Grid%v, previous, current, future, delta_t) + +if(Dyn%grid_tracer) call update_grid_tracer(Dyn%Grid%tr, Dyn%Tend%tr, & + Dyn%Grid%u, Dyn%Grid%v, previous, current, future, delta_t) + +stream = compute_laplacian(Dyn%Spec%vor(:,:,current), -1) +call trans_spherical_to_grid(stream, Dyn%grid%stream) + +return +end subroutine barotropic_dynamics + +!=================================================================================== + +subroutine update_spec_tracer(tr_spec, tr_grid, dt_tr, ug, vg, & + previous, current, future, delta_t) + +complex, intent(inout), dimension(ms:me, ns:ne, num_time_levels) :: tr_spec +real , intent(inout), dimension(is:ie, js:je, num_time_levels) :: tr_grid +real , intent(inout), dimension(is:ie, js:je ) :: dt_tr +real , intent(in ), dimension(is:ie, js:je, num_time_levels) :: ug, vg +real , intent(in ) :: delta_t +integer, intent(in ) :: previous, current, future + +complex, dimension(ms:me, ns:ne) :: dt_trs + +call horizontal_advection (tr_spec(:,:,current), ug(:,:,current), vg(:,:,current), dt_tr) +call trans_grid_to_spherical (dt_tr, dt_trs) +call compute_spectral_damping (tr_spec(:,:,previous), dt_trs, delta_t) +call leapfrog (tr_spec, dt_trs, previous, current, future, delta_t, robert_coeff) +call trans_spherical_to_grid (tr_spec(:,:,future), tr_grid(:,:,future)) + +return +end subroutine update_spec_tracer +!========================================================================== + +subroutine update_grid_tracer(tr_grid, dt_tr_grid, ug, vg, & + previous, current, future, delta_t) + +real , intent(inout), dimension(is:ie, js:je, num_time_levels) :: tr_grid +real , intent(inout), dimension(is:ie, js:je ) :: dt_tr_grid +real , intent(in ), dimension(is:ie, js:je, num_time_levels) :: ug, vg + +real , intent(in ) :: delta_t +integer, intent(in ) :: previous, current, future + +real, dimension(size(tr_grid,1),size(tr_grid,2)) :: tr_current, tr_future + +tr_future = tr_grid(:,:,previous) + delta_t*dt_tr_grid +dt_tr_grid = 0.0 +call a_grid_horiz_advection (ug(:,:,current), vg(:,:,current), tr_future, delta_t, dt_tr_grid) +tr_future = tr_future + delta_t*dt_tr_grid +tr_current = tr_grid(:,:,current) + & + robert_coeff*(tr_grid(:,:,previous) + tr_future - 2.0*tr_grid(:,:,current)) +tr_grid(:,:,current) = tr_current +tr_grid(:,:,future) = tr_future + +return +end subroutine update_grid_tracer + +!========================================================================== + +subroutine read_restart(Dyn) + +type(dynamics_type), intent(inout) :: Dyn + +integer :: unit, m, n, nt +real, dimension(ms:me, ns:ne) :: real_part, imag_part + +if(file_exist('INPUT/barotropic_dynamics.res.nc')) then + do nt = 1, 2 + call read_data('INPUT/barotropic_dynamics.res.nc', 'vors_real', real_part, spectral_domain, timelevel=nt) + call read_data('INPUT/barotropic_dynamics.res.nc', 'vors_imag', imag_part, spectral_domain, timelevel=nt) + do n=ns,ne + do m=ms,me + Dyn%Spec%vor(m,n,nt) = cmplx(real_part(m,n),imag_part(m,n)) + end do + end do + if(Dyn%spec_tracer) then + call read_data('INPUT/barotropic_dynamics.res.nc', 'trs_real', real_part, spectral_domain, timelevel=nt) + call read_data('INPUT/barotropic_dynamics.res.nc', 'trs_imag', imag_part, spectral_domain, timelevel=nt) + do n=ns,ne + do m=ms,me + Dyn%Spec%trs(m,n,nt) = cmplx(real_part(m,n),imag_part(m,n)) + end do + end do + endif + call read_data('INPUT/barotropic_dynamics.res.nc', 'u', Dyn%Grid%u (:,:,nt), grid_domain, timelevel=nt) + call read_data('INPUT/barotropic_dynamics.res.nc', 'v', Dyn%Grid%v (:,:,nt), grid_domain, timelevel=nt) + call read_data('INPUT/barotropic_dynamics.res.nc', 'vor', Dyn%Grid%vor(:,:,nt), grid_domain, timelevel=nt) + if(Dyn%spec_tracer) then + call read_data('INPUT/barotropic_dynamics.res.nc', 'trs', Dyn%Grid%trs(:,:,nt), grid_domain, timelevel=nt) + endif + if(Dyn%grid_tracer) then + call read_data('INPUT/barotropic_dynamics.res.nc', 'tr', Dyn%Grid%tr(:,:,nt), grid_domain, timelevel=nt) + endif + end do +else if(file_exist('INPUT/barotropic_dynamics.res')) then + unit = open_restart_file(file='INPUT/barotropic_dynamics.res',action='read') + + do nt = 1, 2 + call set_domain(spectral_domain) + call read_data(unit,Dyn%Spec%vor(:,:, nt)) + if(Dyn%spec_tracer) call read_data(unit,Dyn%Spec%trs(:,:, nt)) + + call set_domain(grid_domain) + call read_data(unit,Dyn%Grid%u (:,:, nt)) + call read_data(unit,Dyn%Grid%v (:,:, nt)) + call read_data(unit,Dyn%Grid%vor (:,:, nt)) + if(Dyn%spec_tracer) call read_data(unit,Dyn%Grid%trs(:,:, nt)) + if(Dyn%grid_tracer) call read_data(unit,Dyn%Grid%tr (:,:, nt)) + + end do + call close_file(unit) + +else + call error_mesg('read_restart', 'restart does not exist', FATAL) +endif + +return +end subroutine read_restart + +!==================================================================== + +subroutine write_restart(Dyn, previous, current) + +type(dynamics_type), intent(in) :: Dyn +integer, intent(in) :: previous, current + +integer :: unit, nt, nn + +do nt = 1, 2 + if(nt == 1) nn = previous + if(nt == 2) nn = current + call write_data('RESTART/barotropic_dynamics.res.nc', 'vors_real', real(Dyn%Spec%vor(:,:,nn)), spectral_domain) + call write_data('RESTART/barotropic_dynamics.res.nc', 'vors_imag', aimag(Dyn%Spec%vor(:,:,nn)), spectral_domain) + if(Dyn%spec_tracer) then + call write_data('RESTART/barotropic_dynamics.res.nc', 'trs_real', real(Dyn%Spec%trs(:,:,nn)), spectral_domain) + call write_data('RESTART/barotropic_dynamics.res.nc', 'trs_imag', aimag(Dyn%Spec%trs(:,:,nn)), spectral_domain) + endif + call write_data('RESTART/barotropic_dynamics.res.nc', 'u', Dyn%Grid%u (:,:,nn), grid_domain) + call write_data('RESTART/barotropic_dynamics.res.nc', 'v', Dyn%Grid%v (:,:,nn), grid_domain) + call write_data('RESTART/barotropic_dynamics.res.nc', 'vor', Dyn%Grid%vor(:,:,nn), grid_domain) + if(Dyn%spec_tracer) then + call write_data('RESTART/barotropic_dynamics.res.nc', 'trs', Dyn%Grid%trs(:,:,nn), grid_domain) + endif + if(Dyn%grid_tracer) then + call write_data('RESTART/barotropic_dynamics.res.nc', 'tr', Dyn%Grid%tr(:,:,nn), grid_domain) + endif +enddo + +!unit = open_restart_file(file='RESTART/barotropic_dynamics.res', action='write') + +!do nt = 1, 2 +! if(nt == 1) nn = previous +! if(nt == 2) nn = current + +! call set_domain(spectral_domain) +! call write_data(unit,Dyn%Spec%vor(:,:, nn)) +! if(Dyn%spec_tracer) call write_data(unit,Dyn%Spec%trs(:,:, nn)) + +! call set_domain(grid_domain) +! call write_data(unit,Dyn%Grid%u (:,:, nn)) +! call write_data(unit,Dyn%Grid%v (:,:, nn)) +! call write_data(unit,Dyn%Grid%vor (:,:, nn)) +! if(Dyn%spec_tracer) call write_data(unit,Dyn%Grid%trs(:,:, nn)) +! if(Dyn%grid_tracer) call write_data(unit,Dyn%Grid%tr (:,:, nn)) +!end do + +!call close_file(unit) + +end subroutine write_restart + +!==================================================================== + +subroutine barotropic_dynamics_end (Dyn, previous, current) + +type(dynamics_type), intent(inout) :: Dyn +integer, intent(in) :: previous, current + +if(.not.module_is_initialized) then + call error_mesg('barotropic_dynamics','dynamics has not been initialized ', FATAL) +endif + +call transforms_end() +call stirring_end() + +call write_restart (Dyn, previous, current) + +module_is_initialized = .false. + +return +end subroutine barotropic_dynamics_end +!=================================================================================== + +end module barotropic_dynamics_mod diff --git a/src/atmos_spectral_barotropic/barotropic_dynamics.html b/src/atmos_spectral_barotropic/barotropic_dynamics.html new file mode 100644 index 000000000..62c97898a --- /dev/null +++ b/src/atmos_spectral_barotropic/barotropic_dynamics.html @@ -0,0 +1,371 @@ + +module barotropic_dynamics_mod + + +
+ + +

module barotropic_dynamics_mod

+ + +
+     Contact: Isaac Held
+     Reviewers: Peter Phillipps
+
+
+
+ + +
+

OVERVIEW

+ +
+
+   The dynamical core of the spectral transform model for 
+   two-dimensional, non-divergent flow on the surface of the sphere.  
+   
+
+
+ + +
+

DESCRIPTION

+ +
+
+   Integrates the barotropic vorticity equation for nondivergent flow on the
+   sphere using the spectral transform technique.  Also allows for the
+   inclusion of a passive tracer advected by the same spectral advection
+   algorithm as  the vorticity, and a gridpoint tracer advected with a finite
+   volume  algorithm on the transform grid.  The default initial condition 
+   provided as an example is a zonal flow resembling that in the Northern
+   winter,  plus a sinusoidal disurbance localized in midlatitudes.
+
+   For a full description of the model and algorithms used, see 
+     barotropic.ps 
+   
+   For higher level routines for running this barotropic spectral model,
+   see  atmosphere_mod 
+
+
+
+ + + +
+

OTHER MODULES USED

+ +
+
+     fms_mod
+     constants_mod
+     time_manager_mod
+     transforms_mod
+     spectral_damping_mod
+     leapfrog_mod
+     fv_advection_mod
+
+
+
+ + +
+

PUBLIC INTERFACE

+ +
+
+  use barotropic_dynamics_mod [,only: barotropic_dynamics_init,       
+                                      barotropic_dynamics,
+			              barotropic_dynamics_end,
+                                      dynamics_type,
+				      grid_type,
+				      spectral_type,
+				      tendency_type]
+                                
+
+
+ + +
+

PUBLIC DATA

+ +
+     
+
+
+ +type grid_type + real, pointer, dimension(:,:,:) :: u, v, vor, trs, tr, pv + real, pointer, dimension(:,:) :: stream +end type + + allocated space for grid fields + + (:,:,:) => (lon, lat, time_level) + (:,:) => (lon, lat) + (lon, lat) on local computational domain + time_level stores the two time levels needed for the + leapfrog step + + u -- eastward velocity (m/s) + v -- northward velocity (m/s) + vor -- vorticity (1/s) + trs -- tracer advected spectrally + tr -- tracer advected on grid + pv -- absolute vorticity, f + vor, where f = 2*omega*sin(lat) (1/s) + stream -- streamfunction (m^2/s) at current time + + + +
+ + +type spectral_type + complex, pointer, dimension(:,:,:) :: vor, trs +end type + + allocated space for spectral fields + + (:,:,:) => (zonal, meridional, time_level) + + vor -- spectral vorticity + trs -- spectral tracer + +
+
+ +type tendency_type + real, pointer, dimension(:,:) :: u, v, trs, tr +end type + + allocated space for accumulating tendencies, d/dt, in grid space, + for prognostic variables + + (:,:,:) => (lon, lat) + +
+
+ +type dynamics_type + type(grid_type) :: grid + type(spectral_type) :: spec + type(tendency_type) :: tend + integer :: num_lon, num_lat ! size of global domain + logical :: grid_tracer, spec_tracer +end type + + grid_tracer = .true. => tracer with gridpoint advection is beign integrated + similarly for spec_tracer + +
+ +
+ + + +
+

PUBLIC ROUTINES

+ +
+
+subroutine  barotropic_dynamics_init
+subroutine  barotropic _dynamics
+subroutine  barotropic_dynamics_end
+type (grid_type)
+type (spectral_type)
+type (tendency_type)
+type (dynamics_type)
+
+
+
+
+
+ subroutine barotropic_dynamics_init(Dyn,  Time, Time_init)
+ 
+   type(dynamics_type), intent(inout)  :: Dyn
+         type containing all dynamical fields and related information
+	 (see type (dynamics_type))
+	 
+   type(time_type)    , intent(in)     :: Time, Time_init
+         current time and time at which integeration began
+	 time_type defined by time_manager_mod
+         
+
+   Initializes the module;
+   Reads restart from 'INPUT/barotropic_dynamics.res' if Time = Time_init;
+     otherwise uses default initial conditions
+
+
+
+
+ + + + subroutine barotropic_dynamics & + (Time, Time_init, Dyn, previous, current, future, delta_t) + + type(time_type) , intent(inout) :: Time, Time_init + type(dynamics_type), intent(inout) :: Dyn + integer , intent(in ) :: previous, current, future + real , intent(in ) :: delta_t + + previous, current and future = 1 or 2 + these integers refer to the third dimension of the + three-dimensional fields in Dyn + the fields at time t - delta_t are assumed to be in (:,:,previous) + the fields at time t are assumed to be in (:,:,current) + the fields at time t + delta_t are placed in (:,:,future) + overwriting whatever is already there + + delta_t = time step in seconds + + updates dynamical fields by one time step + + + +
+ + + subroutine barotropic_dynamics_end(Dyn, previous, current) + + type(dynamics_type), intent(inout) :: Dyn + integer, intent(in) :: previous, current + + + Terminates module; + writes restart file to 'RESTART/barotropic_dynamics.res' + + + + +
+
+ + + +
+

NAMELIST

+ +
+
+&barotropic_dynamics_nml
+
+  integer :: num_lat            = 128  
+        number of latitudes in global grid
+       
+  integer :: num_lon            = 256
+        number of longitudes in global grid
+        should equal 2*num_lat for Triangular truncation
+  
+  integer :: num_fourier        = 85
+        the retained fourier wavenumber are n*fourier_inc, where
+        n ranges from 0 to num_fourier
+	 
+  integer :: num_spherical      = 86
+        the maximum number of meridional modes for any zonal wavenumber
+        for triangular truncation, set num_spherical = num_fourier +1
+         
+  integer :: fourier_inc        = 1
+        creates a "sector" model if fourier_inc > 1; integration domain is
+	(360 degrees longitude)/fourier_inc
+	
+  (the default values listed above define a standard T85 model)
+
+  logical :: check_fourier_imag = .false.
+        if true, checks to see if fields to be transformed to grid 
+	domain have zero imaginary part to their zonally symmetric
+	modes; useful for debugging
+	
+  logical :: south_to_north     = .true.
+        true => grid runs from south to north
+	false => grid runs from north to south
+	
+  logical :: triangular_trunc   = .true.
+        true  => shape of truncation is triangular
+	false => shape of truncation is rhomboidal
+
+  real    :: robert_coeff       = 0.04
+        x(current) => (1-2r)*x(current) + r*(x(future)+x(previous))
+	where r = robert_coeff (non-dimensional)
+	
+  real    :: longitude_origin   = 0.0
+        longitude of first longitude, in degrees
+	(if you want the westgern boundary of first grid boc to be at 
+         0.0, set longitude_origin = 0.5*360./float(num_lon))
+	 
+  integer :: damping_option     = 'resolution_dependent'
+  integer :: damping_order      = 4
+  real    :: damping_coeff      = 1.e-04
+  
+        damping = nu*(del^2)^n where n = damping order
+	damping_option = 'resolution_dependent' or 'resolution_independent'
+	  = 'resolution_dependent' => nu is set so that the damping rate for the 
+	        mode (m=0,n=num_spherical-1) equals damping_coeff (in 1/s)
+	        For triangular truncation, damping_coeff is then the 
+	        rate of damping of the highest retained mode
+	     
+	  = 'resolution_independent' => nu = damping_coef
+	
+	
+  real     :: zeta_0     = 8.e-05
+  integer  :: m_0        = 4
+  real     :: eddy_width = 15.0
+  real     :: eddy_lat   = 45.0
+  
+         eddy component of the initial condition is sinusoidal with
+	 wavenumber m_0 and with a gaussian distribution of 
+	 vorticity in latitude, centered at eddy_lat with half-width
+	 eddy_width
+	 
+	 zeta_0 ( 1/s)
+	 eddy_width and eddy_lat (degrees)
+
+  logical :: spec_tracer      = .true.
+  logical :: grid_tracer      = .true.
+       spec_tracer = true => a passive tracer is carried that is advected
+          spectrally, with the same algorithm as the vorticity
+       grid_tracer = ture => a passive tracer is carried that is advected
+          on the spectral transform grid by a finite-volume algorithm
+	  (see  barotropic.ps )
+       Both tracers can be carried simultaeneously
+	  
+The vorticity and the tracers are initialized within subroutine
+     barotropic_dynamics_init
+
+  real, dimension(2) :: valid_range_v = -1000., 1000.
+        A valid range for meridional wind. Model terminates if meridional wind
+        goes outside the valid range. Allows model to terminate gracefully when,
+        for example, the model becomes numerically unstable.
+
+
+ + + +
+

ERROR MESSAGES

+ +
+
+   "Dynamics has not been initialized"
+      -- barotropic_dynamics_init must be called before any other
+         routines in the module are called
+	 
+   "restart does not exist" 
+      -- Time is not equal to Time_init at initalization, but the file
+          'INPUT/barotropic_dynamics.res' does not exit 
+	 
+
+
+
+ + +
+ + diff --git a/src/atmos_spectral_barotropic/barotropic_physics.F90 b/src/atmos_spectral_barotropic/barotropic_physics.F90 new file mode 100644 index 000000000..8590bacce --- /dev/null +++ b/src/atmos_spectral_barotropic/barotropic_physics.F90 @@ -0,0 +1,173 @@ +module barotropic_physics_mod + +!----------------------------------------------------------------------- +! GNU General Public License +! +! This program is free software; you can redistribute it and/or modify it and +! are expected to follow the terms of the GNU General Public License +! as published by the Free Software Foundation; either version 2 of +! the License, or (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, but WITHOUT +! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +! License for more details. +! +! For the full text of the GNU General Public License, +! write to: Free Software Foundation, Inc., +! 675 Mass Ave, Cambridge, MA 02139, USA. +! or see: http://www.gnu.org/licenses/gpl.html +!----------------------------------------------------------------------- + +use fms_mod, only: open_namelist_file, & + open_restart_file, & + file_exist, & + check_nml_error, & + error_mesg, & + FATAL, WARNING, & + write_version_number, & + mpp_pe, & + mpp_root_pe, & + fms_init, fms_end, & + read_data, & + write_data, & + set_domain, & + close_file, & + stdlog + +use transforms_mod, only: get_sin_lat, get_cos_lat, & + get_deg_lon, get_deg_lat, & + get_wts_lat, & + get_grid_domain, get_spec_domain, & + grid_domain + +use time_manager_mod, only: time_type + +!======================================================================== +implicit none +private +!======================================================================== + +public :: barotropic_physics_init, & + barotropic_physics, & + barotropic_physics_end, & + phys_type + +! version information +!======================================================================== +character(len=128) :: version = '$Id: barotropic_physics.F90,v 10.0 2003/10/24 22:00:58 fms Exp $' +character(len=128) :: tagname = '$Name: siena_201207 $' +!======================================================================== + +type phys_type + real, pointer, dimension(:,:) :: empty=>NULL() +end type + +logical :: module_is_initialized = .false. + +integer :: is, ie, js, je + + +integer :: pe +logical :: root + +real, allocatable, dimension(:) :: rad_lat, & + deg_lat, & + sin_lat, & + cos_lat, & + wts_lat + +! namelist +!======================================================================== + +logical :: empty + +namelist /barotropic_physics_nml/ empty +!======================================================================== + +contains + +!======================================================================== + +subroutine barotropic_physics_init(Phys) + +type(phys_type), intent(inout) :: Phys + +integer :: j, unit, ierr, io + +call write_version_number (version, tagname) + +pe = mpp_pe() +root = (pe == mpp_root_pe()) + +! read the namelist + +if (file_exist('input.nml')) then + unit = open_namelist_file () + ierr=1 + do while (ierr /= 0) + read (unit, nml=barotropic_physics_nml, iostat=io, end=10) + ierr = check_nml_error (io, 'barotropic_physics_nml') + enddo + 10 call close_file (unit) +endif + +call get_grid_domain(is,ie,js,je) + +allocate ( rad_lat (js:je) ) +allocate ( deg_lat (js:je) ) +allocate ( sin_lat (js:je) ) +allocate ( cos_lat (js:je) ) +allocate ( wts_lat (js:je) ) + +call get_wts_lat(wts_lat) +call get_deg_lat(deg_lat) +rad_lat = deg_lat*atan(1.)/45. +sin_lat = sin(rad_lat) +cos_lat = cos(rad_lat) + +module_is_initialized = .true. + +return +end subroutine barotropic_physics_init + +!======================================================================= + +subroutine barotropic_physics(Time, dt_ug, dt_vg, ug, vg, & + delta_t, previous, current, Phys) + +real, intent(inout), dimension(is:ie, js:je) :: dt_ug, dt_vg +real, intent(in) , dimension(is:ie, js:je, 2) :: ug, vg + +real , intent(in) :: delta_t +integer, intent(in) :: previous, current + +type(time_type), intent(in) :: Time +type(phys_type), intent(inout) :: Phys + +if(.not.module_is_initialized) call error_mesg('barotropic_physics', & + 'barotropic_physics is not initialized', FATAL) + +! dt_ug = dt_ug +f(ug,vg) +! dt_vg = dt_vg +f(ug,vg) +! Phys%empty = + +return +end subroutine barotropic_physics + +!====================================================================== + +subroutine barotropic_physics_end(Phys) + +type(phys_type), intent(in) :: Phys + +if(.not.module_is_initialized) call error_mesg('barotropic_physics_end', & + 'barotropic_physics is not initialized', FATAL) + +module_is_initialized = .false. +return +end subroutine barotropic_physics_end + +!====================================================================== + +end module barotropic_physics_mod diff --git a/src/atmos_spectral_barotropic/barotropic_physics.html b/src/atmos_spectral_barotropic/barotropic_physics.html new file mode 100644 index 000000000..e391ca50f --- /dev/null +++ b/src/atmos_spectral_barotropic/barotropic_physics.html @@ -0,0 +1,165 @@ + +module barotropic_physics_mod + + +
+ + +

module barotropic_physics_mod

+ + +
+     Contact: Isaac Held
+     Reviewers: Peter Phillipps
+
+
+
+ + +
+

OVERVIEW

+ +
+
+   A module that allows one to add processes that act in the grid domain
+   to the dynamics of the barotropic model on the sphere
+   
+
+
+ + +
+

DESCRIPTION

+ +
+
+   A module that allows one to add processes that act in the grid domain
+   to the dynamics of the barotropic model on the sphere.  Currently,
+   does nothing!
+
+
+
+ + +
+

OTHER MODULES USED

+ +
+
+     fms_mod
+     transforms_mod
+     time_manager_mod
+
+
+
+ + +
+

PUBLIC INTERFACE

+ +
+
+  use barotropic_physics_mod [,only: barotropic_physics_init,       
+                                         barotropic_physics,
+					 barotropic_physics_end,
+					 phys_type]
+                                
+
+
+ + +
+

PUBLIC DATA

+ +
+     
+
+
+ +type phys_type + real, pointer, dimension(:,:) :: empty +end type + + fields from physics module made available for diagnostics + +
+
+ +
+ + +
+

PUBLIC ROUTINES

+ +
+
+subroutine  barotropic_physics_init
+subroutine  barotropic_physics
+subroutine  barotropic_physics_end
+type(phys_type)
+
+
+
+
+
+ subroutine barotropic_physics_init(Phys)
+ 
+   type(phys_type)    , intent(inout)     :: Phys
+  
+ 
+   Initializes module
+
+
+
+
+ + + + subroutine barotropic_physics (Time, dt_ug, dt_vg, ug, vg, & + delta_t, previous, current, Phys) + + real, intent(inout), dimension(:,:) :: dt_ug, dt_vg + + the u and v tendencies onto which tendencies due to + the grid-point physics are added (m/(s^2)) + + real, intent(in) , dimension(:,:, 2) :: ug, vg + the grid zonal and meridional velocities (m/s) + the third index is the time-index used in the leapfrog step + + real , intent(in) :: delta_t + time step (s) + + integer, intent(in) :: previous, current + = 1 or 2 + ug(:,:,previous) is the velocity at t-delta_t + ug(:,:,current ) is the velocity at t + + type(time_type), intent(in) :: Time + type(phys_type), intent(inout) :: Phys + + + + +
+ + + + subroutine barotropic_physics_end (Phys) + + type(phys_type), intent(inout) :: Phys + + + + +
+ + + diff --git a/src/atmos_spectral_barotropic/stirring.F90 b/src/atmos_spectral_barotropic/stirring.F90 new file mode 100644 index 000000000..04bdfc280 --- /dev/null +++ b/src/atmos_spectral_barotropic/stirring.F90 @@ -0,0 +1,252 @@ +module stirring_mod + +!----------------------------------------------------------------------- +! GNU General Public License +! +! This program is free software; you can redistribute it and/or modify it and +! are expected to follow the terms of the GNU General Public License +! as published by the Free Software Foundation; either version 2 of +! the License, or (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, but WITHOUT +! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +! License for more details. +! +! For the full text of the GNU General Public License, +! write to: Free Software Foundation, Inc., +! 675 Mass Ave, Cambridge, MA 02139, USA. +! or see: http://www.gnu.org/licenses/gpl.html +!----------------------------------------------------------------------- + +! Stirring is computed as described in the following paper: + +! Vallis, Gerber, Kushner, Cash, 2003: A Mechanism and Simple Dynamical Model of the North Atlantic Oscillation and Annular Modes. +! J. Atmos. Sci., 61, 264-280. + +! Stirring is not part of barotropic_physics because barotropic_physics appears to be intended for +! operations that are done completely in grid space. Stirring is computed partly in spectral space. + +use constants_mod, only: pi + +use time_manager_mod, only: time_type + +use fms_mod, only: open_namelist_file, check_nml_error, close_file, write_version_number, & + stdlog, mpp_pe, mpp_root_pe, file_exist, read_data, write_data, error_mesg, FATAL + +use transforms_mod, only: get_spec_domain, get_grid_domain, trans_spherical_to_grid, trans_grid_to_spherical, & + grid_domain, get_lon_max, get_lat_max, get_deg_lon, get_deg_lat, get_grid_boundaries, & + get_num_fourier, get_num_spherical, spectral_domain + +use diag_manager_mod, only: diag_axis_init, register_static_field, register_diag_field, send_data + +implicit none +private + +integer :: ms,me,ns,ne,is,ie,js,je +integer :: id_str_amp, id_g_stir_sqr, id_stir +logical :: used +logical, allocatable, dimension(:,:) :: wave_mask ! wave_mask(m,n) = .true. if spherical wave (m,n) is to be excited +complex, allocatable, dimension(:,:) :: s_stir ! stirring. Saved from one time step to the next +real, allocatable, dimension(:,:) :: localize ! localizes the stirring +real, allocatable, dimension(:,:) :: g_stir_sqr ! time mean of g_stir**2 over entire integration +integer, allocatable, dimension(:) :: seed ! random number seed +real :: astir, bstir +integer :: num_steps, num_fourier, num_spherical, nseed +character(len=8) :: axiset = 'barotropic' +character(len=84) :: mod_name = 'barotropic_diagnostics' + +logical :: module_is_initialized = .false. + +character(len=128) :: version = '$Id: stirring.F90,v 17.0 2009/07/21 03:00:25 fms Exp $' +character(len=128) :: tagname = '$Name: siena_201207 $' + +public :: stirring_init, stirring, stirring_end + +real :: decay_time=2*86400, amplitude=0.0, lat0=45., widthy=12. + +! Set B to a non-zero value for stirring that has zonal structure. +! The strength of the stirring at latitude=lat0 is: amplitude*(1.0 + B*exp(-.5*((lon-lon0)/widthx)**2)) +real :: lon0=180., B=0.0, widthx=45. ! widthx + +namelist / stirring_nml / decay_time, amplitude, lat0, lon0, widthy, widthx, B + +contains + +!================================================================================================================================ +subroutine stirring_init(dt, Time, id_lon, id_lat, id_lonb, id_latb) +real, intent(in) :: dt +type(time_type), intent(in) :: Time +integer, intent(out) :: id_lon, id_lat, id_lonb, id_latb +real :: xx, kk, rad_to_deg +integer :: i,j,m,n,ierr,io,unit,lon_max,lat_max +real, allocatable, dimension(:) :: ampx, ampy, lon, lat, lonb, latb +real, allocatable, dimension(:,:) :: real_part, imag_part + +if(module_is_initialized) return + +call write_version_number (version, tagname) + +if (file_exist('input.nml')) then + unit = open_namelist_file () + ierr=1 + do while (ierr /= 0) + read (unit, nml=stirring_nml, iostat=io, end=10) + ierr = check_nml_error (io, 'stirring_nml') + enddo + 10 call close_file (unit) +endif +if(mpp_pe() == mpp_root_pe()) write(stdlog(), nml=stirring_nml) + +call get_lon_max(lon_max) +call get_lat_max(lat_max) + +allocate(lon (lon_max )) ; lon = 0.0 +allocate(lat (lat_max )) ; lat = 0.0 +allocate(lonb(lon_max+1)) ; lonb = 0.0 +allocate(latb(lat_max+1)) ; latb = 0.0 + +call get_deg_lon(lon) +call get_deg_lat(lat) +call get_grid_boundaries(lonb,latb,global=.true.) + +rad_to_deg = 180./pi +id_lonb=diag_axis_init('lonb', rad_to_deg*lonb, 'degrees_E', 'x', 'longitude edges', set_name='barotropic', Domain2=grid_domain) +id_latb=diag_axis_init('latb', rad_to_deg*latb, 'degrees_N', 'y', 'latitude edges', set_name='barotropic', Domain2=grid_domain) +id_lon =diag_axis_init('lon', lon, 'degrees_E', 'x', 'longitude', set_name='barotropic', Domain2=grid_domain, edges=id_lonb) +id_lat =diag_axis_init('lat', lat, 'degrees_N', 'y', 'latitude', set_name='barotropic', Domain2=grid_domain, edges=id_latb) + +module_is_initialized = .true. +if(amplitude == 0.0) return ! stirring does nothing more unless amplitude is non-zero + +call get_spec_domain(ms,me,ns,ne) +call get_grid_domain(is,ie,js,je) +call get_num_fourier(num_fourier) +call get_num_spherical(num_spherical) + +allocate(wave_mask(ms:me,ns:ne)); wave_mask = .false. +allocate(s_stir(ms:me,ns:ne)); s_stir = cmplx(0.0,0.0) +allocate(ampx(is:ie)); ampx = 0.0 +allocate(ampy(js:je)); ampy = 0.0 +allocate(localize(is:ie,js:je)); localize = 0.0 +allocate(g_stir_sqr(is:ie,js:je)); g_stir_sqr = 0.0 + +! wave_mask is .true. when (m+n > 9) .and. (m+n < 15) .and. (m > 3) +do m=4,14 + if(m >= ms .and. m <= me) then + do n=10-m,14-m + if(n >= ns .and. n <= ne) then + wave_mask(m,n) = .true. + endif + enddo + endif +enddo + +astir = sqrt(1.0 - exp(-2*dt/decay_time)) +bstir = exp(-dt/decay_time) + +do i=is,ie + xx = lon(i)-lon0 + ! Make sure xx falls in the range -180. to +180. + kk = nint(xx/360.) + xx = xx - 360.*kk + ampx(i) = (1 + B*exp(-.5*(xx/widthx)**2)) +enddo +do j=js,je + ampy(j) = exp(-.5*((lat(j)-lat0)/widthy)**2) +enddo +do j=js,je +do i=is,ie + localize(i,j) = ampx(i)*ampy(j) +enddo +enddo +deallocate(ampx, ampy) + +num_steps = 0 +id_g_stir_sqr = register_static_field('stirring_mod', 'stirring_sqr', (/id_lon,id_lat/), 'stirring sqrared', '1/sec^4') +id_str_amp = register_static_field('stirring_mod', 'stirring_amp', (/id_lon,id_lat/), 'amplitude of stirring', 'none') +id_stir = register_diag_field ('stirring_mod', 'stirring', (/id_lon,id_lat/), Time, 'stirring', '1/sec^2') +used = send_data(id_str_amp, amplitude*localize) + +call random_seed(size=nseed) +allocate(seed(nseed)) + +if(file_exist('INPUT/stirring.res.nc')) then + allocate(real_part(ms:me,ns:ne), imag_part(ms:me,ns:ne)) + call read_data('INPUT/stirring.res.nc', 'stir_real', real_part, spectral_domain) + call read_data('INPUT/stirring.res.nc', 'stir_imag', imag_part, spectral_domain) + do n=ns,ne + do m=ms,me + s_stir(m,n) = cmplx(real_part(m,n),imag_part(m,n)) + end do + end do + deallocate(real_part, imag_part) + call read_data('INPUT/stirring.res.nc', 'ran_nmbr_seed', seed, no_domain=.true.) + call random_seed(put=seed) +endif + +end subroutine stirring_init +!================================================================================================================================ +subroutine stirring(Time, dt_vors) +type(time_type), intent(in) :: Time +complex, dimension(ms:me,ns:ne), intent(inout) :: dt_vors +real, dimension(is:ie,js:je) :: g_stir +complex, dimension(ms:me,ns:ne) :: new_stirring +real, dimension(0:num_fourier,0:num_spherical,2) :: ran_nmbrs +integer :: i,j,m,n +real :: x,y + +if(.not.module_is_initialized) then + call error_mesg('stirring', 'stirring_init has not been called', FATAL) +end if + +if(amplitude == 0.0) return ! stirring does nothing unless amplitude is non-zero + +call random_number(ran_nmbrs) + +do n=ns,ne +do m=ms,me + if(wave_mask(m,n)) then + new_stirring(m,n) = amplitude*astir*cmplx(2*ran_nmbrs(m,n,1)-1, 2*ran_nmbrs(m,n,2)-1) + else + new_stirring(m,n) = cmplx(0.0,0.0) + endif +enddo +enddo +call trans_spherical_to_grid(new_stirring,g_stir) +g_stir = localize*g_stir +call trans_grid_to_spherical(g_stir,new_stirring) +if(ms == 0 .and. ns == 0) then + new_stirring(0,0)=cmplx(0.0,0.0) ! A non-zero global mean is introduced by the grid space computation, but we don't want it. +endif +s_stir = bstir*s_stir + new_stirring + +dt_vors = dt_vors + s_stir +call trans_spherical_to_grid(s_stir,g_stir) +g_stir_sqr = g_stir_sqr + g_stir*g_stir +num_steps = num_steps + 1 +used = send_data(id_stir, g_stir, Time) + +end subroutine stirring +!================================================================================================================================ +subroutine stirring_end + +if(.not.module_is_initialized) return + +if(amplitude == 0.0) return ! stirring does nothing unless amplitude is non-zero + +g_stir_sqr = g_stir_sqr/num_steps +used = send_data(id_g_stir_sqr, g_stir_sqr) + +call write_data('RESTART/stirring.res.nc', 'stir_real', real(s_stir), spectral_domain) +call write_data('RESTART/stirring.res.nc', 'stir_imag', aimag(s_stir), spectral_domain) +call random_seed(get=seed) +call write_data('RESTART/stirring.res.nc', 'ran_nmbr_seed', seed, no_domain=.true.) + +deallocate(wave_mask, s_stir, localize, g_stir_sqr) +module_is_initialized = .false. + +end subroutine stirring_end +!================================================================================================================================ + +end module stirring_mod diff --git a/src/atmos_spectral_shallow/atmosphere.F90 b/src/atmos_spectral_shallow/atmosphere.F90 new file mode 100644 index 000000000..3b59b37fb --- /dev/null +++ b/src/atmos_spectral_shallow/atmosphere.F90 @@ -0,0 +1,279 @@ +Module atmosphere_mod + +!----------------------------------------------------------------------- +! GNU General Public License +! +! This program is free software; you can redistribute it and/or modify it and +! are expected to follow the terms of the GNU General Public License +! as published by the Free Software Foundation; either version 2 of +! the License, or (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, but WITHOUT +! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +! License for more details. +! +! For the full text of the GNU General Public License, +! write to: Free Software Foundation, Inc., +! 675 Mass Ave, Cambridge, MA 02139, USA. +! or see: http://www.gnu.org/licenses/gpl.html +!----------------------------------------------------------------------- + +!========================================================================= + +use fms_mod, only: open_namelist_file, & + open_restart_file, & + file_exist, & + check_nml_error, & + error_mesg, & + FATAL, WARNING, & + write_version_number, & + mpp_pe, & + mpp_root_pe, & + close_file, & + stdlog + +use mpp_mod, only: mpp_max + +use constants_mod, only: radius_earth => radius, & + omega_earth => omega + +use transforms_mod, only : get_deg_lon, & + get_deg_lat, & + get_grid_boundaries, & + get_grid_domain, & + get_spec_domain, & + area_weighted_global_mean, & + atmosphere_domain + +use time_manager_mod, only : time_type, & + set_time, & + get_time, & + interval_alarm, & + operator(+), & + operator(<), & + operator(==) + +use shallow_dynamics_mod, only : shallow_dynamics_init, & + shallow_dynamics, & + shallow_dynamics_end, & + dynamics_type + +use shallow_physics_mod, only : shallow_physics_init, & + shallow_physics, & + shallow_physics_end, & + phys_type + +use shallow_diagnostics_mod, only : shallow_diagnostics_init, & + shallow_diagnostics + + +!======================================================================== +implicit none +private +!======================================================================== + +! version information +!======================================================================== +character(len=128) :: version = '$Id: atmosphere.F90,v 14.0 2007/03/15 22:13:18 fms Exp $' +character(len=128) :: tagname = '$Name: siena_201207 $' +!======================================================================== + +public :: atmosphere_init, & + atmosphere, & + atmosphere_end, & + atmosphere_domain + +!======================================================================== + +integer, parameter :: num_time_levels = 2 + +integer :: unit, seconds, days +integer :: pe, npes +integer :: previous, current, future +logical :: root + +integer :: dt_integer +real :: dt_real +type(time_type) :: dt_time_type, Time_init, Time_step + +real :: delta_t ! = 2*dt_real for leapfrog step + +integer, dimension(2) :: axes + +type(phys_type), save :: Phys +type(dynamics_type), save :: Dyn + +integer :: is, ie, js, je, ms, me, ns, ne +integer :: num_lon, num_lat +integer, dimension(4) :: axis_id ! axes identifiers + +logical :: module_is_initialized =.false. + + +integer :: print_interval +! namelist +!======================================================================== +namelist /atmosphere_nml/ print_interval +!======================================================================== + +contains +!======================================================================= + +subroutine atmosphere_init(Time_init_in, Time, Time_step_in) + +type (time_type), intent(in) :: Time_init_in, Time, Time_step_in + +integer :: i, j, n, nn, ierr, io, unit +integer :: nlon, nlat + +pe = mpp_pe() +root = (pe == mpp_root_pe()) + +Time_step = Time_step_in +call get_time(Time_step, seconds, days) +dt_integer = 86400*days + seconds +dt_real = float(dt_integer) +dt_time_type = Time_step +Time_init = Time_init_in + +! read the namelist + +if (file_exist('input.nml')) then + unit = open_namelist_file () + ierr=1 + do while (ierr /= 0) + read (unit, nml=atmosphere_nml, iostat=io, end=10) + ierr = check_nml_error (io, 'atmosphere_nml') + enddo + 10 call close_file (unit) +endif +call write_version_number(version, tagname) +if (root) write (stdlog(), nml=atmosphere_nml) + +call shallow_dynamics_init (Dyn, Time, Time_init) + +call get_grid_domain(is,ie,js,je) +call get_spec_domain(ms,me,ns,ne) + +num_lon = Dyn%num_lon +num_lat = Dyn%num_lat + +nlon = ie+1-is ! size of grid on each processor +nlat = je+1-js + +call shallow_physics_init(Phys) +call shallow_diagnostics_init(Time, num_lon, num_lat) + +if(Time == Time_init) then + previous = 1 + current = 1 +else + previous = 1 + current = 2 +endif + +module_is_initialized = .true. + +return +end subroutine atmosphere_init + +!===================================================================== + +subroutine atmosphere(Time) + +type (time_type), intent(in) :: Time +integer :: day, second, dt + + +if(.not.module_is_initialized) then + call error_mesg('atmosphere', & + 'atmosphere_init has not been called', FATAL) +end if + +call get_time(Time_step, second, day) +dt = second + 86400*day + +Dyn%Tend%u = 0.0 +Dyn%Tend%v = 0.0 +Dyn%Tend%h = 0.0 +if(Dyn%grid_tracer) Dyn%Tend%tr = 0.0 +if(Dyn%spec_tracer) Dyn%Tend%trs = 0.0 + +if(Time == Time_init) then + delta_t = dt_real + future = 2 +else + delta_t = 2.0*dt_real + future = previous +endif + +call shallow_physics(Time, & + Dyn%Tend%u, Dyn%Tend%v, Dyn%Tend%h, & + Dyn%Grid%u, Dyn%Grid%v, Dyn%Grid%h, & + delta_t, previous, current, & + Phys) + +call shallow_dynamics(Time, Time_init, & + Dyn, previous, current, future, delta_t) + +previous = current +current = future + +call shallow_diagnostics (Time+Time_step, Dyn%Grid, Phys, current) + +call get_time(Time+Time_step, second, day) +if(mod(second+86400*day, print_interval) < dt) & + call global_diag(second, day, current) + +return +end subroutine atmosphere + +!======================================================================================= + +subroutine global_diag(second, day, current) + +integer, intent(in) :: second, day, current + +real :: enstrophy, div_squared, max_Froude +real, dimension(size(Dyn%Grid%u,1), size(Dyn%Grid%u,2)) :: speed + +enstrophy = & +area_weighted_global_mean(Dyn%grid%vor(:,:,current)*Dyn%grid%vor(:,:,current)) + +div_squared = & +area_weighted_global_mean(Dyn%grid%div(:,:,current)*Dyn%grid%div(:,:,current)) + +speed = Dyn%Grid%u(:,:,current)*Dyn%Grid%u(:,:,current) +& + Dyn%Grid%v(:,:,current)*Dyn%Grid%v(:,:,current) +max_Froude = maxval(speed/Dyn%Grid%h(:,:,current)) +call mpp_max(max_Froude) + +if(root) then + write(*,1000) day, second, enstrophy, div_squared, max_Froude +end if +1000 format(1x, 'day =',i6,2x,'second =', i6, & + 2x,'enstrophy = ',e13.6,3x,'div_squared = ',e13.6, 3x, & + 'max_Froude = ', e10.3) + +return +end subroutine global_diag + +!=============================================================================== +subroutine atmosphere_end + +if(.not.module_is_initialized) then + call error_mesg('atmosphere_end', & + 'atmosphere_init has not been called.', FATAL) +end if + +call shallow_physics_end (Phys) +call shallow_dynamics_end (Dyn, previous, current) + +module_is_initialized = .false. + +return +end subroutine atmosphere_end + +!======================================================================================= +end module atmosphere_mod diff --git a/src/atmos_spectral_shallow/atmosphere.html b/src/atmos_spectral_shallow/atmosphere.html new file mode 100644 index 000000000..13e269faf --- /dev/null +++ b/src/atmos_spectral_shallow/atmosphere.html @@ -0,0 +1,164 @@ + +module atmosphere_mod + + +
+ +

module atmosphere_mod

+ + +
+     Contact: Isaac Held
+     Reviewers: Peter Phillipps
+
+
+ + +
+

OVERVIEW

+ +
+   A spectral transform model for the shallow water equations on the sphere
+
+
+ + +
+

DESCRIPTION

+ +
+   Integrates the shallow water equations for hydrostatic flow in a thin layer
+   of homogeneous fluid on the sphere, using the spectral transform technique.
+   Also allows for the inclusion of a passive tracer advected by the 
+   spectral advection algorithm as the vorticity, and a gridpoint tracer 
+   advected with a finite volume algorithm on the transform grid.  
+   The default experiment is forced by a "monsoonal" mass source, starting
+   from a state of rest.
+   
+   For a full description of the model and algorithms used, see shallow.ps
+
+   The interfaces in this module are the generic intefaces required by the
+   main program that can be used to drive various idealized atmospheric
+   models within FMS. Model resolution and related parameters are set in
+   namelists within the modules shallow_xxx.
+
+ + + +
+

OTHER MODULES USED

+ +
+     fms_mod
+     constants_mod
+     transforms_mod
+     time_manager_mod
+     diag_manager_mod
+     shallow_dynamics_mod
+     shallow_physics_mod
+     shallow_diagnostics_mod
+
+
+ + +
+

PUBLIC INTERFACE

+ +
+  use atmosphere_mod [,only: atmosphere_init,       
+                             atmosphere,
+			     atmosphere_end]
+
+
+ + +
+

PUBLIC DATA

+ +
+  There are no public data types
+
+
+ + +
+

PUBLIC ROUTINES

+ +
+subroutine atmosphere_init. Initializes the model.
+subroutine atmosphere.      Integrates forward one time step
+subroutine atmosphere_end.  Terminates model, cleaning up memory and finalizing diagnostics.
+
+
+
+ subroutine atmosphere_init(Time_init, Time, Time_step)
+
+   input:
+
+   type(time_type) :: Time_init -- Initial model time
+
+   type(time_type) :: Time      -- Model time
+
+   type(time_type) :: Time_step -- Time step
+
+   When Time=Time_init, the first time step is a forward
+   step rather than leap frog because a cold start is assumed.
+
+   The FMS main program that runs the solo atmospheric models
+   obtains Time_init from the diag_table and Time from its namelist.
+       
+
+
+ + + subroutine atmosphere(Time) + + input: + + type(time_type) :: Time -- Model time + + Integrates forward one time step + + +
+ + subroutine atmosphere_end + + No calling arguments. + + Terminates model, cleaning up memory and finalizing diagnostics + +
+
+ + +

NAMELIST

+ +
+&atmosphere_nml
+
+   print_interval, integer : time interval in seconds 
+   between prints of global mean energy and enstrophy to standard output
+
+
+ + +
+

ERROR MESSAGES

+ +
+  Fatal error message if subroutine atmosphere or atmosphere_end
+  is called prior to atmosphere_init.
+
+
+ +
+ + diff --git a/src/atmos_spectral_shallow/shallow.pdf b/src/atmos_spectral_shallow/shallow.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3ae5dbd1a0157a5e7710577d64dc696e69f1a415 GIT binary patch literal 62941 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 literal 0 HcmV?d00001 diff --git a/src/atmos_spectral_shallow/shallow_diagnostics.F90 b/src/atmos_spectral_shallow/shallow_diagnostics.F90 new file mode 100644 index 000000000..b8dc52f68 --- /dev/null +++ b/src/atmos_spectral_shallow/shallow_diagnostics.F90 @@ -0,0 +1,139 @@ + +module shallow_diagnostics_mod + +!----------------------------------------------------------------------- +! GNU General Public License +! +! This program is free software; you can redistribute it and/or modify it and +! are expected to follow the terms of the GNU General Public License +! as published by the Free Software Foundation; either version 2 of +! the License, or (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, but WITHOUT +! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +! License for more details. +! +! For the full text of the GNU General Public License, +! write to: Free Software Foundation, Inc., +! 675 Mass Ave, Cambridge, MA 02139, USA. +! or see: http://www.gnu.org/licenses/gpl.html +!----------------------------------------------------------------------- + +use fms_mod, only: write_version_number + +use transforms_mod, only: get_grid_boundaries, & + get_deg_lon, & + get_deg_lat, & + get_grid_domain, & + get_spec_domain, & + grid_domain + +use diag_manager_mod, only: diag_axis_init, & + register_diag_field, & + register_static_field, & + send_data + +use time_manager_mod, only: time_type, & + get_time + + +use shallow_physics_mod, only: phys_type +use shallow_dynamics_mod, only: grid_type + + +implicit none +private + +public :: shallow_diagnostics_init, & + shallow_diagnostics + +character(len=84), parameter :: version = '$Id: shallow_diagnostics.F90,v 10.0 2003/10/24 22:01:02 fms Exp $' +character(len=84), parameter :: tagname = '$Name: siena_201207 $' +character(len=8) :: axiset = 'shallow' +character(len=84) :: mod_name = 'shallow_diagnostics' + +logical :: module_is_initialized = .false. + +integer :: id_vor, id_stream, id_pv, id_u, id_v, id_div, id_h, id_trs, id_tr + +integer :: is, ie, js, je + +contains + +!----------------------------------------------------------------------------------------------------------------- +subroutine shallow_diagnostics_init(Time, lon_max, lat_max) + +type(time_type), intent(in) :: Time +integer, intent(in) :: lon_max, lat_max + +real, dimension(lon_max ) :: lon +real, dimension(lon_max+1) :: lonb +real, dimension(lat_max ) :: lat +real, dimension(lat_max+1) :: latb + +integer, dimension(2) :: axis_2d + +integer :: log_unit, id_lonb, id_lon, id_latb, id_lat +integer :: namelist_unit, ierr, io +real :: rad_to_deg +logical :: used + +call write_version_number(version, tagname) + +call get_grid_domain(is, ie, js, je) + +rad_to_deg = 45./atan(1.) +call get_grid_boundaries(lonb,latb,global=.true.) +call get_deg_lon(lon) +call get_deg_lat(lat) + +id_lonb=diag_axis_init('lonb', rad_to_deg*lonb, 'degrees_E', 'x', 'longitude edges', set_name=axiset, Domain2=grid_domain) +id_latb=diag_axis_init('latb', rad_to_deg*latb, 'degrees_N', 'y', 'latitude edges', set_name=axiset, Domain2=grid_domain) +id_lon =diag_axis_init('lon', lon, 'degrees_E', 'x', 'longitude', set_name=axiset, Domain2=grid_domain, edges=id_lonb) +id_lat =diag_axis_init('lat', lat, 'degrees_N', 'y', 'latitude', set_name=axiset, Domain2=grid_domain, edges=id_latb) + +axis_2d(1) = id_lon +axis_2d(2) = id_lat + +id_u = register_diag_field(mod_name, 'ucomp' , axis_2d, Time, 'u_wind' , 'm/s' ) +id_v = register_diag_field(mod_name, 'vcomp' , axis_2d, Time, 'v_wind' , 'm/s' ) +id_vor = register_diag_field(mod_name, 'vor' , axis_2d, Time, 'relative vorticity' , '1/s' ) +id_div = register_diag_field(mod_name, 'div' , axis_2d, Time, 'divergence' , '1/s' ) +id_h = register_diag_field(mod_name, 'h' , axis_2d, Time, 'geopotential' , 'm2/s2' ) +id_pv = register_diag_field(mod_name, 'pv' , axis_2d, Time, 'potential vorticity' , 's/m2' ) +id_stream = register_diag_field(mod_name, 'stream', axis_2d, Time, 'streamfunction' , 'm^2/s' ) +id_trs = register_diag_field(mod_name, 'trs' , axis_2d, Time, 'spectral tracer' , 'none' ) +id_tr = register_diag_field(mod_name, 'tr' , axis_2d, Time, 'grid tracer' , 'none' ) + +module_is_initialized = .true. + +return +end subroutine shallow_diagnostics_init + +!-------------------------------------------------------------------------------------------- + +subroutine shallow_diagnostics(Time, Grid, Phys, time_index) + +type(time_type), intent(in) :: Time +type(phys_type), intent(in) :: Phys +type(grid_type), intent(in) :: Grid +integer, intent(in) :: time_index + +logical :: used + +if(id_u > 0) used = send_data(id_u , Grid%u (:,:, time_index) , time) +if(id_v > 0) used = send_data(id_v , Grid%v (:,:, time_index) , time) +if(id_vor > 0) used = send_data(id_vor , Grid%vor (:,:, time_index) , time) +if(id_div > 0) used = send_data(id_div , Grid%div (:,:, time_index) , time) +if(id_h > 0) used = send_data(id_h , Grid%h (:,:, time_index) , time) +if(id_pv > 0) used = send_data(id_pv , Grid%pv (:,:) , time) +if(id_stream > 0) used = send_data(id_stream , Grid%stream (:,:) , time) +if(id_tr > 0) used = send_data(id_tr , Grid%tr (:,:, time_index) , time) +if(id_trs > 0) used = send_data(id_trs , Grid%trs (:,:, time_index) , time) + +return +end subroutine shallow_diagnostics +!-------------------------------------------------------------------------------------------- + +end module shallow_diagnostics_mod diff --git a/src/atmos_spectral_shallow/shallow_diagnostics.html b/src/atmos_spectral_shallow/shallow_diagnostics.html new file mode 100644 index 000000000..65db99f52 --- /dev/null +++ b/src/atmos_spectral_shallow/shallow_diagnostics.html @@ -0,0 +1,150 @@ + +module shallow_diagnostics_mod + + +
+ + +

module shallow_diagnostics_mod

+ + +
+     Contact: Isaac Held
+     Reviewers: Peter Phillipps
+
+
+
+ + +
+

OVERVIEW

+ +
+
+   The diagnostics module for the model that solves the shallow water
+   equation on the sphere  
+   
+
+
+ + +
+

DESCRIPTION

+ +
+
+   Using the diagnostics manager, creates output files for the shallow model.
+   Variables currently available for output are
+       zonal wind 
+       meridional wind 
+       relative vorticity
+       absolute vorticity
+       streamfunction
+       spectral tracer in grid domain
+       grid tracer
+       
+   Whether or not these fields are actually output, the location of the 
+   output, the frequency of output, whether or not the output is averaged
+   in time or an instantaneous snapshot, is controlled by a 
+   diag_table file utilized by the diagnostics manager module
+       
+   One can add other diagnostics by following the (somewhat convoluted)
+       pattern within the program
+
+
+
+
+ + +
+

OTHER MODULES USED

+ +
+
+     diag_manaager_mod
+     transforms_mod
+     time_manager_mod
+     shallow_dynamics_mod
+     shallow_physics_mod
+
+
+
+ + +
+

PUBLIC INTERFACE

+ +
+
+  use shallow_diagnostics_mod [,only: shallow_diagnostics_init,       
+                                         shallow_diagnostics]
+                                
+
+
+ + + +
+

PUBLIC ROUTINES

+ +
+
+subroutine  shallow_diagnostics_init
+subroutine  shallow_diagnostics
+
+
+
+
+ subroutine shallow_diagnostics_init(Time, num_lon, num_lat)
+ 
+   type(time_type)    , intent(in)     :: Time
+         current time 
+   integer, intent(in) :: num_lon, num_lat
+      num_lon = number of longitudes in global domain
+      num_lat = number of latitudes in global domain
+         
+
+   Initializes module
+
+
+
+
+ + + + subroutine shallow_diagnostics (Time, Grid, Phys, time_index) + + type(time_type), intent(in) :: Time + type(phys_type), intent(in) :: Phys + type(grid_type), intent(in) :: Grid + integer, intent(in) :: time_index + + phys_type is defined in shallow_physics_mod; ; + + grid_type is defined in shallow_dynamics_mod: + Grid contains all of the fields to be output + + many of the grid fields in grid_type are dimensioned (lon, lat, time_index) + where time_index = 1 or 2 -- the two time levels needed to update the + state of the model using a leapfrog step are toggled between (:,:,1) + and (:,:,2). The input time_index (which must equal either 1 or 2) + determines which of these two fields is output) + + (this is confusing -- the calling program needs to know what has + been placed in which slot -- it would be better to store this + information within the data type) + + + + +
+ + + diff --git a/src/atmos_spectral_shallow/shallow_dynamics.F90 b/src/atmos_spectral_shallow/shallow_dynamics.F90 new file mode 100644 index 000000000..543e37230 --- /dev/null +++ b/src/atmos_spectral_shallow/shallow_dynamics.F90 @@ -0,0 +1,607 @@ +module shallow_dynamics_mod + +!----------------------------------------------------------------------- +! GNU General Public License +! +! This program is free software; you can redistribute it and/or modify it and +! are expected to follow the terms of the GNU General Public License +! as published by the Free Software Foundation; either version 2 of +! the License, or (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, but WITHOUT +! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +! License for more details. +! +! For the full text of the GNU General Public License, +! write to: Free Software Foundation, Inc., +! 675 Mass Ave, Cambridge, MA 02139, USA. +! or see: http://www.gnu.org/licenses/gpl.html +!----------------------------------------------------------------------- + +use fms_mod, only: open_namelist_file, & + open_restart_file, & + file_exist, & + check_nml_error, & + error_mesg, & + FATAL, & + write_version_number, & + mpp_pe, & + mpp_root_pe, & + read_data, & + write_data, & + set_domain, & + close_file, & + stdlog + +use time_manager_mod, only : time_type, & + get_time, & + operator(==), & + operator(-) + +use constants_mod, only : radius, omega + +use transforms_mod, only: transforms_init, transforms_end, & + get_grid_boundaries, horizontal_advection, & + trans_spherical_to_grid, trans_grid_to_spherical, & + compute_laplacian, get_eigen_laplacian, & + get_sin_lat, get_cos_lat, & + get_deg_lon, get_deg_lat, & + get_grid_domain, get_spec_domain, & + spectral_domain, grid_domain, & + vor_div_from_uv_grid, uv_grid_from_vor_div + +use spectral_damping_mod, only: spectral_damping_init, compute_spectral_damping + +use leapfrog_mod, only: leapfrog + +use fv_advection_mod, only : fv_advection_init, a_grid_horiz_advection + +!====================================================================================== +implicit none +private +!====================================================================================== + +public :: shallow_dynamics_init, shallow_dynamics, shallow_dynamics_end, & + dynamics_type, grid_type, spectral_type, tendency_type + + +! version information +!=================================================================== +character(len=128) :: version = '$Id: shallow_dynamics.F90,v 10.0 2003/10/24 22:01:02 fms Exp $' +character(len=128) :: tagname = '$Name: siena_201207 $' +!=================================================================== + +type grid_type + real, pointer, dimension(:,:,:) :: u=>NULL(), v=>NULL(), vor=>NULL(), div=>NULL(), h=>NULL(), trs=>NULL(), tr=>NULL() + real, pointer, dimension(:,:) :: stream=>NULL(), pv=>NULL() +end type +type spectral_type + complex, pointer, dimension(:,:,:) :: vor=>NULL(), div=>NULL(), h=>NULL(), trs=>NULL() +end type +type tendency_type + real, pointer, dimension(:,:) :: u=>NULL(), v=>NULL(), h=>NULL(), trs=>NULL(), tr=>NULL() +end type +type dynamics_type + type(grid_type) :: grid + type(spectral_type) :: spec + type(tendency_type) :: tend + integer :: num_lon, num_lat + logical :: grid_tracer, spec_tracer +end type + + + +integer, parameter :: num_time_levels = 2 + +integer :: is, ie, js, je, ms, me, ns, ne + +logical :: module_is_initialized = .false. + +real, allocatable, dimension(:) :: sin_lat, cos_lat, rad_lat, deg_lat, deg_lon, & + coriolis + +real, allocatable, dimension(:,:) :: eigen + +integer :: pe, npes + + +! namelist parameters with default values + +integer :: num_lon = 256 +integer :: num_lat = 128 +integer :: num_fourier = 85 +integer :: num_spherical = 86 +integer :: fourier_inc = 1 +! (these define a standard T85 model) + +logical :: check_fourier_imag = .false. +logical :: south_to_north = .true. +logical :: triang_trunc = .true. + +real :: robert_coeff = 0.04 +real :: robert_coeff_tracer = 0.04 +real :: longitude_origin = 0.0 + +character(len=64) :: damping_option = 'resolution_dependent' +integer :: damping_order = 4 +real :: damping_coeff = 1.e-04 +real :: h_0 = 3.e04 + +logical :: spec_tracer = .true. +logical :: grid_tracer = .true. + +real, dimension(2) :: valid_range_v = (/-1.e3,1.e3/) + +namelist /shallow_dynamics_nml/ check_fourier_imag, & + south_to_north, triang_trunc, & + num_lon, num_lat, num_fourier, & + num_spherical, fourier_inc, & + longitude_origin, damping_option, & + damping_order, damping_coeff, & + robert_coeff, robert_coeff_tracer, & + h_0, spec_tracer, grid_tracer, & + valid_range_v + +contains + +!======================================================================================= + +subroutine shallow_dynamics_init (Dyn, Time, Time_init) + +type(dynamics_type), intent(inout) :: Dyn +type(time_type) , intent(in) :: Time, Time_init + +integer :: i, j + +real, allocatable, dimension(:) :: glon_bnd, glat_bnd +real :: xx, yy, dd + +integer :: ierr, io, unit +logical :: root + +! < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > + +call write_version_number (version, tagname) + +pe = mpp_pe() +root = (pe == mpp_root_pe()) + +if (file_exist('input.nml')) then + unit = open_namelist_file () + ierr=1 + do while (ierr /= 0) + read (unit, nml=shallow_dynamics_nml, iostat=io, end=10) + ierr = check_nml_error (io, 'shallow_dynamics_nml') + enddo + 10 call close_file (unit) +endif + +if (root) write (stdlog(), nml=shallow_dynamics_nml) + +call transforms_init(radius, num_lat, num_lon, num_fourier, fourier_inc, num_spherical, & + south_to_north=south_to_north, & + triang_trunc=triang_trunc, & + longitude_origin=longitude_origin ) + +call get_grid_domain(is,ie,js,je) +call get_spec_domain(ms,me,ns,ne) + +Dyn%num_lon = num_lon +Dyn%num_lat = num_lat +Dyn%spec_tracer = spec_tracer +Dyn%grid_tracer = grid_tracer + +allocate (sin_lat (js:je)) +allocate (cos_lat (js:je)) +allocate (deg_lat (js:je)) +allocate (deg_lon (is:ie)) +allocate (coriolis (js:je)) + +call get_deg_lon (deg_lon) +call get_deg_lat (deg_lat) +call get_sin_lat (sin_lat) +call get_cos_lat (cos_lat) + +allocate (glon_bnd (num_lon + 1)) +allocate (glat_bnd (num_lat + 1)) +call get_grid_boundaries (glon_bnd, glat_bnd, global=.true.) + +coriolis = 2*omega*sin_lat + +call spectral_damping_init(damping_coeff, damping_order, damping_option, num_fourier, num_spherical, 1, 0., 0., 0.) + +allocate(eigen(ms:me,ns:ne)) +call get_eigen_laplacian(eigen) + +allocate (Dyn%spec%vor (ms:me, ns:ne, num_time_levels)) +allocate (Dyn%spec%div (ms:me, ns:ne, num_time_levels)) +allocate (Dyn%spec%h (ms:me, ns:ne, num_time_levels)) + +allocate (Dyn%grid%u (is:ie, js:je, num_time_levels)) +allocate (Dyn%grid%v (is:ie, js:je, num_time_levels)) +allocate (Dyn%grid%vor (is:ie, js:je, num_time_levels)) +allocate (Dyn%grid%div (is:ie, js:je, num_time_levels)) +allocate (Dyn%grid%h (is:ie, js:je, num_time_levels)) + +allocate (Dyn%tend%u (is:ie, js:je)) +allocate (Dyn%tend%v (is:ie, js:je)) +allocate (Dyn%tend%h (is:ie, js:je)) +allocate (Dyn%grid%stream (is:ie, js:je)) +allocate (Dyn%grid%pv (is:ie, js:je)) + +call fv_advection_init(num_lon, num_lat, glat_bnd, 360./float(fourier_inc)) +if(Dyn%grid_tracer) then + allocate(Dyn%Grid%tr (is:ie, js:je, num_time_levels)) + allocate(Dyn%Tend%tr (is:ie, js:je)) +endif + +if(Dyn%spec_tracer) then + allocate(Dyn%Grid%trs (is:ie, js:je, num_time_levels)) + allocate(Dyn%Tend%trs (is:ie, js:je)) + allocate(Dyn%Spec%trs (ms:me, ns:ne, num_time_levels)) +endif + +if(Time == Time_init) then + + Dyn%Grid%vor(:,:,1) = 0.0 + Dyn%Grid%div(:,:,1) = 0.0 + Dyn%Grid%h (:,:,1) = h_0 + + call trans_grid_to_spherical(Dyn%Grid%vor(:,:,1), Dyn%Spec%vor(:,:,1)) + call trans_grid_to_spherical(Dyn%Grid%div(:,:,1), Dyn%Spec%div(:,:,1)) + call trans_grid_to_spherical(Dyn%Grid%h (:,:,1), Dyn%Spec%h (:,:,1)) + + call uv_grid_from_vor_div (Dyn%Spec%vor(:,:,1), Dyn%Spec%div(:,:,1), & + Dyn%Grid%u (:,:,1), Dyn%Grid%v (:,:,1)) + + if(Dyn%grid_tracer) then + Dyn%Grid%tr = 0.0 + do j = js, je + if(deg_lat(j) > 10.0 .and. deg_lat(j) < 20.0) Dyn%Grid%tr(:,j,1) = 1.0 + if(deg_lat(j) > 70.0 ) Dyn%Grid%tr(:,j,1) = -1.0 + end do + endif + + if(Dyn%spec_tracer) then + Dyn%Grid%trs = 0.0 + do j = js, je + if(deg_lat(j) > 10.0 .and. deg_lat(j) < 20.0) Dyn%Grid%trs(:,j,1) = 1.0 + if(deg_lat(j) > 70.0 ) Dyn%Grid%trs(:,j,1) = -1.0 + end do + call trans_grid_to_spherical(Dyn%Grid%trs(:,:,1), Dyn%Spec%trs(:,:,1)) + endif + +else + + call read_restart(Dyn) + +endif + +module_is_initialized = .true. + +return +end subroutine shallow_dynamics_init + +!======================================================================================== + +subroutine shallow_dynamics(Time, Time_init, Dyn, previous, current, future, delta_t) + +type(time_type) , intent(in) :: Time, Time_init +type(dynamics_type), intent(inout) :: Dyn +integer, intent(in ) :: previous, current, future +real, intent(in ) :: delta_t + +! < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > + +complex, dimension(ms:me, ns:ne) :: dt_vors, dt_divs, dt_hs, stream, bs, work +real, dimension(is:ie, js:je) :: vorg, bg, h_future, h_dt, dt_vorg +integer :: j + +! < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > + +if(.not.module_is_initialized) then + call error_mesg('shallow_dynamics','dynamics has not been initialized ', FATAL) +endif + + +do j = js,je + vorg(:,j) = Dyn%Grid%vor(:,j,current) + coriolis(j) +end do +Dyn%Tend%u = Dyn%Tend%u + vorg*Dyn%Grid%v(:,:,current) +Dyn%Tend%v = Dyn%Tend%v - vorg*Dyn%Grid%u(:,:,current) + +call vor_div_from_uv_grid (Dyn%Tend%u, Dyn%Tend%v, dt_vors, dt_divs) + +call horizontal_advection (Dyn%Spec%h(:,:,current), & + Dyn%Grid%u(:,:,current), Dyn%Grid%v(:,:,current), Dyn%Tend%h) + +Dyn%Tend%h = Dyn%Tend%h - Dyn%Grid%h(:,:,current)*Dyn%Grid%div(:,:,current) + +call trans_grid_to_spherical (Dyn%Tend%h, dt_hs) + +bg = (Dyn%Grid%h(:,:,current) + & + 0.5*(Dyn%Grid%u(:,:,current)**2 + Dyn%Grid%v(:,:,current)**2)) + +call trans_grid_to_spherical(bg, bs) +dt_divs = dt_divs - compute_laplacian(bs) + +call implicit_correction (dt_divs, dt_hs, Dyn%Spec%div, Dyn%Spec%h, & + delta_t, previous, current) + +call compute_spectral_damping(Dyn%Spec%vor(:,:,previous), dt_vors, delta_t) +call compute_spectral_damping(Dyn%Spec%div(:,:,previous), dt_divs, delta_t) +call compute_spectral_damping(Dyn%Spec%h (:,:,previous), dt_hs , delta_t) + +call leapfrog(Dyn%Spec%vor , dt_vors , previous, current, future, delta_t, robert_coeff) +call leapfrog(Dyn%Spec%div , dt_divs , previous, current, future, delta_t, robert_coeff) +call leapfrog(Dyn%Spec%h , dt_hs , previous, current, future, delta_t, robert_coeff) + +call trans_spherical_to_grid(Dyn%Spec%vor(:,:,future), Dyn%Grid%vor(:,:,future)) +call trans_spherical_to_grid(Dyn%Spec%div(:,:,future), Dyn%Grid%div(:,:,future)) + + +call uv_grid_from_vor_div (Dyn%Spec%vor (:,:,future), Dyn%Spec%div(:,:,future), & + Dyn%Grid%u (:,:,future), Dyn%Grid%v (:,:,future)) + +call trans_spherical_to_grid (Dyn%Spec%h (:,:,future), Dyn%Grid%h(:,:,future)) + +if(minval(Dyn%Grid%v) < valid_range_v(1) .or. maxval(Dyn%Grid%v) > valid_range_v(2)) then + call error_mesg('shallow_dynamics','meridional wind out of valid range', FATAL) +endif + +if(Dyn%spec_tracer) call update_spec_tracer(Dyn%Spec%trs, Dyn%Grid%trs, Dyn%Tend%trs, & + Dyn%Grid%u, Dyn%Grid%v, previous, current, future, delta_t) + +if(Dyn%grid_tracer) call update_grid_tracer(Dyn%Grid%tr, Dyn%Tend%tr, & + Dyn%Grid%u, Dyn%Grid%v, previous, current, future, delta_t) + + +! for diagnostics + +stream = compute_laplacian(Dyn%Spec%vor(:,:,current), -1) ! for diagnostic purposes +call trans_spherical_to_grid(stream, Dyn%grid%stream) + +Dyn%Grid%pv = vorg/Dyn%Grid%h(:,:,current) + +return +end subroutine shallow_dynamics +!================================================================================ + +subroutine implicit_correction(dt_divs, dt_hs, divs, hs, delta_t, previous, current) + +complex, intent(inout), dimension(ms:,ns:) :: dt_divs, dt_hs +complex, intent(in), dimension(ms:,ns:,:) :: divs, hs +real , intent(in) :: delta_t +integer, intent(in) :: previous, current + +real :: xi, mu, mu2 + +xi = 0.5 ! centered implicit (for backwards implicit, set xi = 1.0) + +mu = xi*delta_t +mu2 = mu*mu + +dt_hs = dt_hs + h_0*(divs(:,:,current) - divs(:,:,previous)) +dt_divs = dt_divs - eigen*(hs(:,:,current) - hs(:,:,previous)) + +dt_divs = (dt_divs + mu*eigen*dt_hs)/(1.0 + mu2*eigen*h_0) +dt_hs = dt_hs - mu*h_0*dt_divs + +return +end subroutine implicit_correction + +!=================================================================================== + +subroutine update_spec_tracer(tr_spec, tr_grid, dt_tr, ug, vg, & + previous, current, future, delta_t) + +complex, intent(inout), dimension(ms:me, ns:ne, num_time_levels) :: tr_spec +real , intent(inout), dimension(is:ie, js:je, num_time_levels) :: tr_grid +real , intent(inout), dimension(is:ie, js:je ) :: dt_tr +real , intent(in ), dimension(is:ie, js:je, num_time_levels) :: ug, vg +real , intent(in ) :: delta_t +integer, intent(in ) :: previous, current, future + +complex, dimension(ms:me, ns:ne) :: dt_trs + +call horizontal_advection (tr_spec(:,:,current), ug(:,:,current), vg(:,:,current), dt_tr) +call trans_grid_to_spherical (dt_tr, dt_trs) +call compute_spectral_damping (tr_spec(:,:,previous), dt_trs, delta_t) +call leapfrog (tr_spec, dt_trs, previous, current, future, delta_t, robert_coeff) +call trans_spherical_to_grid (tr_spec(:,:,future), tr_grid(:,:,future)) + +return +end subroutine update_spec_tracer +!========================================================================== + +subroutine update_grid_tracer(tr_grid, dt_tr_grid, ug, vg, & + previous, current, future, delta_t) + +real , intent(inout), dimension(is:ie, js:je, num_time_levels) :: tr_grid +real , intent(inout), dimension(is:ie, js:je ) :: dt_tr_grid +real , intent(in ), dimension(is:ie, js:je, num_time_levels) :: ug, vg + +real , intent(in ) :: delta_t +integer, intent(in ) :: previous, current, future + +real, dimension(is:ie,js:je) :: tr_current, tr_future + +tr_future = tr_grid(:,:,previous) + delta_t*dt_tr_grid +dt_tr_grid = 0.0 +call a_grid_horiz_advection (ug(:,:,current), vg(:,:,current), tr_future, delta_t, dt_tr_grid) +tr_future = tr_future + delta_t*dt_tr_grid +tr_current = tr_grid(:,:,current) + & + robert_coeff_tracer*(tr_grid(:,:,previous) + tr_future - 2.0*tr_grid(:,:,current)) +tr_grid(:,:,current) = tr_current +tr_grid(:,:,future) = tr_future + +return +end subroutine update_grid_tracer + +!========================================================================== + +subroutine read_restart(Dyn) + +type(dynamics_type), intent(inout) :: Dyn + +integer :: unit, m, n, nt +real, dimension(ms:me, ns:ne) :: real_part, imag_part + +if(file_exist('INPUT/shallow_dynamics.res.nc')) then + do nt = 1, 2 + call read_data('INPUT/shallow_dynamics.res.nc', 'vors_real', real_part, spectral_domain, timelevel=nt) + call read_data('INPUT/shallow_dynamics.res.nc', 'vors_imag', imag_part, spectral_domain, timelevel=nt) + do n=ns,ne + do m=ms,me + Dyn%Spec%vor(m,n,nt) = cmplx(real_part(m,n),imag_part(m,n)) + end do + end do + call read_data('INPUT/shallow_dynamics.res.nc', 'divs_real', real_part, spectral_domain, timelevel=nt) + call read_data('INPUT/shallow_dynamics.res.nc', 'divs_imag', imag_part, spectral_domain, timelevel=nt) + do n=ns,ne + do m=ms,me + Dyn%Spec%div(m,n,nt) = cmplx(real_part(m,n),imag_part(m,n)) + end do + end do + call read_data('INPUT/shallow_dynamics.res.nc', 'hs_real', real_part, spectral_domain, timelevel=nt) + call read_data('INPUT/shallow_dynamics.res.nc', 'hs_imag', imag_part, spectral_domain, timelevel=nt) + do n=ns,ne + do m=ms,me + Dyn%Spec%h(m,n,nt) = cmplx(real_part(m,n),imag_part(m,n)) + end do + end do + if(Dyn%spec_tracer) then + call read_data('INPUT/shallow_dynamics.res.nc', 'trs_real', real_part, spectral_domain, timelevel=nt) + call read_data('INPUT/shallow_dynamics.res.nc', 'trs_imag', imag_part, spectral_domain, timelevel=nt) + do n=ns,ne + do m=ms,me + Dyn%Spec%trs(m,n,nt) = cmplx(real_part(m,n),imag_part(m,n)) + end do + end do + endif + call read_data('INPUT/shallow_dynamics.res.nc', 'u', Dyn%Grid%u (:,:,nt), grid_domain, timelevel=nt) + call read_data('INPUT/shallow_dynamics.res.nc', 'v', Dyn%Grid%v (:,:,nt), grid_domain, timelevel=nt) + call read_data('INPUT/shallow_dynamics.res.nc', 'vor', Dyn%Grid%vor(:,:,nt), grid_domain, timelevel=nt) + call read_data('INPUT/shallow_dynamics.res.nc', 'div', Dyn%Grid%div(:,:,nt), grid_domain, timelevel=nt) + call read_data('INPUT/shallow_dynamics.res.nc', 'h', Dyn%Grid%h (:,:,nt), grid_domain, timelevel=nt) + if(Dyn%spec_tracer) then + call read_data('INPUT/shallow_dynamics.res.nc', 'trs', Dyn%Grid%trs(:,:,nt), grid_domain, timelevel=nt) + endif + if(Dyn%grid_tracer) then + call read_data('INPUT/shallow_dynamics.res.nc', 'tr', Dyn%Grid%tr(:,:,nt), grid_domain, timelevel=nt) + endif + end do +else if(file_exist('INPUT/shallow_dynamics.res')) then + unit = open_restart_file(file='INPUT/shallow_dynamics.res',action='read') + + do nt = 1, 2 + call set_domain(spectral_domain) + call read_data(unit,Dyn%Spec%vor(:,:, nt)) + call read_data(unit,Dyn%Spec%div(:,:, nt)) + call read_data(unit,Dyn%Spec%h (:,:, nt)) + if(Dyn%spec_tracer) call read_data(unit,Dyn%Spec%trs(:,:, nt)) + + call set_domain(grid_domain) + call read_data(unit,Dyn%Grid%u (:,:, nt)) + call read_data(unit,Dyn%Grid%v (:,:, nt)) + call read_data(unit,Dyn%Grid%vor (:,:, nt)) + call read_data(unit,Dyn%Grid%div (:,:, nt)) + call read_data(unit,Dyn%Grid%h (:,:, nt)) + if(Dyn%spec_tracer) call read_data(unit,Dyn%Grid%trs(:,:, nt)) + if(Dyn%grid_tracer) call read_data(unit,Dyn%Grid%tr (:,:, nt)) + + end do + call close_file(unit) + +else + call error_mesg('read_restart', 'restart does not exist', FATAL) +endif + +return +end subroutine read_restart + +!==================================================================== + +subroutine write_restart(Dyn, previous, current) + +type(dynamics_type), intent(in) :: Dyn +integer, intent(in) :: previous, current + +integer :: unit, nt, nn + +do nt = 1, 2 + if(nt == 1) nn = previous + if(nt == 2) nn = current + call write_data('RESTART/shallow_dynamics.res.nc', 'vors_real', real(Dyn%Spec%vor(:,:,nn)), spectral_domain) + call write_data('RESTART/shallow_dynamics.res.nc', 'vors_imag', aimag(Dyn%Spec%vor(:,:,nn)), spectral_domain) + call write_data('RESTART/shallow_dynamics.res.nc', 'divs_real', real(Dyn%Spec%div(:,:,nn)), spectral_domain) + call write_data('RESTART/shallow_dynamics.res.nc', 'divs_imag', aimag(Dyn%Spec%div(:,:,nn)), spectral_domain) + call write_data('RESTART/shallow_dynamics.res.nc', 'hs_real', real(Dyn%Spec%h (:,:,nn)), spectral_domain) + call write_data('RESTART/shallow_dynamics.res.nc', 'hs_imag', aimag(Dyn%Spec%h (:,:,nn)), spectral_domain) + if(Dyn%spec_tracer) then + call write_data('RESTART/shallow_dynamics.res.nc', 'trs_real', real(Dyn%Spec%trs(:,:,nn)), spectral_domain) + call write_data('RESTART/shallow_dynamics.res.nc', 'trs_imag', aimag(Dyn%Spec%trs(:,:,nn)), spectral_domain) + endif + call write_data('RESTART/shallow_dynamics.res.nc', 'u', Dyn%Grid%u (:,:,nn), grid_domain) + call write_data('RESTART/shallow_dynamics.res.nc', 'v', Dyn%Grid%v (:,:,nn), grid_domain) + call write_data('RESTART/shallow_dynamics.res.nc', 'vor', Dyn%Grid%vor(:,:,nn), grid_domain) + call write_data('RESTART/shallow_dynamics.res.nc', 'div', Dyn%Grid%div(:,:,nn), grid_domain) + call write_data('RESTART/shallow_dynamics.res.nc', 'h', Dyn%Grid%h (:,:,nn), grid_domain) + if(Dyn%spec_tracer) then + call write_data('RESTART/shallow_dynamics.res.nc', 'trs', Dyn%Grid%trs(:,:,nn), grid_domain) + endif + if(Dyn%grid_tracer) then + call write_data('RESTART/shallow_dynamics.res.nc', 'tr', Dyn%Grid%tr(:,:,nn), grid_domain) + endif +enddo + +!unit = open_restart_file(file='RESTART/shallow_dynamics.res', action='write') + +!do n = 1, 2 +! if(n == 1) nn = previous +! if(n == 2) nn = current +! +! call set_domain(spectral_domain) +! call write_data(unit,Dyn%Spec%vor(:,:, nn)) +! call write_data(unit,Dyn%Spec%div(:,:, nn)) +! call write_data(unit,Dyn%Spec%h (:,:, nn)) +! if(Dyn%spec_tracer) call write_data(unit,Dyn%Spec%trs(:,:, nn)) +! +! call set_domain(grid_domain) +! call write_data(unit,Dyn%Grid%u (:,:, nn)) +! call write_data(unit,Dyn%Grid%v (:,:, nn)) +! call write_data(unit,Dyn%Grid%vor (:,:, nn)) +! call write_data(unit,Dyn%Grid%div (:,:, nn)) +! call write_data(unit,Dyn%Grid%h (:,:, nn)) +! if(Dyn%spec_tracer) call write_data(unit,Dyn%Grid%trs(:,:, nn)) +! if(Dyn%grid_tracer) call write_data(unit,Dyn%Grid%tr (:,:, nn)) +! +!end do + +!call close_file(unit) + +end subroutine write_restart + +!==================================================================== + +subroutine shallow_dynamics_end (Dyn, previous, current) + +type(dynamics_type), intent(inout) :: Dyn +integer, intent(in) :: previous, current + +if(.not.module_is_initialized) then + call error_mesg('shallow_dynamics_end','dynamics has not been initialized ', FATAL) +endif + +call write_restart (Dyn, previous, current) + +call transforms_end + +module_is_initialized = .false. + +return +end subroutine shallow_dynamics_end +!=================================================================================== + +end module shallow_dynamics_mod diff --git a/src/atmos_spectral_shallow/shallow_dynamics.html b/src/atmos_spectral_shallow/shallow_dynamics.html new file mode 100644 index 000000000..600933a30 --- /dev/null +++ b/src/atmos_spectral_shallow/shallow_dynamics.html @@ -0,0 +1,370 @@ + +module shallow_dynamics_mod + + +
+ + +

module shallow_dynamics_mod

+ + +
+     Contact: Isaac Held
+     Reviewers: Peter Phillipps
+
+
+
+ + +
+

OVERVIEW

+ +
+
+   The dynamical core of the spectral transform model for 
+   the shallow water equations on the sphere.  
+   
+
+
+ + +
+

DESCRIPTION

+ +
+
+   Integrates the shallow water equation for hydrostatic flow of a homgeoneous,
+   incompressible fluid on the
+   sphere using the spectral transform technique.  Also allows for the
+   inclusion of a passive tracer advected by the the spectral advection
+   algorithm, and a gridpoint tracer advected with a finite
+   volume  algorithm on the transform grid.  Thinking of the model as one of
+   the upper tropopsheric flow, the default experiment involves relaxation of 
+   the geopotential to an "equilibrium value" with maxima (whose amplitude
+   and shape are controlled from the namelist) along the equator and in the 
+   subtropicals.
+
+   For a full description of the model and algorithms used, see 
+     shallow.ps 
+   
+   For higher level routines for running this shallow water model,
+   see  atmosphere_mod 
+
+
+
+ + + +
+

OTHER MODULES USED

+ +
+
+     fms_mod
+     constants_mod
+     time_manager_mod
+     transforms_mod
+     spectral_damping_mod
+     leapfrog_mod
+     fv_advection_mod
+
+
+
+ + +
+

PUBLIC INTERFACE

+ +
+
+  use shallow_dynamics_mod [,only: shallow_dynamics_init,       
+                                   shallow_dynamics,
+			           shallow_dynamics_end,
+                                   dynamics_type,
+				   grid_type,
+				   spectral_type,
+				   tendency_type]
+                                
+
+
+ + +
+

PUBLIC DATA

+ +
+     
+
+
+ +type grid_type + real, pointer, dimension(:,:,:) :: u, v, vor, div, h, trs, tr + real, pointer, dimension(:,:) :: stream, pv +end type + + allocated space for grid fields + + (:,:,:) => (lon, lat, time_level) + (:,:) => (lon, lat) + (lon, lat) on local computational domain + time_level stores the two time levels needed for the + leapfrog step + + u -- eastward velocity (m/s) + v -- northward velocity (m/s) + vor -- vorticity (1/s) + div -- divergence (1/s) + h -- geopotential (m^2/s^2) + trs -- tracer advected spectrally + tr -- tracer advected on grid + pv -- (f + vor)/h, where f = 2*omega*sin(lat) (s/m^2) + stream -- streamfunction (m^2/s) at current time + + + +
+ + +type spectral_type + complex, pointer, dimension(:,:,:) :: vor, div, h, trs +end type + + allocated space for spectral fields + + (:,:,:) => (zonal, meridional, time_level) + + vor -- spectral vorticity + div -- spectral divergence + h -- spectral geopotential + trs -- spectral tracer + +
+
+ +type tendency_type + real, pointer, dimension(:,:) :: u, v, h, trs, tr +end type + + allocated space for accumulating tendencies, d/dt, in grid space, + for prognostic variables + + (:,:,:) => (lon, lat) + +
+
+ +type dynamics_type + type(grid_type) :: grid + type(spectral_type) :: spec + type(tendency_type) :: tend + integer :: num_lon, num_lat ! size of global domain + logical :: grid_tracer, spec_tracer +end type + + grid_tracer = .true. => tracer with gridpoint advection is beign integrated + similarly for spec_tracer + +
+ +
+ + + +
+

PUBLIC ROUTINES

+ +
+
+subroutine  shallow_dynamics_init
+subroutine  shallow _dynamics
+subroutine  shallow_dynamics_end
+type (grid_type)
+type (spectral_type)
+type (tendency_type)
+type (dynamics_type)
+
+
+
+
+
+ subroutine shallow_dynamics_init(Dyn,  Time, Time_init)
+ 
+   type(dynamics_type), intent(inout)  :: Dyn
+         type containing all dynamical fields and related information
+	 (see type (dynamics_type))
+	 
+   type(time_type)    , intent(in)     :: Time, Time_init
+         current time and time at which integeration began
+	 time_type defined by time_manager_mod
+         
+
+   Initializes the module;
+   Reads restart from 'INPUT/shallow_dynamics.res' if Time = Time_init;
+     otherwise uses default initial conditions
+
+
+
+
+ + + + subroutine shallow_dynamics & + (Time, Time_init, Dyn, previous, current, future, delta_t) + + type(time_type) , intent(inout) :: Time, Time_init + type(dynamics_type), intent(inout) :: Dyn + integer , intent(in ) :: previous, current, future + real , intent(in ) :: delta_t + + previous, current and future = 1 or 2 + these integers refer to the third dimension of the + three-dimensional fields in Dyn + the fields at time t - delta_t are assumed to be in (:,:,previous) + the fields at time t are assumed to be in (:,:,current) + the fields at time t + delta_t are placed in (:,:,future) + overwriting whatever is already there + + delta_t = time step in seconds + + updates dynamical fields by one time step + + + +
+ + + subroutine shallow_dynamics_end(Dyn, previous, current) + + type(dynamics_type), intent(inout) :: Dyn + integer, intent(in) :: previous, current + + + Terminates module; + writes restart file to 'RESTART/shallow_dynamics.res' + + + + +
+
+ + + +
+

NAMELIST

+ +
+
+&shallow_dynamics_nml
+
+  integer :: num_lat            = 128  
+        number of latitudes in global grid
+       
+  integer :: num_lon            = 256
+        number of longitudes in global grid
+        should equal 2*num_lat for Triangular truncation
+  
+  integer :: num_fourier        = 85
+        the retained fourier wavenumber are n*fourier_inc, where
+        n ranges from 0 to num_fourier
+	 
+  integer :: num_spherical      = 86
+        the maximum number of meridional modes for any zonal wavenumber
+        for triangular truncation, set num_spherical = num_fourier +1
+         
+  integer :: fourier_inc        = 1
+        creates a "sector" model if fourier_inc > 1; integration domain is
+	(360 degrees longitude)/fourier_inc
+	
+  (the default values listed above define a standard T85 model)
+
+  logical :: check_fourier_imag = .false.
+        if true, checks to see if fields to be transformed to grid 
+	domain have zero imaginary part to their zonally symmetric
+	modes; useful for debugging
+	
+  logical :: south_to_north     = .true.
+        true => grid runs from south to north
+	false => grid runs from north to south
+	
+  logical :: triangular_trunc   = .true.
+        true  => shape of truncation is triangular
+	false => shape of truncation is rhomboidal
+
+  real    :: robert_coeff       = 0.04
+        x(current) => (1-2r)*x(current) + r*(x(future)+x(previous))
+	where r = robert_coeff (non-dimensional)
+	
+  real    :: robert_coeff_tracer       = 0.04
+        (same as robert_coeff, but for grid tracer)
+	
+  real    :: longitude_origin   = 0.0
+        longitude of first longitude, in degrees
+	(if you want the westgern boundary of first grid boc to be at 
+         0.0, set longitude_origin = 0.5*360./float(num_lon))
+	 
+  integer :: damping_option     = 'resolution_dependent'
+  integer :: damping_order      = 4
+  real    :: damping_coeff      = 1.e-04
+  
+        damping = nu*(del^2)^n where n = damping order
+	damping_option = 'resolution_dependent' or 'resolution_independent'
+	  = 'resolution_dependent' => nu is set so that the damping rate for the 
+	        mode (m=0,n=num_spherical-1) equals damping_coeff (in 1/s)
+	        For triangular truncation, damping_coeff is then the 
+	        rate of damping of the highest retained mode
+	     
+	  = 'resolution_independent' => nu = damping_coef
+	  
+  real    :: h_0  = 3.e04
+          (m^2)/(s^2) 
+          the initial condition is a state of rest with geopotential = h_0
+	  (h_0 is also used to determine the part of the divergence equation
+	   that is integrated implicitly)
+	
+  logical :: spec_tracer      = .true.
+  logical :: grid_tracer      = .true.
+       spec_tracer = true => a passive tracer is carried that is advected
+          spectrally, with the same algorithm as the vorticity
+       grid_tracer = ture => a passive tracer is carried that is advected
+          on the spectral transform grid by a finite-volume algorithm
+	  (see  shallow.ps )
+       Both tracers can be carried simultaeneously
+	  
+  real, dimension(2) :: valid_range_v = -1000., 1000.
+        A valid range for meridional wind. Model terminates if meridional wind
+	goes outside the valid range. Allows model to terminate gracefully when,
+	for example, the model becomes numerically unstable.
+
+
+ + + +
+

ERROR MESSAGES

+ +
+
+   "Dynamics has not been initialized"
+      -- shallow_dynamics_init must be called before any other
+         routines in the module are called
+	 
+   "restart does not exist" 
+      -- Time is not equal to Time_init at initalization, but the file
+          'INPUT/shallow_dynamics.res' does not exit 
+	 
+
+
+
+ + +
+ + diff --git a/src/atmos_spectral_shallow/shallow_physics.F90 b/src/atmos_spectral_shallow/shallow_physics.F90 new file mode 100644 index 000000000..8f8896d2e --- /dev/null +++ b/src/atmos_spectral_shallow/shallow_physics.F90 @@ -0,0 +1,232 @@ +module shallow_physics_mod + +!----------------------------------------------------------------------- +! GNU General Public License +! +! This program is free software; you can redistribute it and/or modify it and +! are expected to follow the terms of the GNU General Public License +! as published by the Free Software Foundation; either version 2 of +! the License, or (at your option) any later version. +! +! This program is distributed in the hope that it will be useful, but WITHOUT +! ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +! License for more details. +! +! For the full text of the GNU General Public License, +! write to: Free Software Foundation, Inc., +! 675 Mass Ave, Cambridge, MA 02139, USA. +! or see: http://www.gnu.org/licenses/gpl.html +!----------------------------------------------------------------------- + +use fms_mod, only: open_namelist_file, & + open_restart_file, & + file_exist, & + check_nml_error, & + error_mesg, & + FATAL, WARNING, & + write_version_number, & + mpp_pe, & + mpp_root_pe, & + fms_init, fms_end, & + read_data, & + write_data, & + set_domain, & + close_file, & + stdlog + +use transforms_mod, only: get_sin_lat, get_cos_lat, & + get_deg_lon, get_deg_lat, & + get_wts_lat, & + get_grid_domain, get_spec_domain, & + grid_domain + +use time_manager_mod, only: time_type + +!======================================================================== +implicit none +private +!======================================================================== + +public :: shallow_physics_init, & + shallow_physics, & + shallow_physics_end, & + phys_type + + +! version information +!======================================================================== +character(len=128) :: version = '$Id: shallow_physics.F90,v 10.0 2003/10/24 22:01:02 fms Exp $' +character(len=128) :: tagname = '$Name: siena_201207 $' +!======================================================================== + +type phys_type + real, pointer, dimension(:,:) :: empty=>NULL() +end type + +logical :: module_is_initialized = .false. + +integer :: is, ie, js, je + +integer :: pe +logical :: root + +real, allocatable, dimension(:) :: rad_lat, deg_lat, deg_lon, & + sin_lat, cos_lat, wts_lat + +real, allocatable, dimension(:,:) :: h_eq + +real :: kappa_m, kappa_t + + + +! namelist +!======================================================================== + +real :: fric_damp_time = -20.0 +real :: therm_damp_time = -10.0 +real :: del_h = 1.e04 +real :: h_0 = 3.e04 +real :: h_amp = 2.e04 +real :: h_lon = 90.0 +real :: h_lat = 25.0 +real :: h_width = 15.0 +real :: h_itcz = 1.e05 +real :: itcz_width = 4.0 + +namelist /shallow_physics_nml/ fric_damp_time, therm_damp_time, del_h, h_0, & + h_amp, h_lon, h_lat, h_width, & + itcz_width, h_itcz +!======================================================================== + +contains + +!======================================================================== + +subroutine shallow_physics_init(Phys) + +type(phys_type), intent(inout) :: Phys + +integer :: i, j, unit, ierr, io + +real :: xx, yy, dd + +call write_version_number(version, tagname) + +pe = mpp_pe() +root = (pe == mpp_root_pe()) + +! read the namelist + +if (file_exist('input.nml')) then + unit = open_namelist_file () + ierr=1 + do while (ierr /= 0) + read (unit, nml=shallow_physics_nml, iostat=io, end=10) + ierr = check_nml_error (io, 'shallow_physics_nml') + enddo + 10 call close_file (unit) +endif + +if(fric_damp_time < 0.0) fric_damp_time = - fric_damp_time*86400 +if(therm_damp_time < 0.0) therm_damp_time = - therm_damp_time*86400 + +kappa_m = 0.0 +kappa_t = 0.0 +if( fric_damp_time .ne. 0.0) kappa_m = 1./fric_damp_time +if(therm_damp_time .ne. 0.0) kappa_t = 1./therm_damp_time + +call get_grid_domain(is,ie,js,je) + +allocate ( rad_lat (js:je) ) +allocate ( deg_lat (js:je) ) +allocate ( sin_lat (js:je) ) +allocate ( cos_lat (js:je) ) +allocate ( wts_lat (js:je) ) +allocate ( deg_lon (is:ie) ) +allocate ( h_eq (is:ie,js:je) ) + +call get_wts_lat(wts_lat) +call get_deg_lat(deg_lat) +call get_deg_lon(deg_lon) +rad_lat = deg_lat*atan(1.)/45. +sin_lat = sin(rad_lat) +cos_lat = cos(rad_lat) + + +do j = js, je + do i = is, ie + xx = (deg_lon(i) - h_lon)/(h_width*2.0) + yy = (deg_lat(j) - h_lat)/h_width + dd = xx*xx + yy*yy + h_eq(i,j) = h_0 + h_amp*max(1.e-10, exp(-dd)) + end do +end do + +do j = js, je + yy = deg_lat(j)/itcz_width + dd = yy*yy + h_eq(:,j) = h_eq(:,j) + h_itcz*exp(-dd) +end do + +!if(file_exist('INPUT/shallow_physics.res')) then +! unit = open_restart_file(file='INPUT/shallow_physics.res',action='read') +! call set_domain(grid_domain) +! call close_file(unit) +!else + +!endif + +module_is_initialized = .true. + +return +end subroutine shallow_physics_init + +!======================================================================= + +subroutine shallow_physics(Time, dt_ug, dt_vg, dt_hg, ug, vg, hg, & + delta_t, previous, current, Phys) + +real, intent(inout), dimension(is:ie, js:je) :: dt_ug, dt_vg, dt_hg +real, intent(in) , dimension(is:ie, js:je, 2) :: ug, vg, hg + +real , intent(in) :: delta_t +integer, intent(in) :: previous, current + +type(time_type), intent(in) :: Time +type(phys_type), intent(inout) :: Phys + +dt_ug = dt_ug - kappa_m*ug(:,:,previous) +dt_vg = dt_vg - kappa_m*vg(:,:,previous) +dt_hg = dt_hg - kappa_t*(hg(:,:,previous) - h_eq) + + +return +end subroutine shallow_physics + +!====================================================================== + +subroutine shallow_physics_end(Phys) + +type(phys_type), intent(in) :: Phys + +integer :: unit + +if(.not.module_is_initialized) then + call error_mesg('shallow_physics_end','physics has not been initialized ', FATAL) +endif + +!unit = open_restart_file(file='RESTART/shallow_physics.res', action='write') + +!call set_domain(grid_domain) + +!call close_file(unit) + +module_is_initialized = .false. + +return +end subroutine shallow_physics_end + +!====================================================================== + +end module shallow_physics_mod diff --git a/src/atmos_spectral_shallow/shallow_physics.html b/src/atmos_spectral_shallow/shallow_physics.html new file mode 100644 index 000000000..d3ad34980 --- /dev/null +++ b/src/atmos_spectral_shallow/shallow_physics.html @@ -0,0 +1,210 @@ + +module shallow_physics_mod + + +
+ + +

module shallow_physics_mod

+ + +
+     Contact: Isaac Held
+     Reviewers: Peter Phillipps
+
+
+
+ + +
+

OVERVIEW

+ +
+
+   A module that allows one to add processes that act in the grid domain
+   to the dynamics of the shallow model on the sphere
+   
+
+
+ + +
+

DESCRIPTION

+ +
+
+   A module that allows one to add processes that act in the grid domain
+   to the dynamics of the shallow model on the sphere.  Currently adds
+   a relaxation to a specified  "equilibrium geopotential" and relaxes
+   the winds to zero
+
+
+ + +
+

OTHER MODULES USED

+ +
+
+     fms_mod
+     transforms_mod
+     time_manager_mod
+
+
+
+ + +
+

PUBLIC INTERFACE

+ +
+
+  use shallow_physics_mod [,only: shallow_physics_init,       
+                                         shallow_physics,
+					 shallow_physics_end,
+					 phys_type]
+                                
+
+
+ + +
+

PUBLIC DATA

+ +
+     
+
+
+ +type phys_type + real, pointer, dimension(:,:) :: empty +end type + + fields from physics module made available for diagnostics + +
+
+ +
+ + + +
+

PUBLIC ROUTINES

+ +
+
+subroutine  shallow_physics_init
+subroutine  shallow_physics
+subroutine  shallow_physics_end
+type(phys_type)
+
+
+
+
+
+ subroutine shallow_physics_init(Phys)
+ 
+   type(phys_type)    , intent(inout)     :: Phys
+  
+ 
+   Initializes module
+
+
+
+
+ + + + subroutine shallow_physics (Time, dt_ug, dt_vg, dt_hg, ug, vg, hg, & + delta_t, previous, current, Phys) + + real, intent(inout), dimension(:,:) :: dt_ug, dt_vg, dt_hg + + the u, v and geopotential tendencies onto which tendencies due to + the grid-point physics are added (m/(s^2) for dt_ug, dt_vg; + (m^2)/(s^3) for dt_hg) + + real, intent(in) , dimension(:,:, 2) :: ug, vg, hg + the grid zonal and meridional velocities (m/s) and + geopotential (m^2/s^2) + the third index is the time-index used in the leapfrog step + + real , intent(in) :: delta_t + time step (s) + + integer, intent(in) :: previous, current + = 1 or 2 + ug(:,:,previous) is the velocity at t-delta_t + ug(:,:,current ) is the velocity at t + + type(time_type), intent(in) :: Time + type(phys_type), intent(inout) :: Phys + + + + +
+ + + + subroutine shallow_physics_end (Phys) + + type(phys_type), intent(inout) :: Phys + + + +
+
+ + + + +
+

NAMELIST

+ +
+
+&shallow_physics_nml
+
+real    :: fric_damp_time  = -20.0
+           rate at which ua nd v are relaxed to zero (seconds)
+           (if negative, units are days instead -- negative sign is ignored) 
+      
+real    :: therm_damp_time = -10.0
+           rate at which geopotential is relaxed to h_eq
+	   (units as above)
+
+real    :: h_0             = 3.e04  (m^2/s^2)
+real    :: h_amp           = 2.e04  (m^2/s^2)
+real    :: h_lon           =  90.0  degrees
+real    :: h_lat           =  25.0  degrees
+real    :: h_width         =  15.0  degrees
+real    :: h_itcz          = 1.e05  (m^2/s^2)
+real    :: itcz_width      =  4.0   degrees
+
+           h_eq is defined as
+	   h_0 + h_amp*exp(-r^2) + h_itcz*exp(-d^2)
+	   
+	   where r^2 = xx^2 + yy^2
+	      xx = (lon - h_lon)/(2*h_width)
+	      yy = (lat - h_lat)/h_width
+	      
+	   and d = lat/itcz_width
+	  
+
+
+
+ + +
+ + + From dea4afda3d3062edb3a80332d17542543c18ce4c Mon Sep 17 00:00:00 2001 From: sit23 Date: Tue, 14 May 2019 16:29:41 +0100 Subject: [PATCH 02/24] Copied example input and diag file entries into test case, and set up shallow code base again. --- .../shallow_water/shallow_water_test.py | 107 ++++++++++++++++++ src/extra/python/isca/__init__.py | 2 +- src/extra/python/isca/codebase.py | 10 +- 3 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 exp/test_cases/shallow_water/shallow_water_test.py diff --git a/exp/test_cases/shallow_water/shallow_water_test.py b/exp/test_cases/shallow_water/shallow_water_test.py new file mode 100644 index 000000000..b2d20f8a4 --- /dev/null +++ b/exp/test_cases/shallow_water/shallow_water_test.py @@ -0,0 +1,107 @@ +import os + +import numpy as np + +from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE + +NCORES = 8 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = ShallowCodeBase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics +exp = Experiment('shallow_test_experiment', codebase=cb) + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') + +#Tell model which diagnostics to write +diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'div', time_avg=True) +diag.add_field('shallow_diagnostics', 'h', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv', time_avg=True) +diag.add_field('shallow_diagnostics', 'stream', time_avg=True) +diag.add_field('shallow_diagnostics', 'trs', time_avg=True) +diag.add_field('shallow_diagnostics', 'tr', time_avg=True) + + +exp.diag_table = diag + +#Empty the run directory ready to run +exp.clear_rundir() + +#Define values for the 'core' namelist +exp.namelist = namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 1200, + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml' + 'print_memory_usage':True, + 'domains_stack_size': 200000, + }, + + 'shallow_dynamics_nml':{ + 'num_lon' : 256, + 'num_lat' : 128, + 'num_fourier' : 85, + 'num_spherical' : 86, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 4, + 'damping_coeff' : 1.e-04, + 'h_0' : 3.e04, + 'grid_tracer' : .true., + 'spec_tracer' : .true., + 'robert_coeff' : 0.04 + 'robert_coeff_tracer' : 0.04, + }, + + 'shallow_physics_nml':{ + 'fric_damp_time' : -50.0, + 'therm_damp_time' : -10.0, + 'del_h' : 2.e04, + 'h_0' : 3.e04, + 'h_amp' : 1.e05, + 'h_lon' : 90.0, + 'h_lat' : 25.0, + 'h_width' : 15.0, + 'itcz_width' : 4.0, + 'h_itcz' : 4.e04, + }, +}) + +#Lets do a run! +if __name__=="__main__": + exp.run(1, use_restart=False, num_cores=NCORES) + for i in range(2,121): + exp.run(i, num_cores=NCORES) diff --git a/src/extra/python/isca/__init__.py b/src/extra/python/isca/__init__.py index 495c24e12..1ab4fe8e5 100644 --- a/src/extra/python/isca/__init__.py +++ b/src/extra/python/isca/__init__.py @@ -77,4 +77,4 @@ def emit(self, event, *args, **kwargs): from isca.experiment import Experiment, DiagTable, Namelist, FailedRunError -from isca.codebase import IscaCodeBase, DryCodeBase, GreyCodeBase #, ShallowCodeBase +from isca.codebase import IscaCodeBase, DryCodeBase, GreyCodeBase, ShallowCodeBase diff --git a/src/extra/python/isca/codebase.py b/src/extra/python/isca/codebase.py index b9863999f..8cd57b27a 100644 --- a/src/extra/python/isca/codebase.py +++ b/src/extra/python/isca/codebase.py @@ -303,8 +303,8 @@ class DryCodeBase(GreyCodeBase): -# class ShallowCodeBase(CodeBase): -# """The Shallow Water Equations. -# """ -# name = 'shallow' -# executable_name = 'shallow.x' +class ShallowCodeBase(CodeBase): + """The Shallow Water Equations. + """ + name = 'shallow' + executable_name = 'shallow.x' From a5a6c8e0cc3916110771a8147b7f5138eee0b597 Mon Sep 17 00:00:00 2001 From: sit23 Date: Tue, 14 May 2019 16:47:42 +0100 Subject: [PATCH 03/24] updated experiment to get it to run, and updated leapfrog and damping options in shallow water to get in line with Isca modifications. --- .../shallow_water/shallow_water_test.py | 9 +++++---- src/atmos_spectral_shallow/shallow_dynamics.F90 | 17 ++++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/exp/test_cases/shallow_water/shallow_water_test.py b/exp/test_cases/shallow_water/shallow_water_test.py index b2d20f8a4..53359d36c 100644 --- a/exp/test_cases/shallow_water/shallow_water_test.py +++ b/exp/test_cases/shallow_water/shallow_water_test.py @@ -54,6 +54,7 @@ 'minutes': 0, 'seconds': 0, 'dt_atmos': 1200, + 'calendar': 'no_calendar', }, 'atmosphere_nml':{ @@ -65,7 +66,7 @@ 'fileset_write': 'single' }, - 'fms_nml' + 'fms_nml':{ 'print_memory_usage':True, 'domains_stack_size': 200000, }, @@ -80,9 +81,9 @@ 'damping_order' : 4, 'damping_coeff' : 1.e-04, 'h_0' : 3.e04, - 'grid_tracer' : .true., - 'spec_tracer' : .true., - 'robert_coeff' : 0.04 + 'grid_tracer' : True, + 'spec_tracer' : True, + 'robert_coeff' : 0.04, 'robert_coeff_tracer' : 0.04, }, diff --git a/src/atmos_spectral_shallow/shallow_dynamics.F90 b/src/atmos_spectral_shallow/shallow_dynamics.F90 index 543e37230..98f674084 100644 --- a/src/atmos_spectral_shallow/shallow_dynamics.F90 +++ b/src/atmos_spectral_shallow/shallow_dynamics.F90 @@ -112,7 +112,8 @@ module shallow_dynamics_mod integer :: num_lat = 128 integer :: num_fourier = 85 integer :: num_spherical = 86 -integer :: fourier_inc = 1 +integer :: fourier_inc = 1 +integer :: cutoff_wn = 30 ! (these define a standard T85 model) logical :: check_fourier_imag = .false. @@ -122,6 +123,7 @@ module shallow_dynamics_mod real :: robert_coeff = 0.04 real :: robert_coeff_tracer = 0.04 real :: longitude_origin = 0.0 +real :: raw_filter_coeff = 1.0 character(len=64) :: damping_option = 'resolution_dependent' integer :: damping_order = 4 @@ -141,7 +143,8 @@ module shallow_dynamics_mod damping_order, damping_coeff, & robert_coeff, robert_coeff_tracer, & h_0, spec_tracer, grid_tracer, & - valid_range_v + valid_range_v, cutoff_wn, & + raw_filter_coeff contains @@ -209,7 +212,7 @@ subroutine shallow_dynamics_init (Dyn, Time, Time_init) coriolis = 2*omega*sin_lat -call spectral_damping_init(damping_coeff, damping_order, damping_option, num_fourier, num_spherical, 1, 0., 0., 0.) +call spectral_damping_init(damping_coeff, damping_order, damping_option, cutoff_wn, num_fourier, num_spherical, 1, 0., 0., 0.) allocate(eigen(ms:me,ns:ne)) call get_eigen_laplacian(eigen) @@ -333,9 +336,9 @@ subroutine shallow_dynamics(Time, Time_init, Dyn, previous, current, future, del call compute_spectral_damping(Dyn%Spec%div(:,:,previous), dt_divs, delta_t) call compute_spectral_damping(Dyn%Spec%h (:,:,previous), dt_hs , delta_t) -call leapfrog(Dyn%Spec%vor , dt_vors , previous, current, future, delta_t, robert_coeff) -call leapfrog(Dyn%Spec%div , dt_divs , previous, current, future, delta_t, robert_coeff) -call leapfrog(Dyn%Spec%h , dt_hs , previous, current, future, delta_t, robert_coeff) +call leapfrog(Dyn%Spec%vor , dt_vors , previous, current, future, delta_t, robert_coeff, raw_filter_coeff) +call leapfrog(Dyn%Spec%div , dt_divs , previous, current, future, delta_t, robert_coeff, raw_filter_coeff) +call leapfrog(Dyn%Spec%h , dt_hs , previous, current, future, delta_t, robert_coeff, raw_filter_coeff) call trans_spherical_to_grid(Dyn%Spec%vor(:,:,future), Dyn%Grid%vor(:,:,future)) call trans_spherical_to_grid(Dyn%Spec%div(:,:,future), Dyn%Grid%div(:,:,future)) @@ -408,7 +411,7 @@ subroutine update_spec_tracer(tr_spec, tr_grid, dt_tr, ug, vg, & call horizontal_advection (tr_spec(:,:,current), ug(:,:,current), vg(:,:,current), dt_tr) call trans_grid_to_spherical (dt_tr, dt_trs) call compute_spectral_damping (tr_spec(:,:,previous), dt_trs, delta_t) -call leapfrog (tr_spec, dt_trs, previous, current, future, delta_t, robert_coeff) +call leapfrog (tr_spec, dt_trs, previous, current, future, delta_t, robert_coeff, raw_filter_coeff) call trans_spherical_to_grid (tr_spec(:,:,future), tr_grid(:,:,future)) return From bd7df0686d49b62af7d24bbc395c5ae3ac0ad5a3 Mon Sep 17 00:00:00 2001 From: sit23 Date: Tue, 14 May 2019 17:15:33 +0100 Subject: [PATCH 04/24] Integrated barotropic vorticity equation into Isca framework too. Needed same fixes as shallow dynamics. --- .../barotropic_vor_eq_stirring_test.py | 116 ++++++++++++++++++ .../barotropic_vor_eq_test.py | 100 +++++++++++++++ .../barotropic_dynamics.F90 | 11 +- src/extra/python/isca/__init__.py | 2 +- src/extra/python/isca/codebase.py | 6 + 5 files changed, 230 insertions(+), 5 deletions(-) create mode 100644 exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_stirring_test.py create mode 100644 exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_test.py diff --git a/exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_stirring_test.py b/exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_stirring_test.py new file mode 100644 index 000000000..e03867687 --- /dev/null +++ b/exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_stirring_test.py @@ -0,0 +1,116 @@ +import os + +import numpy as np + +from isca import BarotropicCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE + +NCORES = 8 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = BarotropicCodeBase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics +exp = Experiment('barotropic_stirring_test_experiment', codebase=cb) + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') + +#Tell model which diagnostics to write +diag.add_field('barotropic_diagnostics', 'ucomp', time_avg=True) +diag.add_field('barotropic_diagnostics', 'vcomp', time_avg=True) +diag.add_field('barotropic_diagnostics', 'vor', time_avg=True) +diag.add_field('barotropic_diagnostics', 'pv', time_avg=True) +diag.add_field('barotropic_diagnostics', 'stream', time_avg=True) +diag.add_field('barotropic_diagnostics', 'trs', time_avg=True) +diag.add_field('barotropic_diagnostics', 'tr', time_avg=True) +diag.add_field('barotropic_diagnostics', 'eddy_vor', time_avg=True) +diag.add_field('barotropic_diagnostics', 'delta_u', time_avg=True) +diag.add_field('stirring_mod', 'stirring', time_avg=True) +diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) +diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) + +exp.diag_table = diag + +#Empty the run directory ready to run +exp.clear_rundir() + +#Define values for the 'core' namelist +exp.namelist = namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 1200, + 'calendar': 'no_calendar', + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml':{ + 'print_memory_usage':True, + 'domains_stack_size': 200000, + }, + + 'barotropic_dynamics_nml':{ + 'triang_trunc' : True, + 'num_lat' : 128, + 'num_lon' : 256, + 'num_fourier' : 85, + 'num_spherical' : 86, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 2, + 'damping_coeff' : 1.157E-4, + 'damping_coeff_r': 1.929E-6, + 'grid_tracer' : True, + 'spec_tracer' : True, + 'm_0' : 6, + 'zeta_0' : 0.0, + 'eddy_lat' : 45.0, + 'eddy_width' : 10.0, + 'robert_coeff' : 0.04, + 'initial_zonal_wind' : 'zero', + }, + + 'barotropic_physics_nml':{ + }, + + 'stirring_nml': { + 'decay_time':172800, + 'amplitude':3.e-11, + 'lat0':45., + 'lon0':180., + 'widthy':12., + 'widthx':45., + 'B':1.0, + }, + +}) + +#Lets do a run! +if __name__=="__main__": + exp.run(1, use_restart=False, num_cores=NCORES) + for i in range(2,121): + exp.run(i, num_cores=NCORES) diff --git a/exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_test.py b/exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_test.py new file mode 100644 index 000000000..fec772b66 --- /dev/null +++ b/exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_test.py @@ -0,0 +1,100 @@ +import os + +import numpy as np + +from isca import BarotropicCodebase, DiagTable, Experiment, Namelist, GFDL_BASE + +NCORES = 8 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = BarotropicCodebase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics +exp = Experiment('barotropic_test_experiment', codebase=cb) + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') + +#Tell model which diagnostics to write +diag.add_field('barotropic_diagnostics', 'ucomp', time_avg=True) +diag.add_field('barotropic_diagnostics', 'vcomp', time_avg=True) +diag.add_field('barotropic_diagnostics', 'vor', time_avg=True) +diag.add_field('barotropic_diagnostics', 'pv', time_avg=True) +diag.add_field('barotropic_diagnostics', 'stream', time_avg=True) +diag.add_field('barotropic_diagnostics', 'trs', time_avg=True) +diag.add_field('barotropic_diagnostics', 'tr', time_avg=True) +diag.add_field('barotropic_diagnostics', 'eddy_vor', time_avg=True) +diag.add_field('barotropic_diagnostics', 'delta_u', time_avg=True) + +exp.diag_table = diag + +#Empty the run directory ready to run +exp.clear_rundir() + +#Define values for the 'core' namelist +exp.namelist = namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 1200, + 'calendar': 'no_calendar', + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml':{ + 'print_memory_usage':True, + 'domains_stack_size': 200000, + }, + + 'barotropic_dynamics_nml':{ + 'triang_trunc' : True, + 'num_lat' : 128, + 'num_lon' : 256, + 'num_fourier' : 85, + 'num_spherical' : 86, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 4, + 'damping_coeff' : 1.e-04, + 'grid_tracer' : True, + 'spec_tracer' : True, + 'm_0' : 4, + 'zeta_0' : 8.e-05, + 'eddy_lat' : 45.0, + 'eddy_width' : 15.0, + 'robert_coeff' : 0.04, + }, + + 'barotropic_physics_nml':{ + }, +}) + +#Lets do a run! +if __name__=="__main__": + exp.run(1, use_restart=False, num_cores=NCORES) + for i in range(2,121): + exp.run(i, num_cores=NCORES) diff --git a/src/atmos_spectral_barotropic/barotropic_dynamics.F90 b/src/atmos_spectral_barotropic/barotropic_dynamics.F90 index 07922fdbc..64be9cd8d 100644 --- a/src/atmos_spectral_barotropic/barotropic_dynamics.F90 +++ b/src/atmos_spectral_barotropic/barotropic_dynamics.F90 @@ -122,6 +122,7 @@ module barotropic_dynamics_mod real :: robert_coeff = 0.04 real :: longitude_origin = 0.0 +real :: raw_filter_coeff = 1.0 character(len=64) :: damping_option = 'resolution_dependent' integer :: damping_order = 4 @@ -141,6 +142,7 @@ module barotropic_dynamics_mod integer :: num_fourier = 85 integer :: num_spherical = 86 integer :: fourier_inc = 1 +integer :: cutoff_wn = 30 real, dimension(2) :: valid_range_v = (/-1.e3,1.e3/) character(len=64) :: initial_zonal_wind = 'two_jets' @@ -154,7 +156,8 @@ module barotropic_dynamics_mod damping_coeff_r, robert_coeff, & spec_tracer, grid_tracer, & eddy_lat, eddy_width, zeta_0, m_0, & - valid_range_v, initial_zonal_wind + valid_range_v, initial_zonal_wind, & + cutoff_wn contains @@ -231,7 +234,7 @@ subroutine barotropic_dynamics_init (Dyn, Time, Time_init, dt_real, id_lon, id_l rad_lat = deg_lat*atan(1.0)/45.0 rad_lon = deg_lon*atan(1.0)/45.0 -call spectral_damping_init(damping_coeff, damping_order, damping_option, num_fourier, num_spherical, 1, 0., 0., 0., & +call spectral_damping_init(damping_coeff, damping_order, damping_option, cutoff_wn, num_fourier, num_spherical, 1, 0., 0., 0., & damping_coeff_r=damping_coeff_r) call stirring_init(dt_real, Time, id_lon, id_lat, id_lonb, id_latb) @@ -363,7 +366,7 @@ subroutine barotropic_dynamics(Time, Time_init, Dyn, previous, current, future, call stirring(Time, dt_vors) -call leapfrog(Dyn%Spec%vor , dt_vors , previous, current, future, delta_t, robert_coeff) +call leapfrog(Dyn%Spec%vor , dt_vors , previous, current, future, delta_t, robert_coeff, raw_filter_coeff) call trans_spherical_to_grid(Dyn%Spec%vor(:,:,future), Dyn%Grid%vor(:,:,future)) @@ -404,7 +407,7 @@ subroutine update_spec_tracer(tr_spec, tr_grid, dt_tr, ug, vg, & call horizontal_advection (tr_spec(:,:,current), ug(:,:,current), vg(:,:,current), dt_tr) call trans_grid_to_spherical (dt_tr, dt_trs) call compute_spectral_damping (tr_spec(:,:,previous), dt_trs, delta_t) -call leapfrog (tr_spec, dt_trs, previous, current, future, delta_t, robert_coeff) +call leapfrog (tr_spec, dt_trs, previous, current, future, delta_t, robert_coeff, raw_filter_coeff) call trans_spherical_to_grid (tr_spec(:,:,future), tr_grid(:,:,future)) return diff --git a/src/extra/python/isca/__init__.py b/src/extra/python/isca/__init__.py index 1ab4fe8e5..6573fdf85 100644 --- a/src/extra/python/isca/__init__.py +++ b/src/extra/python/isca/__init__.py @@ -77,4 +77,4 @@ def emit(self, event, *args, **kwargs): from isca.experiment import Experiment, DiagTable, Namelist, FailedRunError -from isca.codebase import IscaCodeBase, DryCodeBase, GreyCodeBase, ShallowCodeBase +from isca.codebase import IscaCodeBase, DryCodeBase, GreyCodeBase, ShallowCodeBase, BarotropicCodebase diff --git a/src/extra/python/isca/codebase.py b/src/extra/python/isca/codebase.py index 8cd57b27a..d29f661dc 100644 --- a/src/extra/python/isca/codebase.py +++ b/src/extra/python/isca/codebase.py @@ -308,3 +308,9 @@ class ShallowCodeBase(CodeBase): """ name = 'shallow' executable_name = 'shallow.x' + +class BarotropicCodebase(CodeBase): + """The Barotropic vorticity equations. + """ + name = 'barotropic' + executable_name = 'barotropic_isca.x' \ No newline at end of file From 4c22f20c342c753c6470514566d21fc20d5827dd Mon Sep 17 00:00:00 2001 From: sit23 Date: Tue, 14 May 2019 17:18:04 +0100 Subject: [PATCH 05/24] Fixed small typo in barotropic codebase object. --- .../barotropic_vorticity_equation/barotropic_vor_eq_test.py | 4 ++-- src/extra/python/isca/__init__.py | 2 +- src/extra/python/isca/codebase.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_test.py b/exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_test.py index fec772b66..01cdcc687 100644 --- a/exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_test.py +++ b/exp/test_cases/barotropic_vorticity_equation/barotropic_vor_eq_test.py @@ -2,13 +2,13 @@ import numpy as np -from isca import BarotropicCodebase, DiagTable, Experiment, Namelist, GFDL_BASE +from isca import BarotropicCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE NCORES = 8 base_dir = os.path.dirname(os.path.realpath(__file__)) # a CodeBase can be a directory on the computer, # useful for iterative development -cb = BarotropicCodebase.from_directory(GFDL_BASE) +cb = BarotropicCodeBase.from_directory(GFDL_BASE) # or it can point to a specific git repo and commit id. # This method should ensure future, independent, reproducibility of results. diff --git a/src/extra/python/isca/__init__.py b/src/extra/python/isca/__init__.py index 6573fdf85..cd9e8af1b 100644 --- a/src/extra/python/isca/__init__.py +++ b/src/extra/python/isca/__init__.py @@ -77,4 +77,4 @@ def emit(self, event, *args, **kwargs): from isca.experiment import Experiment, DiagTable, Namelist, FailedRunError -from isca.codebase import IscaCodeBase, DryCodeBase, GreyCodeBase, ShallowCodeBase, BarotropicCodebase +from isca.codebase import IscaCodeBase, DryCodeBase, GreyCodeBase, ShallowCodeBase, BarotropicCodeBase diff --git a/src/extra/python/isca/codebase.py b/src/extra/python/isca/codebase.py index d29f661dc..8ce9b35b7 100644 --- a/src/extra/python/isca/codebase.py +++ b/src/extra/python/isca/codebase.py @@ -309,7 +309,7 @@ class ShallowCodeBase(CodeBase): name = 'shallow' executable_name = 'shallow.x' -class BarotropicCodebase(CodeBase): +class BarotropicCodeBase(CodeBase): """The Barotropic vorticity equations. """ name = 'barotropic' From 717a94abe0bed959dc7b9e8e5929ac645edea675 Mon Sep 17 00:00:00 2001 From: sit23 Date: Thu, 16 May 2019 10:11:41 +0100 Subject: [PATCH 06/24] Rewrite of stirring module to retain functionality, but to get rid of it defining grid for output. This should make it possible to use stirring in the shallow water model. --- src/atmos_spectral_barotropic/atmosphere.F90 | 6 +++- .../barotropic_diagnostics.F90 | 28 +++++++++++++++++-- .../barotropic_dynamics.F90 | 6 ++-- src/atmos_spectral_barotropic/stirring.F90 | 9 +----- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/atmos_spectral_barotropic/atmosphere.F90 b/src/atmos_spectral_barotropic/atmosphere.F90 index 40a01ebb1..6b878fe98 100644 --- a/src/atmos_spectral_barotropic/atmosphere.F90 +++ b/src/atmos_spectral_barotropic/atmosphere.F90 @@ -63,6 +63,9 @@ module atmosphere_mod use barotropic_diagnostics_mod, only: barotropic_diagnostics_init, & barotropic_diagnostics +use stirring_mod, only: stirring_init + + !======================================================================== implicit none private @@ -142,7 +145,7 @@ subroutine atmosphere_init(Time_init_in, Time, Time_step_in) call write_version_number(version, tagname) if (root) write (stdlog(), nml=atmosphere_nml) -call barotropic_dynamics_init (Dyn, Time, Time_init, dt_real, id_lon, id_lat, id_lonb, id_latb) +call barotropic_dynamics_init (Dyn, Time, Time_init, dt_real) call get_grid_domain(is,ie,js,je) call get_spec_domain(ms,me,ns,ne) @@ -155,6 +158,7 @@ subroutine atmosphere_init(Time_init_in, Time, Time_step_in) call barotropic_physics_init(Phys) call barotropic_diagnostics_init(Time, num_lon, num_lat, id_lon, id_lat, id_lonb, id_latb) +call stirring_init(dt_real, Time, id_lon, id_lat, id_lonb, id_latb) if(Time == Time_init) then previous = 1 diff --git a/src/atmos_spectral_barotropic/barotropic_diagnostics.F90 b/src/atmos_spectral_barotropic/barotropic_diagnostics.F90 index 69cfc096e..fa632893a 100644 --- a/src/atmos_spectral_barotropic/barotropic_diagnostics.F90 +++ b/src/atmos_spectral_barotropic/barotropic_diagnostics.F90 @@ -28,11 +28,15 @@ module barotropic_diagnostics_mod use transforms_mod, only: get_grid_domain, & get_spec_domain, & grid_domain, & - trans_spherical_to_grid + trans_spherical_to_grid, & + get_deg_lon, & + get_deg_lat, & + get_grid_boundaries use diag_manager_mod, only: register_diag_field, & register_static_field, & - send_data + send_data, & + diag_axis_init use time_manager_mod, only: time_type, & get_time @@ -63,10 +67,18 @@ module barotropic_diagnostics_mod subroutine barotropic_diagnostics_init(Time, lon_max, lat_max, id_lon, id_lat, id_lonb, id_latb) type(time_type), intent(in) :: Time -integer, intent(in) :: lon_max, lat_max, id_lon, id_lat, id_lonb, id_latb +integer, intent(in) :: lon_max, lat_max +integer, intent(out):: id_lon, id_lat, id_lonb, id_latb + +real, dimension(lon_max ) :: lon +real, dimension(lon_max+1) :: lonb +real, dimension(lat_max ) :: lat +real, dimension(lat_max+1) :: latb integer, dimension(2) :: axis_2d +real :: rad_to_deg + integer :: log_unit integer :: namelist_unit, ierr, io logical :: used @@ -76,6 +88,16 @@ subroutine barotropic_diagnostics_init(Time, lon_max, lat_max, id_lon, id_lat, i call get_grid_domain(is, ie, js, je) call get_spec_domain(ms, me, ns, ne) +call get_deg_lon(lon) +call get_deg_lat(lat) +call get_grid_boundaries(lonb,latb,global=.true.) + +rad_to_deg = 45./atan(1.) +id_lonb=diag_axis_init('lonb', rad_to_deg*lonb, 'degrees_E', 'x', 'longitude edges', set_name=axiset, Domain2=grid_domain) +id_latb=diag_axis_init('latb', rad_to_deg*latb, 'degrees_N', 'y', 'latitude edges', set_name=axiset, Domain2=grid_domain) +id_lon =diag_axis_init('lon', lon, 'degrees_E', 'x', 'longitude', set_name=axiset, Domain2=grid_domain, edges=id_lonb) +id_lat =diag_axis_init('lat', lat, 'degrees_N', 'y', 'latitude', set_name=axiset, Domain2=grid_domain, edges=id_latb) + axis_2d(1) = id_lon axis_2d(2) = id_lat diff --git a/src/atmos_spectral_barotropic/barotropic_dynamics.F90 b/src/atmos_spectral_barotropic/barotropic_dynamics.F90 index 64be9cd8d..ac18b6127 100644 --- a/src/atmos_spectral_barotropic/barotropic_dynamics.F90 +++ b/src/atmos_spectral_barotropic/barotropic_dynamics.F90 @@ -61,7 +61,7 @@ module barotropic_dynamics_mod use fv_advection_mod, only: fv_advection_init, & a_grid_horiz_advection -use stirring_mod, only: stirring_init, stirring, stirring_end +use stirring_mod, only: stirring, stirring_end !=============================================================================================== implicit none @@ -163,12 +163,11 @@ module barotropic_dynamics_mod !=============================================================================================== -subroutine barotropic_dynamics_init (Dyn, Time, Time_init, dt_real, id_lon, id_lat, id_lonb, id_latb) +subroutine barotropic_dynamics_init (Dyn, Time, Time_init, dt_real) type(dynamics_type), intent(inout) :: Dyn type(time_type) , intent(in) :: Time, Time_init real, intent(in) :: dt_real -integer, intent(out) :: id_lon, id_lat, id_lonb, id_latb integer :: i, j @@ -236,7 +235,6 @@ subroutine barotropic_dynamics_init (Dyn, Time, Time_init, dt_real, id_lon, id_l call spectral_damping_init(damping_coeff, damping_order, damping_option, cutoff_wn, num_fourier, num_spherical, 1, 0., 0., 0., & damping_coeff_r=damping_coeff_r) -call stirring_init(dt_real, Time, id_lon, id_lat, id_lonb, id_latb) allocate (Dyn%spec%vor (ms:me, ns:ne, num_time_levels)) allocate (Dyn%grid%u (is:ie, js:je, num_time_levels)) diff --git a/src/atmos_spectral_barotropic/stirring.F90 b/src/atmos_spectral_barotropic/stirring.F90 index 04bdfc280..88aad46a8 100644 --- a/src/atmos_spectral_barotropic/stirring.F90 +++ b/src/atmos_spectral_barotropic/stirring.F90 @@ -77,7 +77,7 @@ module stirring_mod subroutine stirring_init(dt, Time, id_lon, id_lat, id_lonb, id_latb) real, intent(in) :: dt type(time_type), intent(in) :: Time -integer, intent(out) :: id_lon, id_lat, id_lonb, id_latb +integer, intent(in) :: id_lon, id_lat, id_lonb, id_latb real :: xx, kk, rad_to_deg integer :: i,j,m,n,ierr,io,unit,lon_max,lat_max real, allocatable, dimension(:) :: ampx, ampy, lon, lat, lonb, latb @@ -108,13 +108,6 @@ subroutine stirring_init(dt, Time, id_lon, id_lat, id_lonb, id_latb) call get_deg_lon(lon) call get_deg_lat(lat) -call get_grid_boundaries(lonb,latb,global=.true.) - -rad_to_deg = 180./pi -id_lonb=diag_axis_init('lonb', rad_to_deg*lonb, 'degrees_E', 'x', 'longitude edges', set_name='barotropic', Domain2=grid_domain) -id_latb=diag_axis_init('latb', rad_to_deg*latb, 'degrees_N', 'y', 'latitude edges', set_name='barotropic', Domain2=grid_domain) -id_lon =diag_axis_init('lon', lon, 'degrees_E', 'x', 'longitude', set_name='barotropic', Domain2=grid_domain, edges=id_lonb) -id_lat =diag_axis_init('lat', lat, 'degrees_N', 'y', 'latitude', set_name='barotropic', Domain2=grid_domain, edges=id_latb) module_is_initialized = .true. if(amplitude == 0.0) return ! stirring does nothing more unless amplitude is non-zero From 2f6acc087a84ebd6531cd1d5692e79645928136a Mon Sep 17 00:00:00 2001 From: sit23 Date: Thu, 16 May 2019 10:20:05 +0100 Subject: [PATCH 07/24] Updated shallow code to include stirring, but thanks to rewrite of stirring, we can output stirring variables from within shallow water framework. --- src/atmos_spectral_shallow/atmosphere.F90 | 8 +++++--- src/atmos_spectral_shallow/shallow_diagnostics.F90 | 5 +++-- src/atmos_spectral_shallow/shallow_dynamics.F90 | 10 ++++++++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/atmos_spectral_shallow/atmosphere.F90 b/src/atmos_spectral_shallow/atmosphere.F90 index 3b59b37fb..7336f9b72 100644 --- a/src/atmos_spectral_shallow/atmosphere.F90 +++ b/src/atmos_spectral_shallow/atmosphere.F90 @@ -67,6 +67,7 @@ Module atmosphere_mod use shallow_diagnostics_mod, only : shallow_diagnostics_init, & shallow_diagnostics +use stirring_mod, only: stirring_init !======================================================================== implicit none @@ -124,7 +125,7 @@ subroutine atmosphere_init(Time_init_in, Time, Time_step_in) type (time_type), intent(in) :: Time_init_in, Time, Time_step_in -integer :: i, j, n, nn, ierr, io, unit +integer :: i, j, n, nn, ierr, io, unit, id_lon, id_lat, id_lonb, id_latb integer :: nlon, nlat pe = mpp_pe() @@ -151,7 +152,7 @@ subroutine atmosphere_init(Time_init_in, Time, Time_step_in) call write_version_number(version, tagname) if (root) write (stdlog(), nml=atmosphere_nml) -call shallow_dynamics_init (Dyn, Time, Time_init) +call shallow_dynamics_init (Dyn, Time, Time_init, dt_real) call get_grid_domain(is,ie,js,je) call get_spec_domain(ms,me,ns,ne) @@ -163,7 +164,8 @@ subroutine atmosphere_init(Time_init_in, Time, Time_step_in) nlat = je+1-js call shallow_physics_init(Phys) -call shallow_diagnostics_init(Time, num_lon, num_lat) +call shallow_diagnostics_init(Time, num_lon, num_lat, id_lon, id_lat, id_lonb, id_latb) +call stirring_init(dt_real, Time, id_lon, id_lat, id_lonb, id_latb) if(Time == Time_init) then previous = 1 diff --git a/src/atmos_spectral_shallow/shallow_diagnostics.F90 b/src/atmos_spectral_shallow/shallow_diagnostics.F90 index b8dc52f68..e0fd0052a 100644 --- a/src/atmos_spectral_shallow/shallow_diagnostics.F90 +++ b/src/atmos_spectral_shallow/shallow_diagnostics.F90 @@ -62,10 +62,11 @@ module shallow_diagnostics_mod contains !----------------------------------------------------------------------------------------------------------------- -subroutine shallow_diagnostics_init(Time, lon_max, lat_max) +subroutine shallow_diagnostics_init(Time, lon_max, lat_max, id_lon, id_lat, id_lonb, id_latb) type(time_type), intent(in) :: Time integer, intent(in) :: lon_max, lat_max +integer, intent(out):: id_lon, id_lat, id_lonb, id_latb real, dimension(lon_max ) :: lon real, dimension(lon_max+1) :: lonb @@ -74,7 +75,7 @@ subroutine shallow_diagnostics_init(Time, lon_max, lat_max) integer, dimension(2) :: axis_2d -integer :: log_unit, id_lonb, id_lon, id_latb, id_lat +integer :: log_unit integer :: namelist_unit, ierr, io real :: rad_to_deg logical :: used diff --git a/src/atmos_spectral_shallow/shallow_dynamics.F90 b/src/atmos_spectral_shallow/shallow_dynamics.F90 index 98f674084..eacbfc159 100644 --- a/src/atmos_spectral_shallow/shallow_dynamics.F90 +++ b/src/atmos_spectral_shallow/shallow_dynamics.F90 @@ -57,6 +57,8 @@ module shallow_dynamics_mod use fv_advection_mod, only : fv_advection_init, a_grid_horiz_advection +use stirring_mod, only : stirring, stirring_end + !====================================================================================== implicit none private @@ -150,17 +152,18 @@ module shallow_dynamics_mod !======================================================================================= -subroutine shallow_dynamics_init (Dyn, Time, Time_init) +subroutine shallow_dynamics_init (Dyn, Time, Time_init, dt_real) type(dynamics_type), intent(inout) :: Dyn type(time_type) , intent(in) :: Time, Time_init +real , intent(in) :: dt_real integer :: i, j real, allocatable, dimension(:) :: glon_bnd, glat_bnd real :: xx, yy, dd -integer :: ierr, io, unit +integer :: ierr, io, unit, id_lon, id_lat, id_lonb, id_latb logical :: root ! < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > @@ -336,6 +339,8 @@ subroutine shallow_dynamics(Time, Time_init, Dyn, previous, current, future, del call compute_spectral_damping(Dyn%Spec%div(:,:,previous), dt_divs, delta_t) call compute_spectral_damping(Dyn%Spec%h (:,:,previous), dt_hs , delta_t) +call stirring(Time, dt_vors) + call leapfrog(Dyn%Spec%vor , dt_vors , previous, current, future, delta_t, robert_coeff, raw_filter_coeff) call leapfrog(Dyn%Spec%div , dt_divs , previous, current, future, delta_t, robert_coeff, raw_filter_coeff) call leapfrog(Dyn%Spec%h , dt_hs , previous, current, future, delta_t, robert_coeff, raw_filter_coeff) @@ -600,6 +605,7 @@ subroutine shallow_dynamics_end (Dyn, previous, current) call write_restart (Dyn, previous, current) call transforms_end +call stirring_end module_is_initialized = .false. From 6c696ee3c208bc1a4db138bd3c7dba4457a8348b Mon Sep 17 00:00:00 2001 From: sit23 Date: Thu, 16 May 2019 10:23:39 +0100 Subject: [PATCH 08/24] Remove needless string definitions. --- src/atmos_spectral_barotropic/stirring.F90 | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/atmos_spectral_barotropic/stirring.F90 b/src/atmos_spectral_barotropic/stirring.F90 index 88aad46a8..7ceafdb82 100644 --- a/src/atmos_spectral_barotropic/stirring.F90 +++ b/src/atmos_spectral_barotropic/stirring.F90 @@ -53,8 +53,6 @@ module stirring_mod integer, allocatable, dimension(:) :: seed ! random number seed real :: astir, bstir integer :: num_steps, num_fourier, num_spherical, nseed -character(len=8) :: axiset = 'barotropic' -character(len=84) :: mod_name = 'barotropic_diagnostics' logical :: module_is_initialized = .false. From 993966c732a603b51a07fd99b5a276b1e8a3707e Mon Sep 17 00:00:00 2001 From: sit23 Date: Thu, 16 May 2019 11:16:02 +0100 Subject: [PATCH 09/24] Adding comments to stirring file to point out origin. --- .../shallow_water_stirring_test.py | 126 ++++++++++++++++++ src/atmos_spectral_barotropic/stirring.F90 | 2 +- 2 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 exp/test_cases/shallow_water/shallow_water_stirring_test.py diff --git a/exp/test_cases/shallow_water/shallow_water_stirring_test.py b/exp/test_cases/shallow_water/shallow_water_stirring_test.py new file mode 100644 index 000000000..d6571c2c1 --- /dev/null +++ b/exp/test_cases/shallow_water/shallow_water_stirring_test.py @@ -0,0 +1,126 @@ +import os + +import numpy as np + +from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE + +NCORES = 8 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = ShallowCodeBase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics +exp = Experiment('shallow_stirring_test_experiment', codebase=cb) + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') + +#Tell model which diagnostics to write +diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'div', time_avg=True) +diag.add_field('shallow_diagnostics', 'h', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv', time_avg=True) +diag.add_field('shallow_diagnostics', 'stream', time_avg=True) +diag.add_field('shallow_diagnostics', 'trs', time_avg=True) +diag.add_field('shallow_diagnostics', 'tr', time_avg=True) +diag.add_field('stirring_mod', 'stirring', time_avg=True) +diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) +diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) + +exp.diag_table = diag + +#Empty the run directory ready to run +exp.clear_rundir() + +#Define values for the 'core' namelist +exp.namelist = namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 1200, + 'calendar': 'no_calendar', + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml':{ + 'print_memory_usage':True, + 'domains_stack_size': 200000, + }, + + 'shallow_dynamics_nml':{ + 'num_lon' : 256, + 'num_lat' : 128, + 'num_fourier' : 85, + 'num_spherical' : 86, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 4, + 'damping_coeff' : 1.e-04, + 'h_0' : 3.e04, + 'grid_tracer' : True, + 'spec_tracer' : True, + 'robert_coeff' : 0.04, + 'robert_coeff_tracer' : 0.04, + }, + + 'shallow_physics_nml':{ + 'fric_damp_time' : -50.0, + 'therm_damp_time' : -10.0, + 'del_h' : 2.e04, + 'h_0' : 3.e04, + 'h_amp' : 1.e05, + 'h_lon' : 90.0, + 'h_lat' : 25.0, + 'h_width' : 15.0, + 'itcz_width' : 4.0, + 'h_itcz' : 4.e04, + }, + +#The below stirring parameters are those of Vallis et al 2004 DOI: 10.1175/1520-0469(2004)061<0264:AMASDM>2.0.CO;2 +#They have a decorrelation time set by 'decay_time', chosen to be 2 days by default. The forcing is also localised in +#latitude and longitude, with the centre of the forcing set by lat0 and lon0, and the width of the gaussians set by +#'widthy and widthx'. B sets the variation in longitude, with ampx = 1 + B*exp(-xx/widthx**2) + + 'stirring_nml': { + 'decay_time':172800, + 'amplitude':3.e-13, + 'lat0':45., + 'lon0':180., + 'widthy':12., + 'widthx':45., + 'B':1.0, + }, + +}) + +#Lets do a run! +if __name__=="__main__": + exp.run(1, use_restart=False, num_cores=NCORES) + for i in range(2,122): + exp.run(i, num_cores=NCORES) diff --git a/src/atmos_spectral_barotropic/stirring.F90 b/src/atmos_spectral_barotropic/stirring.F90 index 7ceafdb82..687fb81f9 100644 --- a/src/atmos_spectral_barotropic/stirring.F90 +++ b/src/atmos_spectral_barotropic/stirring.F90 @@ -210,7 +210,7 @@ subroutine stirring(Time, dt_vors) if(ms == 0 .and. ns == 0) then new_stirring(0,0)=cmplx(0.0,0.0) ! A non-zero global mean is introduced by the grid space computation, but we don't want it. endif -s_stir = bstir*s_stir + new_stirring +s_stir = bstir*s_stir + new_stirring !This is equation A.6 in Vallis et al 2004 - DOI:10.1175/1520-0469(2004)061<0264:AMASDM>2.0.CO;2 dt_vors = dt_vors + s_stir call trans_spherical_to_grid(s_stir,g_stir) From 4693d72a31bf6286422c370f9a4d2912b509b0a1 Mon Sep 17 00:00:00 2001 From: sit23 Date: Thu, 16 May 2019 14:12:44 +0100 Subject: [PATCH 10/24] Making the wavenumber range of the forcing a namelist parameter set. --- src/atmos_spectral_barotropic/stirring.F90 | 27 ++++++++++++++-------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/atmos_spectral_barotropic/stirring.F90 b/src/atmos_spectral_barotropic/stirring.F90 index 687fb81f9..7de10c3f1 100644 --- a/src/atmos_spectral_barotropic/stirring.F90 +++ b/src/atmos_spectral_barotropic/stirring.F90 @@ -62,12 +62,16 @@ module stirring_mod public :: stirring_init, stirring, stirring_end real :: decay_time=2*86400, amplitude=0.0, lat0=45., widthy=12. +logical :: do_localize=.true.!Default true to allow forcing to be localized in physical space. Set to false to have forcing everywhere. ! Set B to a non-zero value for stirring that has zonal structure. ! The strength of the stirring at latitude=lat0 is: amplitude*(1.0 + B*exp(-.5*((lon-lon0)/widthx)**2)) -real :: lon0=180., B=0.0, widthx=45. ! widthx +real :: lon0=180., B=0.0, widthx=45., C=1.0 ! widthx +integer :: n_total_forcing_max = 15 !total wavenumbers LESS THAN this number will be forced +integer :: n_total_forcing_min = 9 !total wavenumbers GREATER THAN this number will be forced +integer :: zonal_forcing_min = 3 !Zonal wavenumbers GREATER THAN this number will be forced, subject to total wavenumber constraints -namelist / stirring_nml / decay_time, amplitude, lat0, lon0, widthy, widthx, B +namelist / stirring_nml / decay_time, amplitude, lat0, lon0, widthy, widthx, B, do_localize, n_total_forcing_max, n_total_forcing_min, zonal_forcing_min contains @@ -123,9 +127,9 @@ subroutine stirring_init(dt, Time, id_lon, id_lat, id_lonb, id_latb) allocate(g_stir_sqr(is:ie,js:je)); g_stir_sqr = 0.0 ! wave_mask is .true. when (m+n > 9) .and. (m+n < 15) .and. (m > 3) -do m=4,14 +do m=(zonal_forcing_min+1),(n_total_forcing_max-1) if(m >= ms .and. m <= me) then - do n=10-m,14-m + do n=(n_total_forcing_min+1)-m,(n_total_forcing_max-1)-m if(n >= ns .and. n <= ne) then wave_mask(m,n) = .true. endif @@ -146,11 +150,16 @@ subroutine stirring_init(dt, Time, id_lon, id_lat, id_lonb, id_latb) do j=js,je ampy(j) = exp(-.5*((lat(j)-lat0)/widthy)**2) enddo -do j=js,je -do i=is,ie - localize(i,j) = ampx(i)*ampy(j) -enddo -enddo +if (do_localize) then + do j=js,je + do i=is,ie + localize(i,j) = ampx(i)*ampy(j) + enddo + enddo +else + localize = 1.0 +endif + deallocate(ampx, ampy) num_steps = 0 From f8fcd5c1fa9f34c93d4bcffac15ef70ced110c59 Mon Sep 17 00:00:00 2001 From: sit23 Date: Thu, 16 May 2019 14:13:08 +0100 Subject: [PATCH 11/24] Trying to make scott and polvani 2007 esque flows. --- ...shallow_water_small_scale_stirring_test.py | 151 ++++++++++++++++++ ...iant_planet_shallow_water_stirring_test.py | 148 +++++++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py create mode 100644 exp/shallow_water_giant_planet/giant_planet_shallow_water_stirring_test.py diff --git a/exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py b/exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py new file mode 100644 index 000000000..a45007b8b --- /dev/null +++ b/exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py @@ -0,0 +1,151 @@ +import os + +import numpy as np + +from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE + +import pdb + +NCORES = 8 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = ShallowCodeBase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') +diag.add_file('atmos_daily', 1, 'days', time_units='days') + +#Tell model which diagnostics to write +diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'div', time_avg=True) +diag.add_field('shallow_diagnostics', 'h', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv', time_avg=True) +diag.add_field('shallow_diagnostics', 'stream', time_avg=True) +# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) +# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) +diag.add_field('stirring_mod', 'stirring', time_avg=True) +# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) +diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) + + +#Empty the run directory ready to run + +#Define values for the 'core' namelist +namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 1200, + 'calendar': 'no_calendar', + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml':{ + 'print_memory_usage':False, + 'domains_stack_size': 200000, + }, + + 'shallow_dynamics_nml':{ + 'num_lon' : 512, + 'num_lat' : 256, + 'num_fourier' : 170, + 'num_spherical' : 171, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 4, + 'damping_coeff' : 1.e-04, + 'h_0' : 3.e04, + 'grid_tracer' : False, + 'spec_tracer' : False, + 'robert_coeff' : 0.04, + 'robert_coeff_tracer' : 0.04, + }, + + 'shallow_physics_nml':{ + 'fric_damp_time' : 0.0, + 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. + 'h_amp' : 0., + 'h_itcz' : 0., + }, + + 'stirring_nml': { + 'B':0.0, + 'do_localize': False, + }, + +}) + +#Lets do a run! +if __name__=="__main__": + + for number_ld_in_radius_units in [10.]: + + exp = Experiment('giant_shallow_stirring_test_experiment_uniform_small_scale_stirring_mk3', codebase=cb) + + exp.diag_table = diag + exp.namelist = namelist + exp.clear_rundir() + + rotation_period = ((9.*3600.)+55.*60 + 30.) + omega = 2.*np.pi/ rotation_period + radius = 69911e3 + grav = 24.79 + + # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. + + equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. + equilibrium_depth = equilibrium_geopotential/grav + + exp.update_namelist({ + 'shallow_dynamics_nml':{ + 'h_0': equilibrium_geopotential + }, + 'shallow_physics_nml': { + 'h_0': equilibrium_geopotential, + 'therm_damp_time' : rotation_period * 1., #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) + }, + 'constants_nml': { + 'omega': omega, + 'radius': radius, + }, + 'stirring_nml': { + 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. + 'amplitude':3.e-13, + 'n_total_forcing_max': 45, + 'n_total_forcing_min': 39, + + }, + + }) + + exp.run(1, use_restart=False, num_cores=NCORES) + for i in range(2,122): + exp.run(i, num_cores=NCORES) diff --git a/exp/shallow_water_giant_planet/giant_planet_shallow_water_stirring_test.py b/exp/shallow_water_giant_planet/giant_planet_shallow_water_stirring_test.py new file mode 100644 index 000000000..fa19bc3c5 --- /dev/null +++ b/exp/shallow_water_giant_planet/giant_planet_shallow_water_stirring_test.py @@ -0,0 +1,148 @@ +import os + +import numpy as np + +from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE + +import pdb + +NCORES = 8 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = ShallowCodeBase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') +diag.add_file('atmos_daily', 1, 'days', time_units='days') + +#Tell model which diagnostics to write +diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'div', time_avg=True) +diag.add_field('shallow_diagnostics', 'h', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv', time_avg=True) +diag.add_field('shallow_diagnostics', 'stream', time_avg=True) +# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) +# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) +diag.add_field('stirring_mod', 'stirring', time_avg=True) +# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) +diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) + + +#Empty the run directory ready to run + +#Define values for the 'core' namelist +namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 1200, + 'calendar': 'no_calendar', + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml':{ + 'print_memory_usage':False, + 'domains_stack_size': 200000, + }, + + 'shallow_dynamics_nml':{ + 'num_lon' : 512, + 'num_lat' : 256, + 'num_fourier' : 170, + 'num_spherical' : 171, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 4, + 'damping_coeff' : 1.e-04, + 'h_0' : 3.e04, + 'grid_tracer' : False, + 'spec_tracer' : False, + 'robert_coeff' : 0.04, + 'robert_coeff_tracer' : 0.04, + }, + + 'shallow_physics_nml':{ + 'fric_damp_time' : 0.0, + 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. + 'h_amp' : 0., + 'h_itcz' : 0., + }, + + 'stirring_nml': { + 'B':0.0, + 'do_localize': False, + }, + +}) + +#Lets do a run! +if __name__=="__main__": + + for number_ld_in_radius_units in [10.]: + + exp = Experiment('giant_shallow_stirring_test_experiment_uniform_stirring_mk3', codebase=cb) + + exp.diag_table = diag + exp.namelist = namelist + exp.clear_rundir() + + rotation_period = ((9.*3600.)+55.*60 + 30.) + omega = 2.*np.pi/ rotation_period + radius = 69911e3 + grav = 24.79 + + # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. + + equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. + equilibrium_depth = equilibrium_geopotential/grav + + exp.update_namelist({ + 'shallow_dynamics_nml':{ + 'h_0': equilibrium_geopotential + }, + 'shallow_physics_nml': { + 'h_0': equilibrium_geopotential, + 'therm_damp_time' : rotation_period * 1., #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) + }, + 'constants_nml': { + 'omega': omega, + 'radius': radius, + }, + 'stirring_nml': { + 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. + 'amplitude':3.e-13, + }, + + }) + + exp.run(1, use_restart=False, num_cores=NCORES) + for i in range(2,122): + exp.run(i, num_cores=NCORES) From a2796269c0530356a675bee8cecdaf12ee7aad5f Mon Sep 17 00:00:00 2001 From: sit23 Date: Thu, 16 May 2019 14:15:51 +0100 Subject: [PATCH 12/24] Adding missing model files that I forgot to commit. These are necessary for compilation of new codes. --- src/extra/model/barotropic/field_table | 0 src/extra/model/barotropic/path_names | 138 +++++++++++++++++++++++++ src/extra/model/shallow/path_names | 138 +++++++++++++++++++++++++ 3 files changed, 276 insertions(+) create mode 100644 src/extra/model/barotropic/field_table create mode 100644 src/extra/model/barotropic/path_names create mode 100644 src/extra/model/shallow/path_names diff --git a/src/extra/model/barotropic/field_table b/src/extra/model/barotropic/field_table new file mode 100644 index 000000000..e69de29bb diff --git a/src/extra/model/barotropic/path_names b/src/extra/model/barotropic/path_names new file mode 100644 index 000000000..e7c619d86 --- /dev/null +++ b/src/extra/model/barotropic/path_names @@ -0,0 +1,138 @@ +atmos_solo/atmos_model.F90 +atmos_spectral_barotropic/atmosphere.F90 +atmos_spectral_barotropic/barotropic_diagnostics.F90 +atmos_spectral_barotropic/barotropic_dynamics.F90 +atmos_spectral_barotropic/barotropic_physics.F90 +atmos_spectral_barotropic/stirring.F90 +atmos_spectral/model/fv_advection.F90 +atmos_spectral/model/leapfrog.F90 +atmos_spectral/model/spectral_damping.F90 +atmos_spectral/tools/gauss_and_legendre.F90 +atmos_spectral/tools/grid_fourier.F90 +atmos_spectral/tools/spec_mpp.F90 +atmos_spectral/tools/spherical.F90 +atmos_spectral/tools/spherical_fourier.F90 +atmos_spectral/tools/transforms.F90 +shared/constants/constants.F90 +shared/diag_manager/diag_axis.F90 +shared/diag_manager/diag_data.F90 +shared/diag_manager/diag_grid.F90 +shared/diag_manager/diag_manager.F90 +shared/diag_manager/diag_output.F90 +shared/diag_manager/diag_table.F90 +shared/diag_manager/diag_util.F90 +shared/fft/fft99.F90 +shared/fft/fft.F90 +shared/field_manager/field_manager.F90 +shared/field_manager/fm_util.F90 +shared/field_manager/parse.inc +shared/fms/fms.F90 +shared/fms/fms_io.F90 +shared/fms/read_data_2d.inc +shared/fms/read_data_3d.inc +shared/fms/read_data_4d.inc +shared/fms/test_fms_io.F90 +shared/fms/write_data.inc +shared/include/fms_platform.h +shared/memutils/memuse.c +shared/memutils/memutils.F90 +shared/mosaic/constant.h +shared/mosaic/create_xgrid.c +shared/mosaic/create_xgrid.h +shared/mosaic/gradient_c2l.c +shared/mosaic/gradient_c2l.h +shared/mosaic/gradient.F90 +shared/mosaic/grid.F90 +shared/mosaic/interp.c +shared/mosaic/interp.h +shared/mosaic/mosaic.F90 +shared/mosaic/mosaic_util.c +shared/mosaic/mosaic_util.h +shared/mosaic/read_mosaic.c +shared/mosaic/read_mosaic.h +shared/mpp/affinity.c +shared/mpp/include/mpp_chksum.h +shared/mpp/include/mpp_chksum_int.h +shared/mpp/include/mpp_chksum_scalar.h +shared/mpp/include/mpp_comm.inc +shared/mpp/include/mpp_comm_mpi.inc +shared/mpp/include/mpp_comm_nocomm.inc +shared/mpp/include/mpp_comm_sma.inc +shared/mpp/include/mpp_data_mpi.inc +shared/mpp/include/mpp_data_nocomm.inc +shared/mpp/include/mpp_data_sma.inc +shared/mpp/include/mpp_define_nest_domains.inc +shared/mpp/include/mpp_do_check.h +shared/mpp/include/mpp_do_checkV.h +shared/mpp/include/mpp_do_get_boundary.h +shared/mpp/include/mpp_do_global_field.h +shared/mpp/include/mpp_domains_comm.inc +shared/mpp/include/mpp_domains_define.inc +shared/mpp/include/mpp_domains_misc.inc +shared/mpp/include/mpp_domains_reduce.inc +shared/mpp/include/mpp_domains_util.inc +shared/mpp/include/mpp_do_redistribute.h +shared/mpp/include/mpp_do_update_ad.h +shared/mpp/include/mpp_do_update.h +shared/mpp/include/mpp_do_update_nest.h +shared/mpp/include/mpp_do_update_nonblock.h +shared/mpp/include/mpp_do_updateV_ad.h +shared/mpp/include/mpp_do_updateV.h +shared/mpp/include/mpp_do_updateV_nonblock.h +shared/mpp/include/mpp_error_a_a.h +shared/mpp/include/mpp_error_a_s.h +shared/mpp/include/mpp_error_s_a.h +shared/mpp/include/mpp_error_s_s.h +shared/mpp/include/mpp_gather.h +shared/mpp/include/mpp_get_boundary.h +shared/mpp/include/mpp_global_field.h +shared/mpp/include/mpp_global_reduce.h +shared/mpp/include/mpp_global_sum_ad.h +shared/mpp/include/mpp_global_sum.h +shared/mpp/include/mpp_global_sum_tl.h +shared/mpp/include/mpp_io_connect.inc +shared/mpp/include/mpp_io_misc.inc +shared/mpp/include/mpp_io_read.inc +shared/mpp/include/mpp_io_util.inc +shared/mpp/include/mpp_io_write.inc +shared/mpp/include/mpp_read_2Ddecomp.h +shared/mpp/include/mpp_reduce_mpi.h +shared/mpp/include/mpp_reduce_nocomm.h +shared/mpp/include/mpp_reduce_sma.h +shared/mpp/include/mpp_sum.inc +shared/mpp/include/mpp_sum_mpi.h +shared/mpp/include/mpp_sum_nocomm.h +shared/mpp/include/mpp_sum_sma.h +shared/mpp/include/mpp_transmit.inc +shared/mpp/include/mpp_transmit_mpi.h +shared/mpp/include/mpp_transmit_nocomm.h +shared/mpp/include/mpp_transmit_sma.h +shared/mpp/include/mpp_update_domains2D_ad.h +shared/mpp/include/mpp_update_domains2D.h +shared/mpp/include/mpp_update_domains2D_nonblock.h +shared/mpp/include/mpp_update_nest_domains.h +shared/mpp/include/mpp_util.inc +shared/mpp/include/mpp_util_mpi.inc +shared/mpp/include/mpp_util_nocomm.inc +shared/mpp/include/mpp_util_sma.inc +shared/mpp/include/mpp_write_2Ddecomp.h +shared/mpp/include/mpp_write.h +shared/mpp/include/system_clock.h +shared/mpp/mpp_data.F90 +shared/mpp/mpp_domains.F90 +shared/mpp/mpp.F90 +shared/mpp/mpp_io.F90 +shared/mpp/mpp_memutils.F90 +shared/mpp/mpp_parameter.F90 +shared/mpp/mpp_pset.F90 +shared/mpp/mpp_utilities.F90 +shared/mpp/nsclock.c +shared/mpp/test_mpp_domains.F90 +shared/mpp/test_mpp.F90 +shared/mpp/test_mpp_io.F90 +shared/mpp/test_mpp_pset.F90 +shared/mpp/threadloc.c +shared/platform/platform.F90 +shared/time_manager/get_cal_time.F90 +shared/time_manager/time_manager.F90 +shared/tracer_manager/tracer_manager.F90 diff --git a/src/extra/model/shallow/path_names b/src/extra/model/shallow/path_names new file mode 100644 index 000000000..14f1c56f1 --- /dev/null +++ b/src/extra/model/shallow/path_names @@ -0,0 +1,138 @@ +atmos_solo/atmos_model.F90 +atmos_spectral/model/fv_advection.F90 +atmos_spectral/model/leapfrog.F90 +atmos_spectral/model/spectral_damping.F90 +atmos_spectral_shallow/atmosphere.F90 +atmos_spectral_shallow/shallow_diagnostics.F90 +atmos_spectral_shallow/shallow_dynamics.F90 +atmos_spectral_shallow/shallow_physics.F90 +atmos_spectral_barotropic/stirring.F90 +atmos_spectral/tools/gauss_and_legendre.F90 +atmos_spectral/tools/grid_fourier.F90 +atmos_spectral/tools/spec_mpp.F90 +atmos_spectral/tools/spherical.F90 +atmos_spectral/tools/spherical_fourier.F90 +atmos_spectral/tools/transforms.F90 +shared/constants/constants.F90 +shared/diag_manager/diag_axis.F90 +shared/diag_manager/diag_data.F90 +shared/diag_manager/diag_grid.F90 +shared/diag_manager/diag_manager.F90 +shared/diag_manager/diag_output.F90 +shared/diag_manager/diag_table.F90 +shared/diag_manager/diag_util.F90 +shared/fft/fft99.F90 +shared/fft/fft.F90 +shared/field_manager/field_manager.F90 +shared/field_manager/fm_util.F90 +shared/field_manager/parse.inc +shared/fms/fms.F90 +shared/fms/fms_io.F90 +shared/fms/read_data_2d.inc +shared/fms/read_data_3d.inc +shared/fms/read_data_4d.inc +shared/fms/test_fms_io.F90 +shared/fms/write_data.inc +shared/include/fms_platform.h +shared/memutils/memuse.c +shared/memutils/memutils.F90 +shared/mosaic/constant.h +shared/mosaic/create_xgrid.c +shared/mosaic/create_xgrid.h +shared/mosaic/gradient_c2l.c +shared/mosaic/gradient_c2l.h +shared/mosaic/gradient.F90 +shared/mosaic/grid.F90 +shared/mosaic/interp.c +shared/mosaic/interp.h +shared/mosaic/mosaic.F90 +shared/mosaic/mosaic_util.c +shared/mosaic/mosaic_util.h +shared/mosaic/read_mosaic.c +shared/mosaic/read_mosaic.h +shared/mpp/affinity.c +shared/mpp/include/mpp_chksum.h +shared/mpp/include/mpp_chksum_int.h +shared/mpp/include/mpp_chksum_scalar.h +shared/mpp/include/mpp_comm.inc +shared/mpp/include/mpp_comm_mpi.inc +shared/mpp/include/mpp_comm_nocomm.inc +shared/mpp/include/mpp_comm_sma.inc +shared/mpp/include/mpp_data_mpi.inc +shared/mpp/include/mpp_data_nocomm.inc +shared/mpp/include/mpp_data_sma.inc +shared/mpp/include/mpp_define_nest_domains.inc +shared/mpp/include/mpp_do_check.h +shared/mpp/include/mpp_do_checkV.h +shared/mpp/include/mpp_do_get_boundary.h +shared/mpp/include/mpp_do_global_field.h +shared/mpp/include/mpp_domains_comm.inc +shared/mpp/include/mpp_domains_define.inc +shared/mpp/include/mpp_domains_misc.inc +shared/mpp/include/mpp_domains_reduce.inc +shared/mpp/include/mpp_domains_util.inc +shared/mpp/include/mpp_do_redistribute.h +shared/mpp/include/mpp_do_update_ad.h +shared/mpp/include/mpp_do_update.h +shared/mpp/include/mpp_do_update_nest.h +shared/mpp/include/mpp_do_update_nonblock.h +shared/mpp/include/mpp_do_updateV_ad.h +shared/mpp/include/mpp_do_updateV.h +shared/mpp/include/mpp_do_updateV_nonblock.h +shared/mpp/include/mpp_error_a_a.h +shared/mpp/include/mpp_error_a_s.h +shared/mpp/include/mpp_error_s_a.h +shared/mpp/include/mpp_error_s_s.h +shared/mpp/include/mpp_gather.h +shared/mpp/include/mpp_get_boundary.h +shared/mpp/include/mpp_global_field.h +shared/mpp/include/mpp_global_reduce.h +shared/mpp/include/mpp_global_sum_ad.h +shared/mpp/include/mpp_global_sum.h +shared/mpp/include/mpp_global_sum_tl.h +shared/mpp/include/mpp_io_connect.inc +shared/mpp/include/mpp_io_misc.inc +shared/mpp/include/mpp_io_read.inc +shared/mpp/include/mpp_io_util.inc +shared/mpp/include/mpp_io_write.inc +shared/mpp/include/mpp_read_2Ddecomp.h +shared/mpp/include/mpp_reduce_mpi.h +shared/mpp/include/mpp_reduce_nocomm.h +shared/mpp/include/mpp_reduce_sma.h +shared/mpp/include/mpp_sum.inc +shared/mpp/include/mpp_sum_mpi.h +shared/mpp/include/mpp_sum_nocomm.h +shared/mpp/include/mpp_sum_sma.h +shared/mpp/include/mpp_transmit.inc +shared/mpp/include/mpp_transmit_mpi.h +shared/mpp/include/mpp_transmit_nocomm.h +shared/mpp/include/mpp_transmit_sma.h +shared/mpp/include/mpp_update_domains2D_ad.h +shared/mpp/include/mpp_update_domains2D.h +shared/mpp/include/mpp_update_domains2D_nonblock.h +shared/mpp/include/mpp_update_nest_domains.h +shared/mpp/include/mpp_util.inc +shared/mpp/include/mpp_util_mpi.inc +shared/mpp/include/mpp_util_nocomm.inc +shared/mpp/include/mpp_util_sma.inc +shared/mpp/include/mpp_write_2Ddecomp.h +shared/mpp/include/mpp_write.h +shared/mpp/include/system_clock.h +shared/mpp/mpp_data.F90 +shared/mpp/mpp_domains.F90 +shared/mpp/mpp.F90 +shared/mpp/mpp_io.F90 +shared/mpp/mpp_memutils.F90 +shared/mpp/mpp_parameter.F90 +shared/mpp/mpp_pset.F90 +shared/mpp/mpp_utilities.F90 +shared/mpp/nsclock.c +shared/mpp/test_mpp_domains.F90 +shared/mpp/test_mpp.F90 +shared/mpp/test_mpp_io.F90 +shared/mpp/test_mpp_pset.F90 +shared/mpp/threadloc.c +shared/platform/platform.F90 +shared/time_manager/get_cal_time.F90 +shared/time_manager/time_manager.F90 +shared/tracer_manager/tracer_manager.F90 From e74e5c0d9c28ac7933570c711d74dc3a72f5638f Mon Sep 17 00:00:00 2001 From: sit23 Date: Fri, 17 May 2019 17:02:59 +0100 Subject: [PATCH 13/24] Added ability to do deep velocities, I think. Seems reasonable. Now testing. --- .../shallow_diagnostics.F90 | 4 +++- .../shallow_dynamics.F90 | 20 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/atmos_spectral_shallow/shallow_diagnostics.F90 b/src/atmos_spectral_shallow/shallow_diagnostics.F90 index e0fd0052a..447cf64aa 100644 --- a/src/atmos_spectral_shallow/shallow_diagnostics.F90 +++ b/src/atmos_spectral_shallow/shallow_diagnostics.F90 @@ -55,7 +55,7 @@ module shallow_diagnostics_mod logical :: module_is_initialized = .false. -integer :: id_vor, id_stream, id_pv, id_u, id_v, id_div, id_h, id_trs, id_tr +integer :: id_vor, id_stream, id_pv, id_u, id_v, id_div, id_h, id_trs, id_tr, id_d_geopot integer :: is, ie, js, je @@ -106,6 +106,7 @@ subroutine shallow_diagnostics_init(Time, lon_max, lat_max, id_lon, id_lat, id_l id_stream = register_diag_field(mod_name, 'stream', axis_2d, Time, 'streamfunction' , 'm^2/s' ) id_trs = register_diag_field(mod_name, 'trs' , axis_2d, Time, 'spectral tracer' , 'none' ) id_tr = register_diag_field(mod_name, 'tr' , axis_2d, Time, 'grid tracer' , 'none' ) +id_d_geopot = register_diag_field(mod_name, 'deep_geopot', axis_2d, Time, 'deep_geopot' , 'm2/s2') module_is_initialized = .true. @@ -132,6 +133,7 @@ subroutine shallow_diagnostics(Time, Grid, Phys, time_index) if(id_stream > 0) used = send_data(id_stream , Grid%stream (:,:) , time) if(id_tr > 0) used = send_data(id_tr , Grid%tr (:,:, time_index) , time) if(id_trs > 0) used = send_data(id_trs , Grid%trs (:,:, time_index) , time) +if(id_d_geopot > 0) used = send_data(id_d_geopot, Grid%deep_geopot (:,:) , time) return end subroutine shallow_diagnostics diff --git a/src/atmos_spectral_shallow/shallow_dynamics.F90 b/src/atmos_spectral_shallow/shallow_dynamics.F90 index eacbfc159..79946cf0a 100644 --- a/src/atmos_spectral_shallow/shallow_dynamics.F90 +++ b/src/atmos_spectral_shallow/shallow_dynamics.F90 @@ -39,7 +39,7 @@ module shallow_dynamics_mod operator(==), & operator(-) -use constants_mod, only : radius, omega +use constants_mod, only : radius, omega, DEG_TO_RAD use transforms_mod, only: transforms_init, transforms_end, & get_grid_boundaries, horizontal_advection, & @@ -76,7 +76,7 @@ module shallow_dynamics_mod type grid_type real, pointer, dimension(:,:,:) :: u=>NULL(), v=>NULL(), vor=>NULL(), div=>NULL(), h=>NULL(), trs=>NULL(), tr=>NULL() - real, pointer, dimension(:,:) :: stream=>NULL(), pv=>NULL() + real, pointer, dimension(:,:) :: stream=>NULL(), pv=>NULL(), deep_geopot=>NULL() end type type spectral_type complex, pointer, dimension(:,:,:) :: vor=>NULL(), div=>NULL(), h=>NULL(), trs=>NULL() @@ -132,6 +132,9 @@ module shallow_dynamics_mod real :: damping_coeff = 1.e-04 real :: h_0 = 3.e04 +real :: u_deep_mag = 0. +real :: n_merid_deep_flow = 3. + logical :: spec_tracer = .true. logical :: grid_tracer = .true. @@ -146,7 +149,8 @@ module shallow_dynamics_mod robert_coeff, robert_coeff_tracer, & h_0, spec_tracer, grid_tracer, & valid_range_v, cutoff_wn, & - raw_filter_coeff + raw_filter_coeff, & + u_deep_mag, n_merid_deep_flow contains @@ -235,6 +239,8 @@ subroutine shallow_dynamics_init (Dyn, Time, Time_init, dt_real) allocate (Dyn%tend%h (is:ie, js:je)) allocate (Dyn%grid%stream (is:ie, js:je)) allocate (Dyn%grid%pv (is:ie, js:je)) +allocate (Dyn%grid%deep_geopot(is:ie, js:je)) + call fv_advection_init(num_lon, num_lat, glat_bnd, 360./float(fourier_inc)) if(Dyn%grid_tracer) then @@ -248,6 +254,10 @@ subroutine shallow_dynamics_init (Dyn, Time, Time_init, dt_real) allocate(Dyn%Spec%trs (ms:me, ns:ne, num_time_levels)) endif +do i = is, ie + Dyn%grid%deep_geopot(i, js:je) = -2.*omega * u_deep_mag * radius * (1./(1.-n_merid_deep_flow**2.))*(-cos(n_merid_deep_flow*DEG_TO_RAD*deg_lat(js:je))*cos(DEG_TO_RAD*deg_lat(js:je)) - n_merid_deep_flow * (sin(n_merid_deep_flow*DEG_TO_RAD*deg_lat(js:je))*sin(DEG_TO_RAD*deg_lat(js:je))-sin(n_merid_deep_flow*(2.*atan(1.))))) +enddo + if(Time == Time_init) then Dyn%Grid%vor(:,:,1) = 0.0 @@ -326,7 +336,7 @@ subroutine shallow_dynamics(Time, Time_init, Dyn, previous, current, future, del call trans_grid_to_spherical (Dyn%Tend%h, dt_hs) -bg = (Dyn%Grid%h(:,:,current) + & +bg = (Dyn%Grid%h(:,:,current) + Dyn%grid%deep_geopot(:,:) + & 0.5*(Dyn%Grid%u(:,:,current)**2 + Dyn%Grid%v(:,:,current)**2)) call trans_grid_to_spherical(bg, bs) @@ -370,7 +380,7 @@ subroutine shallow_dynamics(Time, Time_init, Dyn, previous, current, future, del stream = compute_laplacian(Dyn%Spec%vor(:,:,current), -1) ! for diagnostic purposes call trans_spherical_to_grid(stream, Dyn%grid%stream) -Dyn%Grid%pv = vorg/Dyn%Grid%h(:,:,current) +Dyn%Grid%pv = vorg/(Dyn%Grid%h(:,:,current)+Dyn%grid%deep_geopot(:,:)) return end subroutine shallow_dynamics From 172087f14c844ee6c2e798d833757a1f1e5744fa Mon Sep 17 00:00:00 2001 From: sit23 Date: Fri, 31 May 2019 10:07:09 +0100 Subject: [PATCH 14/24] Updaing shallow water code to better account for deep velocities in ics and in PV definition, which I previously modified incorrectly. --- .../shallow_diagnostics.F90 | 45 +++++++++++++++++-- .../shallow_dynamics.F90 | 12 +++-- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/atmos_spectral_shallow/shallow_diagnostics.F90 b/src/atmos_spectral_shallow/shallow_diagnostics.F90 index 447cf64aa..ce485758b 100644 --- a/src/atmos_spectral_shallow/shallow_diagnostics.F90 +++ b/src/atmos_spectral_shallow/shallow_diagnostics.F90 @@ -27,7 +27,8 @@ module shallow_diagnostics_mod get_deg_lat, & get_grid_domain, & get_spec_domain, & - grid_domain + grid_domain, & + area_weighted_global_mean use diag_manager_mod, only: diag_axis_init, & register_diag_field, & @@ -55,7 +56,7 @@ module shallow_diagnostics_mod logical :: module_is_initialized = .false. -integer :: id_vor, id_stream, id_pv, id_u, id_v, id_div, id_h, id_trs, id_tr, id_d_geopot +integer :: id_vor, id_stream, id_pv, id_u, id_v, id_div, id_h, id_trs, id_tr, id_d_geopot, id_u_sqd, id_v_sqd, id_h_sqd, id_u_sqd_mean, id_v_sqd_mean, id_h_sqd_mean, id_ekin integer :: is, ie, js, je @@ -102,12 +103,22 @@ subroutine shallow_diagnostics_init(Time, lon_max, lat_max, id_lon, id_lat, id_l id_vor = register_diag_field(mod_name, 'vor' , axis_2d, Time, 'relative vorticity' , '1/s' ) id_div = register_diag_field(mod_name, 'div' , axis_2d, Time, 'divergence' , '1/s' ) id_h = register_diag_field(mod_name, 'h' , axis_2d, Time, 'geopotential' , 'm2/s2' ) -id_pv = register_diag_field(mod_name, 'pv' , axis_2d, Time, 'potential vorticity' , 's/m2' ) +id_pv = register_diag_field(mod_name, 'pv_corrected' , axis_2d, Time, 'potential vorticity' , 's/m2' ) id_stream = register_diag_field(mod_name, 'stream', axis_2d, Time, 'streamfunction' , 'm^2/s' ) id_trs = register_diag_field(mod_name, 'trs' , axis_2d, Time, 'spectral tracer' , 'none' ) id_tr = register_diag_field(mod_name, 'tr' , axis_2d, Time, 'grid tracer' , 'none' ) id_d_geopot = register_diag_field(mod_name, 'deep_geopot', axis_2d, Time, 'deep_geopot' , 'm2/s2') +id_u_sqd = register_diag_field(mod_name, 'ucomp_sqd' , axis_2d, Time, 'u_wind_sqd' , 'm^2/s^2' ) +id_v_sqd = register_diag_field(mod_name, 'vcomp_sqd' , axis_2d, Time, 'v_wind_sqd' , 'm^2/s^2' ) +id_h_sqd = register_diag_field(mod_name, 'h_sqd' , axis_2d, Time, 'geopotential_sqd' , 'm4/s4' ) + +id_u_sqd_mean = register_diag_field(mod_name, 'ucomp_sqd_mean' , Time, 'u_wind_sqd_mean' , 'm^2/s^2' ) +id_v_sqd_mean = register_diag_field(mod_name, 'vcomp_sqd_mean' , Time, 'v_wind_sqd_mean' , 'm^2/s^2' ) +id_h_sqd_mean = register_diag_field(mod_name, 'h_sqd_mean' , Time, 'geopotential_sqd_mean' , 'm4/s4' ) + +id_ekin = register_diag_field(mod_name, 'e_kin' , Time, 'kinetic_energy' , 'm^2/s^2' ) + module_is_initialized = .true. return @@ -135,6 +146,34 @@ subroutine shallow_diagnostics(Time, Grid, Phys, time_index) if(id_trs > 0) used = send_data(id_trs , Grid%trs (:,:, time_index) , time) if(id_d_geopot > 0) used = send_data(id_d_geopot, Grid%deep_geopot (:,:) , time) +if (id_u_sqd > 0) then + used = send_data(id_u_sqd , Grid%u (:,:, time_index)**2 , time) +endif + +if (id_v_sqd > 0) then + used = send_data(id_v_sqd , Grid%v (:,:, time_index)**2 , time) +endif + +if (id_h_sqd > 0) then + used = send_data(id_h_sqd , Grid%h (:,:, time_index)**2 , time) +endif + +if (id_u_sqd_mean > 0) then + used = send_data(id_u_sqd_mean , area_weighted_global_mean(Grid%u (:,:, time_index)**2) , time) +endif + +if (id_v_sqd_mean > 0) then + used = send_data(id_v_sqd_mean , area_weighted_global_mean(Grid%v (:,:, time_index)**2) , time) +endif + +if (id_h_sqd_mean > 0) then + used = send_data(id_h_sqd_mean , area_weighted_global_mean(Grid%h (:,:, time_index)**2) , time) +endif + +if (id_ekin > 0) then + used = send_data(id_ekin , 0.5*(area_weighted_global_mean(Grid%u (:,:, time_index)**2) + area_weighted_global_mean(Grid%v (:,:, time_index)**2)) , time) +endif + return end subroutine shallow_diagnostics !-------------------------------------------------------------------------------------------- diff --git a/src/atmos_spectral_shallow/shallow_dynamics.F90 b/src/atmos_spectral_shallow/shallow_dynamics.F90 index 79946cf0a..8953ca662 100644 --- a/src/atmos_spectral_shallow/shallow_dynamics.F90 +++ b/src/atmos_spectral_shallow/shallow_dynamics.F90 @@ -49,7 +49,8 @@ module shallow_dynamics_mod get_deg_lon, get_deg_lat, & get_grid_domain, get_spec_domain, & spectral_domain, grid_domain, & - vor_div_from_uv_grid, uv_grid_from_vor_div + vor_div_from_uv_grid, uv_grid_from_vor_div, & + area_weighted_global_mean use spectral_damping_mod, only: spectral_damping_init, compute_spectral_damping @@ -165,7 +166,7 @@ subroutine shallow_dynamics_init (Dyn, Time, Time_init, dt_real) integer :: i, j real, allocatable, dimension(:) :: glon_bnd, glat_bnd -real :: xx, yy, dd +real :: xx, yy, dd, deep_geopot_global_mean integer :: ierr, io, unit, id_lon, id_lat, id_lonb, id_latb logical :: root @@ -258,11 +259,14 @@ subroutine shallow_dynamics_init (Dyn, Time, Time_init, dt_real) Dyn%grid%deep_geopot(i, js:je) = -2.*omega * u_deep_mag * radius * (1./(1.-n_merid_deep_flow**2.))*(-cos(n_merid_deep_flow*DEG_TO_RAD*deg_lat(js:je))*cos(DEG_TO_RAD*deg_lat(js:je)) - n_merid_deep_flow * (sin(n_merid_deep_flow*DEG_TO_RAD*deg_lat(js:je))*sin(DEG_TO_RAD*deg_lat(js:je))-sin(n_merid_deep_flow*(2.*atan(1.))))) enddo +deep_geopot_global_mean = area_weighted_global_mean(Dyn%grid%deep_geopot(:,:)) +Dyn%grid%deep_geopot(:,:) = Dyn%grid%deep_geopot(:,:)-deep_geopot_global_mean + if(Time == Time_init) then Dyn%Grid%vor(:,:,1) = 0.0 Dyn%Grid%div(:,:,1) = 0.0 - Dyn%Grid%h (:,:,1) = h_0 + Dyn%Grid%h (:,:,1) = h_0 - Dyn%grid%deep_geopot(:,:) call trans_grid_to_spherical(Dyn%Grid%vor(:,:,1), Dyn%Spec%vor(:,:,1)) call trans_grid_to_spherical(Dyn%Grid%div(:,:,1), Dyn%Spec%div(:,:,1)) @@ -380,7 +384,7 @@ subroutine shallow_dynamics(Time, Time_init, Dyn, previous, current, future, del stream = compute_laplacian(Dyn%Spec%vor(:,:,current), -1) ! for diagnostic purposes call trans_spherical_to_grid(stream, Dyn%grid%stream) -Dyn%Grid%pv = vorg/(Dyn%Grid%h(:,:,current)+Dyn%grid%deep_geopot(:,:)) +Dyn%Grid%pv = vorg/(Dyn%Grid%h(:,:,current)) return end subroutine shallow_dynamics From de1f769f32623a424ea193af9882b0a67cf73e46 Mon Sep 17 00:00:00 2001 From: sit23 Date: Fri, 31 May 2019 10:08:11 +0100 Subject: [PATCH 15/24] First lot of experiments for poster. Run at T170 and forced at small-ish scale. --- ...et_shallow_water_deep_velocity_test_mk1.py | 166 +++++++++++++++++ ...ter_deep_velocity_test_mk1_vary_damping.py | 169 +++++++++++++++++ ...et_shallow_water_deep_velocity_test_mk1.py | 167 +++++++++++++++++ ...et_shallow_water_deep_velocity_test_mk2.py | 170 ++++++++++++++++++ ...shallow_water_small_scale_stirring_test.py | 14 +- 5 files changed, 679 insertions(+), 7 deletions(-) create mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py create mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1_vary_damping.py create mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk1.py create mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk2.py diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py new file mode 100644 index 000000000..56d419739 --- /dev/null +++ b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py @@ -0,0 +1,166 @@ +import os + +import numpy as np + +from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE + +import pdb + +NCORES = 16 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = ShallowCodeBase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') +# diag.add_file('atmos_daily', 1, 'days', time_units='days') + +#Tell model which diagnostics to write +diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'div', time_avg=True) +diag.add_field('shallow_diagnostics', 'h', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv_corrected', time_avg=True) +diag.add_field('shallow_diagnostics', 'stream', time_avg=True) +diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) +# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) +# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) +diag.add_field('stirring_mod', 'stirring', time_avg=True) +# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) +diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) +diag.add_field('shallow_diagnostics', 'h_sqd_mean', time_avg=True) + +#Empty the run directory ready to run + +#Define values for the 'core' namelist +namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 1200, + 'calendar': 'no_calendar', + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml':{ + 'print_memory_usage':False, + 'domains_stack_size': 200000, + }, + + 'shallow_dynamics_nml':{ + 'num_lon' : 512, + 'num_lat' : 256, + 'num_fourier' : 170, + 'num_spherical' : 171, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 4, + 'damping_coeff' : 1.e-04, + 'h_0' : 3.e04, + 'grid_tracer' : False, + 'spec_tracer' : False, + 'robert_coeff' : 0.04, + 'robert_coeff_tracer' : 0.04, + }, + + 'shallow_physics_nml':{ + 'fric_damp_time' : 0.0, + 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. + 'h_amp' : 0., + 'h_itcz' : 0., + }, + + 'stirring_nml': { + 'B':0.0, + 'do_localize': False, + }, + +}) + +#Lets do a run! +if __name__=="__main__": + + for ld_value in [10.0, 0.1, 0.05, 0.01]: + + for u_deep_mag_val in [50., 0.]: + + if u_deep_mag_val!=0.: + u_deep_merid_arr = [3, 11, 19, 26] + else: + u_deep_merid_arr = [3] + + for u_deep_merid in u_deep_merid_arr: + + exp = Experiment('giant_planet_fixed_deep_ics_forced_no_rad_damping_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid)), codebase=cb) + + exp.diag_table = diag + exp.namelist = namelist + exp.clear_rundir() + + rotation_period = ((9.*3600.)+55.*60 + 30.) + omega = 2.*np.pi/ rotation_period + radius = 69911e3 + grav = 24.79 + number_ld_in_radius_units = ld_value + + # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. + + equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. + equilibrium_depth = equilibrium_geopotential/grav + + exp.update_namelist({ + 'shallow_dynamics_nml':{ + 'h_0': equilibrium_geopotential, + 'u_deep_mag' : u_deep_mag_val, + 'n_merid_deep_flow': u_deep_merid, + }, + 'shallow_physics_nml': { + 'h_0': equilibrium_geopotential, + 'therm_damp_time' : rotation_period * 0., #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) + }, + 'constants_nml': { + 'omega': omega, + 'radius': radius, + }, + 'stirring_nml': { + 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. + 'amplitude':3.e-13, + 'n_total_forcing_max': 85, + 'n_total_forcing_min': 79, + + }, + + }) + + exp.run(1, use_restart=False, num_cores=NCORES) + for i in range(2,361): + exp.run(i, num_cores=NCORES) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1_vary_damping.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1_vary_damping.py new file mode 100644 index 000000000..c2335a0be --- /dev/null +++ b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1_vary_damping.py @@ -0,0 +1,169 @@ +import os + +import numpy as np + +from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE + +import pdb + +NCORES = 16 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = ShallowCodeBase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') +# diag.add_file('atmos_daily', 1, 'days', time_units='days') + +#Tell model which diagnostics to write +diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'div', time_avg=True) +diag.add_field('shallow_diagnostics', 'h', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv_correct', time_avg=True) + +diag.add_field('shallow_diagnostics', 'stream', time_avg=True) +diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) +# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) +# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) +diag.add_field('stirring_mod', 'stirring', time_avg=True) +# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) +diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) +diag.add_field('shallow_diagnostics', 'h_sqd_mean', time_avg=True) + +#Empty the run directory ready to run + +#Define values for the 'core' namelist +namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 1200, + 'calendar': 'no_calendar', + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml':{ + 'print_memory_usage':False, + 'domains_stack_size': 200000, + }, + + 'shallow_dynamics_nml':{ + 'num_lon' : 512, + 'num_lat' : 256, + 'num_fourier' : 170, + 'num_spherical' : 171, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 4, + 'damping_coeff' : 1.e-04, + 'h_0' : 3.e04, + 'grid_tracer' : False, + 'spec_tracer' : False, + 'robert_coeff' : 0.04, + 'robert_coeff_tracer' : 0.04, + }, + + 'shallow_physics_nml':{ + 'fric_damp_time' : 0.0, + 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. + 'h_amp' : 0., + 'h_itcz' : 0., + }, + + 'stirring_nml': { + 'B':0.0, + 'do_localize': False, + }, + +}) + +#Lets do a run! +if __name__=="__main__": + + for ld_value in [0.1]: + + for u_deep_mag_val in [0., 50.]: + + if u_deep_mag_val!=0.: + u_deep_merid_arr = [3, 11, 19, 26] + else: + u_deep_merid_arr = [3] + + for u_deep_merid in u_deep_merid_arr: + + for damping_time_rot in [1000., 10000.]: #, 0., 100., Also want to do these, but can alias existing runs for them + + exp = Experiment('giant_planet_fixed_deep_ics_forced_rad_damping_'+str(damping_time_rot)+'_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid)), codebase=cb) + + exp.diag_table = diag + exp.namelist = namelist + exp.clear_rundir() + + rotation_period = ((9.*3600.)+55.*60 + 30.) + omega = 2.*np.pi/ rotation_period + radius = 69911e3 + grav = 24.79 + number_ld_in_radius_units = ld_value + + # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. + + equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. + equilibrium_depth = equilibrium_geopotential/grav + + exp.update_namelist({ + 'shallow_dynamics_nml':{ + 'h_0': equilibrium_geopotential, + 'u_deep_mag' : u_deep_mag_val, + 'n_merid_deep_flow': u_deep_merid, + }, + 'shallow_physics_nml': { + 'h_0': equilibrium_geopotential, + 'therm_damp_time' : rotation_period * damping_time_rot, #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) + }, + 'constants_nml': { + 'omega': omega, + 'radius': radius, + }, + 'stirring_nml': { + 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. + 'amplitude':3.e-13, + 'n_total_forcing_max': 85, + 'n_total_forcing_min': 79, + + }, + + }) + + exp.run(1, use_restart=False, num_cores=NCORES) + for i in range(2,721): + exp.run(i, num_cores=NCORES) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk1.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk1.py new file mode 100644 index 000000000..0d5ce04b4 --- /dev/null +++ b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk1.py @@ -0,0 +1,167 @@ +import os + +import numpy as np + +from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE + +import pdb + +NCORES = 16 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = ShallowCodeBase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') +# diag.add_file('atmos_daily', 1, 'days', time_units='days') + +#Tell model which diagnostics to write +diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'div', time_avg=True) +diag.add_field('shallow_diagnostics', 'h', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv', time_avg=True) +diag.add_field('shallow_diagnostics', 'stream', time_avg=True) +diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) +# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) +# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) +diag.add_field('stirring_mod', 'stirring', time_avg=True) +# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) +diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) + + +#Empty the run directory ready to run + +#Define values for the 'core' namelist +namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 1200, + 'calendar': 'no_calendar', + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml':{ + 'print_memory_usage':False, + 'domains_stack_size': 200000, + }, + + 'shallow_dynamics_nml':{ + 'num_lon' : 512, + 'num_lat' : 256, + 'num_fourier' : 170, + 'num_spherical' : 171, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 4, + 'damping_coeff' : 1.e-04, + 'h_0' : 3.e04, + 'grid_tracer' : False, + 'spec_tracer' : False, + 'robert_coeff' : 0.04, + 'robert_coeff_tracer' : 0.04, + }, + + 'shallow_physics_nml':{ + 'fric_damp_time' : 0.0, + 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. + 'h_amp' : 0., + 'h_itcz' : 0., + }, + + 'stirring_nml': { + 'B':0.0, + 'do_localize': False, + }, + +}) + +#Lets do a run! +if __name__=="__main__": + + for ld_value in [10.0]: + for u_deep_mag_val in [50.,]: + #for u_deep_mag_val in [-50.]: + + if u_deep_mag_val!=0.: + u_deep_merid_arr = [3,] + else: + u_deep_merid_arr = [3] + + #u_deep_merid_arr = [3] + + for u_deep_merid in u_deep_merid_arr: + + exp = Experiment('giant_planet_shallow_water_deep_velocity_test_mk2_no_forcing_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid)), codebase=cb) + + exp.diag_table = diag + exp.namelist = namelist + exp.clear_rundir() + + rotation_period = ((9.*3600.)+55.*60 + 30.) + omega = 2.*np.pi/ rotation_period + radius = 69911e3 + grav = 24.79 + number_ld_in_radius_units = ld_value + + # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. + + equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. + equilibrium_depth = equilibrium_geopotential/grav + + exp.update_namelist({ + 'shallow_dynamics_nml':{ + 'h_0': equilibrium_geopotential, + 'u_deep_mag' : u_deep_mag_val, + 'n_merid_deep_flow': u_deep_merid, + }, + 'shallow_physics_nml': { + 'h_0': equilibrium_geopotential, + 'therm_damp_time' : rotation_period * 100., #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) + }, + 'constants_nml': { + 'omega': omega, + 'radius': radius, + }, + 'stirring_nml': { + 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. + 'amplitude':0., + 'n_total_forcing_max': 85, + 'n_total_forcing_min': 79, + + }, + + }) + + exp.run(1, use_restart=False, num_cores=NCORES) + for i in range(2,2101): + exp.run(i, num_cores=NCORES) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk2.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk2.py new file mode 100644 index 000000000..711b2c34b --- /dev/null +++ b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk2.py @@ -0,0 +1,170 @@ +import os + +import numpy as np + +from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE + +import pdb + +NCORES = 16 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = ShallowCodeBase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') +# diag.add_file('atmos_daily', 1, 'days', time_units='days') +# diag.add_file('atmos_timestep', 1200, 'seconds', time_units='days') + + +#Tell model which diagnostics to write +diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'div', time_avg=True) +diag.add_field('shallow_diagnostics', 'h', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv', time_avg=True) +diag.add_field('shallow_diagnostics', 'stream', time_avg=True) +diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) +# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) +# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) +diag.add_field('stirring_mod', 'stirring', time_avg=True) +# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) +diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) + + + +#Empty the run directory ready to run + +#Define values for the 'core' namelist +namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 1200, + 'calendar': 'no_calendar', + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml':{ + 'print_memory_usage':False, + 'domains_stack_size': 200000, + }, + + 'shallow_dynamics_nml':{ + 'num_lon' : 512, + 'num_lat' : 256, + 'num_fourier' : 170, + 'num_spherical' : 171, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 4, + 'damping_coeff' : 1.e-04, + 'h_0' : 3.e04, + 'grid_tracer' : False, + 'spec_tracer' : False, + 'robert_coeff' : 0.04, + 'robert_coeff_tracer' : 0.04, + }, + + 'shallow_physics_nml':{ + 'fric_damp_time' : 0.0, + 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. + 'h_amp' : 0., + 'h_itcz' : 0., + }, + + 'stirring_nml': { + 'B':0.0, + 'do_localize': False, + }, + +}) + +#Lets do a run! +if __name__=="__main__": + + for ld_value in [0.1, 10.0]: + # for u_deep_mag_val in [50., 0., 25.]: + for u_deep_mag_val in [50., 0.]: + + # if u_deep_mag_val!=0.: + # u_deep_merid_arr = [3, 11, 19, 26] + # else: + # u_deep_merid_arr = [3] + + u_deep_merid_arr = [3] + + for u_deep_merid in u_deep_merid_arr: + + exp = Experiment('giant_planet_shallow_water_deep_velocity_test_mk8_no_forcing_no_damping_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid)), codebase=cb) + + exp.diag_table = diag + exp.namelist = namelist + exp.clear_rundir() + + rotation_period = ((9.*3600.)+55.*60 + 30.) + omega = 2.*np.pi/ rotation_period + radius = 69911e3 + grav = 24.79 + number_ld_in_radius_units = ld_value + + # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. + + equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. + equilibrium_depth = equilibrium_geopotential/grav + + exp.update_namelist({ + 'shallow_dynamics_nml':{ + 'h_0': equilibrium_geopotential, + 'u_deep_mag' : u_deep_mag_val, + 'n_merid_deep_flow': u_deep_merid, + }, + 'shallow_physics_nml': { + 'h_0': equilibrium_geopotential, + 'therm_damp_time' : 0. + }, + 'constants_nml': { + 'omega': omega, + 'radius': radius, + }, + 'stirring_nml': { + 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. + 'amplitude':0., + 'n_total_forcing_max': 85, + 'n_total_forcing_min': 79, + + }, + + }) + + exp.run(1, use_restart=False, num_cores=NCORES) + for i in range(2,121): + exp.run(i, num_cores=NCORES) diff --git a/exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py b/exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py index a45007b8b..14c4b323c 100644 --- a/exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py +++ b/exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py @@ -6,7 +6,7 @@ import pdb -NCORES = 8 +NCORES = 16 base_dir = os.path.dirname(os.path.realpath(__file__)) # a CodeBase can be a directory on the computer, # useful for iterative development @@ -106,9 +106,9 @@ #Lets do a run! if __name__=="__main__": - for number_ld_in_radius_units in [10.]: + for number_ld_in_radius_units in [0.1]: - exp = Experiment('giant_shallow_stirring_test_experiment_uniform_small_scale_stirring_mk3', codebase=cb) + exp = Experiment('giant_shallow_stirring_test_experiment_uniform_smaller_120_scale_stirring_mk3_longer_damping_ld_'+str(number_ld_in_radius_units), codebase=cb) exp.diag_table = diag exp.namelist = namelist @@ -130,7 +130,7 @@ }, 'shallow_physics_nml': { 'h_0': equilibrium_geopotential, - 'therm_damp_time' : rotation_period * 1., #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) + 'therm_damp_time' : rotation_period * 10000., #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) }, 'constants_nml': { 'omega': omega, @@ -139,13 +139,13 @@ 'stirring_nml': { 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. 'amplitude':3.e-13, - 'n_total_forcing_max': 45, - 'n_total_forcing_min': 39, + 'n_total_forcing_max': 125, + 'n_total_forcing_min': 119, }, }) exp.run(1, use_restart=False, num_cores=NCORES) - for i in range(2,122): + for i in range(2,121): exp.run(i, num_cores=NCORES) From c09ad56ad00ceb7c6cc1d259a68edc2054347d8f Mon Sep 17 00:00:00 2001 From: sit23 Date: Tue, 18 Jun 2019 19:05:55 +0100 Subject: [PATCH 16/24] Updating outputs for energy diagnostics. --- ...et_shallow_water_deep_velocity_test_mk1.py | 23 ++++-- .../shallow_diagnostics.F90 | 72 ++++++++++++++++++- .../shallow_dynamics.F90 | 9 ++- 3 files changed, 96 insertions(+), 8 deletions(-) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py index 56d419739..fe65deba8 100644 --- a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py +++ b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py @@ -49,6 +49,14 @@ diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) diag.add_field('shallow_diagnostics', 'h_sqd_mean', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_kin_density', time_avg=True) +diag.add_field('shallow_diagnostics', 'eq_geopot', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_kin_real_units', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_pot_real_units', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_tot_real_units', time_avg=True) +diag.add_field('shallow_diagnostics', 'u_rms', time_avg=True) + + #Empty the run directory ready to run #Define values for the 'core' namelist @@ -109,18 +117,22 @@ #Lets do a run! if __name__=="__main__": - for ld_value in [10.0, 0.1, 0.05, 0.01]: + # for ld_value in [10.0, 0.1, 0.05, 0.01]: + for ld_value in [0.05,]: - for u_deep_mag_val in [50., 0.]: + + for u_deep_mag_val in [50.]: if u_deep_mag_val!=0.: - u_deep_merid_arr = [3, 11, 19, 26] + u_deep_merid_arr = [27] + # u_deep_merid_arr = [5,7,9] + else: u_deep_merid_arr = [3] for u_deep_merid in u_deep_merid_arr: - exp = Experiment('giant_planet_fixed_deep_ics_forced_no_rad_damping_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid)), codebase=cb) + exp = Experiment('giant_planet_fixed_deep_ics_forced_no_rad_damping_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid))+'_energy_outputs_3', codebase=cb) exp.diag_table = diag exp.namelist = namelist @@ -141,7 +153,8 @@ 'shallow_dynamics_nml':{ 'h_0': equilibrium_geopotential, 'u_deep_mag' : u_deep_mag_val, - 'n_merid_deep_flow': u_deep_merid, + 'n_merid_deep_flow': u_deep_merid, + # 'u_upper_mag_init': u_deep_mag_val, }, 'shallow_physics_nml': { 'h_0': equilibrium_geopotential, diff --git a/src/atmos_spectral_shallow/shallow_diagnostics.F90 b/src/atmos_spectral_shallow/shallow_diagnostics.F90 index ce485758b..7a8cbed09 100644 --- a/src/atmos_spectral_shallow/shallow_diagnostics.F90 +++ b/src/atmos_spectral_shallow/shallow_diagnostics.F90 @@ -56,7 +56,7 @@ module shallow_diagnostics_mod logical :: module_is_initialized = .false. -integer :: id_vor, id_stream, id_pv, id_u, id_v, id_div, id_h, id_trs, id_tr, id_d_geopot, id_u_sqd, id_v_sqd, id_h_sqd, id_u_sqd_mean, id_v_sqd_mean, id_h_sqd_mean, id_ekin +integer :: id_vor, id_stream, id_pv, id_u, id_v, id_div, id_h, id_trs, id_tr, id_d_geopot, id_u_sqd, id_v_sqd, id_h_sqd, id_u_sqd_mean, id_v_sqd_mean, id_h_sqd_mean, id_ekin, id_ekin_density, id_eq_geopot, id_e_kin_real_units, id_e_pot_real_units, id_e_tot_real_units, id_u_rms integer :: is, ie, js, je @@ -118,6 +118,14 @@ subroutine shallow_diagnostics_init(Time, lon_max, lat_max, id_lon, id_lat, id_l id_h_sqd_mean = register_diag_field(mod_name, 'h_sqd_mean' , Time, 'geopotential_sqd_mean' , 'm4/s4' ) id_ekin = register_diag_field(mod_name, 'e_kin' , Time, 'kinetic_energy' , 'm^2/s^2' ) +id_ekin_density = register_diag_field(mod_name, 'e_kin_density' , Time, 'kinetic_energy_density' , 'm^3/s^2' ) + +id_eq_geopot = register_diag_field(mod_name, 'eq_geopot' , Time, 'equilibrium_geopotential' , 'm^2/s^2' ) +id_e_kin_real_units = register_diag_field(mod_name, 'e_kin_real_units' , Time, 'e_kin_real_units' , 'J/kg' ) +id_e_pot_real_units = register_diag_field(mod_name, 'e_pot_real_units' , Time, 'e_pot_real_units' , 'J/kg' ) +id_e_tot_real_units = register_diag_field(mod_name, 'e_tot_real_units' , Time, 'e_tot_real_units' , 'J/kg' ) + +id_u_rms = register_diag_field(mod_name, 'u_rms' , Time, 'r_rms' , 'm/s' ) module_is_initialized = .true. @@ -133,6 +141,8 @@ subroutine shallow_diagnostics(Time, Grid, Phys, time_index) type(grid_type), intent(in) :: Grid integer, intent(in) :: time_index +real :: e_kin_real_units, e_pot_real_units, e_tot_real_units, eq_geopot + logical :: used if(id_u > 0) used = send_data(id_u , Grid%u (:,:, time_index) , time) @@ -174,6 +184,66 @@ subroutine shallow_diagnostics(Time, Grid, Phys, time_index) used = send_data(id_ekin , 0.5*(area_weighted_global_mean(Grid%u (:,:, time_index)**2) + area_weighted_global_mean(Grid%v (:,:, time_index)**2)) , time) endif +if (id_ekin_density > 0) then + used = send_data(id_ekin_density , 0.5*(area_weighted_global_mean(Grid%h (:,:, time_index)*(Grid%u (:,:, time_index)**2)) + area_weighted_global_mean(Grid%h (:,:, time_index)*(Grid%v (:,:, time_index)**2))) , time) +endif + +eq_geopot = 0. +e_kin_real_units = 0. +e_pot_real_units = 0. + +if (id_eq_geopot > 0) then + + eq_geopot = area_weighted_global_mean(Grid%h (:,:, time_index)) + used = send_data(id_eq_geopot , eq_geopot, time) + +endif + + +if (id_e_kin_real_units > 0) then + + if (eq_geopot == 0.) eq_geopot = area_weighted_global_mean(Grid%h (:,:, time_index)) + + e_kin_real_units = 0.5*(area_weighted_global_mean(Grid%h (:,:, time_index)*(Grid%u (:,:, time_index)**2)) + area_weighted_global_mean(Grid%h (:,:, time_index)*(Grid%v (:,:, time_index)**2))) / eq_geopot + + used = send_data(id_e_kin_real_units , e_kin_real_units, time) + +endif + +if (id_e_pot_real_units > 0) then + + if (eq_geopot == 0.) eq_geopot = area_weighted_global_mean(Grid%h (:,:, time_index)) + + e_pot_real_units = 0.5*(area_weighted_global_mean(Grid%h (:,:, time_index)**2.)) / eq_geopot + + used = send_data(id_e_pot_real_units , e_pot_real_units, time) + +endif + +if (id_e_tot_real_units > 0) then + + if (eq_geopot == 0.) eq_geopot = area_weighted_global_mean(Grid%h (:,:, time_index)) + + if (e_kin_real_units == 0.) then + e_kin_real_units = 0.5*(area_weighted_global_mean(Grid%h (:,:, time_index)*(Grid%u (:,:, time_index)**2)) + area_weighted_global_mean(Grid%h (:,:, time_index)*(Grid%v (:,:, time_index)**2))) / eq_geopot + endif + + if (e_pot_real_units == 0.) then + e_pot_real_units = 0.5*(area_weighted_global_mean(Grid%h (:,:, time_index)**2.)) / eq_geopot + endif + + e_tot_real_units = e_kin_real_units + e_pot_real_units + + used = send_data(id_e_tot_real_units , e_tot_real_units, time) + +endif + +if (id_u_rms > 0) then + + used = send_data(id_u_rms , (area_weighted_global_mean(Grid%u (:,:, time_index)**2) + area_weighted_global_mean(Grid%v (:,:, time_index)**2))**0.5, time) + +endif + return end subroutine shallow_diagnostics !-------------------------------------------------------------------------------------------- diff --git a/src/atmos_spectral_shallow/shallow_dynamics.F90 b/src/atmos_spectral_shallow/shallow_dynamics.F90 index 8953ca662..67ce5b3e8 100644 --- a/src/atmos_spectral_shallow/shallow_dynamics.F90 +++ b/src/atmos_spectral_shallow/shallow_dynamics.F90 @@ -135,6 +135,7 @@ module shallow_dynamics_mod real :: u_deep_mag = 0. real :: n_merid_deep_flow = 3. +real :: u_upper_mag_init = 0. logical :: spec_tracer = .true. logical :: grid_tracer = .true. @@ -151,7 +152,8 @@ module shallow_dynamics_mod h_0, spec_tracer, grid_tracer, & valid_range_v, cutoff_wn, & raw_filter_coeff, & - u_deep_mag, n_merid_deep_flow + u_deep_mag, n_merid_deep_flow, & + u_upper_mag_init contains @@ -264,7 +266,10 @@ subroutine shallow_dynamics_init (Dyn, Time, Time_init, dt_real) if(Time == Time_init) then - Dyn%Grid%vor(:,:,1) = 0.0 + do i = is, ie + Dyn%Grid%vor(i,js:je,1) = -((u_upper_mag_init * n_merid_deep_flow)/radius) * sin(DEG_to_RAD * deg_lat(js:je)) + enddo + Dyn%Grid%div(:,:,1) = 0.0 Dyn%Grid%h (:,:,1) = h_0 - Dyn%grid%deep_geopot(:,:) From c1a3f2af8c6d75cb92a2fd7277a62ae34e94a5fe Mon Sep 17 00:00:00 2001 From: sit23 Date: Sat, 29 Jun 2019 22:21:21 +0100 Subject: [PATCH 17/24] Updated experiments. --- ...w_water_deep_velocity_test_mk1_high_res.py | 175 ++++++++++++++++++ ...w_water_deep_velocity_test_mk1_high_res.py | 175 ++++++++++++++++++ 2 files changed, 350 insertions(+) create mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py create mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/part_2/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py new file mode 100644 index 000000000..5772107da --- /dev/null +++ b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py @@ -0,0 +1,175 @@ +import os + +import numpy as np + +from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE + +import pdb + +NCORES = 32 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = ShallowCodeBase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') +# diag.add_file('atmos_daily', 1, 'days', time_units='days') + +#Tell model which diagnostics to write +diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'div', time_avg=True) +diag.add_field('shallow_diagnostics', 'h', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv_corrected', time_avg=True) +diag.add_field('shallow_diagnostics', 'stream', time_avg=True) +diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) +# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) +# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) +diag.add_field('stirring_mod', 'stirring', time_avg=True) +# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) +diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) +diag.add_field('shallow_diagnostics', 'h_sqd_mean', time_avg=True) + +diag.add_field('shallow_diagnostics', 'e_kin_density', time_avg=True) +diag.add_field('shallow_diagnostics', 'eq_geopot', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_kin_real_units', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_pot_real_units', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_tot_real_units', time_avg=True) +diag.add_field('shallow_diagnostics', 'u_rms', time_avg=True) + +#Empty the run directory ready to run + +#Define values for the 'core' namelist +namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 600, + 'calendar': 'no_calendar', + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml':{ + 'print_memory_usage':False, + 'domains_stack_size': 200000, + }, + + 'shallow_dynamics_nml':{ + 'num_lon' : 1024, + 'num_lat' : 512, + 'num_fourier' : 341, + 'num_spherical' : 342, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 4, + 'damping_coeff' : 1.e-04, + 'h_0' : 3.e04, + 'grid_tracer' : False, + 'spec_tracer' : False, + 'robert_coeff' : 0.04, + 'robert_coeff_tracer' : 0.04, + }, + + 'shallow_physics_nml':{ + 'fric_damp_time' : 0.0, + 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. + 'h_amp' : 0., + 'h_itcz' : 0., + }, + + 'stirring_nml': { + 'B':0.0, + 'do_localize': False, + }, + +}) + +#Lets do a run! +if __name__=="__main__": + + for forcing_amplitude in [7.5, 5., 10.]: + + for damping_time in [ 10000., 1000., 100000.]: + u_deep_mag_val = 50. + + if u_deep_mag_val!=0.: + u_deep_merid_arr = [27] + else: + u_deep_merid_arr = [3] + + for u_deep_merid in u_deep_merid_arr: + + ld_value = 0.025 + exp = Experiment('high_res_small_forcing_giant_planet_fixed_deep_ics_forced_'+str(damping_time)+'_rad_damping_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid))+'_strong_forcing_'+str(forcing_amplitude), codebase=cb) + + exp.diag_table = diag + exp.namelist = namelist + exp.clear_rundir() + + rotation_period = ((9.*3600.)+55.*60 + 30.) + omega = 2.*np.pi/ rotation_period + radius = 69911e3 + grav = 24.79 + number_ld_in_radius_units = ld_value + + # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. + + equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. + equilibrium_depth = equilibrium_geopotential/grav + + exp.update_namelist({ + 'shallow_dynamics_nml':{ + 'h_0': equilibrium_geopotential, + 'u_deep_mag' : u_deep_mag_val, + 'n_merid_deep_flow': u_deep_merid, + }, + 'shallow_physics_nml': { + 'h_0': equilibrium_geopotential, + 'therm_damp_time' : rotation_period * damping_time, #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) + }, + 'constants_nml': { + 'omega': omega, + 'radius': radius, + }, + 'stirring_nml': { + 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. + 'amplitude':3.e-13*forcing_amplitude, + 'n_total_forcing_max': 170, + 'n_total_forcing_min': 164, + + }, + + }) + + exp.run(1, use_restart=False, num_cores=NCORES, multi_node=True) + for i in range(2,721): + exp.run(i, num_cores=NCORES, multi_node=True) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/part_2/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/part_2/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py new file mode 100644 index 000000000..2c6a8f028 --- /dev/null +++ b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/part_2/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py @@ -0,0 +1,175 @@ +import os + +import numpy as np + +from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE + +import pdb + +NCORES = 32 +base_dir = os.path.dirname(os.path.realpath(__file__)) +# a CodeBase can be a directory on the computer, +# useful for iterative development +cb = ShallowCodeBase.from_directory(GFDL_BASE) + +# or it can point to a specific git repo and commit id. +# This method should ensure future, independent, reproducibility of results. +# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') + +# compilation depends on computer specific settings. The $GFDL_ENV +# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file +# is used to load the correct compilers. The env file is always loaded from +# $GFDL_BASE and not the checked out git repo. + +cb.compile() # compile the source code to working directory $GFDL_WORK/codebase + +# create an Experiment object to handle the configuration of model parameters +# and output diagnostics + +#Tell model how to write diagnostics +diag = DiagTable() +diag.add_file('atmos_monthly', 30, 'days', time_units='days') +# diag.add_file('atmos_daily', 1, 'days', time_units='days') + +#Tell model which diagnostics to write +diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) +diag.add_field('shallow_diagnostics', 'vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'div', time_avg=True) +diag.add_field('shallow_diagnostics', 'h', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv', time_avg=True) +diag.add_field('shallow_diagnostics', 'pv_corrected', time_avg=True) +diag.add_field('shallow_diagnostics', 'stream', time_avg=True) +diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) +# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) +# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) +diag.add_field('stirring_mod', 'stirring', time_avg=True) +# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) +diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) +diag.add_field('shallow_diagnostics', 'h_sqd_mean', time_avg=True) + +diag.add_field('shallow_diagnostics', 'e_kin_density', time_avg=True) +diag.add_field('shallow_diagnostics', 'eq_geopot', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_kin_real_units', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_pot_real_units', time_avg=True) +diag.add_field('shallow_diagnostics', 'e_tot_real_units', time_avg=True) +diag.add_field('shallow_diagnostics', 'u_rms', time_avg=True) + +#Empty the run directory ready to run + +#Define values for the 'core' namelist +namelist = Namelist({ + 'main_nml':{ + 'days' : 30, + 'hours' : 0, + 'minutes': 0, + 'seconds': 0, + 'dt_atmos': 600, + 'calendar': 'no_calendar', + }, + + 'atmosphere_nml':{ + 'print_interval': 86400, + }, + +'fms_io_nml':{ + 'threading_write' :'single', + 'fileset_write': 'single' + }, + + 'fms_nml':{ + 'print_memory_usage':False, + 'domains_stack_size': 200000, + }, + + 'shallow_dynamics_nml':{ + 'num_lon' : 1024, + 'num_lat' : 512, + 'num_fourier' : 341, + 'num_spherical' : 342, + 'fourier_inc' : 1, + 'damping_option' : 'resolution_dependent', + 'damping_order' : 4, + 'damping_coeff' : 1.e-04, + 'h_0' : 3.e04, + 'grid_tracer' : False, + 'spec_tracer' : False, + 'robert_coeff' : 0.04, + 'robert_coeff_tracer' : 0.04, + }, + + 'shallow_physics_nml':{ + 'fric_damp_time' : 0.0, + 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. + 'h_amp' : 0., + 'h_itcz' : 0., + }, + + 'stirring_nml': { + 'B':0.0, + 'do_localize': False, + }, + +}) + +#Lets do a run! +if __name__=="__main__": + + for forcing_amplitude in [ 10.]: + + for damping_time in [ 10000., 1000., 100000.]: + u_deep_mag_val = 50. + + if u_deep_mag_val!=0.: + u_deep_merid_arr = [27] + else: + u_deep_merid_arr = [3] + + for u_deep_merid in u_deep_merid_arr: + + ld_value = 0.025 + exp = Experiment('high_res_small_forcing_giant_planet_fixed_deep_ics_forced_'+str(damping_time)+'_rad_damping_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid))+'_strong_forcing_'+str(forcing_amplitude), codebase=cb) + + exp.diag_table = diag + exp.namelist = namelist + exp.clear_rundir() + + rotation_period = ((9.*3600.)+55.*60 + 30.) + omega = 2.*np.pi/ rotation_period + radius = 69911e3 + grav = 24.79 + number_ld_in_radius_units = ld_value + + # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. + + equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. + equilibrium_depth = equilibrium_geopotential/grav + + exp.update_namelist({ + 'shallow_dynamics_nml':{ + 'h_0': equilibrium_geopotential, + 'u_deep_mag' : u_deep_mag_val, + 'n_merid_deep_flow': u_deep_merid, + }, + 'shallow_physics_nml': { + 'h_0': equilibrium_geopotential, + 'therm_damp_time' : rotation_period * damping_time, #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) + }, + 'constants_nml': { + 'omega': omega, + 'radius': radius, + }, + 'stirring_nml': { + 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. + 'amplitude':3.e-13*forcing_amplitude, + 'n_total_forcing_max': 170, + 'n_total_forcing_min': 164, + + }, + + }) + + exp.run(1, use_restart=False, num_cores=NCORES, multi_node=True) + for i in range(2,721): + exp.run(i, num_cores=NCORES, multi_node=True) From 4e46f2ce6011e952f4eb441b41040964822ea94e Mon Sep 17 00:00:00 2001 From: sit23 Date: Tue, 2 Jul 2019 14:43:47 +0100 Subject: [PATCH 18/24] Ignorning supercomputer log files. --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 89b27824a..a414eda46 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,6 @@ src/extra/python/scripts/*.nc src/extra/python/scripts/archived/ mima_pz.txt test/.cache -test/results.xml \ No newline at end of file +test/results.xml +*.sh.e* +*.sh.o* From f1cc51d60631154c87ee718be4d0f4dd6c2668d3 Mon Sep 17 00:00:00 2001 From: sit23 Date: Tue, 2 Jul 2019 14:54:52 +0100 Subject: [PATCH 19/24] Adding diagnostics for momentum budget. --- src/atmos_spectral_shallow/shallow_diagnostics.F90 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/atmos_spectral_shallow/shallow_diagnostics.F90 b/src/atmos_spectral_shallow/shallow_diagnostics.F90 index 7a8cbed09..3ea5dc0a8 100644 --- a/src/atmos_spectral_shallow/shallow_diagnostics.F90 +++ b/src/atmos_spectral_shallow/shallow_diagnostics.F90 @@ -56,7 +56,7 @@ module shallow_diagnostics_mod logical :: module_is_initialized = .false. -integer :: id_vor, id_stream, id_pv, id_u, id_v, id_div, id_h, id_trs, id_tr, id_d_geopot, id_u_sqd, id_v_sqd, id_h_sqd, id_u_sqd_mean, id_v_sqd_mean, id_h_sqd_mean, id_ekin, id_ekin_density, id_eq_geopot, id_e_kin_real_units, id_e_pot_real_units, id_e_tot_real_units, id_u_rms +integer :: id_vor, id_stream, id_pv, id_u, id_v, id_div, id_h, id_trs, id_tr, id_d_geopot, id_u_sqd, id_v_sqd, id_h_sqd, id_u_sqd_mean, id_v_sqd_mean, id_h_sqd_mean, id_ekin, id_ekin_density, id_eq_geopot, id_e_kin_real_units, id_e_pot_real_units, id_e_tot_real_units, id_u_rms, id_vcomp_vor, id_ucomp_vcomp integer :: is, ie, js, je @@ -127,6 +127,10 @@ subroutine shallow_diagnostics_init(Time, lon_max, lat_max, id_lon, id_lat, id_l id_u_rms = register_diag_field(mod_name, 'u_rms' , Time, 'r_rms' , 'm/s' ) +id_vcomp_vor = register_diag_field(mod_name, 'vcomp_vor' , axis_2d, Time, 'vcomp * relative vorticity' , 'm/s^2' ) + +id_ucomp_vcomp = register_diag_field(mod_name, 'ucomp_vcomp' , axis_2d, Time, 'ucomp * vcomp' , 'm^2/s^2' ) + module_is_initialized = .true. return @@ -244,6 +248,10 @@ subroutine shallow_diagnostics(Time, Grid, Phys, time_index) endif + +if(id_vcomp_vor > 0) used = send_data(id_vcomp_vor , Grid%v (:,:, time_index) * Grid%vor (:,:, time_index) , time) +if(id_ucomp_vcomp > 0) used = send_data(id_ucomp_vcomp , Grid%u (:,:, time_index) * Grid%v (:,:, time_index) , time) + return end subroutine shallow_diagnostics !-------------------------------------------------------------------------------------------- From ee7394d7b9283eb141742b05e07a0f3b48752740 Mon Sep 17 00:00:00 2001 From: sit23 Date: Thu, 18 Jul 2019 15:06:45 +0100 Subject: [PATCH 20/24] Added daily output for more useful diagnostics. --- ...t_planet_shallow_water_deep_velocity_test_mk1_high_res.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py index 5772107da..b512fec67 100644 --- a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py +++ b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py @@ -29,7 +29,7 @@ #Tell model how to write diagnostics diag = DiagTable() diag.add_file('atmos_monthly', 30, 'days', time_units='days') -# diag.add_file('atmos_daily', 1, 'days', time_units='days') +#diag.add_file('atmos_daily', 1, 'days', time_units='days') #Tell model which diagnostics to write diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) @@ -41,6 +41,9 @@ diag.add_field('shallow_diagnostics', 'pv_corrected', time_avg=True) diag.add_field('shallow_diagnostics', 'stream', time_avg=True) diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp_vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'ucomp_vcomp', time_avg=True) + # diag.add_field('shallow_diagnostics', 'trs', time_avg=True) # diag.add_field('shallow_diagnostics', 'tr', time_avg=True) diag.add_field('stirring_mod', 'stirring', time_avg=True) From bee23e085fe10c0fa4ae494563069410b3af592a Mon Sep 17 00:00:00 2001 From: sit23 Date: Thu, 18 Jul 2019 15:09:17 +0100 Subject: [PATCH 21/24] Adding momentum budget analysis outputs. --- .../giant_planet_shallow_water_deep_velocity_test_mk1.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py index fe65deba8..40c853e40 100644 --- a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py +++ b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py @@ -41,6 +41,9 @@ diag.add_field('shallow_diagnostics', 'pv_corrected', time_avg=True) diag.add_field('shallow_diagnostics', 'stream', time_avg=True) diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) +diag.add_field('shallow_diagnostics', 'vcomp_vor', time_avg=True) +diag.add_field('shallow_diagnostics', 'ucomp_vcomp', time_avg=True) + # diag.add_field('shallow_diagnostics', 'trs', time_avg=True) # diag.add_field('shallow_diagnostics', 'tr', time_avg=True) diag.add_field('stirring_mod', 'stirring', time_avg=True) @@ -124,7 +127,7 @@ for u_deep_mag_val in [50.]: if u_deep_mag_val!=0.: - u_deep_merid_arr = [27] + u_deep_merid_arr = [23] # u_deep_merid_arr = [5,7,9] else: @@ -175,5 +178,5 @@ }) exp.run(1, use_restart=False, num_cores=NCORES) - for i in range(2,361): + for i in range(2,481): exp.run(i, num_cores=NCORES) From cbca8c77abe3adb65ce09ff479a1b93b6e8eb5a3 Mon Sep 17 00:00:00 2001 From: sit23 Date: Fri, 7 Feb 2020 09:11:16 +0000 Subject: [PATCH 22/24] parameter updates. --- ..._planet_shallow_water_deep_velocity_test_mk1_high_res.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py index b512fec67..c7af1d59c 100644 --- a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py +++ b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py @@ -119,9 +119,9 @@ #Lets do a run! if __name__=="__main__": - for forcing_amplitude in [7.5, 5., 10.]: + for forcing_amplitude in [7.5]: - for damping_time in [ 10000., 1000., 100000.]: + for damping_time in [ 100000.]: u_deep_mag_val = 50. if u_deep_mag_val!=0.: @@ -174,5 +174,5 @@ }) exp.run(1, use_restart=False, num_cores=NCORES, multi_node=True) - for i in range(2,721): + for i in range(721,841): exp.run(i, num_cores=NCORES, multi_node=True) From bb15cef1f0443c852a0cccec72e230e434ec6460 Mon Sep 17 00:00:00 2001 From: sit23 Date: Thu, 19 Mar 2020 08:49:02 +0000 Subject: [PATCH 23/24] Update shallow code to include vortex migration experiments. --- .../scripts/run_plevel.py | 17 +-- .../shallow_dynamics.F90 | 65 +++++++++- .../remove_certain_restart_and_data_files.py | 111 ++++++++++-------- 3 files changed, 130 insertions(+), 63 deletions(-) diff --git a/postprocessing/plevel_interpolation/scripts/run_plevel.py b/postprocessing/plevel_interpolation/scripts/run_plevel.py index 294ecb53a..6b6b9bfe7 100644 --- a/postprocessing/plevel_interpolation/scripts/run_plevel.py +++ b/postprocessing/plevel_interpolation/scripts/run_plevel.py @@ -7,11 +7,12 @@ import subprocess start_time=time.time() -base_dir='/scratch/sit204/Data_2013/' -exp_name_list = ['no_ice_flux_lhe_exps_q_flux_hadgem_anoms_3'] +base_dir='/disca/share/sit204/data_from_isca_cpu/cssp_perturb_exps/anoms/' +#exp_name_list = ['soc_ga3_files_smooth_topo_fftw_mk1_fresh_compile_long', 'soc_ga3_files_smooth_topo_old_fft_mk2_long'] +exp_name_list = [f'soc_ga3_do_simple_false_cmip_o3_bucket_perturbed_ens_{f}' for f in range(100, 200)] avg_or_daily_list=['monthly'] -start_file=287 -end_file=288 +start_file=1 +end_file=1 nfiles=(end_file-start_file)+1 do_extra_averaging=False #If true, then 6hourly data is averaged into daily data using cdo @@ -44,7 +45,7 @@ var_names['timestep']='-a' var_names['6hourly']='ucomp slp height vor t_surf vcomp omega' var_names['daily']='ucomp slp height vor t_surf vcomp omega temp' - file_suffix='_interp_new_height_temp' + file_suffix='_interp_new_height_temp_not_below_ground' elif level_set=='ssw_diagnostics': plevs['6hourly']=' -p "1000 10000"' @@ -66,10 +67,12 @@ number_prefix='' - if n+start_file < 100: + if n+start_file < 1000: number_prefix='0' - if n+start_file < 10: + if n+start_file < 100: number_prefix='00' + if n+start_file < 10: + number_prefix = '000' nc_file_in = base_dir+'/'+exp_name+'/run'+number_prefix+str(n+start_file)+'/atmos_'+avg_or_daily+'.nc' nc_file_out = out_dir+'/'+exp_name+'/run'+number_prefix+str(n+start_file)+'/atmos_'+avg_or_daily+file_suffix+'.nc' diff --git a/src/atmos_spectral_shallow/shallow_dynamics.F90 b/src/atmos_spectral_shallow/shallow_dynamics.F90 index 67ce5b3e8..7ba1ec3f8 100644 --- a/src/atmos_spectral_shallow/shallow_dynamics.F90 +++ b/src/atmos_spectral_shallow/shallow_dynamics.F90 @@ -140,6 +140,18 @@ module shallow_dynamics_mod logical :: spec_tracer = .true. logical :: grid_tracer = .true. +!Options for injecting an initial vortex pair +real :: lon_centre_init_cyc = 0. +real :: lat_centre_init_cyc = 60. +real :: lon_centre_init_acyc = 180. +real :: lat_centre_init_acyc = 60. +real :: init_vortex_radius_deg = 5. +real :: init_vortex_vor_f = 0.5 +real :: init_vortex_h_h_0 = 0.1 +logical :: add_initial_vortex_pair = .false. +logical :: add_initial_vortex_as_height = .true. + + real, dimension(2) :: valid_range_v = (/-1.e3,1.e3/) namelist /shallow_dynamics_nml/ check_fourier_imag, & @@ -153,7 +165,17 @@ module shallow_dynamics_mod valid_range_v, cutoff_wn, & raw_filter_coeff, & u_deep_mag, n_merid_deep_flow, & - u_upper_mag_init + u_upper_mag_init, & + lon_centre_init_cyc, & + lat_centre_init_cyc, & + lon_centre_init_acyc, & + lat_centre_init_acyc, & + init_vortex_radius_deg, & + init_vortex_vor_f, & + init_vortex_h_h_0, & + add_initial_vortex_pair, & + add_initial_vortex_as_height + contains @@ -168,7 +190,7 @@ subroutine shallow_dynamics_init (Dyn, Time, Time_init, dt_real) integer :: i, j real, allocatable, dimension(:) :: glon_bnd, glat_bnd -real :: xx, yy, dd, deep_geopot_global_mean +real :: xx, yy, dd, deep_geopot_global_mean, radius_loc_cyc, radius_loc_acyc integer :: ierr, io, unit, id_lon, id_lat, id_lonb, id_latb logical :: root @@ -266,12 +288,45 @@ subroutine shallow_dynamics_init (Dyn, Time, Time_init, dt_real) if(Time == Time_init) then + Dyn%Grid%div(:,:,1) = 0.0 + Dyn%Grid%h (:,:,1) = h_0 - Dyn%grid%deep_geopot(:,:) + do i = is, ie Dyn%Grid%vor(i,js:je,1) = -((u_upper_mag_init * n_merid_deep_flow)/radius) * sin(DEG_to_RAD * deg_lat(js:je)) - enddo - Dyn%Grid%div(:,:,1) = 0.0 - Dyn%Grid%h (:,:,1) = h_0 - Dyn%grid%deep_geopot(:,:) + if (add_initial_vortex_pair) then + + do j=js, je + + radius_loc_cyc = ((min((deg_lon(i)-lon_centre_init_cyc)**2., (deg_lon(i)-lon_centre_init_cyc-360.)**2.)+(deg_lat(j)-lat_centre_init_cyc)**2.)**0.5)/init_vortex_radius_deg + radius_loc_acyc = ((min((deg_lon(i)-lon_centre_init_acyc)**2., (deg_lon(i)-lon_centre_init_acyc-360.)**2.)+(deg_lat(j)-lat_centre_init_acyc)**2.)**0.5)/init_vortex_radius_deg + + + if(radius_loc_cyc.le.1.0 .and. radius_loc_acyc.le.1.0) then + call error_mesg('shallow_dynamics','Cannot initialise cyclone and anticyclone in same grid box ', FATAL) + endif + + if(add_initial_vortex_as_height) then + if (radius_loc_cyc.le.2.0) then + Dyn%Grid%h(i,j,1) = Dyn%Grid%h(i,j,1) + init_vortex_h_h_0 * -h_0 * exp(-radius_loc_cyc**2.) + elseif (radius_loc_acyc.le.2.0) then + Dyn%Grid%h(i,j,1) = Dyn%Grid%h(i,j,1) + init_vortex_h_h_0 * h_0 * exp(-radius_loc_acyc**2.) + endif + else + if (radius_loc_cyc.le.1.0) then + Dyn%Grid%vor(i,j,1) = init_vortex_vor_f * 2.*omega + elseif (radius_loc_acyc.le.1.0) then + Dyn%Grid%vor(i,j,1) = init_vortex_vor_f * -2.*omega + endif + + endif + + enddo + + + endif + + enddo call trans_grid_to_spherical(Dyn%Grid%vor(:,:,1), Dyn%Spec%vor(:,:,1)) call trans_grid_to_spherical(Dyn%Grid%div(:,:,1), Dyn%Spec%div(:,:,1)) diff --git a/src/extra/python/scripts/remove_certain_restart_and_data_files.py b/src/extra/python/scripts/remove_certain_restart_and_data_files.py index 98d658a95..582a05c9c 100644 --- a/src/extra/python/scripts/remove_certain_restart_and_data_files.py +++ b/src/extra/python/scripts/remove_certain_restart_and_data_files.py @@ -1,6 +1,7 @@ import sh import os import pdb +from glob import glob P = os.path.join @@ -12,11 +13,15 @@ def __init__(self, basedir, workdir, datadir, exp_name): self.expname = exp_name -def create_exp_object(exp_name): +def create_exp_object(exp_name, data_directory=None): + + if data_directory is None: + datadir = os.environ['GFDL_DATA'] + else: + datadir = data_directory - basedir = os.environ['GFDL_BASE'] workdir = os.environ['GFDL_WORK'] - datadir = os.environ['GFDL_DATA'] + basedir = os.environ['GFDL_BASE'] expname = '/'+exp_name+'/' exp_object = temporary_exp_object(basedir, workdir, datadir, exp_name) @@ -24,34 +29,42 @@ def create_exp_object(exp_name): return exp_object -def keep_only_certain_restart_files(exp_object, max_num_files, interval=12): +# def keep_only_certain_restart_files(exp_object, max_num_files, interval=12): - # sh.ls(sh.glob(P(self.workdir,'restarts','res_*.cpio'))) #TODO get max_num_files calculated in line, rather than a variable to pass. +# # sh.ls(sh.glob(P(self.workdir,'restarts','res_*.cpio'))) #TODO get max_num_files calculated in line, rather than a variable to pass. - #First defines a list of ALL the restart file numbers - files_to_remove=list(range(0,max_num_files)) +# #First defines a list of ALL the restart file numbers +# files_to_remove=list(range(0,max_num_files)) - #Then defines a list of the ones we want to KEEP - files_to_keep =list(range(0,max_num_files,interval)) +# #Then defines a list of the ones we want to KEEP +# files_to_keep =list(range(0,max_num_files,interval)) - #Then we remove the files we want to keep from the list of all files, giving a list of those we wish to remove - for x in files_to_keep: - files_to_remove.remove(x) +# #Then we remove the files we want to keep from the list of all files, giving a list of those we wish to remove +# for x in files_to_keep: +# files_to_remove.remove(x) - #Then we remove them. - for entry in files_to_remove: - try: - sh.rm(P(exp_object.workdir,exp_object.expname,'restarts','res_'+str(entry)+'.cpio')) -# print P(exp_object.workdir,exp_object.expname,'restarts','res_'+str(entry)+'.cpio') +# #Then we remove them. +# for entry in files_to_remove: +# try: +# sh.rm(P(exp_object.workdir,exp_object.expname,'restarts','res_'+str(entry)+'.cpio')) +# # print P(exp_object.workdir,exp_object.expname,'restarts','res_'+str(entry)+'.cpio') - except sh.ErrorReturnCode_1: - pass -# print 'Tried to remove some restart files, but number '+str(entry)+' does not exist' +# except sh.ErrorReturnCode_1: +# pass +# # print 'Tried to remove some restart files, but number '+str(entry)+' does not exist' -def keep_only_certain_restart_files_data_dir(exp_object, max_num_files, interval=12): +def keep_only_certain_restart_files_data_dir(exp_object, max_num_files=None, interval=12): # sh.ls(sh.glob(P(self.workdir,'restarts','res_*.cpio'))) #TODO get max_num_files calculated in line, rather than a variable to pass. + if max_num_files is None: + month_list = glob(P(exp_object.datadir,exp_object.expname, 'restarts')+'/res*.tar.gz') + if len(month_list)==0: + return + else: + final_month = month_list[-1].split('/res') + max_num_files = int(final_month[-1].split('.tar.gz')[0]) + #First defines a list of ALL the restart file numbers files_to_remove=list(range(0,max_num_files)) @@ -62,13 +75,27 @@ def keep_only_certain_restart_files_data_dir(exp_object, max_num_files, interval for x in files_to_keep: files_to_remove.remove(x) + first_to_be_removed = True + number_removed = 0 + number_not_removed = 0 #Then we remove them. - for entry in files_to_remove: + for entry in files_to_remove[1:-1]: try: - sh.rm(P(exp_object.datadir,exp_object.expname,'run%03d' % entry,'INPUT','res')) -# print 'would be removing ' + P(exp_object.datadir,exp_object.expname,'run'+str(entry),'INPUT','res') + file_to_remove = P(exp_object.datadir,exp_object.expname, 'restarts', 'res%04d.tar.gz' % entry) + if os.path.isfile(file_to_remove) and first_to_be_removed: + first_to_be_removed=False + number_not_removed+=1 + # print('would have removed '+file_to_remove+' but wanted to make sure not to delete the first restart') + else: + sh.rm(file_to_remove) + number_removed+=1 + # print('have removed ' + file_to_remove) except sh.ErrorReturnCode_1: + number_not_removed+=1 + # print('could not remove ' + file_to_remove) pass + print(P(exp_object.datadir,exp_object.expname), 'number removed '+str(number_removed), 'number not removed '+str(number_not_removed)) + # print 'Tried to remove some restart files, but number '+str(entry)+' does not exist' def keep_only_certain_daily_data_uninterp(exp_object, max_num_files, interval=None, file_name = 'atmos_daily.nc'): @@ -88,8 +115,8 @@ def keep_only_certain_daily_data_uninterp(exp_object, max_num_files, interval=No #Then we remove them. for entry in files_to_remove: try: - sh.rm(P(exp_object.datadir,exp_object.expname,'run%03d' % entry,file_name)) - print(('Removed '+P(exp_object.datadir,exp_object.expname,'run%03d' % entry,file_name))) + sh.rm(P(exp_object.datadir,exp_object.expname,'run%04d' % entry,file_name)) + print(('Removed '+P(exp_object.datadir,exp_object.expname,'run%04d' % entry,file_name))) except sh.ErrorReturnCode_1: pass # print 'Tried to remove some atmos_daily files, but number '+str(entry)+' does not exist' @@ -98,36 +125,18 @@ def keep_only_certain_daily_data_uninterp(exp_object, max_num_files, interval=No if __name__=="__main__": - max_num_files_input = 325 + max_num_files_input = None -# exp_name_list=['simple_continents_post_princeton_qflux_anoms_'+str(x) for x in range(31,32)] - -# exp_name_list=['aquaplanet_qflux_anoms_'+str(x) for x in [12,18,23,32,8]] - -# exp_name_list = ['simple_continents_post_princeton_qflux_control_1','simple_continents_post_princeton_fixed_sst_1', 'simple_continents_post_princeton_qflux_control_nod_1', 'simple_continents_post_princeton_qflux_control_scf_1'] -# -# exp_name_list = ['annual_mean_ice_princeton_qflux_control_matrix_qflux_2017_code_1', 'annual_mean_ice_post_princeton_fixed_sst_1', 'annual_mean_ice_princeton_fixed_sst_1'] -# -# exp_name_list.extend(['annual_mean_ice_post_princeton_fixed_sst_el_nino_1']) - -# exp_name_list = ['simple_continents_post_princeton_qflux_control_1'] - -# exp_name_list = ['annual_mean_ice_princeton_qflux_control_1']#, 'annual_mean_ice_post_princeton_qflux_control_1'] - -# exp_name_list = ['annual_mean_ice_post_princeton_fixed_sst_TEST_1', 'annual_mean_ice_princeton_qflux_control_matrix_qflux_1'] - -# exp_name_list.extend(['simple_continents_post_princeton_fixed_sst_1']) - -# exp_name_list = ['giant_drag_exp_chai_values_without_dc_bug_latest_1'] -# exp_name_list = ['aquaplanet_qflux_control_1'] + # exp_name_list = [''] + exp_name_list = glob('/disca/share/sit204/data_isca_from_gv5/frierson_post_soc_fix_*/') - exp_name_list = ['giant_drag_exp_chai_values_with_dc_bug_latest_start_to_finish_1', 'giant_drag_exp_chai_values_without_dc_bug_latest_start_to_finish_1'] for exp_name_input in exp_name_list: - temp_obj = create_exp_object(exp_name_input) - keep_only_certain_restart_files(temp_obj, max_num_files_input) + print('Percentage progress through list:'+str(exp_name_list.index(exp_name_input)/len(exp_name_list))) + temp_obj = create_exp_object(exp_name_input, data_directory='/disca/share/sit204/data_from_isca_cpu/') + # keep_only_certain_restart_files(temp_obj, max_num_files_input) keep_only_certain_restart_files_data_dir(temp_obj, max_num_files_input) - keep_only_certain_daily_data_uninterp(temp_obj, max_num_files_input, file_name = 'fms_moist.x') + # keep_only_certain_daily_data_uninterp(temp_obj, max_num_files_input, file_name = 'fms_moist.x') # keep_only_certain_daily_data_uninterp(temp_obj, max_num_files_input) \ No newline at end of file From d706b3407f103732c818c010f4abf447c6614efc Mon Sep 17 00:00:00 2001 From: sit23 Date: Thu, 10 Dec 2020 17:53:17 +0000 Subject: [PATCH 24/24] Removing unecessary experiment files. --- ...et_shallow_water_deep_velocity_test_mk1.py | 182 ------------------ ...ter_deep_velocity_test_mk1_vary_damping.py | 169 ---------------- ...w_water_deep_velocity_test_mk1_high_res.py | 178 ----------------- ...w_water_deep_velocity_test_mk1_high_res.py | 175 ----------------- ...et_shallow_water_deep_velocity_test_mk1.py | 167 ---------------- ...et_shallow_water_deep_velocity_test_mk2.py | 170 ---------------- ...shallow_water_small_scale_stirring_test.py | 151 --------------- ...iant_planet_shallow_water_stirring_test.py | 148 -------------- 8 files changed, 1340 deletions(-) delete mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py delete mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1_vary_damping.py delete mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py delete mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/part_2/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py delete mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk1.py delete mode 100644 exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk2.py delete mode 100644 exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py delete mode 100644 exp/shallow_water_giant_planet/giant_planet_shallow_water_stirring_test.py diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py deleted file mode 100644 index 40c853e40..000000000 --- a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1.py +++ /dev/null @@ -1,182 +0,0 @@ -import os - -import numpy as np - -from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE - -import pdb - -NCORES = 16 -base_dir = os.path.dirname(os.path.realpath(__file__)) -# a CodeBase can be a directory on the computer, -# useful for iterative development -cb = ShallowCodeBase.from_directory(GFDL_BASE) - -# or it can point to a specific git repo and commit id. -# This method should ensure future, independent, reproducibility of results. -# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') - -# compilation depends on computer specific settings. The $GFDL_ENV -# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file -# is used to load the correct compilers. The env file is always loaded from -# $GFDL_BASE and not the checked out git repo. - -cb.compile() # compile the source code to working directory $GFDL_WORK/codebase - -# create an Experiment object to handle the configuration of model parameters -# and output diagnostics - -#Tell model how to write diagnostics -diag = DiagTable() -diag.add_file('atmos_monthly', 30, 'days', time_units='days') -# diag.add_file('atmos_daily', 1, 'days', time_units='days') - -#Tell model which diagnostics to write -diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vor', time_avg=True) -diag.add_field('shallow_diagnostics', 'div', time_avg=True) -diag.add_field('shallow_diagnostics', 'h', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv_corrected', time_avg=True) -diag.add_field('shallow_diagnostics', 'stream', time_avg=True) -diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) -diag.add_field('shallow_diagnostics', 'vcomp_vor', time_avg=True) -diag.add_field('shallow_diagnostics', 'ucomp_vcomp', time_avg=True) - -# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) -# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) -diag.add_field('stirring_mod', 'stirring', time_avg=True) -# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) -diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) -diag.add_field('shallow_diagnostics', 'h_sqd_mean', time_avg=True) - -diag.add_field('shallow_diagnostics', 'e_kin_density', time_avg=True) -diag.add_field('shallow_diagnostics', 'eq_geopot', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_kin_real_units', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_pot_real_units', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_tot_real_units', time_avg=True) -diag.add_field('shallow_diagnostics', 'u_rms', time_avg=True) - - -#Empty the run directory ready to run - -#Define values for the 'core' namelist -namelist = Namelist({ - 'main_nml':{ - 'days' : 30, - 'hours' : 0, - 'minutes': 0, - 'seconds': 0, - 'dt_atmos': 1200, - 'calendar': 'no_calendar', - }, - - 'atmosphere_nml':{ - 'print_interval': 86400, - }, - -'fms_io_nml':{ - 'threading_write' :'single', - 'fileset_write': 'single' - }, - - 'fms_nml':{ - 'print_memory_usage':False, - 'domains_stack_size': 200000, - }, - - 'shallow_dynamics_nml':{ - 'num_lon' : 512, - 'num_lat' : 256, - 'num_fourier' : 170, - 'num_spherical' : 171, - 'fourier_inc' : 1, - 'damping_option' : 'resolution_dependent', - 'damping_order' : 4, - 'damping_coeff' : 1.e-04, - 'h_0' : 3.e04, - 'grid_tracer' : False, - 'spec_tracer' : False, - 'robert_coeff' : 0.04, - 'robert_coeff_tracer' : 0.04, - }, - - 'shallow_physics_nml':{ - 'fric_damp_time' : 0.0, - 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. - 'h_amp' : 0., - 'h_itcz' : 0., - }, - - 'stirring_nml': { - 'B':0.0, - 'do_localize': False, - }, - -}) - -#Lets do a run! -if __name__=="__main__": - - # for ld_value in [10.0, 0.1, 0.05, 0.01]: - for ld_value in [0.05,]: - - - for u_deep_mag_val in [50.]: - - if u_deep_mag_val!=0.: - u_deep_merid_arr = [23] - # u_deep_merid_arr = [5,7,9] - - else: - u_deep_merid_arr = [3] - - for u_deep_merid in u_deep_merid_arr: - - exp = Experiment('giant_planet_fixed_deep_ics_forced_no_rad_damping_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid))+'_energy_outputs_3', codebase=cb) - - exp.diag_table = diag - exp.namelist = namelist - exp.clear_rundir() - - rotation_period = ((9.*3600.)+55.*60 + 30.) - omega = 2.*np.pi/ rotation_period - radius = 69911e3 - grav = 24.79 - number_ld_in_radius_units = ld_value - - # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. - - equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. - equilibrium_depth = equilibrium_geopotential/grav - - exp.update_namelist({ - 'shallow_dynamics_nml':{ - 'h_0': equilibrium_geopotential, - 'u_deep_mag' : u_deep_mag_val, - 'n_merid_deep_flow': u_deep_merid, - # 'u_upper_mag_init': u_deep_mag_val, - }, - 'shallow_physics_nml': { - 'h_0': equilibrium_geopotential, - 'therm_damp_time' : rotation_period * 0., #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) - }, - 'constants_nml': { - 'omega': omega, - 'radius': radius, - }, - 'stirring_nml': { - 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. - 'amplitude':3.e-13, - 'n_total_forcing_max': 85, - 'n_total_forcing_min': 79, - - }, - - }) - - exp.run(1, use_restart=False, num_cores=NCORES) - for i in range(2,481): - exp.run(i, num_cores=NCORES) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1_vary_damping.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1_vary_damping.py deleted file mode 100644 index c2335a0be..000000000 --- a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/giant_planet_shallow_water_deep_velocity_test_mk1_vary_damping.py +++ /dev/null @@ -1,169 +0,0 @@ -import os - -import numpy as np - -from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE - -import pdb - -NCORES = 16 -base_dir = os.path.dirname(os.path.realpath(__file__)) -# a CodeBase can be a directory on the computer, -# useful for iterative development -cb = ShallowCodeBase.from_directory(GFDL_BASE) - -# or it can point to a specific git repo and commit id. -# This method should ensure future, independent, reproducibility of results. -# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') - -# compilation depends on computer specific settings. The $GFDL_ENV -# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file -# is used to load the correct compilers. The env file is always loaded from -# $GFDL_BASE and not the checked out git repo. - -cb.compile() # compile the source code to working directory $GFDL_WORK/codebase - -# create an Experiment object to handle the configuration of model parameters -# and output diagnostics - -#Tell model how to write diagnostics -diag = DiagTable() -diag.add_file('atmos_monthly', 30, 'days', time_units='days') -# diag.add_file('atmos_daily', 1, 'days', time_units='days') - -#Tell model which diagnostics to write -diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vor', time_avg=True) -diag.add_field('shallow_diagnostics', 'div', time_avg=True) -diag.add_field('shallow_diagnostics', 'h', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv_correct', time_avg=True) - -diag.add_field('shallow_diagnostics', 'stream', time_avg=True) -diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) -# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) -# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) -diag.add_field('stirring_mod', 'stirring', time_avg=True) -# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) -diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) -diag.add_field('shallow_diagnostics', 'h_sqd_mean', time_avg=True) - -#Empty the run directory ready to run - -#Define values for the 'core' namelist -namelist = Namelist({ - 'main_nml':{ - 'days' : 30, - 'hours' : 0, - 'minutes': 0, - 'seconds': 0, - 'dt_atmos': 1200, - 'calendar': 'no_calendar', - }, - - 'atmosphere_nml':{ - 'print_interval': 86400, - }, - -'fms_io_nml':{ - 'threading_write' :'single', - 'fileset_write': 'single' - }, - - 'fms_nml':{ - 'print_memory_usage':False, - 'domains_stack_size': 200000, - }, - - 'shallow_dynamics_nml':{ - 'num_lon' : 512, - 'num_lat' : 256, - 'num_fourier' : 170, - 'num_spherical' : 171, - 'fourier_inc' : 1, - 'damping_option' : 'resolution_dependent', - 'damping_order' : 4, - 'damping_coeff' : 1.e-04, - 'h_0' : 3.e04, - 'grid_tracer' : False, - 'spec_tracer' : False, - 'robert_coeff' : 0.04, - 'robert_coeff_tracer' : 0.04, - }, - - 'shallow_physics_nml':{ - 'fric_damp_time' : 0.0, - 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. - 'h_amp' : 0., - 'h_itcz' : 0., - }, - - 'stirring_nml': { - 'B':0.0, - 'do_localize': False, - }, - -}) - -#Lets do a run! -if __name__=="__main__": - - for ld_value in [0.1]: - - for u_deep_mag_val in [0., 50.]: - - if u_deep_mag_val!=0.: - u_deep_merid_arr = [3, 11, 19, 26] - else: - u_deep_merid_arr = [3] - - for u_deep_merid in u_deep_merid_arr: - - for damping_time_rot in [1000., 10000.]: #, 0., 100., Also want to do these, but can alias existing runs for them - - exp = Experiment('giant_planet_fixed_deep_ics_forced_rad_damping_'+str(damping_time_rot)+'_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid)), codebase=cb) - - exp.diag_table = diag - exp.namelist = namelist - exp.clear_rundir() - - rotation_period = ((9.*3600.)+55.*60 + 30.) - omega = 2.*np.pi/ rotation_period - radius = 69911e3 - grav = 24.79 - number_ld_in_radius_units = ld_value - - # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. - - equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. - equilibrium_depth = equilibrium_geopotential/grav - - exp.update_namelist({ - 'shallow_dynamics_nml':{ - 'h_0': equilibrium_geopotential, - 'u_deep_mag' : u_deep_mag_val, - 'n_merid_deep_flow': u_deep_merid, - }, - 'shallow_physics_nml': { - 'h_0': equilibrium_geopotential, - 'therm_damp_time' : rotation_period * damping_time_rot, #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) - }, - 'constants_nml': { - 'omega': omega, - 'radius': radius, - }, - 'stirring_nml': { - 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. - 'amplitude':3.e-13, - 'n_total_forcing_max': 85, - 'n_total_forcing_min': 79, - - }, - - }) - - exp.run(1, use_restart=False, num_cores=NCORES) - for i in range(2,721): - exp.run(i, num_cores=NCORES) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py deleted file mode 100644 index c7af1d59c..000000000 --- a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py +++ /dev/null @@ -1,178 +0,0 @@ -import os - -import numpy as np - -from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE - -import pdb - -NCORES = 32 -base_dir = os.path.dirname(os.path.realpath(__file__)) -# a CodeBase can be a directory on the computer, -# useful for iterative development -cb = ShallowCodeBase.from_directory(GFDL_BASE) - -# or it can point to a specific git repo and commit id. -# This method should ensure future, independent, reproducibility of results. -# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') - -# compilation depends on computer specific settings. The $GFDL_ENV -# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file -# is used to load the correct compilers. The env file is always loaded from -# $GFDL_BASE and not the checked out git repo. - -cb.compile() # compile the source code to working directory $GFDL_WORK/codebase - -# create an Experiment object to handle the configuration of model parameters -# and output diagnostics - -#Tell model how to write diagnostics -diag = DiagTable() -diag.add_file('atmos_monthly', 30, 'days', time_units='days') -#diag.add_file('atmos_daily', 1, 'days', time_units='days') - -#Tell model which diagnostics to write -diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vor', time_avg=True) -diag.add_field('shallow_diagnostics', 'div', time_avg=True) -diag.add_field('shallow_diagnostics', 'h', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv_corrected', time_avg=True) -diag.add_field('shallow_diagnostics', 'stream', time_avg=True) -diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) -diag.add_field('shallow_diagnostics', 'vcomp_vor', time_avg=True) -diag.add_field('shallow_diagnostics', 'ucomp_vcomp', time_avg=True) - -# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) -# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) -diag.add_field('stirring_mod', 'stirring', time_avg=True) -# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) -diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) -diag.add_field('shallow_diagnostics', 'h_sqd_mean', time_avg=True) - -diag.add_field('shallow_diagnostics', 'e_kin_density', time_avg=True) -diag.add_field('shallow_diagnostics', 'eq_geopot', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_kin_real_units', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_pot_real_units', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_tot_real_units', time_avg=True) -diag.add_field('shallow_diagnostics', 'u_rms', time_avg=True) - -#Empty the run directory ready to run - -#Define values for the 'core' namelist -namelist = Namelist({ - 'main_nml':{ - 'days' : 30, - 'hours' : 0, - 'minutes': 0, - 'seconds': 0, - 'dt_atmos': 600, - 'calendar': 'no_calendar', - }, - - 'atmosphere_nml':{ - 'print_interval': 86400, - }, - -'fms_io_nml':{ - 'threading_write' :'single', - 'fileset_write': 'single' - }, - - 'fms_nml':{ - 'print_memory_usage':False, - 'domains_stack_size': 200000, - }, - - 'shallow_dynamics_nml':{ - 'num_lon' : 1024, - 'num_lat' : 512, - 'num_fourier' : 341, - 'num_spherical' : 342, - 'fourier_inc' : 1, - 'damping_option' : 'resolution_dependent', - 'damping_order' : 4, - 'damping_coeff' : 1.e-04, - 'h_0' : 3.e04, - 'grid_tracer' : False, - 'spec_tracer' : False, - 'robert_coeff' : 0.04, - 'robert_coeff_tracer' : 0.04, - }, - - 'shallow_physics_nml':{ - 'fric_damp_time' : 0.0, - 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. - 'h_amp' : 0., - 'h_itcz' : 0., - }, - - 'stirring_nml': { - 'B':0.0, - 'do_localize': False, - }, - -}) - -#Lets do a run! -if __name__=="__main__": - - for forcing_amplitude in [7.5]: - - for damping_time in [ 100000.]: - u_deep_mag_val = 50. - - if u_deep_mag_val!=0.: - u_deep_merid_arr = [27] - else: - u_deep_merid_arr = [3] - - for u_deep_merid in u_deep_merid_arr: - - ld_value = 0.025 - exp = Experiment('high_res_small_forcing_giant_planet_fixed_deep_ics_forced_'+str(damping_time)+'_rad_damping_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid))+'_strong_forcing_'+str(forcing_amplitude), codebase=cb) - - exp.diag_table = diag - exp.namelist = namelist - exp.clear_rundir() - - rotation_period = ((9.*3600.)+55.*60 + 30.) - omega = 2.*np.pi/ rotation_period - radius = 69911e3 - grav = 24.79 - number_ld_in_radius_units = ld_value - - # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. - - equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. - equilibrium_depth = equilibrium_geopotential/grav - - exp.update_namelist({ - 'shallow_dynamics_nml':{ - 'h_0': equilibrium_geopotential, - 'u_deep_mag' : u_deep_mag_val, - 'n_merid_deep_flow': u_deep_merid, - }, - 'shallow_physics_nml': { - 'h_0': equilibrium_geopotential, - 'therm_damp_time' : rotation_period * damping_time, #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) - }, - 'constants_nml': { - 'omega': omega, - 'radius': radius, - }, - 'stirring_nml': { - 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. - 'amplitude':3.e-13*forcing_amplitude, - 'n_total_forcing_max': 170, - 'n_total_forcing_min': 164, - - }, - - }) - - exp.run(1, use_restart=False, num_cores=NCORES, multi_node=True) - for i in range(721,841): - exp.run(i, num_cores=NCORES, multi_node=True) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/part_2/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/part_2/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py deleted file mode 100644 index 2c6a8f028..000000000 --- a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/high_res/smaller_forcing/tuned_galperin_forcing/part_2/giant_planet_shallow_water_deep_velocity_test_mk1_high_res.py +++ /dev/null @@ -1,175 +0,0 @@ -import os - -import numpy as np - -from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE - -import pdb - -NCORES = 32 -base_dir = os.path.dirname(os.path.realpath(__file__)) -# a CodeBase can be a directory on the computer, -# useful for iterative development -cb = ShallowCodeBase.from_directory(GFDL_BASE) - -# or it can point to a specific git repo and commit id. -# This method should ensure future, independent, reproducibility of results. -# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') - -# compilation depends on computer specific settings. The $GFDL_ENV -# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file -# is used to load the correct compilers. The env file is always loaded from -# $GFDL_BASE and not the checked out git repo. - -cb.compile() # compile the source code to working directory $GFDL_WORK/codebase - -# create an Experiment object to handle the configuration of model parameters -# and output diagnostics - -#Tell model how to write diagnostics -diag = DiagTable() -diag.add_file('atmos_monthly', 30, 'days', time_units='days') -# diag.add_file('atmos_daily', 1, 'days', time_units='days') - -#Tell model which diagnostics to write -diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vor', time_avg=True) -diag.add_field('shallow_diagnostics', 'div', time_avg=True) -diag.add_field('shallow_diagnostics', 'h', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv_corrected', time_avg=True) -diag.add_field('shallow_diagnostics', 'stream', time_avg=True) -diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) -# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) -# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) -diag.add_field('stirring_mod', 'stirring', time_avg=True) -# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) -diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) -diag.add_field('shallow_diagnostics', 'h_sqd_mean', time_avg=True) - -diag.add_field('shallow_diagnostics', 'e_kin_density', time_avg=True) -diag.add_field('shallow_diagnostics', 'eq_geopot', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_kin_real_units', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_pot_real_units', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_tot_real_units', time_avg=True) -diag.add_field('shallow_diagnostics', 'u_rms', time_avg=True) - -#Empty the run directory ready to run - -#Define values for the 'core' namelist -namelist = Namelist({ - 'main_nml':{ - 'days' : 30, - 'hours' : 0, - 'minutes': 0, - 'seconds': 0, - 'dt_atmos': 600, - 'calendar': 'no_calendar', - }, - - 'atmosphere_nml':{ - 'print_interval': 86400, - }, - -'fms_io_nml':{ - 'threading_write' :'single', - 'fileset_write': 'single' - }, - - 'fms_nml':{ - 'print_memory_usage':False, - 'domains_stack_size': 200000, - }, - - 'shallow_dynamics_nml':{ - 'num_lon' : 1024, - 'num_lat' : 512, - 'num_fourier' : 341, - 'num_spherical' : 342, - 'fourier_inc' : 1, - 'damping_option' : 'resolution_dependent', - 'damping_order' : 4, - 'damping_coeff' : 1.e-04, - 'h_0' : 3.e04, - 'grid_tracer' : False, - 'spec_tracer' : False, - 'robert_coeff' : 0.04, - 'robert_coeff_tracer' : 0.04, - }, - - 'shallow_physics_nml':{ - 'fric_damp_time' : 0.0, - 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. - 'h_amp' : 0., - 'h_itcz' : 0., - }, - - 'stirring_nml': { - 'B':0.0, - 'do_localize': False, - }, - -}) - -#Lets do a run! -if __name__=="__main__": - - for forcing_amplitude in [ 10.]: - - for damping_time in [ 10000., 1000., 100000.]: - u_deep_mag_val = 50. - - if u_deep_mag_val!=0.: - u_deep_merid_arr = [27] - else: - u_deep_merid_arr = [3] - - for u_deep_merid in u_deep_merid_arr: - - ld_value = 0.025 - exp = Experiment('high_res_small_forcing_giant_planet_fixed_deep_ics_forced_'+str(damping_time)+'_rad_damping_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid))+'_strong_forcing_'+str(forcing_amplitude), codebase=cb) - - exp.diag_table = diag - exp.namelist = namelist - exp.clear_rundir() - - rotation_period = ((9.*3600.)+55.*60 + 30.) - omega = 2.*np.pi/ rotation_period - radius = 69911e3 - grav = 24.79 - number_ld_in_radius_units = ld_value - - # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. - - equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. - equilibrium_depth = equilibrium_geopotential/grav - - exp.update_namelist({ - 'shallow_dynamics_nml':{ - 'h_0': equilibrium_geopotential, - 'u_deep_mag' : u_deep_mag_val, - 'n_merid_deep_flow': u_deep_merid, - }, - 'shallow_physics_nml': { - 'h_0': equilibrium_geopotential, - 'therm_damp_time' : rotation_period * damping_time, #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) - }, - 'constants_nml': { - 'omega': omega, - 'radius': radius, - }, - 'stirring_nml': { - 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. - 'amplitude':3.e-13*forcing_amplitude, - 'n_total_forcing_max': 170, - 'n_total_forcing_min': 164, - - }, - - }) - - exp.run(1, use_restart=False, num_cores=NCORES, multi_node=True) - for i in range(2,721): - exp.run(i, num_cores=NCORES, multi_node=True) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk1.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk1.py deleted file mode 100644 index 0d5ce04b4..000000000 --- a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk1.py +++ /dev/null @@ -1,167 +0,0 @@ -import os - -import numpy as np - -from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE - -import pdb - -NCORES = 16 -base_dir = os.path.dirname(os.path.realpath(__file__)) -# a CodeBase can be a directory on the computer, -# useful for iterative development -cb = ShallowCodeBase.from_directory(GFDL_BASE) - -# or it can point to a specific git repo and commit id. -# This method should ensure future, independent, reproducibility of results. -# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') - -# compilation depends on computer specific settings. The $GFDL_ENV -# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file -# is used to load the correct compilers. The env file is always loaded from -# $GFDL_BASE and not the checked out git repo. - -cb.compile() # compile the source code to working directory $GFDL_WORK/codebase - -# create an Experiment object to handle the configuration of model parameters -# and output diagnostics - -#Tell model how to write diagnostics -diag = DiagTable() -diag.add_file('atmos_monthly', 30, 'days', time_units='days') -# diag.add_file('atmos_daily', 1, 'days', time_units='days') - -#Tell model which diagnostics to write -diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vor', time_avg=True) -diag.add_field('shallow_diagnostics', 'div', time_avg=True) -diag.add_field('shallow_diagnostics', 'h', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv', time_avg=True) -diag.add_field('shallow_diagnostics', 'stream', time_avg=True) -diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) -# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) -# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) -diag.add_field('stirring_mod', 'stirring', time_avg=True) -# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) -diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) - - -#Empty the run directory ready to run - -#Define values for the 'core' namelist -namelist = Namelist({ - 'main_nml':{ - 'days' : 30, - 'hours' : 0, - 'minutes': 0, - 'seconds': 0, - 'dt_atmos': 1200, - 'calendar': 'no_calendar', - }, - - 'atmosphere_nml':{ - 'print_interval': 86400, - }, - -'fms_io_nml':{ - 'threading_write' :'single', - 'fileset_write': 'single' - }, - - 'fms_nml':{ - 'print_memory_usage':False, - 'domains_stack_size': 200000, - }, - - 'shallow_dynamics_nml':{ - 'num_lon' : 512, - 'num_lat' : 256, - 'num_fourier' : 170, - 'num_spherical' : 171, - 'fourier_inc' : 1, - 'damping_option' : 'resolution_dependent', - 'damping_order' : 4, - 'damping_coeff' : 1.e-04, - 'h_0' : 3.e04, - 'grid_tracer' : False, - 'spec_tracer' : False, - 'robert_coeff' : 0.04, - 'robert_coeff_tracer' : 0.04, - }, - - 'shallow_physics_nml':{ - 'fric_damp_time' : 0.0, - 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. - 'h_amp' : 0., - 'h_itcz' : 0., - }, - - 'stirring_nml': { - 'B':0.0, - 'do_localize': False, - }, - -}) - -#Lets do a run! -if __name__=="__main__": - - for ld_value in [10.0]: - for u_deep_mag_val in [50.,]: - #for u_deep_mag_val in [-50.]: - - if u_deep_mag_val!=0.: - u_deep_merid_arr = [3,] - else: - u_deep_merid_arr = [3] - - #u_deep_merid_arr = [3] - - for u_deep_merid in u_deep_merid_arr: - - exp = Experiment('giant_planet_shallow_water_deep_velocity_test_mk2_no_forcing_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid)), codebase=cb) - - exp.diag_table = diag - exp.namelist = namelist - exp.clear_rundir() - - rotation_period = ((9.*3600.)+55.*60 + 30.) - omega = 2.*np.pi/ rotation_period - radius = 69911e3 - grav = 24.79 - number_ld_in_radius_units = ld_value - - # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. - - equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. - equilibrium_depth = equilibrium_geopotential/grav - - exp.update_namelist({ - 'shallow_dynamics_nml':{ - 'h_0': equilibrium_geopotential, - 'u_deep_mag' : u_deep_mag_val, - 'n_merid_deep_flow': u_deep_merid, - }, - 'shallow_physics_nml': { - 'h_0': equilibrium_geopotential, - 'therm_damp_time' : rotation_period * 100., #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) - }, - 'constants_nml': { - 'omega': omega, - 'radius': radius, - }, - 'stirring_nml': { - 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. - 'amplitude':0., - 'n_total_forcing_max': 85, - 'n_total_forcing_min': 79, - - }, - - }) - - exp.run(1, use_restart=False, num_cores=NCORES) - for i in range(2,2101): - exp.run(i, num_cores=NCORES) diff --git a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk2.py b/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk2.py deleted file mode 100644 index 711b2c34b..000000000 --- a/exp/shallow_water_giant_planet/first_param_sweep_deep_velocities/no_forcing_giant_planet_shallow_water_deep_velocity_test_mk2.py +++ /dev/null @@ -1,170 +0,0 @@ -import os - -import numpy as np - -from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE - -import pdb - -NCORES = 16 -base_dir = os.path.dirname(os.path.realpath(__file__)) -# a CodeBase can be a directory on the computer, -# useful for iterative development -cb = ShallowCodeBase.from_directory(GFDL_BASE) - -# or it can point to a specific git repo and commit id. -# This method should ensure future, independent, reproducibility of results. -# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') - -# compilation depends on computer specific settings. The $GFDL_ENV -# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file -# is used to load the correct compilers. The env file is always loaded from -# $GFDL_BASE and not the checked out git repo. - -cb.compile() # compile the source code to working directory $GFDL_WORK/codebase - -# create an Experiment object to handle the configuration of model parameters -# and output diagnostics - -#Tell model how to write diagnostics -diag = DiagTable() -diag.add_file('atmos_monthly', 30, 'days', time_units='days') -# diag.add_file('atmos_daily', 1, 'days', time_units='days') -# diag.add_file('atmos_timestep', 1200, 'seconds', time_units='days') - - -#Tell model which diagnostics to write -diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vor', time_avg=True) -diag.add_field('shallow_diagnostics', 'div', time_avg=True) -diag.add_field('shallow_diagnostics', 'h', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv', time_avg=True) -diag.add_field('shallow_diagnostics', 'stream', time_avg=True) -diag.add_field('shallow_diagnostics', 'deep_geopot', time_avg=True) -# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) -# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) -diag.add_field('stirring_mod', 'stirring', time_avg=True) -# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) -diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) -diag.add_field('shallow_diagnostics', 'e_kin', time_avg=True) - - - -#Empty the run directory ready to run - -#Define values for the 'core' namelist -namelist = Namelist({ - 'main_nml':{ - 'days' : 30, - 'hours' : 0, - 'minutes': 0, - 'seconds': 0, - 'dt_atmos': 1200, - 'calendar': 'no_calendar', - }, - - 'atmosphere_nml':{ - 'print_interval': 86400, - }, - -'fms_io_nml':{ - 'threading_write' :'single', - 'fileset_write': 'single' - }, - - 'fms_nml':{ - 'print_memory_usage':False, - 'domains_stack_size': 200000, - }, - - 'shallow_dynamics_nml':{ - 'num_lon' : 512, - 'num_lat' : 256, - 'num_fourier' : 170, - 'num_spherical' : 171, - 'fourier_inc' : 1, - 'damping_option' : 'resolution_dependent', - 'damping_order' : 4, - 'damping_coeff' : 1.e-04, - 'h_0' : 3.e04, - 'grid_tracer' : False, - 'spec_tracer' : False, - 'robert_coeff' : 0.04, - 'robert_coeff_tracer' : 0.04, - }, - - 'shallow_physics_nml':{ - 'fric_damp_time' : 0.0, - 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. - 'h_amp' : 0., - 'h_itcz' : 0., - }, - - 'stirring_nml': { - 'B':0.0, - 'do_localize': False, - }, - -}) - -#Lets do a run! -if __name__=="__main__": - - for ld_value in [0.1, 10.0]: - # for u_deep_mag_val in [50., 0., 25.]: - for u_deep_mag_val in [50., 0.]: - - # if u_deep_mag_val!=0.: - # u_deep_merid_arr = [3, 11, 19, 26] - # else: - # u_deep_merid_arr = [3] - - u_deep_merid_arr = [3] - - for u_deep_merid in u_deep_merid_arr: - - exp = Experiment('giant_planet_shallow_water_deep_velocity_test_mk8_no_forcing_no_damping_ld_'+str(ld_value)+'_udeep_mag_'+str(u_deep_mag_val)+'_u_deep_merid_'+str(int(u_deep_merid)), codebase=cb) - - exp.diag_table = diag - exp.namelist = namelist - exp.clear_rundir() - - rotation_period = ((9.*3600.)+55.*60 + 30.) - omega = 2.*np.pi/ rotation_period - radius = 69911e3 - grav = 24.79 - number_ld_in_radius_units = ld_value - - # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. - - equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. - equilibrium_depth = equilibrium_geopotential/grav - - exp.update_namelist({ - 'shallow_dynamics_nml':{ - 'h_0': equilibrium_geopotential, - 'u_deep_mag' : u_deep_mag_val, - 'n_merid_deep_flow': u_deep_merid, - }, - 'shallow_physics_nml': { - 'h_0': equilibrium_geopotential, - 'therm_damp_time' : 0. - }, - 'constants_nml': { - 'omega': omega, - 'radius': radius, - }, - 'stirring_nml': { - 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. - 'amplitude':0., - 'n_total_forcing_max': 85, - 'n_total_forcing_min': 79, - - }, - - }) - - exp.run(1, use_restart=False, num_cores=NCORES) - for i in range(2,121): - exp.run(i, num_cores=NCORES) diff --git a/exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py b/exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py deleted file mode 100644 index 14c4b323c..000000000 --- a/exp/shallow_water_giant_planet/giant_planet_shallow_water_small_scale_stirring_test.py +++ /dev/null @@ -1,151 +0,0 @@ -import os - -import numpy as np - -from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE - -import pdb - -NCORES = 16 -base_dir = os.path.dirname(os.path.realpath(__file__)) -# a CodeBase can be a directory on the computer, -# useful for iterative development -cb = ShallowCodeBase.from_directory(GFDL_BASE) - -# or it can point to a specific git repo and commit id. -# This method should ensure future, independent, reproducibility of results. -# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') - -# compilation depends on computer specific settings. The $GFDL_ENV -# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file -# is used to load the correct compilers. The env file is always loaded from -# $GFDL_BASE and not the checked out git repo. - -cb.compile() # compile the source code to working directory $GFDL_WORK/codebase - -# create an Experiment object to handle the configuration of model parameters -# and output diagnostics - -#Tell model how to write diagnostics -diag = DiagTable() -diag.add_file('atmos_monthly', 30, 'days', time_units='days') -diag.add_file('atmos_daily', 1, 'days', time_units='days') - -#Tell model which diagnostics to write -diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vor', time_avg=True) -diag.add_field('shallow_diagnostics', 'div', time_avg=True) -diag.add_field('shallow_diagnostics', 'h', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv', time_avg=True) -diag.add_field('shallow_diagnostics', 'stream', time_avg=True) -# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) -# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) -diag.add_field('stirring_mod', 'stirring', time_avg=True) -# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) -diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) - - -#Empty the run directory ready to run - -#Define values for the 'core' namelist -namelist = Namelist({ - 'main_nml':{ - 'days' : 30, - 'hours' : 0, - 'minutes': 0, - 'seconds': 0, - 'dt_atmos': 1200, - 'calendar': 'no_calendar', - }, - - 'atmosphere_nml':{ - 'print_interval': 86400, - }, - -'fms_io_nml':{ - 'threading_write' :'single', - 'fileset_write': 'single' - }, - - 'fms_nml':{ - 'print_memory_usage':False, - 'domains_stack_size': 200000, - }, - - 'shallow_dynamics_nml':{ - 'num_lon' : 512, - 'num_lat' : 256, - 'num_fourier' : 170, - 'num_spherical' : 171, - 'fourier_inc' : 1, - 'damping_option' : 'resolution_dependent', - 'damping_order' : 4, - 'damping_coeff' : 1.e-04, - 'h_0' : 3.e04, - 'grid_tracer' : False, - 'spec_tracer' : False, - 'robert_coeff' : 0.04, - 'robert_coeff_tracer' : 0.04, - }, - - 'shallow_physics_nml':{ - 'fric_damp_time' : 0.0, - 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. - 'h_amp' : 0., - 'h_itcz' : 0., - }, - - 'stirring_nml': { - 'B':0.0, - 'do_localize': False, - }, - -}) - -#Lets do a run! -if __name__=="__main__": - - for number_ld_in_radius_units in [0.1]: - - exp = Experiment('giant_shallow_stirring_test_experiment_uniform_smaller_120_scale_stirring_mk3_longer_damping_ld_'+str(number_ld_in_radius_units), codebase=cb) - - exp.diag_table = diag - exp.namelist = namelist - exp.clear_rundir() - - rotation_period = ((9.*3600.)+55.*60 + 30.) - omega = 2.*np.pi/ rotation_period - radius = 69911e3 - grav = 24.79 - - # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. - - equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. - equilibrium_depth = equilibrium_geopotential/grav - - exp.update_namelist({ - 'shallow_dynamics_nml':{ - 'h_0': equilibrium_geopotential - }, - 'shallow_physics_nml': { - 'h_0': equilibrium_geopotential, - 'therm_damp_time' : rotation_period * 10000., #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) - }, - 'constants_nml': { - 'omega': omega, - 'radius': radius, - }, - 'stirring_nml': { - 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. - 'amplitude':3.e-13, - 'n_total_forcing_max': 125, - 'n_total_forcing_min': 119, - - }, - - }) - - exp.run(1, use_restart=False, num_cores=NCORES) - for i in range(2,121): - exp.run(i, num_cores=NCORES) diff --git a/exp/shallow_water_giant_planet/giant_planet_shallow_water_stirring_test.py b/exp/shallow_water_giant_planet/giant_planet_shallow_water_stirring_test.py deleted file mode 100644 index fa19bc3c5..000000000 --- a/exp/shallow_water_giant_planet/giant_planet_shallow_water_stirring_test.py +++ /dev/null @@ -1,148 +0,0 @@ -import os - -import numpy as np - -from isca import ShallowCodeBase, DiagTable, Experiment, Namelist, GFDL_BASE - -import pdb - -NCORES = 8 -base_dir = os.path.dirname(os.path.realpath(__file__)) -# a CodeBase can be a directory on the computer, -# useful for iterative development -cb = ShallowCodeBase.from_directory(GFDL_BASE) - -# or it can point to a specific git repo and commit id. -# This method should ensure future, independent, reproducibility of results. -# cb = DryCodeBase.from_repo(repo='https://github.com/isca/isca', commit='isca1.1') - -# compilation depends on computer specific settings. The $GFDL_ENV -# environment variable is used to determine which `$GFDL_BASE/src/extra/env` file -# is used to load the correct compilers. The env file is always loaded from -# $GFDL_BASE and not the checked out git repo. - -cb.compile() # compile the source code to working directory $GFDL_WORK/codebase - -# create an Experiment object to handle the configuration of model parameters -# and output diagnostics - -#Tell model how to write diagnostics -diag = DiagTable() -diag.add_file('atmos_monthly', 30, 'days', time_units='days') -diag.add_file('atmos_daily', 1, 'days', time_units='days') - -#Tell model which diagnostics to write -diag.add_field('shallow_diagnostics', 'ucomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vcomp', time_avg=True) -diag.add_field('shallow_diagnostics', 'vor', time_avg=True) -diag.add_field('shallow_diagnostics', 'div', time_avg=True) -diag.add_field('shallow_diagnostics', 'h', time_avg=True) -diag.add_field('shallow_diagnostics', 'pv', time_avg=True) -diag.add_field('shallow_diagnostics', 'stream', time_avg=True) -# diag.add_field('shallow_diagnostics', 'trs', time_avg=True) -# diag.add_field('shallow_diagnostics', 'tr', time_avg=True) -diag.add_field('stirring_mod', 'stirring', time_avg=True) -# diag.add_field('stirring_mod', 'stirring_amp', time_avg=True) -diag.add_field('stirring_mod', 'stirring_sqr', time_avg=True) - - -#Empty the run directory ready to run - -#Define values for the 'core' namelist -namelist = Namelist({ - 'main_nml':{ - 'days' : 30, - 'hours' : 0, - 'minutes': 0, - 'seconds': 0, - 'dt_atmos': 1200, - 'calendar': 'no_calendar', - }, - - 'atmosphere_nml':{ - 'print_interval': 86400, - }, - -'fms_io_nml':{ - 'threading_write' :'single', - 'fileset_write': 'single' - }, - - 'fms_nml':{ - 'print_memory_usage':False, - 'domains_stack_size': 200000, - }, - - 'shallow_dynamics_nml':{ - 'num_lon' : 512, - 'num_lat' : 256, - 'num_fourier' : 170, - 'num_spherical' : 171, - 'fourier_inc' : 1, - 'damping_option' : 'resolution_dependent', - 'damping_order' : 4, - 'damping_coeff' : 1.e-04, - 'h_0' : 3.e04, - 'grid_tracer' : False, - 'spec_tracer' : False, - 'robert_coeff' : 0.04, - 'robert_coeff_tracer' : 0.04, - }, - - 'shallow_physics_nml':{ - 'fric_damp_time' : 0.0, - 'h_0' : 3.e04, #Scott and Polvani begin with L_D_polar = 10 radii in size, i.e. depth of 9,910 metres. - 'h_amp' : 0., - 'h_itcz' : 0., - }, - - 'stirring_nml': { - 'B':0.0, - 'do_localize': False, - }, - -}) - -#Lets do a run! -if __name__=="__main__": - - for number_ld_in_radius_units in [10.]: - - exp = Experiment('giant_shallow_stirring_test_experiment_uniform_stirring_mk3', codebase=cb) - - exp.diag_table = diag - exp.namelist = namelist - exp.clear_rundir() - - rotation_period = ((9.*3600.)+55.*60 + 30.) - omega = 2.*np.pi/ rotation_period - radius = 69911e3 - grav = 24.79 - - # Model uses geopotential as its height co-ordinate. So depth is h_0/grav. - - equilibrium_geopotential = (2.*number_ld_in_radius_units*omega*radius)**2. - equilibrium_depth = equilibrium_geopotential/grav - - exp.update_namelist({ - 'shallow_dynamics_nml':{ - 'h_0': equilibrium_geopotential - }, - 'shallow_physics_nml': { - 'h_0': equilibrium_geopotential, - 'therm_damp_time' : rotation_period * 1., #Thermal damping time in Scott and Polvani is 1 rotation period (v_l = 1) - }, - 'constants_nml': { - 'omega': omega, - 'radius': radius, - }, - 'stirring_nml': { - 'decay_time':10.*rotation_period, #Scott and Polvani use decorrelation time of 10 planetary rotations - i.e. a long time for Jupiter. - 'amplitude':3.e-13, - }, - - }) - - exp.run(1, use_restart=False, num_cores=NCORES) - for i in range(2,122): - exp.run(i, num_cores=NCORES)