Adding a Microphysics Variable to wrfout John D McMillen This document describes the programming required to extract a local microphysics variable from within a microphysics scheme in the WRF_ARW and add the local variable to the standard wrfout variable set. In addition, I will outline the process and coding I used to extract a local variable. It will also highlight difficulties I encountered while programming the WRF to perform this task. Resources To start, here are some resources I found very useful in understanding the WRF and my problem in particular. http://www.mmm.ucar.edu/wrf/users/tutorial/201207/WRF_Registry_and_Examples.pdf The link above points to a pdf file that describes the Registry and in slides 54-66 provides step-by-step instructions for creating a new array from existing microphysics data. I recommend programming this array by following the instructions to help you understand the WRF data-handling process. (Note I used version 3.4 of the WRF_ARW and the guide was created for a different version. At one point it adds the new array to the call for the microphysics driver within a Fortran file called first_rk_step_part1.F. In my version of WRF the call for the microphysics driver was in solve_em.F) http://www.mmm.ucar.edu/wrf/users/tutorial/tutorial_presentation_summer_2012.htm The link above has several presentations describing the WRF model. I recommend reading the presentation entitled architecture. The architecture presentation describes the domain, patch, and tile system which allows for parallel processing and which is used to define the dimensions of the various arrays passed through the WRF processing system. I will try to clear that up below when I talk about the programming I did. http://forum.wrfforum.com/index.php The link above is for the WRF Forum. This was useful to search and find similar problems, and their solution. This particular thread was very similar to what I was trying to do: http://forum.wrfforum.com/viewtopic.php?f=9&t=3514 There were still differences, but I referred to this particular thread many times. General Process After researching the resources above, the first step is problem identification. In this case, identify the variable to include in the wrfout and the characteristics of the variable such as dimension, intent and type. Next, identify all of the code that must be changed to pass the variable out of the subroutine it exists in all the way to a routine or subroutine that operates on the domain/grid level. To pass the variable out of its subroutine, the relationship between the subroutine and other routines and subroutines must be known. Another significant consideration as the variable is passed up to the domain/grid level is any kind of dimension, intent, and/or type transformations that may be required or that occur to the variable along the way. Finally, the registry must be edited to add the new variable to the wrfout file. After identifying the problem and the aspects of the problem listed above, the various routines, subroutines, and the registry can be edited. Once editing is complete the WRF must be recompiled. In cases where the registry and/or the WRF code itself has been changed a full recompile must be done including the clean, configure and compile steps. Always write out the results of the recompile and search for severe or fatal errors. Also look in the main folder for the WRF executables. If there are no executables, another round of coding and a recompile will be required. Check the compile output to determine what compiling errors caused the compilation failure. Even if executables were created check the compile output for errors. If errors are present attempt to find and correct them. After recompiling, run the WRF to test the output. Based on my experience a run with the mpi command and a run without should be tested. For several of my iterations I successfully wrote my variable to the wrfout while running without the mpi command, but not when I ran the WRF with the mpi command. I am not sure why this occurred, furthermore I am not sure if I would trust the output from the run without the mpi command if the mpi run wouldn’t compute correctly. My Case I programmed the WRF to write the value of a microphysics tendency source term to the wrfout file. I first found the code for the microphysics scheme. All of the programming was done on select files within the WRFV3 folders (directories, sorry I started in windows gui land) listed below: drwxr-xr-x drwxr-xr-x drwxr-xr-x 2 u0758091 steenbur 2 u0758091 steenbur 2 u0758091 steenbur 8192 Feb 20480 Feb 4096 Feb 1 10:34 dyn_em 1 10:32 phys 1 10:23 Registry … The microphysics scheme is inside the phys folder and saved in a Fortran file called module_mp_thompson.F. Within the microphysics scheme are equations for the tendency of every microphysics species in the scheme. These equations are a sum of several source and sink terms. For example: qsten(k) = qsten(k) + (prs_iau(k) + prs_sde(k) & + prs_sci(k) + prs_scw(k) + prs_rcs(k) & + prs_ide(k) - prs_ihm(k) - prr_sml(k)) & * orho Here qsten(k) is the tendency of snow and the various terms on the RHS are the sources and sinks of snow due to various processes. I chose to write out prs_iau(k), which represents the auto-conversion of cloud ice to snow. Note that these variables are column arrays which are indicated by the (k), I will return to that point later. Now that I found the variable I wanted to write out, I needed to figure out how to pass the variable out from inside the microphysics scheme to the grid/domain. prs_iau is in module_mp_thompson.F but there are multiple subroutines in the file. I brute force traced the variable assignment and subroutine calls throughout the WRFV3 file structure. (A better method is the find command: find –iname “*.F” | xargs grep –iR what you want to find > find.txt After the command finishes running, open up the text file and there will be a list of everywhere the “what you want to find” is written in a .F file. You can use this to search for a variable or the scheme name or the name of a subroutine to find what other routines and subroutines reference it. Not all places that “what you want to find” is written will be relevant to this process, but if you don’t check them all out and make sure editing code and debugging will be painful. Remember you are looking for the most direct path from the variable of interest to the grid/domain level. Another good use of this tool is to find your variables if you need to eliminate them.) I found within module_mp_thompson.F there were two relevant subroutines, mp_thompson and mp_gt_driver. I also found that subroutine mp_gt_driver was called by subroutine microphysics_driver within module_microphysics_driver.F. I further found that subroutine microphysics_driver was called by subroutine solve_em within solve_em.F. solve_em.F works on variables at the grid level so I needed to pass prs_iau or its equivalent from subroutine mp_thompson through to subroutine solve_em to allow prs_iau or its equivalent to appear in the wrfout file. Passing prs_iau through each of these routines required me to edit variable declarations, subroutine assignments, and subroutine calls in each of these subroutines. In addition I needed to add prs_iau or its equivalent to the registry. Displayed roughly hierarchically the paragraph above looks like: solve_em.F {grid/domain operations} solve_em calls microphysics_driver module_microphysics_driver.F microphysics_driver calls mp_gt_driver module_mp_thompson.F mp_gt_driver calls mp_thompson {prs_iau locally defined} The last bit of preparation I needed to do before adjusting the code was to figure out the characteristics of the variable. This is the point I referenced earlier. Within subroutine mp_thompson, prs_iau(k) is declared as a local variable by the following statement: DOUBLE PRECISION, DIMENSION(kts:kte):: prs_iau The variable is a one-dimensional array of double precision values. The dimension is a vertical column indexed by tile indices. kts indicates the axis, k, the type of index, t for tile, and s indicates start while e indicates end. Here are the dimensions of the various data subdivisions as they appear in the variable call of subroutine mp_gt_driver ids,ide, jds,jde, kds,kde, & ims,ime, jms,jme, kms,kme, & its,ite, jts,jte, kts,kte, & ! domain dims ! memory dims ! tile dims (I think data stored and processed in the tile subdivision is usually created at the beginning of each time step and then deleted at the end of each time step. Data in the memory and domain subdivisions is usually carried from time step to time step. I know these subdivisions exist to ensure that the code can be run in parallel, but I do not quite understand how this is done. For example several times during my coding and debugging process I could compile correctly and run the WRF but the output from running WRF with mpi would be incorrect in strange ways {see the Problems I Encountered section for more details}. The output from runs without the mpi command seemed to be fine. The main point here is the need to establish what the variable characteristics are in order to compare them to similar variables, variables in the registry, and to facilitate any transformations if required.) In the registry folder, in a file called Registry.EM_COMMON, variables are defined and several columns of metadata exist describing the behavior of the variables. I noted that no double precision variables exist in the registry. Based on other variables in the Thompson scheme and the example from the resources section, I thought about how to establish my variable in the registry. Here are the metadata columns in the registry: <Table><Type><Sym><Dims><Use><NumTLev><Stagger><IO><DNAME><DESCRIP><UNITS> <Table> should be state. All grid/domain level variables are state. <Type> should be real because there are no double precision variables in the registry. This was my first transformation issue. I needed to convert from a double precision number to a real number at some point in the code as prs_iau passed out of the microphysics scheme. <Sym> is the variable name. My plan was to examine multiple microphysics schemes and extract the same source and sink terms from each. I decided to create a new variable name that could be tied to multiple microphysics schemes. I believe it also helps in dealing with the Type transformation. When my code is done I will not have one variable name associated with two different Types within the code. <Dims> are the dimensions of the variable. I needed to know the microphysics sources and sinks at every grid point. Therefore I needed a three dimensional array. This is the second transformation I had to make. prs_iau is one dimensional, but other variables output from the microphysics scheme are three dimensional so I needed to pay close attention to how the microphysics scheme changes the dimensions of its variables and either copy their approach or ensure my code is inside the schemes’ dimension transforming loop. <Use> associates the variable with groups of other variables. I found that I was unable to compile if it was not set to dyn_em. I do not know why. <NumTLev> I am not sure what this does. I used a dash. <Stagger> sets the variable on the momentum grid if X,Y, and/or Z are specified. I set a dash because moisture variables are not staggered. <IO> describes the input and output handling of the variable. I set the column to h for history. This will put the variable into the output stream. There are other options here, I know the i stands for input and r stands for restart. The resources listed above document other options for this column. <DNAME> sets the variable name as it will appear in the wrfout file. <DESCRIP> text description of the variable. <UNITS> text description of the variables’ units. After I chose a variable; traced its path through the WRF code; determined the need to add a variable in order to transform from the original variables dimension and type; and determined the characteristics of the final variable should be; I was ready to code. Here is the registry definition I added for my microphysics variable, iausn (sorry for the wrap around): <Table><Type><Sym><Dims><Use><NumTLev><Stagger><IO> <DNAME><DESCRIP><UNITS> state real iausn ikj dyn_em h "Ice Auto Snow" "Ice autoconverted to snow" "kg kg-1" Next I edited the subroutine solve_em in solve_em.F. solve_em.F is found in the dyn_em folder. I found and edited the call for subroutine microphysics_driver within the subroutine solve_em as below: CALL microphysics_driver( … & , iausn=grid%iausn & ) This call lists all of the variables used by microphysics_driver. As noted above iausn will need to come through this subroutine, so I added iausn to the call for microphysics_driver. The way variables are assigned at this level is by referencing them to the grid that is why the variable is assigned by iausn=grid%iausn. I added iausn to the end of the call. I don’t think position matters. This is all I had to do in the solve_em.F file. The next two files I edited are in the phys folder; module_microphysics_driver.F and module_mp_thompson.F. After opening module_microphysics_driver.F, I found and edited the subroutine microphysics_driver. First I added my variable to the subroutine microphysics_driver subroutine variable list: SUBROUTINE microphysics_driver( … ,iausn) & In the microphysics_driver subroutine I also declared iausn with the following statement: REAL,DIMENSION(ims:ime,kms:kme,jms:jme),INTENT(INOUT):: iausn Note: Type matches the registry, as do Dims, and Sym. The dimension type is memory. I chose memory because other variables that pass in and out of subroutines have memory dimensions. The INTENT(INOUT) portion of the declaration allows the variable to pass between subroutines. If no INTENT(XXX) statement is declared for a variable it is considered a local variable for the subroutine. I wanted iausn to pass through this subroutine so I declared INTENT(INOUT). The microphysics_driver subroutine includes a call to the mp_gt_driver subroutine. I needed to add iausn to the mp_gt_driver subroutine variable call list as well. I didn’t add iausn to the end of the call list in this subroutine, it’s in the middle, but I don’t think it makes a difference. The call list is below: CALL mp_gt_driver( … iausn=iausn, & & Next I opened module_mp_thompson.F to edit subroutine mp_gt_driver and subroutine mp_thompson. I added iausn to the subroutine mp_gt_driver variable list: SUBROUTINE mp_gt_driver(qv, qc, qr, qi, qs, qg, ni, nr, & … iausn) In addition I declared iausn in the subroutine mp_gt_driver variable declaration list. I also declared prs_iau, as a local variable in this subroutine so I could code the transformation of variable type and variable dimension. No INTENT(XXX) statement is declared for prs_iau so it is a local variable for the subroutine. REAL,DIMENSION(ims:ime, kms:kme, jms:jme),INTENT(INOUT):: iausn DOUBLE PRECISION, DIMENSION(kts:kte):: prs_iau I chose this subroutine as the step to make the transformation between iausn and prs_iau because the subroutine included code to perform variable dimension transformations for several other variables. I then examined the subroutine to determine where my code changes needed to be inserted and what they should look like. Here is an excerpt of the code without modification: … kmax_ni = 0 kmax_nr = 0 do i = 1, 256 mp_debug(i:i) = char(0) enddo j_loop: i_loop: do j = j_start, j_end do i = i_start, i_end pptrain = 0. pptsnow = 0. … do k = kts, kte t1d(k) = th(i,k,j)*pii(i,k,j) p1d(k) = p(i,k,j) … enddo call mp_thompson(qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & nr1d, t1d, p1d, dz1d, & pptrain, pptsnow, pptgraul, pptice, & kts, kte, dt, i) pcp_ra(i,j) = pptrain pcp_sn(i,j) = pptsnow … do k = kts, kte qv(i,k,j) = qv1d(k) qc(i,k,j) = qc1d(k) … write(mp_debug,*) 'WARNING, negative qc ', qc1d(k), ' at i,j,k=', i,j,k CALL wrf_debug(150, mp_debug) … enddo enddo i_loop enddo j_loop … END SUBROUTINE mp_gt_driver & I have added ellipsis to shorten the code into blocks, where the code within the blocks seem to perform similar functions. The functions of these code blocks are important because they reveal where my code edits should be placed. I believe my early attempts failed because my edits were not in the correct location in the code. The first block of code initializes several variables of various type and dimension to zero. The second block of code loops through the tile index (k) and equates a local onedimensional variable with a tile index of (k) to a non-local three-dimensional variable with a memory index of (i,k,j). This step is required because the subroutine mp_thompson operates in one dimension with a tile index of (k) and these variables are passed to the subroutine mp_thompson to compute the microphysics scheme. The next block of code is the call to the subroutine mp_thompson. All code after this call will have access to all of the variables produced by the subroutine mp_thompson. Any extraction of variables must occur after this block of code. In fact the two lines immediately following the close parentheses of the call and the next block of code do just that. The two lines immediately following the close parentheses of the call to the subroutine mp_thompson equate a local variable to a non-local variable that appears in the subroutine mp_thompson call statement. The next block of code is a loop through the tile index (k) and equates a non-local three-dimensional variable with a memory index of (i,k,j)to a local one-dimensional variable with a tile index of (k) that has been populated within the subroutine mp_thompson. This code is actually writing out the results of the scheme. Therefore, this block of code is the likely spot to transform prs_iau to iausn. The next three blocks of code are debugging of some sort; closing off the do loops; and the completion of the subroutine. With a rough understanding of how this subroutine worked I added my edited code to the subroutine. First I initialized my variable: iausn(i,k,j) = -999.9 I placed this bit of code in the first block at the very beginning of the subroutine outside of any loop structures. At first I attempted to initialize with a loop copied from the example in the resources section, but I did not get good results in wrfout if I ran the WRF with the mpi command. I believe my attempt at a loop approach to initialization failed because I didn’t use the correct index variables in the loop. Note that in block one above the i_loop and j_loop index through variables called i_start, i_end and j_start, j_end . Not shown in the excerpt are statements that set i_start, i_end and j_start, j_end equal to the general tile dimension variables its, ite and jts, jte. My point is to be aware of index assignments and try to use what is in the subroutine already or forgo them as I did. An example I found online was similar to my code above so I used it. With such an odd value I could easily tell if iausn had been written over by looking for values of -999.9 in my wrfout file. I did not edit anything in block two despite my need to transform my threedimensional variable to one dimension. The reason I didn’t edit at this step is because I would not be passing iausn into the subroutine mp_thompson. My next edit was in the block of code with the call to the subroutine mp_thompson: call mp_thompson(qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & nr1d, t1d, p1d, dz1d, & pptrain, pptsnow, pptgraul, pptice, & #ifdef WRF_CHEM rainprod1d, evapprod1d, & #endif kts, kte, dt, i, j,prs_iau) Note that the last variable in the call variable list is prs_iau. This variable must appear in the call variable list so that it can be passed out of the subroutine mp_thompson and manipulated in this subroutine mp_gt_driver. My final edit in subroutine mp_gt_driver is to actually assign the value of prs_iau to iausn. In the fourth block of code a loop through the tile index (k)equates a non-local three dimensional variable with a memory index of (i,k,j)to a local one dimensional variable with a tile index of (k) that has been populated within the subroutine mp_thompson. I took advantage of the existing loop and added a line within the loop to equate iausn to prs_iau as below: do k = kts, kte {EXISTING CODE} iausn(i,k,j) = prs_iau(k) … {EXISTING CODE} enddo {EXISTING CODE} This code completed the transformation of iausn in both dimension and type. Apparently within WRF if you set a real number equal to a double precision number no additional code is necessary. I believe setting a double precision number equal to a real number requires the addition of code double = DBLE(real). Your mileage may vary. The last editing I did was in subroutine mp_thompson, where I added prs_iau to the end of the subroutine variable list: subroutine mp_thompson (qv1d, qc1d, qi1d, qr1d, qs1d, qg1d, ni1d, & nr1d, t1d, p1d, dzq, & pptrain, pptsnow, pptgraul, pptice, & #ifdef WRF_CHEM rainprod, evapprod, & #endif kts, kte, dt, ii, jj,prs_iau) I also changed prs_iau from a local variable within subroutine mp_thompson to a nonlocal variable by editing the variable declaration. Again this was done by declaring INTENT(INOUT). DOUBLE PRECISION, DIMENSION(kts:kte),INTENT(INOUT):: prs_iau prs_iau is manipulated extensively within subroutine mp_thompson. By only changing the INTENT(INOUT) I believe I have preserved calculation of the variable and all variables that depend on it in the scheme. After performing the edits noted above I recompiled. I navigated to the WRFV3 folder. Once in this folder I executed the ./clean –a command. This command removed executables and various files created by the compiling process. I then reinstated my configure.wrf file with the command mv configure.wrf.backup configure.wrf. This is necessary because the ./clean – a command converts configure.wrf to configure.wrf.backup. The next step was to configure the WRF with the ./configure command. Working on ATMOS01 options 4 and 1 are required at the prompts. Then I compiled using the ./compile em_real > & compile.txt command. This generated a text file, compile.txt that recorded any compilation errors. After the compile was complete I looked into the main folder to see if the WRF executables were present and I checked compile.txt for errors. Finding none I ran the WRF. After the first history output after the initial hour was produced I checked the wrfout using ncview. I saw iausn was in the list of three-dimensional variables by the <DNAME> “Ice Auto Snow” that I had assigned in Registry.EM_COMMON. I opened it up and was able to view the data. The values and placement appeared to correspond with other microphysics variables so I knew I had successfully written the variable out. Problems I Encountered I worked on this issue for a few weeks. I would edit the code, go through the compiling process, fix compiling errors, run the WRF, find out it hadn’t produced correct values of the variable and repeat. This is not a simple task. Take your time and be methodical. I actually knew the relationship between all of the routines and subroutines early in the first week. The devil was in the details of deciding how far to pass the actual microphysics variable out through the subroutines and how to edit the code to accomplish that task. Compiling errors are easily seen in compile.txt. When the severe or fatal error is found in the text file it is then easy to search for the error in the file and line of code specified in the error. Finally it is easy to edit the code and recompile. However, a successful compile does not mean success. This took most of my time and was the most frustrating. By all means fix the errors pointed out by the compiler, but also think about the logic of your variable passing. Think about if your edits are in the appropriate place in the code or not. Think about if the variable types and dimensions match, etc. Late in the process I found out that at some point I had changed the type of prs_iau to real. I was also trying to equate iausn to prs_iau with the DBLE command. After I reverted prs_iau to double precision and did away with the awkward DBLE conversion I successfully got iausn from wrfout. This problem reveals a lack of a methodical approach. I had at some point made multiple edits and actually generated a conflict. Try to only change one aspect of your edits at a time. Finally and most significantly, I frequently successfully compiled but when I ran the WRF using the mpi command, the output was incorrect. Specifically for me, at model level 5, three tiles had the same incorrect value of iausn over the entire tile. The incorrect tiles were in the southeast corner of the domain. Running the WRF without the mpi command resulted in correct output. I have no good explanation for why this would occur at this time. It might have been related to the mismatch in the type of my variable and the actual microphysics variable. It might have been related to the initialization approach.