123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
- !
- ! This program creates a remapping grid file for Gaussian lat/lon
- ! grids (for spectral transform codes).
- !
- !-----------------------------------------------------------------------
- !
- ! CVS:$Id: convertgauss.f,v 1.3 2000/04/19 22:05:57 pwjones Exp $
- !
- ! Copyright (c) 1997, 1998 the Regents of the University of
- ! California.
- !
- ! Unless otherwise indicated, this software has been authored
- ! by an employee or employees of the University of California,
- ! operator of the Los Alamos National Laboratory under Contract
- ! No. W-7405-ENG-36 with the U.S. Department of Energy. The U.S.
- ! Government has rights to use, reproduce, and distribute this
- ! software. The public may copy and use this software without
- ! charge, provided that this Notice and any statement of authorship
- ! are reproduced on all copies. Neither the Government nor the
- ! University makes any warranty, express or implied, or assumes
- ! any liability or responsibility for the use of this software.
- !
- !***********************************************************************
- program convert_gauss
- !-----------------------------------------------------------------------
- !
- ! This file creates a remapping grid file for a Gaussian grid
- !
- !-----------------------------------------------------------------------
- use kinds_mod
- use constants
- use iounits
- use netcdf_mod
- implicit none
- !-----------------------------------------------------------------------
- !
- ! variables that describe the grid
- !
- ! T42: nx=128 ny=64
- ! T62: nx=192 ny=94
- !
- !-----------------------------------------------------------------------
- integer (kind=int_kind), parameter ::
- & nx = 192, ny = 94,
- & grid_size = nx*ny,
- & grid_rank = 2,
- & grid_corners = 4
- character(char_len), parameter ::
- & grid_name = 'T62 Gaussian Grid',
- & grid_file_out = 'remap_grid_T62.nc'
- integer (kind=int_kind), dimension(grid_rank) ::
- & grid_dims
- !-----------------------------------------------------------------------
- !
- ! grid coordinates and masks
- !
- !-----------------------------------------------------------------------
- integer (kind=int_kind), dimension(grid_size) ::
- & grid_imask
- real (kind=dbl_kind), dimension(grid_size) ::
- & grid_center_lat, ! lat/lon coordinates for
- & grid_center_lon ! each grid center in degrees
- real (kind=dbl_kind), dimension(grid_corners,grid_size) ::
- & grid_corner_lat, ! lat/lon coordinates for
- & grid_corner_lon ! each grid corner in degrees
- !-----------------------------------------------------------------------
- !
- ! other local variables
- !
- !-----------------------------------------------------------------------
- integer (kind=int_kind) :: i, j, iunit, atm_add
- integer (kind=int_kind) ::
- & ncstat, ! general netCDF status variable
- & nc_grid_id, ! netCDF grid dataset id
- & nc_gridsize_id, ! netCDF grid size dim id
- & nc_gridcorn_id, ! netCDF grid corner dim id
- & nc_gridrank_id, ! netCDF grid rank dim id
- & nc_griddims_id, ! netCDF grid dimension size id
- & nc_grdcntrlat_id, ! netCDF grid center lat id
- & nc_grdcntrlon_id, ! netCDF grid center lon id
- & nc_grdimask_id, ! netCDF grid mask id
- & nc_grdcrnrlat_id, ! netCDF grid corner lat id
- & nc_grdcrnrlon_id ! netCDF grid corner lon id
- integer (kind=int_kind), dimension(2) ::
- & nc_dims2_id ! netCDF dim id array for 2-d arrays
- real (kind=dbl_kind) :: dlon, minlon, maxlon, centerlon,
- & minlat, maxlat, centerlat
- real (kind=dbl_kind), dimension(ny) :: gauss_root, gauss_wgt
- !-----------------------------------------------------------------------
- !
- ! compute longitudes of cell centers and corners. set up alon
- ! array for search routine.
- !
- !-----------------------------------------------------------------------
- grid_dims(1) = nx
- grid_dims(2) = ny
- dlon = 360./nx
- do i=1,nx
- centerlon = (i-1)*dlon
- minlon = centerlon - half*dlon
- maxlon = centerlon + half*dlon
- do j=1,ny
- atm_add = (j-1)*nx + i
- grid_center_lon(atm_add ) = centerlon
- grid_corner_lon(1,atm_add) = minlon
- grid_corner_lon(2,atm_add) = maxlon
- grid_corner_lon(3,atm_add) = maxlon
- grid_corner_lon(4,atm_add) = minlon
- end do
- end do
- !-----------------------------------------------------------------------
- !
- ! compute Gaussian latitudes and store in gauss_wgt.
- !
- !-----------------------------------------------------------------------
- call gquad(ny, gauss_root, gauss_wgt)
- do j=1,ny
- gauss_wgt(j) = pih - gauss_root(ny+1-j)
- end do
- !-----------------------------------------------------------------------
- !
- ! compute latitudes at cell centers and corners. set up alat
- ! array for search routine.
- !
- !-----------------------------------------------------------------------
- do j=1,ny
- centerlat = gauss_wgt(j)
- if (j .eq. 1) then
- minlat = -pih
- else
- minlat = ATAN((COS(gauss_wgt(j-1)) -
- & COS(gauss_wgt(j )))/
- & (SIN(gauss_wgt(j )) -
- & SIN(gauss_wgt(j-1))))
- endif
- if (j .eq. ny) then
- maxlat = pih
- else
- maxlat = ATAN((COS(gauss_wgt(j )) -
- & COS(gauss_wgt(j+1)))/
- & (SIN(gauss_wgt(j+1)) -
- & SIN(gauss_wgt(j ))))
- endif
- do i=1,nx
- atm_add = (j-1)*nx + i
- grid_center_lat(atm_add ) = centerlat*360./pi2
- grid_corner_lat(1,atm_add) = minlat*360./pi2
- grid_corner_lat(2,atm_add) = minlat*360./pi2
- grid_corner_lat(3,atm_add) = maxlat*360./pi2
- grid_corner_lat(4,atm_add) = maxlat*360./pi2
- end do
- end do
- !-----------------------------------------------------------------------
- !
- ! define mask
- !
- !-----------------------------------------------------------------------
- grid_imask = 1
- !-----------------------------------------------------------------------
- !
- ! set up attributes for netCDF file
- !
- !-----------------------------------------------------------------------
- !***
- !*** create netCDF dataset for this grid
- !***
- ncstat = nf_create (grid_file_out, NF_CLOBBER,
- & nc_grid_id)
- call netcdf_error_handler(ncstat)
- ncstat = nf_put_att_text (nc_grid_id, NF_GLOBAL, 'title',
- & len_trim(grid_name), grid_name)
- call netcdf_error_handler(ncstat)
- !***
- !*** define grid size dimension
- !***
- ncstat = nf_def_dim (nc_grid_id, 'grid_size', grid_size,
- & nc_gridsize_id)
- call netcdf_error_handler(ncstat)
- !***
- !*** define grid corner dimension
- !***
- ncstat = nf_def_dim (nc_grid_id, 'grid_corners', grid_corners,
- & nc_gridcorn_id)
- call netcdf_error_handler(ncstat)
- !***
- !*** define grid rank dimension
- !***
- ncstat = nf_def_dim (nc_grid_id, 'grid_rank', grid_rank,
- & nc_gridrank_id)
- call netcdf_error_handler(ncstat)
- !***
- !*** define grid dimension size array
- !***
- ncstat = nf_def_var (nc_grid_id, 'grid_dims', NF_INT,
- & 1, nc_gridrank_id, nc_griddims_id)
- call netcdf_error_handler(ncstat)
- !***
- !*** define grid center latitude array
- !***
- ncstat = nf_def_var (nc_grid_id, 'grid_center_lat', NF_DOUBLE,
- & 1, nc_gridsize_id, nc_grdcntrlat_id)
- call netcdf_error_handler(ncstat)
- ncstat = nf_put_att_text (nc_grid_id, nc_grdcntrlat_id, 'units',
- & 7, 'degrees')
- call netcdf_error_handler(ncstat)
- !***
- !*** define grid center longitude array
- !***
- ncstat = nf_def_var (nc_grid_id, 'grid_center_lon', NF_DOUBLE,
- & 1, nc_gridsize_id, nc_grdcntrlon_id)
- call netcdf_error_handler(ncstat)
- ncstat = nf_put_att_text (nc_grid_id, nc_grdcntrlon_id, 'units',
- & 7, 'degrees')
- call netcdf_error_handler(ncstat)
- !***
- !*** define grid mask
- !***
- ncstat = nf_def_var (nc_grid_id, 'grid_imask', NF_INT,
- & 1, nc_gridsize_id, nc_grdimask_id)
- call netcdf_error_handler(ncstat)
- ncstat = nf_put_att_text (nc_grid_id, nc_grdimask_id, 'units',
- & 8, 'unitless')
- call netcdf_error_handler(ncstat)
- !***
- !*** define grid corner latitude array
- !***
- nc_dims2_id(1) = nc_gridcorn_id
- nc_dims2_id(2) = nc_gridsize_id
- ncstat = nf_def_var (nc_grid_id, 'grid_corner_lat', NF_DOUBLE,
- & 2, nc_dims2_id, nc_grdcrnrlat_id)
- call netcdf_error_handler(ncstat)
- ncstat = nf_put_att_text (nc_grid_id, nc_grdcrnrlat_id, 'units',
- & 7, 'degrees')
- call netcdf_error_handler(ncstat)
- !***
- !*** define grid corner longitude array
- !***
- ncstat = nf_def_var (nc_grid_id, 'grid_corner_lon', NF_DOUBLE,
- & 2, nc_dims2_id, nc_grdcrnrlon_id)
- call netcdf_error_handler(ncstat)
- ncstat = nf_put_att_text (nc_grid_id, nc_grdcrnrlon_id, 'units',
- & 7, 'degrees')
- call netcdf_error_handler(ncstat)
- !***
- !*** end definition stage
- !***
- ncstat = nf_enddef(nc_grid_id)
- call netcdf_error_handler(ncstat)
- !-----------------------------------------------------------------------
- !
- ! write grid data
- !
- !-----------------------------------------------------------------------
- ncstat = nf_put_var_int(nc_grid_id, nc_griddims_id, grid_dims)
- call netcdf_error_handler(ncstat)
- ncstat = nf_put_var_int(nc_grid_id, nc_grdimask_id, grid_imask)
- call netcdf_error_handler(ncstat)
- ncstat = nf_put_var_double(nc_grid_id, nc_grdcntrlat_id,
- & grid_center_lat)
- call netcdf_error_handler(ncstat)
- ncstat = nf_put_var_double(nc_grid_id, nc_grdcntrlon_id,
- & grid_center_lon)
- call netcdf_error_handler(ncstat)
- ncstat = nf_put_var_double(nc_grid_id, nc_grdcrnrlat_id,
- & grid_corner_lat)
- call netcdf_error_handler(ncstat)
- ncstat = nf_put_var_double(nc_grid_id, nc_grdcrnrlon_id,
- & grid_corner_lon)
- call netcdf_error_handler(ncstat)
- ncstat = nf_close(nc_grid_id)
- call netcdf_error_handler(ncstat)
- !-----------------------------------------------------------------------
- end program convert_gauss
- !***********************************************************************
- subroutine gquad(l,root,w)
- !-----------------------------------------------------------------------
- !
- ! This subroutine finds the l roots (in theta) and gaussian weights
- ! associated with the legendre polynomial of degree l > 1.
- !
- !-----------------------------------------------------------------------
- use kinds_mod
- use constants
- implicit none
- !-----------------------------------------------------------------------
- !
- ! intent(in)
- !
- !-----------------------------------------------------------------------
- integer (kind=int_kind), intent(in) :: l
- !-----------------------------------------------------------------------
- !
- ! intent(out)
- !
- !-----------------------------------------------------------------------
- real (kind=dbl_kind), dimension(l), intent(out) ::
- & root, w
- !-----------------------------------------------------------------------
- !
- ! local
- !
- !-----------------------------------------------------------------------
- integer (kind=int_kind) :: l1, l2, l22, l3, k, i, j
- real (kind=dbl_kind) ::
- & del,co,p1,p2,p3,t1,t2,slope,s,c,pp1,pp2,p00
- !-----------------------------------------------------------------------
- !
- ! Define useful constants.
- !
- !-----------------------------------------------------------------------
- del= pi/float(4*l)
- l1 = l+1
- co = float(2*l+3)/float(l1**2)
- p2 = 1.0
- t2 = -del
- l2 = l/2
- k = 1
- p00 = one/sqrt(two)
- !-----------------------------------------------------------------------
- !
- ! Start search for each root by looking for crossing point.
- !
- !-----------------------------------------------------------------------
- do i=1,l2
- 10 t1 = t2
- t2 = t1+del
- p1 = p2
- s = sin(t2)
- c = cos(t2)
- pp1 = 1.0
- p3 = p00
- do j=1,l1
- pp2 = pp1
- pp1 = p3
- p3 = 2.0*sqrt((float(j**2)-0.250)/float(j**2))*c*pp1-
- & sqrt(float((2*j+1)*(j-1)*(j-1))/
- & float((2*j-3)*j*j))*pp2
- end do
- p2 = pp1
- if ((k*p2).gt.0) goto 10
- !-----------------------------------------------------------------------
- !
- ! Now converge using Newton-Raphson.
- !
- !-----------------------------------------------------------------------
- k = -k
- 20 continue
- slope = (t2-t1)/(p2-p1)
- t1 = t2
- t2 = t2-slope*p2
- p1 = p2
- s = sin(t2)
- c = cos(t2)
- pp1 = 1.0
- p3 = p00
- do j=1,l1
- pp2 = pp1
- pp1 = p3
- p3 = 2.0*sqrt((float(j**2)-0.250)/float(j**2))*c*pp1-
- & sqrt(float((2*j+1)*(j-1)*(j-1))/
- & float((2*j-3)*j*j))*pp2
- end do
- p2 = pp1
- if (abs(p2).gt.1.e-10) goto 20
- root(i) = t2
- w(i) = co*(sin(t2)/p3)**2
- end do
- !-----------------------------------------------------------------------
- !
- ! If l is odd, take care of odd point.
- !
- !-----------------------------------------------------------------------
- l22 = 2*l2
- if (l22 .ne. l) then
- l2 = l2+1
- t2 = pi/2.0
- root(l2) = t2
- s = sin(t2)
- c = cos(t2)
- pp1 = 1.0
- p3 = p00
- do j=1,l1
- pp2 = pp1
- pp1 = p3
- p3 = 2.0*sqrt((float(j**2)-0.250)/float(j**2))*c*pp1-
- & sqrt(float((2*j+1)*(j-1)*(j-1))/
- & float((2*j-3)*j*j))*pp2
- end do
- p2 = pp1
- w(l2) = co/p3**2
- endif
- !-----------------------------------------------------------------------
- !
- ! Use symmetry to compute remaining roots and weights.
- !
- !-----------------------------------------------------------------------
- l3 = l2+1
- do i=l3,l
- root(i) = pi-root(l-i+1)
- w(i) = w(l-i+1)
- end do
- !-----------------------------------------------------------------------
- end subroutine gquad
- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|