- Always use “implicit none” when writing new code
- Always make your module “private”
- Seperate declaration of input variables with local variables
- Always put intent(in), intent(out), or intent(inout) on all arguments. Note these attributes are used by Doxygen to create meaningful documentation.
- If you use Fortran2008 features beware that not all compilers may support this
- When using optional arguments always use “present” inquire function before using it
- Be careful when using intent(out) for pointers and derived types (e.g. type(matrix)); this will on some platforms make the pointer disassociated entering the routine, and memory already allocated for the matrix will be lost. Instead, use intent(inout) for derived types which should really be intent(out).
- Never initialize a local variable when declaring it. A local variable that is initialized when declared has an implicit save attribute
- When you change your already documented code, REMEMBER TO CHANGE ALSO THE DOCUMENTATION! Otherwise the documentation will quickly become useless.
- Minimize dependencies between different program components.
- All variables/data structures/objects should be declared in the smallest scope possible. For example, if a variable can be made local to a subroutine, rather than coming as input from a higher-level subroutine, this is preferable. Sometimes time-critical or memory-critical subroutines/functions may need to reduce the number of local variables. In such cases this should be clearly commented.
- The behavior of a subroutine/function should depend only on its input arguments. Access to variables that are neither subroutine arguments nor local variables inside a subroutine (e.g. global variables in F77 common blocks or Fortran 90 modules) introduce global data-dependencies which by definition break the modularity and make it harder to ensure the correctness of the program.
- Subroutines/functions should receive as little extraneous data as possible. That is, the input arguments should not contain more that than is necessary to produce the desired output.
- When it is easy (and non-time consuming) to do so, subroutines/functions should check that its input is reasonable. Even when a logically airtight test is impractically complicated, it is typically simple to test that the input satisfies some conservative preconditions. When the input data is unreasonable, this should be flagged in the output somehow and checked by the calling subroutine/function.
- Data structures should ideally represent concepts that are natural from the point of view of problem domain and/or algorithm at hand, and reflect the terms in which the programmer thinks about the functionality.
- Adopting some principles of Object-Oriented Programming is a good idea. For example, Fortran 90 supports some encapsulation and data-hiding through the keyword PRIVATE. Use of PRIVATE whereever reasonable is encouraged as it reduces bugs as well as makes it harder for other programmers to deviate from the intended usage of data structures and/or subroutines.
- The ideal structure of a program or directory or module is a library-like hierarchy of subroutines/functions/objects. At the lowest level in the hierarchy are “level 0” subroutines/functions/objects that are either self-contained or depend only on each other. At the next level are “level 1” subroutines/functions/objects that depend on each other and “level 0” subroutines/functions/objects. “Level 2” subroutines/functions/objects should ideally depend on each other and “level 1” subroutines/functions/objects, and not on “level 0”, and so on. Document what the purpose and intended usage is of the different levels.
- A subroutine/function should not be longer than approximately one A4 page. Long subroutines/functions should be broken down into smaller components.
- Duplicate functionality as little as possible, within the constraints of producing readable, modular code. Functionality that is needed in several places should be implemented in a reusable, library-like way.
People leaving the group should write an “exit document” which should contain some comments about the code - some general info about - the main driver - the general scheme - general thinking - basic idea - so that a new developer would have some idea to know where to start modifing the code.
The LSDALTON.OUT file contains way too much information compared to what the “user” need. We suggest to start reducing printout significantly.
The default printlevel should be 0 which only prints the very basics like,
Input files (full) possible DFT grid info SCF convergence Final SCF energy CCSD convergence Final CCSD energy Time for full calculation
basicly nothing else.
1) All restart files should be names *.restart - currently we have files like overlapmatrix and cmo_orbitals.u and DECorbitals.info
2) It would be nice that the lcm_orbitals.u (renamed to lcm_orbitals.restart) would be the final orbitals if the localization converged and the file from which the localization could be restarted from if it did not.
3) The keyword “.RESTART” is used under *DENSOPT, *CC, **DEC but under **LOCALIZE ORBITALS it is called “.RESTART LOCALIZATION” which should be changed.
User forbidden features:
The global logical “developer” in ls_parameters.F90 is an attempt to avoid that the general users tries out bad keyword combinations.
For example one method that might be available for full molecular calculations (**CC) but that has not been properly tested with **DEC, you might one to prevent the general user to combine those keywords by using the “developer” globale logical variable. It is false by default. But you can make true e.g. by setting:
Divide Expand Consolidate (deccc directory)
New DEC model/correction:
If you want to implement energies for a new model/correction in DEC, then please do the following:
a) Define whether you want to introduce a new MODEL (e.g. CC3) OR a new CORRECTION (e.g. F12) which can be added to various existing models/corrections.
b) The global integers MODEL_* in dec_typedef.F90 define the various models. If you include a new model, then add it here. If you include a new correction (e.g. F12), then there is nothing to add here.
c) Since we have different partitioning schemes for each CC model, it is necessary to have another set of global integers which define the fragment model (e.g. occupied partitioning scheme for CCSD). These are defined as the global integers FRAGMODEL_* in dec_typedef.F90. If you include a new model OR correction, then add it here. At the same time, you need to increase the global integer ndecenergies in lsutil/dec_typedef.F90 accordingly. E.g. if your new model/correction requires N additional energies to be stored, increase ndecenergies by N.
- Define your model in dec_set_model_names and find_model_number_from_input.
- Add model to input keyword(s) in config_dec_input. (For example, see what is done for CCSD and do something similar).
- Insert logical describing whether correction should be done in type DECsettings in lsutil/dec_typedef.f90.
- Set defaults in dec_set_default_config and add input keyword(s) in config_dec_input. (For example, see what is done for F12 and do something similar).
For new model (e.g. RPA): Grep for “MODIFY FOR NEW MODEL” in all files in the DEC code. These are the main places you need to change to include your new model. It is hopefully clear from the context and the comments in the code what needs to be done to include the new model.
For new correction (e.g. F12): Grep for “MODIFY FOR NEW CORRECTION” in all files in the DEC code. These are the main places you need to change to include your new model. It is hopefully clear from the context and the comments in the code what needs to be to include the new correction”.
If you have to introduce workarounds on specific systems introduce them in dec_workarounds.F90 with a specific precompiler flag for your issue at hand. Rationale: Usually workarounds are compiler and system dependent and a clean version of the code should be maintained by default
Note: Feel free to update and improve this notes!
AGAIN, ALL MODULE SHOULD BE PRIVATE!
The list below should ALWAYS be kept up to date!
- Files at level X is allowed to use a subroutine/function in a file on level Y if and only if X>Y!
- You are of course allowed to introduce new files, shuffle things around etc. If you do so, make sure that each files has a place in the hierarchy and that this readme-file is updated!
- If modifying dependencies, make sure that all DEC depencies are put under the “! DEC DEPENDENCIES (within deccc directory)” comment within each file.
Level 12 dec_main
Level 11 snoop_main
Level 10 full_driver, dec_driver, decmpiSlave, full_rimp2f12
Level 9 dec_driver_slave
Level 8 fragment_energy
Level 7 cc_driver, cc_debug_routines
Level 6 rpa,snoop_tools
Level 5 pno_ccsd, ccsd, dec_atom, ccsdpt, mp2_gradient, f12_integrals, rif12_integrals, cc_response_tools
Level 4 full_mp3
Level 3 full_mp2
Level 2 fullmolecule, mp2, cc_integrals, crop_tools, rimp2, ri_util
Level 1 ccorbital, ccarray2_simple, ccarray3_simple, ccarray4_simple, decmpi, dec_utils
Level 0 dec_settings, full_driver_f12contractions, CABS, cc_tools, f12ri_util array3_memory, array4_memory, f12_routines, dec_workarounds, dec_tools
when you add a file to the deccc directory make sure to update this list as well as the one in the dec_readme file. (Maybe only one list should be kept)