Browse Source

Enabled automatic generation of namcouple.

Introduced a command-line argument such that flux_calculator only generates
the namcouple and does nothing else.
The executable with this switch has to be started in advance to the actual model run
(then without the switch)
distribute-radiation-on-surface-types
Sven Karsten 2 years ago
parent
commit
2e92067867
  1. 6
      build_haumea.sh
  2. 40
      src/flux_calculator.F90
  3. 159
      src/flux_calculator_create_namcouple.F90
  4. 47
      src/flux_calculator_io.F90
  5. 55
      src/flux_calculator_parse_arg.F90

6
build_haumea.sh

@ -54,10 +54,12 @@ $AR rv flux_library.a *.o
#$FC -c $FFLAGS ../src/read_grid.F90 -DUSE_DOUBLE_PRECISION -I${IOW_ESM_NETCDF_INCLUDE} $LIBS
#$FC -c $FFLAGS ../src/decomp_def.F90 -DUSE_DOUBLE_PRECISION -I${IOW_ESM_NETCDF_INCLUDE} $LIBS
#$FC -c $FFLAGS ../src/read_dimgrid.F90 -DUSE_DOUBLE_PRECISION -I${IOW_ESM_NETCDF_INCLUDE} $LIBS
$FC -c $FFLAGS ../src/flux_calculator_basic.F90
$FC -c $FFLAGS ../src/flux_calculator_basic.F90
$FC -c $FFLAGS ../src/flux_calculator_prepare.F90
$FC -c $FFLAGS ../src/flux_calculator_calculate.F90
$FC -c $FFLAGS ../src/flux_calculator_parse_arg.F90
$FC -c $FFLAGS ../src/flux_calculator_io.F90 -I${IOW_ESM_NETCDF_INCLUDE} $LIBS
$FC $FFLAGS -o ../bin/flux_calculator ../src/flux_calculator.F90 flux_calculator_basic.o flux_calculator_prepare.o flux_calculator_calculate.o flux_calculator_io.o flux_library.a $INCLUDES $LIBS -Wl,-rpath,${IOW_ESM_NETCDF_LIBRARY}
$FC -c $FFLAGS ../src/flux_calculator_create_namcouple.F90
$FC $FFLAGS -o ../bin/flux_calculator ../src/flux_calculator.F90 flux_calculator_basic.o flux_calculator_prepare.o flux_calculator_calculate.o flux_calculator_io.o flux_calculator_parse_arg.o flux_calculator_create_namcouple.o flux_library.a $INCLUDES $LIBS -Wl,-rpath,${IOW_ESM_NETCDF_LIBRARY}
cd ..

40
src/flux_calculator.F90

@ -12,6 +12,9 @@ PROGRAM flux_calculator
USE flux_calculator_prepare ! Functions to check if we have all we need to do the calculations
USE flux_calculator_calculate ! Functions to actually do the calculations
USE flux_calculator_parse_arg
USE flux_calculator_create_namcouple
! Use OASIS communication library
USE mod_oasis
USE mod_oasis_data, only: oasis_debug
@ -52,6 +55,7 @@ PROGRAM flux_calculator
! Namelist variables
INTEGER :: timestep = 0 ! coupling timestep in seconds
INTEGER :: num_timesteps = 0 ! number of time steps in this run
CHARACTER(50) :: name_atmos_model = ''
CHARACTER(50), DIMENSION(MAX_BOTTOM_MODELS) :: name_bottom_model = ''
CHARACTER(1), DIMENSION(MAX_BOTTOM_MODELS) :: letter_bottom_model = ''
INTEGER, DIMENSION(MAX_BOTTOM_MODELS) :: num_tasks_per_model = 0
@ -104,6 +108,7 @@ PROGRAM flux_calculator
CHARACTER(len=20), DIMENSION(MAX_BOTTOM_MODELS, MAX_SURFACE_TYPES) :: which_flux_radiation_blackbody = 'none' ! 'none' 'StBo' -> RBBR
NAMELIST /input/ timestep, num_timesteps, &
name_atmos_model, &
name_bottom_model, letter_bottom_model, &
num_tasks_per_model, &
num_t_grid_cells, num_u_grid_cells, num_v_grid_cells, &
@ -157,6 +162,8 @@ PROGRAM flux_calculator
TYPE(sparse_regridding_matrix) :: regrid_u_to_t_matrix, regrid_t_to_u_matrix
TYPE(sparse_regridding_matrix) :: regrid_v_to_t_matrix, regrid_t_to_v_matrix
LOGICAL :: generate_namcouple = .FALSE.
!###############################################################################
!# STEP 1: INITIALIZATION #
@ -173,17 +180,30 @@ PROGRAM flux_calculator
! Initialize the idx_???? variables which store the index of a variable name
CALL init_varname_idx
! Check if we should generate the namcouple file from here,
! if yes, nothing else will be done
IF (find_argument("--generate_namcouple")) THEN
generate_namcouple = .TRUE.
ENDIF
!###############################################################################
!# STEP 1.2: OASIS INITIALIZATION #
!###############################################################################
CALL MPI_Init(ierror)
! if we generate the namcouple from here, we must not use OASIS coupler
IF (.NOT. generate_namcouple) THEN
!!!!!!!!!!!!!!!!! OASIS_INIT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
CALL oasis_init_comp (comp_id, comp_name, ierror ) ! get component id
IF (ierror /= 0) THEN
WRITE(0,*) 'oasis_init_comp abort by flux_calculator compid ',comp_id
CALL oasis_abort(comp_id,comp_name,'Failed to call oasis_init_comp')
ENDIF
ENDIF
!
! Unit for output messages : one file for each process
CALL MPI_Comm_Rank ( MPI_COMM_WORLD, rank, ierror ) ! get my own rank (globally) - we will not use it
@ -202,6 +222,9 @@ PROGRAM flux_calculator
WRITE (w_unit,*) 'I am component ', TRIM(comp_name), ' rank :',rank
WRITE (w_unit,*) '----------------------------------------------------------'
CALL flush(w_unit)
! if we generate the namcouple from here, we must not use OASIS coupler
IF (.NOT. generate_namcouple) THEN
!
!!!!!!!!!!!!!!!!! OASIS_GET_LOCALCOMM !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
@ -211,6 +234,9 @@ PROGRAM flux_calculator
WRITE (w_unit,*) 'oasis_get_localcomm abort by flux_calculator compid ',comp_id
CALL oasis_abort(comp_id,comp_name,'Failed to call oasis_get_localcomm')
ENDIF
ELSE
localComm = MPI_COMM_WORLD
ENDIF
!
! Get MPI size and rank
CALL MPI_Comm_Size ( localComm, npes, ierror ) ! get number of PEs running flux_calculator
@ -606,7 +632,7 @@ PROGRAM flux_calculator
CALL prepare_flux_momentum_north(i, 3, which_flux_momentum(my_bottom_model,i), grid_size(3), local_field) ! VMOM on v_grid
ENDDO
CALL prepare_regridding(idx_VMOM, 0, local_field, my_bottom_model, regrid_u_to_t, regrid_v_to_t, regrid_t_to_u, regrid_t_to_v, grid_size)
!###############################################################################
!# STEP 1.7: FIND OUT WHAT I SHALL SEND, #
!# AND IF I WILL HAVE CALCULATED EVERYTHING I NEED FOR THAT #
@ -715,6 +741,18 @@ PROGRAM flux_calculator
WRITE(w_unit,*) ' ',output_field(i)%name,' on grid ',output_field(i)%which_grid
ENDDO
!###############################################################################
!# STEP 1.7.1: generate namcouple file #
!###############################################################################
IF (generate_namcouple) THEN
CALL create_namcouple(input_field, num_input_fields, output_field, num_output_fields, &
name_atmos_model, name_bottom_model, letter_bottom_model, &
timestep, num_timesteps)
CALL mpi_finalize(ierror)
STOP ! if we generate the namcouple from here, we are done
ENDIF
!###############################################################################
!# STEP 1.8: OASIS GRID INITIALIZATION #
!###############################################################################

159
src/flux_calculator_create_namcouple.F90

@ -0,0 +1,159 @@
MODULE flux_calculator_create_namcouple
USE flux_calculator_basic
USE flux_calculator_io
IMPLICIT NONE
!!!!!!!!!! FUNCTIONS DEFINED IN THIS MODULE
PUBLIC create_namcouple
INTEGER, SAVE :: w_namcouple ! a logfile to write the progress and error messages
!!!!!!!!!! NOW EVERYTHING ELSE
CONTAINS
SUBROUTINE write_header(num_input_fields, num_output_fields, timestep, num_timesteps)
INTEGER, INTENT(IN) :: num_input_fields, num_output_fields, timestep, num_timesteps
WRITE(w_namcouple,*) '####################################################################'
WRITE(w_namcouple,*) ' $NFIELDS'
WRITE(w_namcouple,*) num_input_fields + num_output_fields
WRITE(w_namcouple,*) ' $END'
WRITE(w_namcouple,*) '############################################'
WRITE(w_namcouple,*) ' $RUNTIME'
WRITE(w_namcouple,*) timestep * num_timesteps
WRITE(w_namcouple,*) ' $END'
WRITE(w_namcouple,*) '############################################'
WRITE(w_namcouple,*) ' $NLOGPRT'
WRITE(w_namcouple,*) '1 1'
WRITE(w_namcouple,*) ' $END'
WRITE(w_namcouple,*) '############################################'
WRITE(w_namcouple,*) ' $STRINGS'
END SUBROUTINE write_header
SUBROUTINE create_namcouple_entry(io_field, name_atmos_model, name_bottom_model, letter_bottom_model, timestep)
TYPE(io_fields_type), INTENT(IN) :: io_field
CHARACTER(*), INTENT(IN) :: name_atmos_model
CHARACTER(*), DIMENSION(*), INTENT(IN) :: name_bottom_model
CHARACTER(*), DIMENSION(*), INTENT(IN) :: letter_bottom_model
INTEGER, INTENT(IN) :: timestep
CHARACTER(len=32) :: my_model_name ! name of the model form/to the filed is received/sent
CHARACTER(len=8) :: my_grid_name ! grid on which the filed lives
CHARACTER :: my_io ! Role of flux_calculator variable (can be 'R' if the variable is received by the flux_calculator or 'S' if it is sent by flux_calculato)
CHARACTER :: other_io ! Opposite of my_io
CHARACTER (len=8) :: counterpart ! name of the variable that is received/sent from/by the model
CHARACTER(len=128) :: mapping_file ! name of the mapping file used for this coupling entry
TYPE(remapping_info_type) :: remapping_info ! info we get from the mapping file
INTEGER :: i ! counter
! find out from or to which model this variable is received or sent
IF (io_field%name(2:2) == 'A') THEN
my_model_name = name_atmos_model
ELSE
DO i = 1, MAX_BOTTOM_MODELS
IF (io_field%name(2:2) == letter_bottom_model(i)) THEN
my_model_name = name_bottom_model(i)
EXIT
ENDIF
ENDDO
ENDIF
! find out on which grid the field lives
my_grid_name = grid_name(io_field%which_grid)
! if we receive, then this variable must be sent to us and vice versa
my_io = io_field%name(1:1)
IF (my_io == 'R') THEN
other_io = 'S'
ELSE
other_io = 'R'
ENDIF
! contruct the name of the mapping file for this coupling
IF (my_io == 'R') THEN
! if we receive from a model we have to map from model grid to exchange grid
mapping_file = "mappings/remap_" // TRIM(my_grid_name) // "_" // TRIM(my_model_name) // "_to_exchangegrid.nc"
ELSE
! if we send to a model we have to map from exchange grid to model grid
mapping_file = "mappings/remap_" // TRIM(my_grid_name) // "_exchangegrid_to_" // TRIM(my_model_name) // ".nc"
ENDIF
! get information on the mapping
CALL read_remapping(mapping_file, remapping_info)
! construct counterpart of variable from/for the model
counterpart = io_field%name
counterpart(1:1) = io_field%name(2:2)
counterpart(2:2) = other_io
! write entry
IF (my_io == 'R') THEN
WRITE(w_namcouple,*) counterpart, ' ', io_field%name, ' 1 ', timestep, ' 2 restart_flc_'//TRIM(io_field%name(3:6))//'_'//TRIM(my_model_name)//'.nc EXPOUT'
ELSE
WRITE(w_namcouple,*) io_field%name, ' ', counterpart, ' 1 ', timestep, ' 2 restart_flc_'//TRIM(io_field%name(3:6))//'_'//TRIM(my_model_name)//'.nc EXPOUT'
ENDIF
WRITE(w_namcouple,*) remapping_info%src_grid_dims, remapping_info%dst_grid_dims, '___ ___ LAG=0' ! TODO: get rid off string literals here
WRITE(w_namcouple,*) "R 0 R 0"
WRITE(w_namcouple,*) "LOCTRANS MAPPING"
WRITE(w_namcouple,*) "INSTANT"
WRITE(w_namcouple,*) TRIM(mapping_file)
WRITE(w_namcouple,*) "####"
END SUBROUTINE create_namcouple_entry
SUBROUTINE create_namcouple(input_field, num_input_fields, output_field, num_output_fields, &
name_atmos_model, name_bottom_model, letter_bottom_model, &
timestep, num_timesteps)
INTEGER, INTENT(IN) :: num_input_fields, num_output_fields, timestep, num_timesteps
TYPE(io_fields_type), DIMENSION(*), INTENT(IN) :: input_field
TYPE(io_fields_type), DIMENSION(*), INTENT(IN) :: output_field
CHARACTER(*), INTENT(IN) :: name_atmos_model
CHARACTER(*), DIMENSION(*), INTENT(IN) :: name_bottom_model
CHARACTER(*), DIMENSION(*), INTENT(IN) :: letter_bottom_model
INTEGER :: i
CHARACTER(len=16) :: namcouple_filename = "namcouple"
INTEGER :: sys_status
w_namcouple = 200 ! TODO find a better solution
OPEN(w_namcouple,file=namcouple_filename,form='formatted')
CALL write_header(num_input_fields, num_output_fields, timestep, num_timesteps)
DO i = 1, num_output_fields
CALL create_namcouple_entry(output_field(i), name_atmos_model, name_bottom_model, letter_bottom_model, timestep)
ENDDO
DO i = 1, num_input_fields
CALL create_namcouple_entry(input_field(i), name_atmos_model, name_bottom_model, letter_bottom_model, timestep)
ENDDO
CLOSE(w_namcouple)
CALL SYSTEM("cp "//namcouple_filename//" ../"//TRIM(name_atmos_model)//"/")
WRITE(w_unit,*) "cp "//namcouple_filename//" ../"//TRIM(name_atmos_model)//"/"
! IF(sys_status /= 0) THEN
! WRITE(w_unit,*) "cp "//namcouple_filename//" ../"//name_atmos_model//"/"
! ENDIF
DO i = 1, MAX_BOTTOM_MODELS
IF (name_bottom_model(i) /= '') THEN
CALL SYSTEM("cp "//namcouple_filename//" ../"//TRIM(name_bottom_model(i))//"/")
WRITE(w_unit,*) "cp "//namcouple_filename//" ../"//TRIM(name_bottom_model(i))//"/"
! IF(sys_status /= 0) THEN
! WRITE(w_unit,*) "cp "//namcouple_filename//" ../"//name_bottom_model(i)//"/"
! ENDIF
ENDIF
ENDDO
END SUBROUTINE create_namcouple
END MODULE flux_calculator_create_namcouple

47
src/flux_calculator_io.F90

@ -5,7 +5,13 @@ MODULE flux_calculator_io
IMPLICIT NONE
public read_scrip_grid_dimensions, read_regridding_matrix
public read_scrip_grid_dimensions, read_regridding_matrix, read_remapping
! define a type to store info about remapping
TYPE remapping_info_type
INTEGER, DIMENSION(2) :: src_grid_dims
INTEGER, DIMENSION(2) :: dst_grid_dims
END TYPE remapping_info_type
contains
@ -148,6 +154,45 @@ MODULE flux_calculator_io
END SUBROUTINE read_regridding_matrix
SUBROUTINE read_remapping(remapping_filename, remapping_info)
USE netcdf
CHARACTER(len=128), INTENT(IN) :: remapping_filename
TYPE(remapping_info_type), INTENT(OUT) :: remapping_info
INTEGER :: nc ! NetCDF file id
INTEGER :: varid ! NetCDF variable id
INTEGER :: src_grid_rank, dst_grid_rank
! read in the dimensions for remapping
CALL hdlerr(NF90_OPEN(remapping_filename, NF90_NOWRITE, nc), __LINE__ )
CALL hdlerr( NF90_INQ_DIMID(nc, 'src_grid_rank' , varid), __LINE__ ) ! get variable id
CALL hdlerr( NF90_INQUIRE_DIMENSION(nc, varid, len=src_grid_rank), __LINE__ ) ! get variable values
WRITE (*,*) 'src_grid_rank ', src_grid_rank
CALL hdlerr( NF90_INQ_VARID(nc, 'src_grid_dims' , varid), __LINE__ ) ! get variable id
CALL hdlerr( NF90_GET_VAR (nc, varid, remapping_info%src_grid_dims(:), [1], [src_grid_rank]), __LINE__ ) ! get variable values
IF (src_grid_rank == 1) THEN
remapping_info%src_grid_dims(2) = 1
ENDIF
CALL hdlerr( NF90_INQ_DIMID(nc, 'dst_grid_rank' , varid), __LINE__ ) ! get variable id
CALL hdlerr( NF90_INQUIRE_DIMENSION(nc, varid, len=dst_grid_rank), __LINE__ ) ! get variable values
CALL hdlerr( NF90_INQ_VARID(nc, 'dst_grid_dims' , varid), __LINE__ ) ! get variable id
CALL hdlerr( NF90_GET_VAR (nc, varid, remapping_info%dst_grid_dims(:), [1], [dst_grid_rank]), __LINE__ ) ! get variable values
IF (dst_grid_rank == 1) THEN
remapping_info%dst_grid_dims(2) = 1
ENDIF
CALL hdlerr(NF90_CLOSE(nc), __LINE__ )
END SUBROUTINE read_remapping
SUBROUTINE hdlerr(istatus, line)
! handle errors during NetCDF calls
use netcdf

55
src/flux_calculator_parse_arg.F90

@ -0,0 +1,55 @@
MODULE flux_calculator_parse_arg
IMPLICIT NONE
!!!!!!!!!! FUNCTIONS DEFINED IN THIS MODULE
PUBLIC get_args
PUBLIC find_argument
!!!!!!!!!! NOW EVERYTHING ELSE
INTEGER , SAVE :: num_args = -1
CHARACTER(len=64), DIMENSION(:), ALLOCATABLE, SAVE :: args
CONTAINS
SUBROUTINE get_args()
INTEGER :: ix
IF (num_args /= -1) THEN
RETURN
ENDIF
num_args = command_argument_count()
IF (num_args == 0) THEN
RETURN
ENDIF
ALLOCATE(args(num_args))
DO ix = 1, num_args
CALL get_command_argument(ix,args(ix))
ENDDO
END SUBROUTINE get_args
FUNCTION find_argument(argument) RESULT(found)
CHARACTER(*), INTENT(IN) :: argument
LOGICAL :: found
INTEGER :: ix
found = .FALSE.
CALL get_args()
DO ix = 1, num_args
IF (TRIM(args(ix)) == TRIM(argument)) THEN
found = .TRUE.
RETURN
ENDIF
ENDDO
END FUNCTION find_argument
END MODULE flux_calculator_parse_arg
Loading…
Cancel
Save