Programming guide

This page is for anyone writing code for the CASINO distribution: the main program, its utilities and its converters. It sets out the rules the code follows and the route by which a change reaches the repository. The full Fortran style guide is in the manual, in its section on programming style; this page summarises it and adds what the manual does not cover. If you have not yet read Developing CASINO, start there.

Languages
  • Fortran 2008, and nothing later. The main program and most utilities are Fortran. CASINO is built with many compilers, some of them old, and a feature that a recent gfortran accepts without comment may stop another compiler altogether. Do not use Fortran 2018 features, assumed-type and assumed-rank arguments (TYPE(*), DIMENSION(..)) among them, or any vendor extension.
  • C appears only in two small routines in src/, etime.c and alloc_shm.c, which are the models for layout. Use C only where Fortran cannot do the job, and use /* */ comments, never //.
  • Shell scripts, such as runqmc and its relatives, are written for bash. Any script that reads or computes with numbers from CASINO’s output does its arithmetic under LC_ALL=C: in a locale with a decimal comma, which many of CASINO’s users have, awk and printf misread numbers without any warning.
  • Converters and analysis tools may be written in Fortran or in Python 3. A Python tool states in its README the Python version and any packages it needs, and avoids packages it can do without. Anything else, ask first.
  • Libraries. The main program calls no external library other than MPI, BLAS and LAPACK, and it must still build and run without MPI.
Fortran style

The code should read as if one person wrote it, so that it is easy to read and so that a text search finds every instance of a thing. The source in src/ is the reference. In summary:

  • One module per file.
  • Compile-time keywords in upper case (MODULE, SUBROUTINE, FUNCTION, declarations); executable code in lower case.
  • Indent the body of each if, do and select case block by one space.
  • Relational operators as ==, /=, <, <=, >, >=, never .eq. and its relatives.
  • Lines of 80 characters at most. A continued line ends with & and the next begins with one.
  • endif and enddo, not end if and end do.
  • Declarations use :: only where the language requires it (INTEGER ialloc, but INTEGER,INTENT(in) :: n). Dummy arguments come first, in the order in, inout, out, then local variables; within each group the types run INTEGER, REAL(sp), REAL(dp), COMPLEX(sp), COMPLEX(dp), LOGICAL, CHARACTER, TYPE. Write CHARACTER(12), not CHARACTER*12.
  • USE statements in alphabetical order, followed by the USE ... ONLY statements, also in alphabetical order. When you add or remove a USE statement in src/, run build-tools/update-makefile-tool from src/ to bring the Makefile’s dependencies up to date.
  • No tab characters; no return before END SUBROUTINE or END FUNCTION; no GOTO where it can be avoided; two blank lines between routines.
  • Input/output units are allocated with open_units, never chosen by hand.
  • Comments are sentences: capital letter, correct spelling, full stop. They say what the reader needs and cannot see.

Errors are reported through errstop, errstop_master and errwarn in run_control.f90, called as call errstop('ROUTINE_NAME','Message.'). Use errstop_master only where every process reaches the same call with the same condition; if only one process can see the condition, for instance because only the master has read the file in question, use errstop, or the other processes wait for ever. Only the master process writes to the output file.

A new input keyword is registered, with its help text, in src/esdf_key.f90, and documented in the manual.

The style checker, utils/casinostyle_checker/casinostyle_checker.py, should report nothing new in a file you have changed. Compare its output on your version with its output on the original, since some older files do not pass it.

Headers and Changes logs

Every routine begins with a boxed comment giving its name, what it does, and its author’s initials and date (month and year). Every change to an existing routine, however small, adds a dated line to the Changes section of that routine’s box, in the box’s own format, for example

! 10.2026 VK Analytical derivatives with respect to the cutoff.      !

padded to the box’s right-hand edge. Use your own initials; the key to initials lists those already in the code. Code imported from another program keeps a single box at the top of the file recording where it came from, with its own Changes log.

Scope: dimensions, orbitals and methods

A new facility should work for systems periodic in 0, 1, 2 and 3 dimensions, with every type of orbital CASINO supports, and in VMC, DMC and RMC, or else refuse the input with a clear message. It must never run and return a wrong answer in a case it was not written for. You are not expected to test every combination. Say in the note that comes with your patch which combinations you ran, which go through the same code and so are covered by reading, which are refused, and which you have not examined. The same applies to utilities.

Speed and scale

CASINO’s speed was bought over many years and is easily given back. Say whether your change is in code executed for every move, for every block, or once at setup.

  • A change to code executed for every move comes with timings before and after, on a system of realistic size, at the number of processes it would be run with, repeated often enough to show the noise. For a small change, instruction counts from valgrind’s callgrind are more reliable than timings. A change that makes the code slower needs a reason; a speed-up that changes printed numbers needs an explanation.
  • DMC runs on very large numbers of processes. Decisions about redistributing walkers are taken within groups of about 500 processes, so that their cost does not grow with the size of the machine. Code executed for every move must not add arrays dimensioned by the number of processes, loops over processes, or new collective communication outside that machinery.
  • Prefer MPI calls the code already uses. A new one must also be provided in the serial stand-in for the communications module, so that CASINO still builds without MPI.
  • timing_info=T in the input prints a breakdown of where the time goes. It is off by default because it slows the run.
Testing

The regression suite is in examples/TEST, and its README is the authority on how to run it. Run it in serial and in parallel, building the reference library from the unmodified code separately for each, since serial and parallel output cannot be compared with each other: four runs in all. For example,

cd examples/TEST
./autotest --library -- --binary=casino_orig            # reference, serial
./autotest                                              # your code, serial
./autotest --library -- --binary=casino_orig --nproc=4  # reference, parallel
./autotest -- --nproc=4                                 # your code, parallel

where casino_orig is a binary built from the unmodified code. If you run the suite from a second copy of the source, check that the runqmc found first on your PATH is that copy’s, or you will test the wrong program. A new facility brings a test case of its own.

The suite runs the main program only. A change to a utility or a converter is tested by running it before and after on named inputs and comparing the results, and those inputs are described in the note with the patch.

For debugging, make debug in the CASINO directory or in src/ builds with checking enabled, and runqmc --debug (or runqmc -d) runs that build; autotest uses it by default. The debug build stops at the first invalid floating-point operation, division by zero or overflow: treat a stop as a finding, not as noise. runqmc --debugger=gdb runs under a debugger. Test with more than one compiler where you can (gfortran, Intel ifx, and NAG, whose checking is the strictest), and on more than one process. When looking for a fault, simplify the input first: remove the Jastrow factor, the cusp correction or the backflow and see whether it persists.

Submitting a patch

Small fixes are welcome without notice. For anything larger, write first, so that the work is not duplicated and the approach is agreed before you spend time on it.

  • Work against the current development version, one logical change per commit, and send the result of git format-patch to Mike Towler. Pablo López Ríos’s guide to git in CASINO shows how.
  • Never include the DIARY or VERSION files, which the build generates.
  • With the patch, send a short note: what was wrong or is new, what you ran, numbers before and after, the scope statement above, and anything the manual or an example in examples/ should gain, which may be part of the patch itself.

Each patch is built, run against the suite in serial and in parallel, and read in full by a reviewer other than its author. It is then either returned with the reasons or applied to the repository under its author’s name.

Commit messages

Each commit message becomes an entry in the development log, which ships with CASINO and is read by its users, so it is written for them.

  • The subject line is in the imperative and says what CASINO now does, prefixed with the file’s name where one file dominates the change.
  • The body is in the past tense and says what was wrong and what a user sees now, or, for something new, what it is and in a sentence how to use it. Two or three sentences are usually enough.
  • A change made for speed states the speed-up measured, for which system and on how many processes, and whether any printed number changes.
  • The message does not describe how the change was made or tested; that belongs in the note that comes with the patch.

For example:

reblock.f90: don't print a failed effective-population estimate as a number.

POPSTATS's effective population and measured inefficiency could come
out negative and were printed as if they were results. When the
estimate fails they, and the two error bars built on them, now print
as unavailable, with a warning that the estimator failed and not the
walk. No other printed number changes.

The CHANGES file is a short summary of the log for users, kept by the maintainer, and records only new capabilities, significant speed-ups and changes that users at large will notice. If you think your change belongs there, say so in your note.

Bug reports and requests

Report a fault on the forum, with the input files that show it, the version line printed at the top of the output file, and the compiler and machine. A fault that can be reproduced is already a contribution. Requests for new features are welcome there too; many items on the list of things to do began that way.

Leave a Reply