Sometimes it may be desirable to modify MODFLOW in some way. For example, a new package may be added or an existing package may be modified to provide new capabilities. The way in which the modifications are made may either facilitate or inhibit further modifications by others. One of the original goals of MODFLOW was to facilitate the addition of new capabilities (McDonald and Harbaugh, 2003). The following is a list of suggestion on how to make changes to MODFLOW in a way that will facilitate further enhancements.
1.Avoid using hard-coded unit numbers. If you write a specific unit number into the code, that unit number can not be used for anything else. Instead, let the user specify a unit number in the Name file.
2.If you must use a hard-coded unit number, be sure to document it's usage. Any developer of some other package will need to know to avoid the unit number that you have used. In addition, any user of your code will need to know that the unit number you have used is not available for any other purpose. In MODFLOW-2005, unit number 99 is a hard-coded and is used in "OPEN/CLOSE" statements.
3.Let the user control the names of output files. Like hard-coded unit numbers, hard coded output file names should be avoided. Let the user specify the output file names in the Name file.
4.Maintain backwards compatibility. If you are modifying an existing package, allowing existing input files for the package to still work will facilitate running existing models with the updated version of MODFLOW. If new variables are required in the new version, it may be necessary to provide default values for those variables if they are not included in the previous version of the input file.
There are at least two ways to maintain backwards compatibility. (1) Use the sign of a number as a flag that signals a new input format. However, this approach is discouraged for reasons detailed below. (2) Use a key word as a flag that signals a new input format. This was the approach used for maintaining backwards compatibility in the transition from MODFLOW-96 to MODFLOW-2000 in the WEL, RIV, DRN, and GHB packages. To use a key word as a flag, the subroutine URWORD in utl7.f can be used to check for the existence of a key word in a line. For an example of how this is done, see the subroutine UPARLSTAL in parutil7.f.
5.If backwards compatibility is not possible, provide an automated way of converting the old files to the new ones. This approach was used in the transition from MODFLOW-96 to MODFLOW-2000 to split the BCF input file into a file with the new BCF input format plus a file with the discretization information previously included in the BCF file.
6.Avoid using the sign of a number as a flag. One way to maintain backwards compatibility of an existing package with its previous input format is to use a negative value of a number in the previous format as a flag to read additional new variables. However, this approach has several disadvantages and is also unnecessary. One disadvantage is that there are only two possible signs: positive and negative. If, at a later time, additional modifications are desired, it will not be possible to use the sign of that same number to signal that additional input variables need to be read. A second disadvantage is that it makes the meaning of the original variable confusing especially if the sign of the number has no relationship to the absolute value of the the number. For an example of how using the sign of a number makes enhancement difficult, see the variable IRUNBND in the UZF package. When the SFR and LAK packages were written, the sign of the inflow or outflow segment was used in the SFR package to indicate whether flow was to a stream segment or to a lake. This same approach was extended to IRUNBND in the UZF package. When the Surface Water Routing process was added, this approach broke down.
Using the sign of a number as a flag is defensible, in order to save memory if a different approach would require another large array to be allocated. For example, the sign of WETDRY is used in this fashion. The sign of WETDRY is used to signal which neighboring cells may cause a dry cell to convert to wet. However, even in such cases, a different approach could be used that would conserve memory. For example, a different approach that could have been used with WETDRY would have been to have a wetting threshold array and a wetting flag array in the input file but instead of storing the wetting flag array in memory, it would just be used to set the sign of the values in the wetting threshold array. Internally, the same amount of memory would have been used. However, future enhancements would have been facilitated by having the arrays separate in the input files.
7.Don't use fixed format for reading variables in new code. When MODFLOW was first written, all input was in fixed format, usually with 10 character fields. That was sufficient for single-precision real-number variables but not for double-precision variables. At that time all real-number variables in MODFLOW were single precision. Now some models require that all real-number variables be double precision.
8.Be sure to document the meaning of all variables that have more than local scope. It is difficult for others to understand the source code when the meanings of variables are not defined. This is especially true if the meaning of a variable changes from one part of a package to another or depends on the context.
9.Include comments explaining any code that is at all complicated.
10.Use the MODFLOW naming conventions for variables and subroutines because this makes it easier to understand the program structure and avoid conflicts between packages. However, you should still document what the variables represent and what the subroutines do.
11.Allow for multiple comment lines at the beginning of each input file. Many, but not all, of the input files for MODFLOW allow for comment lines at the beginning. Such comment lines are valuable because they allow the user to document their model in the input files themselves.
12.It is a good idea to define one or more parameters for any new package for which the user may wish to calibrate the input values. By providing parameters, you facilitate automated parameter calibration.
13.Become familiar with the utility subroutines in MODFLOW. The files utl7.f and parutl7.f provide a number of utility subroutines that can be helpful in writing new code for MODFLOW. You can check how the utility subroutines are used in existing packages to help understand how to use them.
14.Limit interactions between packages as much as possible. When packages interact with each other, the complexity increases according to the factorial of the number of interacting packages. Thus, if three packages interact with each other the complexity increases by 3! or 3*2*1. Thus for each new interaction it becomes that much harder to understand what the package is actually doing. In addition, it is easy to make mistakes when packages interact with each other because of a failure to understand all the package between which the interaction is occurring. Interactions with the HUF2 package are especially prone to error because of the complexity of the HUF2 package and because the meanings of values stored in its arrays may not be completely obvious from the names of the arrays.
15.If interactions between packages are required, be sure to document them. For example, it would be a mistake to modify the values of an array of one package inside another package without documenting that fact because users would have a hard time understanding why the calculated budget values were not what was expected.
16.Make sure your code compiles with multiple compilers. Using only standard FORTRAN is one way to make your code more portable. However, not all commonly used compilers, support the latest features of FORTRAN. At the time of this writing, for example, gfortran does not fully support FORTRAN 2003 and thus can not be used to compile MODFLOW-NWT.
17.When saving budget terms be sure to make sure to use the subroutine UBDSV1 when the compact option is used and UBUDSV otherwise.
18.Be sure you understand how auxiliary variables are used in MODPATH to get a better idea of whether they should be included in new packages. Generally speaking, it is a good idea to include auxiliary variables in stress packages.
19.Consider using derived types instead of arrays for defining the properties of boundaries. To take a simple case, for the well package, you could define a derived type that has members for the layer, row, column, specified flow rate, actual flow rate and an array of auxiliary variables.
20.If creating a derived type is too much trouble, consider using named constants rather than hard-coded values to access specific positions in arrays. For example, in the well package, instead of
C5A-----GET LAYER, ROW & COLUMN OF CELL CONTAINING WELL.
you could have
IROW = 2
ICOL = 3
ILAY = 1
C Many lines skipped here...
C5A-----GET LAYER, ROW & COLUMN OF CELL CONTAINING WELL.
By using a well named constant, you make it easier to understand the code. For the well package, this isn't much of a concern because the data used by the well package is relatively simple. For some other packages, the data is much more complex.