etmc/tmLQCD — comment on commit 9cec2dfa2caf7302d34f8f3b14bf9019d51c5a6b
File:  line 0
By deuzeman:

Hmm, not quite, though there should be some 'sample' code soon. It might be good to describe the general idea, though. It's all pretty straightforward.

The idea was to provide a compromise between the big advantage of global fields (namely, that they don't need to be allocated and freed all the time) and the flexibility needed for having multiple (e.g., smeared at different levels) versions of those fields around. We wanted to avoid the existence of a large pool of fields for temporary use that one writes to haphazardly, since that creates a lot of opportunity for interference and makes for hard to read code.

In the new setup, gauge fields are stored in a struct 'gauge_field_t', that contains (among others) a pointer 'field' that can be used in the same way as the current global gauge field. We will initialize a global struct once, at the beginning of the program. Using the 'get_gauge_field' routine, one obtains a fully initialized gauge field struct, that is yours to use locally. If no free gauge fields are available anymore when you request one, a new one will be allocated for you -- up to a given maximum. After usage, it has to be returned using 'return_gauge_field', so that it can be recycled. If you forget this, new fields will be allocated continuously, creating a huge memory leak until you either run out of memory or the maximum number of fields has been allocated and the routines signal an error. At the end of the program, all fields are freed. There will also be an option to free any unused fields at an intermediate stage, for those cases when memory is tight and the program needs to temporarily allocate different types of fields.

When writing routines, you should generally avoid using global routines; instead, try to pass any fields you need. If you need some temporary storage, just use the 'get_gauge_field' and 'return_gauge_field' routines within your function. It should be only marginally slower than allocating static fields and will be much more memory efficient. It is fine to pass a 'gauge_field_t' by value, as it is only a thin wrapper around pointers. You can therefore even use them as a return value for a function, so there should be no need to build big monolithic functions.

If you need to store several fields -- different steps in an iterative procedure, for example -- you can also obtain a gauge_field_array_t struct, that stores an array of gauge fields. The functions 'get_gauge_field_array' and 'return_gauge_field_array' do exactly what you'd expect. The memory pool is shared between 'gauge_field_t' and 'gauge_field_array_t', so the choice between the two is just a matter of convenience.

We plan to implement the exact same system for all other fields in the program. It will hopefully make it easier to keep track of the flow of information in the code, especially when it comes to newer features like smearing, gauge fixing or gradient flow. I hope this explanation is of use to you, but let me know if something is still unclear.