Presentation is loading. Please wait.

Presentation is loading. Please wait.

Guidelines for the CMM coding project 5 October 2006 (or, “How to make your life easier in the long run”)

Similar presentations


Presentation on theme: "Guidelines for the CMM coding project 5 October 2006 (or, “How to make your life easier in the long run”)"— Presentation transcript:

1 Guidelines for the CMM coding project 5 October 2006 (or, “How to make your life easier in the long run”)

2 Guiding philosophies of this advice… I. A good model code is easy to read and trouble shoot… you can find what you’re looking for quickly and you can see what each line of code is supposed to be doing II. A good model code preserves forward compatibility, so that as we add new features, we don’t have to reinvent the wheel

3 1.Start each and every program and subroutine with… IMPLICIT NONE

4 2. Define physical constants and model configurations in parameter statements, not in the body of the code! INTEGER NT PARAMETER(NT=1000) This prevents accidental overwriting of a variable somewhere else in the code

5 3. Determine whether a variable needs to be an integer, a single precision real, or a double precision real, and declare it properly INTEGER NT PARAMETER(NT=1000) REAL DT PARAMETER(DT=2.0) DOUBLE PRECISION PI PARAMETER(PI=3.14159265359D+00)

6 4. Along with this, remember that for many compilers, the product of two kinds of variables is restricted by the less precise variable INTEGER I REAL A, B I=2 A=2.2 B=A*I B=A*REAL(I) B may be = 4 on some compilers (On many compilers, IMPLICIT NONE alleviates this problem)

7 5. Comment your code heavily! Our goal in this class is to understand every line of code in our model… believe it or not, in a week or a month, you will forget why you coded something in a particular way, or you will forget what a particular line of code is meant to do.

8 6. Call your variables and subroutines by names that bring to mind what they represent! EPS ASSELINCOEF We all like to save keystrokes and keep our code compact, but which of these is unambiguous? EPSILON

9 7. Similarly, make your calculations look like the equations you’re trying to represent Often it’s possible to really combine and condense a lot of coefficients into one compact variable… Models do this to save on the number of calculations… but, when you are trying to modify that line (or debug it, or base another line off of it) you will have to go back and figure out where the compact variable is defined, whether it is defined correctly, whether it needs to be modified for a new application, etc. GAMMA = K * DT / DX**2.

10 8. Continuing the theme… don’t use a bunch of temporary/dummy variables for multiple things at various points in the code Some models do this to save on RAM… but, when you are trying to modify a line (or debug it, or base another line off of it) you will have the problems previously mentioned. In addition, when you look at a random line of code, you can’t be sure of what the dummy variable means! ! Check for parcel buoyancy DUM=PTPAR-PTENV IF(DUM.GE.0.0) CAPE = CAPE + G*DZ*DUM/PTENV And later… ! Condense excess vapor from parcel DUM = QVS*LV*17.27*237.0/(CP * (TEMP-36.0)**2) DUM = (QVPAR-QVS)/(1+DUM) QVPAR = QVPAR - MAX(DUM,0.0)

11 9. Cosmetics: avoid IF statements when possible (they run slowly and look ugly!) ! Upstream scheme depending upon flow direction IF(C.GE.0.0) THEN PHI(I,N+1)=PHI(I,N)-C*DT*(PHI(I,N)-PHI(I-1,N))/DX ELSE PHI(I,N+1)=PHI(I,N)-C*DT*(PHI(I+1,N)-PHI(I,N))/DX ENDIF ! Upstream scheme depending upon flow direction PHI(I,N+1)=PHI(I,N) & -0.5*(C+ABS(C))*DT*(PHI(I,N)-PHI(I-1,N))/DX & -0.5*(C-ABS(C))*DT*(PHI(I+1,N)-PHI(I,N))/DX

12 10. A three-level time scheme (e.g. leapfrog) only requires the time dimension of the arrays to be 3 (not NT) INTEGER NX, NT PARAMETER(NX=100, NT=10000) REAL PSI(NX,NT) INTEGER I, N ! Omit the initial condition statements for now DO N=2,NT DO I=2,NX PSI(I,N+1)=PSI(I,N-1) + forcing[PSI(I,N)] ENDDO

13 10. A three-level time scheme (e.g. leapfrog) only requires the time dimension of the arrays to be 3 (not NT) INTEGER NX, NT PARAMETER(NX=100, NT=10000) REAL PSIP(NX), PSIC(NX), PSIF(NX) ! Past, current, future INTEGER I, N ! Omit the initial condition statements for now DO N=2,NT PSIP=PSIC PSIC=PSIF DO I=2,NX PSIF(I)=PSIP(I) + forcing[PSIC(I)] ENDDO Only practical approach for long simulations! (RAM)

14 11. Obviously, this requires writing output during the run (not waiting until the very end) ! Omit the declaration statements for now ! Omit the initial condition statements for now DO N=2,NT TIMENOW=REAL(N-1)*DT PSIP=PSIC PSIC=PSIF DO I=2,NX PSIF(I)=PSIP(I) + forcing[PSIC(I)] ENDDO ! if it's time, dump output IF(TIMENOW.GE.THISDUMP) THEN CALL GRADSHISTORYDUMP ! set next time for output THISDUMP = THISDUMP + DTOUTPUT ENDIF ENDDO

15 12. In the atmosphere, all processes happen simultaneously… in the model, they must happen in a certain order. In other words, you can’t just put things anywhere you want! Example… what is the correct order for these processes in a model? Predict “dry” change in temperature Compute saturation mixing ratio Update water vapor for evap/cond Apply boundary conditions Update temperature for evap/cond 5 4 13 2

16 13. Use modular code… A. Creating a “driver” code and using subroutines B. Breaking your code up into meaningful files i) Using INCLUDE ii) Declaring everything in one place iii) Using COMMON blocks iii) Compiling a group of files

17 Breaking your code up into meaningful files… -Using INCLUDE -Declaring everything in one place constants.inc:

18 Breaking your code up into meaningful files… -Using INCLUDE -Declaring everything in one place

19 Using COMMON blocks USE: The preamble to each subroutine is a series of INCLUDE statements that define all the variables. The final thing after all the included definitions is then the INCLUDE statement for the file that contains the COMMON block Declare the variables once (only), in one place Never have to worry about whether a variable is being passed to subroutines Saves RAM, because each subroutine looks at the same place in the memory (don’t use extra memory to declare a redundant copy of variables passed to the subroutine) When a variable is updated in a subroutine, it is updated everywhere in the code

20 Recall: creating a “driver” code and using subroutines… So, each subroutine also begins with the INCLUDE statements!

21 Breaking your code up into meaningful files… -Using INCLUDE -Declaring everything in one place

22 Breaking your code up into meaningful files… -Compiling a group of files Your model code can become quite long…(the last time I did this project, the 2D model driver with simple microphysics was 1431 lines, excluding all declarations) Why not break the subroutines up, too? All subroutines related to initial conditions: init.F All subroutines related to boundary conditions: boundaries.F All subroutines related to writing out data: writeout.F All subroutines related to main integration: integration.F All subroutines related to main driver: modeldriver.F

23 Breaking your code up into meaningful files… -Compiling a group of files Then, to compile, create a shell script: compile.sh #!/bin/csh rm cmm.exe cat modeldriver.F init.F boundaries.F writeout.F integration.F > onefile.F f90 –o cmm.exe onefile.F Compiling the model is now simple, and you know right where to look if you want to work on the boundary conditions!


Download ppt "Guidelines for the CMM coding project 5 October 2006 (or, “How to make your life easier in the long run”)"

Similar presentations


Ads by Google