Scheduled Downtime
On Tuesday 24 October 2023 @ 5pm MT the forums will be in read only mode in preparation for the downtime. On Wednesday 25 October 2023 @ 5am MT, this website will be down for maintenance and expected to return online later in the morning.
Normal Operations
The forums are back online with normal operations. If you notice any issues or errors related to the forums, please reach out to help@ucar.edu

How to know how a variable (in the MASTERFIELD list) is calculated?

pybl

Binghan Liu
Member
Hello,

I am wondering how to know how a variable (in the MASTERFIELD list) is calculated in CESM2?

For example, I am interested in plotting the albedo, and I found ASDIR and ASDIF but their descriptions are too brief to understand how they are calculated.

call addfld ('ASDIR', '1', 1, 'A','albedo: shortwave, direct', phys_decomp)
call addfld ('ASDIF', '1', 1, 'A','albedo: shortwave, diffuse', phys_decomp)

I have tried looking into the source code, but it seems ASDIR/ASDIF are 'merged state of sea-ice, land and ocean parametrization', and unfortunately I did not find how they are computed. The question is that I want to figure out how these two variables are different from the bond albedo computed by FSUTOA/FSNT (upwelling short wave/total incident wave at the top of atmosphere).

Thank you for your help in advance!
 

brianpm

Active Member
The answer to your specific question, "what is the difference between ASDIR and ASDIF and the TOA albedo?" is that they are different quantities. ASDIR and ASDIF are the *surface* albedo, for direct and diffuse visible radiation, respectively. The planetary albedo, calculated from the fluxes at the top of the model include atmospheric scattering, including clouds, and so is very different from the surface albedo.

The answer to your more general question, the title of the topic here, is much more difficult to answer. There are a number of strategies, but ultimately the solution is to carefully read the source code. For this example, one could start by going into the CAM source code and doing a search for ASDIR or ASDIFF:
Code:
grep -Iinr --exclude="*.svn*" "ASDIR" .
is how I just did it.

That is just the beginning, since often the name shows up in many files. Where I usually start is by finding the OUTFLD call, which is where the field gets written to the history file. In this case, it's in cam_diagnostics:
Code:
./physics/cam/cam_diagnostics.F90:1810:      call outfld('ASDIR',    cam_in%asdir,     pcols, lchnk)
Inspection there just shows that this is a convenience function, as it is just writing output from the cam_in data structure, so then I would look for where this subroutine is called:
Code:
$ grep -Iinr --exclude="*.svn*" "call diag_surf" .
./physics/simple/physpkg.F90:616:    call diag_surf(cam_in, cam_out, state, pbuf)
./physics/cam/physpkg.F90:1170:       call diag_surf(cam_in(c), cam_out(c), phys_state(c), phys_buffer_chunk)

That's always discouraging because physpkg is the high-level driver for the whole physics package. In this specific case, however, it's pretty telling that the routine is called diag_surf, but that might not always be the case. Reading around this part of CAM's physpkg, we would find that this call is in the subroutine phys_run2, and more closely looking shows that diag_surf happens just before tphysac. That's the physics that happens "after coupling". That leaves us with the question still of where asdir came from that goes into phys_run2. Another grep and we see that phys_run2 is called by cam_run2; that subroutine has a useful comment at the top:
Code:
!-----------------------------------------------------------------------
!
! Purpose:   Second phase of atmosphere model run method.
!            Run the second phase physics, run methods that
!            require the surface model updates.  And run the
!            second phase of dynamics that at least couples
!            between physics to dynamics.
!
!-----------------------------------------------------------------------
This is a strong hint that the albedo must involve the surface models and/or the coupler. It can be complicated to track things back through the coupler. Some additional inspection shows that asdir variable comes into CAM from the coupler in the atm_import subroutine of atm_import_export.F90.
Code:
cam_in(c)%asdir(i)     =  x2a(index_x2a_Sx_avsdr, ig)
And that index is mapped to the coupler's data structure in cam_cpl_indices.F90, it's called
Code:
'Sx_avsdr'

At this point, it really becomes hard (for me at least) to follow all the paths. I think for this case, each component model is responsible for getting the surface albedos and passing them to the coupler where they get merged into the field that CAM imports. Finding the individual calculations takes a lot of time for various reasons, including the different styles that are used in the different component models.

One place where the calculation is more straightforward is for the ocean albedo. To see this, look at seq_flux_ocnalb_mct in cime/src/drivers/mct/main/seq_flux_mct.F90. This calculation is called from cime_comp_mod. Even here, there is a lot of logic that directs the calculation. One interesting bit in this case is that if calculation is done here for the direct beam albedo, the diffuse albedo must still come from the namelist, and it looks like the default value is 0.06 (unless it is an aquaplanet compset, in which case it is 0.07). Both can be specified in the driver namelist however, as seq_flux_mct_albdif and seq_flux_mct_albdir, and both have the same default values. Indeed, it looks like for common cases, like F2000climo, this is exactly how ASDIR and ASDIF are determined for ocean locations. Ice- and land-covered areas use their own calculations, as far as I can tell.
 

pybl

Binghan Liu
Member
Thank you for this detailed inspection!

It truly helps to see how others tackle the problem step by step.

I am just wondering why you check the subroutine called 'diag_surf' at the step after knowing ASDIR comes from cam_in data structure.
 

brianpm

Active Member
When I ran the first search:
Code:
grep -Iinr --exclude="*.svn*" "ASDIR" .

The output shows there are a bunch of files that mention "ASDIR" (case insensitive for this search). I know that when this shows up in an outfld call, that is where the variable on the history files is *really* being written, That's the best place to start tracing backward. In this case, the outfld call happens in
Code:
./physics/cam/cam_diagnostics.F90
at line 1810 (see above). Looking at that file, I find that the outfld call happens in a subroutine called diag_surf:

Code:
1717   subroutine diag_surf (cam_in, cam_out, state, pbuf)
   1718
   1719     !-----------------------------------------------------------------------
   1720     !
   1721     ! Purpose: record surface diagnostics
   1722     !
   1723     !-----------------------------------------------------------------------
   <snip>
   1804       call outfld('TBOT',     cam_out%tbot,     pcols, lchnk)
   1805       call outfld('TS',       cam_in%ts,        pcols, lchnk)
   1806       call outfld('TSMN',     cam_in%ts,        pcols, lchnk)
   1807       call outfld('TSMX',     cam_in%ts,        pcols, lchnk)
   1808       call outfld('SNOWHLND', cam_in%snowhland, pcols, lchnk)
   1809       call outfld('SNOWHICE', cam_in%snowhice,  pcols, lchnk)
   1810       call outfld('ASDIR',    cam_in%asdir,     pcols, lchnk)
   1811       call outfld('ASDIF',    cam_in%asdif,     pcols, lchnk)
   1812       call outfld('ALDIR',    cam_in%aldir,     pcols, lchnk)
   1813       call outfld('ALDIF',    cam_in%aldif,     pcols, lchnk)
   1814       call outfld('SST',      cam_in%sst,       pcols, lchnk)
   1815
   1816       if (co2_transport()) then
   1817         do m = 1,4
   1818           call outfld(sflxnam(c_i(m)), cam_in%cflx(:,c_i(m)), pcols, lchnk)
   1819         end do
   1820       end if
   1821     end if
   1822
   1823   end subroutine diag_surf

From there, I just searched for where this subroutine is invoked, which is in the subroutine phys_run2 in the physkpg module.
 
Top