3.5.4
User-defined output quantities
A very typical request of users is the
calculation and
output of
quantities which are not part of PALM's standard output. The basic user
interface includes a number of subroutines which allow the calculation
of user-defined quantities and output of these quantities as 1.
(horizontally averaged) vertical
profiles, 2. time
series, 3. 2d cross
section or 3d volume data,
4. dvrp objects, and 5. spectra. The respective
subroutines
contain sample code lines (written as comment lines) for defining,
calculating and
output of such quantities.
Output times, averaging
intervals, etc. are steered by the same variables as used for the
standard PALM output quantities, e.g. dt_data_output.
The
following five parts of this chapter explains step-by-step how
to modify/extend the
respective default user interface subroutines in order to generate the respective
output:
- (horizontally averaged) vertical profiles,
- time series,
- 2d cross
section or 3d
volume data,
- dvrp objects,
and
- spectra.
1. Output of user-defined
vertical profiles
This example shows the output of the
quantity "turbulent resolved-scale horizontal momentum flux" (u*v*). If
more than one user-defined
quantity shall be output, the following steps have to be carried out in
the
same way for each of the quantities.
- The
quantity has to be given a unique string identifier, e.g. 'u*v*'.
This identifier must be different from the identifiers used for the
PALM standard output (see list in description of parameter data_output_pr).
To switch on output of this quantity, the user has to assign the string
identifier to the parameter data_output_pr_user,
eg.:
data_output_pr_user = 'u*v*',
- For
the
quantity, an identification number, a physical unit, and the vertical
grid on which it is defined (u- or w-grid), has to be assigned
(subroutine user_check_data_output_pr):
CASE (
'u*v*' )
index = pr_palm + 1
! identification number
dopr_index(var_count) = index
dopr_unit(var_count) = 'm2/s2'
!
physical unit
hom(:,2,index,:) = SPREAD( zu, 2,
statistic_regions+1 ) ! vertical grid
Here
only the those parts in red
color have to be given by the user appropriately.
The
identification number (index)
must be within the range [
pr_palm+1 , pr_palm+max_pr_user ], where max_pr_user
is the number of user-defined profiles as given by parameter data_output_pr_user
in the respective PALM run. The physical unit has to be given
with respect to the NetCDF conventions. If no unit is given,
PALM will abort. The vertical grid has to be either zu
(u-grid) or zw
(w-grid).
- The quantity has to
be calculated for all gridpoints (subroutine user_statistics):
!$OMP
DO
DO i = nxl, nxr
DO j = nys, nyn
DO k = nzb_s_inner(j,i)+1, nzt
sums_l(k,pr_palm+1,tn)
= sums_l(k,pr_palm+1,tn)
+
&
( 0.5 * ( u(k,j,i) +
u(k,j,i+1) ) - hom(k,1,1,sr) ) * &
( 0.5 * ( v(k,j,i) + v(k,j+1,i) ) - hom(k,1,2,sr) ) &
* rmask(j,i,sr)
ENDDO
ENDDO
ENDDO
Once again, only those parts
in red
have to be adjusted by the user.
The
turbulent resolved-scale momentum flux u*v* is defined as the product
of the deviations of the horizontal velocities from their respective
horizontally averaged mean values. These mean values are stored in
array hom(..,1,1,sr)
and hom(..,1,2,sr)
for the u- and v-component, respectively. Since due to the staggered
grid, u
and v
are not defined at the same gridpoints, they have to be interpolated
appropriately (here to the center of the gridbox). The result of the
calculation is stored in array sums_l.
The second index of this array is the identification number of the
profile which must match the one given in the previous step 2.
2. Output of user-defined
timeseries
This example shows the output of two time series
for the absolut extremal values of the horizontal velocities u and v. If more than one
user-defined
quantity shall be output, the following steps have to be carried out in
the
same way for each of the quantities.
- For
each time series quantity you have to give a label and a unit
(subroutine user_init),
which will be used for the NetCDF file. They must not contain more than
seven characters. The value of
dots_num
has
to be increased by the number of new time series quantities. Its old
value has to be stored in dots_num_palm
.
dots_label(dots_num+1)
= 'abs_umx'
dots_unit(dots_num+1)
= 'm/s'
dots_label(dots_num+2)
= 'abs_vmx'
dots_unit(dots_num+2)
= 'm/s'
dots_num_palm = dots_num
dots_num = dots_num +
2
Only those parts in red have to be
adjusted by the user.
- These
quantities are calculated and output in subroutine user_statistics
for every statistic region
sr
defined by the
user, but at least for the region "total domain":
ts_value(dots_num_palm+1,sr) = ABS( u_max )
ts_value(dots_num_palm+2,sr) = ABS( v_max )
3.
Output of user-defined 2d cross sections or 3d volume data
This
example shows the output of the
quantity "square of the u-component" (Note: this quantity
could of course easily be calculated from the u-component by
postprocessing the PALM output so that calculation within PALM is not
necessarily required). If more than one user-defined
quantity shall be output, the following steps have to be carried out in
the
same way for each of the quantities.
- The
quantity has to be given a unique string identifier, e.g. 'u2'.
This identifier must be different from the identifiers used for the
PALM standard output (see list in description of parameter data_output).
To switch on output of this quantity, the user has to assign the string
identifier to the parameter data_output_user,
eg.:
data_output_user = 'u2', 'u2_xy_av'
The
pure string 'u2'
switches on the output of instantaneous 3d volume data. Output of cross
section data and time averaged data is switched on by additionally
appending the strings '_xy',
'_xz', '_yz', and/or '_av' (for a
detailed explanation see parameter data_output).
- In
order to store the quantities' grid point data within PALM, a 3d data
array has to be declared in module user:
REAL,
DIMENSION(:,:,:), ALLOCATABLE :: u2, u2_av
The
second array u2_av
is needed in case that output of time averaged data is requested. It is
used to store the sum of the data of the respective time levels over
which the average has to be carried out.
- The
data array has to be allocated in subroutine user_init:
ALLOCATE( u2(nzb:nzt+1,nys-1:nyn+1,nxl-1:nxr+1) )
In
case that output of time averaged data is requested, the array
containing the sum has possibly to be read from the restart file (local
filename BININ)
by executing the following code in user_init:
IF ( initializing_actions == 'read_restart_data' )
THEN
READ ( 13 ) field_char
DO WHILE ( TRIM( field_char ) /= '*** end
user ***' )
SELECT CASE ( TRIM( field_char ) )
CASE ( 'u2_av' )
ALLOCATE(
u2_av(nzb:nzt+1,nys-1:nyn+1,nxl-1:nxr+1) )
READ ( 13 ) u2_av
CASE DEFAULT
PRINT*,
'+++ user_init: unknown
variable named "', &
TRIM( field_char ), '" found in'
PRINT*,
'
data from prior run on PE ', myid
CALL local_stop
END SELECT
ENDDO
ENDIF
- The
quantity has to be given a unit (subroutine user_check_data_output):
CASE (
'u2' )
unit = 'm2/s2'
Otherwise,
PALM will abort.
- The
vertical grid on which the quantity is defined (given by the levels
'zu' or 'zw', on which the u- or w-component of the velocity are
defined) has to be specified for the NetCDF output files in subroutine user_define_netcdf_grid:
CASE ( 'u2', 'u2_xy', 'u2_xz', 'u2_yz' )
grid = 'zu'
As
the example shows, this grid has to be defined for the 3d volume data
as well as for all of the three cross sections.
- After
each timestep, the quantity has to be calculated at all gridpoints and
to be stored. This has to be done in subroutine user_actions
at location 'after_integration':
CASE
( 'after_integration' )
!
!--
Enter actions to be done after every time integration (before
!--
data output)
!--
Sample for user-defined output:
DO i = nxl-1, nxr+1
DO j = nys-1, nyn+1
DO k = nzb, nzt+1
u2(k,j,i) = u(k,j,i)**2
ENDDO
ENDDO
ENDDO
- In
case that output of time-averaged data is requested, the sum- and
average-operations as well as the allocation of the sum-array have to
be carried out in subroutine user_3d_data_averaging:
IF ( mode == 'allocate' ) THEN
...
CASE ( 'u2' )
IF ( .NOT. ALLOCATED( u2_av ) ) THEN
ALLOCATE( u2_av(nzb:nzt+1,nys-1:nyn+1,nxl-1:nxr+1) )
ENDIF
u2_av = 0.0
...
ELSEIF ( mode == 'sum' ) THEN
...
CASE
( 'u2' )
DO i = nxl-1, nxr+1
DO j = nys-1, nyn+1
DO k = nzb, nzt+1
u2_av(k,j,i) = u2_av(k,j,i) + u2(k,j,i)
ENDDO
ENDDO
ENDDO
...
ELSEIF ( mode == 'average' ) THEN
...
CASE
( 'u2' )
DO i = nxl-1, nxr+1
DO j = nys-1, nyn+1
DO k = nzb, nzt+1
u2_av(k,j,i) = u2_av(k,j,i) / REAL( average_count_3d )
ENDDO
ENDDO
ENDDO
- For
output of 2d cross sections, the gridpoint data of the quantity has to
be resorted to array local_pf
in subroutine user_data_output_2d.
Also the vertical grid, on which the quantity is defined, has to be set
again:
CASE
( 'u2_xy', 'u2_xz', 'u2_yz' )
IF ( av == 0 ) THEN
DO i = nxl-1, nxr+1
DO j = nys-1, nyn+1
DO k = nzb, nzt+1
local_pf(i,j,k) = u2(k,j,i)
ENDDO
ENDDO
ENDDO
ELSE
DO i = nxl-1, nxr+1
DO j = nys-1, nyn+1
DO k = nzb, nzt+1
local_pf(i,j,k) = u2_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
grid = 'zu'
The ELSE case is
only needed in case that output of time-averaged data is requested.
As a special case, xy cross section output can also be defined at one single level at height k=nzb+1
on the u-grid. This features is useful for output of surface data (e.g.
heat fluxes). In this case, the corresponding 2d data has to be
resorted to the array local_pf(i,j,nzb+1). In addition to this, the grid in user_define_netcdf_grid as well as in user_data_output_2d must be set to grid = 'zu1'.
CASE
( 'u2_xy' )
IF ( av == 0 ) THEN
DO i = nxl-1, nxr+1
DO j = nys-1, nyn+1
local_pf(i,j,nzb+1) = u2(j,i)
ENDDO
ENDDO
ELSE
DO i = nxl-1, nxr+1
DO j = nys-1, nyn+1
local_pf(i,j,nzb+1) = u2_av(j,i)
ENDDO
ENDDO
ENDIF
grid = 'zu1'
two_d = .TRUE.
Note that two_d = .TRUE. is necessary for output of a 2d data slice.
- For
output of 3d volume data, the gridpoint data of the quantity has to be
resorted to array local_pf
in subroutine user_data_output_3d.:
CASE
( 'u2' )
IF ( av == 0 ) THEN
DO i = nxl-1, nxr+1
DO j = nys-1, nyn+1
DO k = nzb, nz_do
local_pf(i,j,k) = u2(k,j,i)
ENDDO
ENDDO
ENDDO
ELSE
DO i = nxl-1, nxr+1
DO j = nys-1, nyn+1
DO k = nzb, nz_do
local_pf(i,j,k) = u2_av(k,j,i)
ENDDO
ENDDO
ENDDO
ENDIF
The ELSE case is
only needed in case that output of time-averaged data is requested.
- In
case of job chains, the sum array has to be written to the (binary)
restart file (local filename BINOUT)
in subroutine user_last_actions:
IF ( ALLOCATED( u2_av ) ) THEN
WRITE ( 14 )
'u2_av
'; WRITE ( 14 ) u2_av
ENDIF
Otherwise,
the calculated
time-average may be wrong. In the restart run, this quantity has to be
read from the restart file by including the following code in
subroutine user_read_restart_data:
IF ( initializing_actions == 'read_restart_data' ) THEN
READ ( 13 ) field_char
DO WHILE ( TRIM( field_char ) /= '*** end user ***' )
SELECT CASE ( TRIM( field_char ) )
CASE ( 'u2_av' )
IF ( .NOT. ALLOCATED( u2_av ) ) THEN
ALLOCATE( u2_av(nzb:nzt+1,nys-1:nyn+1,nxl-1:nxr+1) )
ENDIF
READ ( 13 ) tmp_3d
u2_av(:,nysc-1:nync+1,nxlc-1:nxrc+1) = &
tmp_3d(:,nysf-1:nynf+1,nxlf-1:nxrf+1)
CASE DEFAULT
PRINT*, '+++ user_init: unknown variable named "', &
TRIM( field_char ), '" found in'
PRINT*,
'
data from prior run on PE ', myid
CALL local_stop
END SELECT
READ ( 13 ) field_char
ENDDO
ENDIF
4. Output of user-defined DVRP objects
This
example shows the output of the
quantity "square of the u-component", u2.
If more than one user-defined
quantity shall be output, the following steps have to be carried out in
the
same way for each of the quantities. First, steps 1 - 6
of part 3. (2d cross
section or 3d
volume data) are required. Second, the gridpoint
data
of the quantity has to
be resorted to array local_pf
in subroutine user_data_output_dvrp
as follows:
CASE ( 'u2',
'u2_xy',
'u2_xz',
'u2_yz'
)
DO i = nxl, nxr+1
DO j = nys, nyn+1
DO k = nzb, nz_do3d
local_pf(i,j,k) = u2(k,j,i)
ENDDO
ENDDO
ENDDO
Only those parts in red have to be
adjusted by the user.
After performing these steps,
the user-defined quantity 'u2'
can be
selected like standard model quantities by the dvrp_graphics
package parameter mode_dvrp.
5. Output of user-defined spectra
This
example shows the output of the
quantity "turbulent resolved-scale horizontal momentum flux" (u*v*). If
more than one user-defined
quantity shall be output, the following steps have to be carried out in
the
same way for each of the quantities.
- The
calculation of user-defined spectra is closely linked with the
calculation of part 1.
(user-defined
vertical
profiles) and part 3. (user-defined 3d volume data). Therefore, the
following prerequisites apply
for each user-defined
spectra quantity:
- From part 1.
(user-defined
vertical
profiles)
steps 2 and 3.
See the sample code (as comment lines) for 'u*v*' and ustvst
,
respectively. (Actual output of vertical profiles - step 1 - is not
required.) - From part 3. (user-defined 3d volume data) steps 2, 3,
4, 5, and 6.
See the sample code (as comment lines) for 'u*v*' and ustvst
,
respectively. (Actual output of 3d volume data - step 1 - is not
required.) - The quantity has to be given a unique
string identifier, e.g. 'u*v*'.
This identifier must be different from the identifiers used for the
PALM standard output (see list in description of package parameter data_output_sp).
To switch on output of this quantity, the user has to assign the string
identifier to the package parameter data_output_sp,
eg.:
data_output_sp = 'u*v*'
A.
and B. as prerequisites for C. require a naming convention of identical
identifiers, e.g. data_output_pr_user = 'u*v*', data_output_user =
'u*v*' and data_output_sp = 'u*v*'. This naming convention applies only
in case of user-defined spectra.
- Edit
the subroutine user_spectra
(only those parts in red)
as follows:
IF ( mode == 'preprocess' ) THEN
SELECT CASE ( TRIM( data_output_sp(m) ) )
CASE ( 'u', 'v', 'w', 'pt', 'q' )
!--
Not allowed here since these are the standard quantities used in
!--
preprocess_spectra.
CASE ( 'u*v*' )
pr = pr_palm+1
d(nzb+1:nzt,nys:nyn,nxl:nxr) = ustvst(nzb+1:nzt,nys:nyn,nxl:nxr)
CASE DEFAULT
PRINT*, '+++ user_spectra/preprocess: Spectra of ', &
TRIM( data_output_sp(m) ), ' can not be calculated'
END SELECT
ELSEIF (
mode == 'data_output' ) THEN
SELECT CASE ( TRIM( data_output_sp(m) ) )
CASE ( 'u', 'v', 'w', 'pt', 'q' )
!--
Not allowed here since these are the standard quantities used in
!--
data_output_spectra.
CASE ( 'u*v*' )
pr = 6
CASE DEFAULT
PRINT*, '+++ user_spectra/data_output: Spectra of ', &
TRIM( data_output_sp(m) ), ' are not defined'
END SELECT
ENDIF
Note
that spectra output is an optional
software package (see chapter
3.7). Therefore user-defined spectra also require the package
activation via mrun -p spectra
.
Last
change: $Id: chapter_3.5.4.html 136 2007-11-26
02:47:32Z letzel $