FIREBALL-framework Developers' Handbook.

 

 

 

 

 

World FIREBALL Congress

June 18 - 21, 2012 Orlando, FL

 

 

Preface

 

This book was written for the Fireball Conference in Orlando, Florida which took place on the 18th - 21st of June, 2012. It came about to serve as a "Developers Manual" for the new Fireball code base. Much of this book, especially the reference section that discusses the Fireball modules, is directly taken from the comments in the code.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


FIREBALL-framework Developers' Handbook. 1

Preface. 3

A short comment on documentation.. 15

Fortran features "new" to new Fireball. 17

Modules. 17

Derived Types (a.k.a. structures). 18

Pointers. 20

Array manipulation. 20

Explicit interfaces. 21

Conclusions. 22

Main structures implemented in the new Fireball-framework.. 23

Fdata in the new Fireball-framework. 30

Block(:,:). 32

Conclusions. 35

General module framework. 36

Copyright Notice. 36

Module Description. 37

Module Declaration. 38

Type Declaration. 39

Module variables. 39

Module procedures. 40

Subroutine and description. 40

Subroutine declaration. 41

Argument declaration and description. 42

Parameters and data declaration. 42

Variable declaration and description. 42

Allocate arrays. 42

Procedure. 43

Deallocate arrays. 44

Format statements. 44

End subroutine. 44

Other Subroutines. 44

Functions. 44

End module statement. 44

List of commonly-used TG variables and their new Fireball equivalent. 46

Walkthrough- a Fireball "Hello World". 55

The "Driver" program. 61

Editing the Makefile. 63

Walkthrough- from TG-Framework to New Fireball-Framework. 65

Module Documentation.. 69

New Fireball Call Tree. 70

M_atom_functions.f90.. 71

Name of Type: T_data_shell 71

Name of Type: T_data_species. 72

Name of subroutine: initialize_wf. 72

Name of subroutine: read_wavefunctions. 73

Name of subroutine: read_napotentials. 74

Name of function: psiofr. 74

Name of function: vnaofr. 75

M_atom_PPfunctions_KB.f90.. 76

Name of Type: T_shell_PP_data. 77

Name of Type: T_species_PP. 77

Name of subroutine: read_vPP. 78

Name of subroutine: calculate_vPP. 79

Name of function: vPPofr. 79

Name of function: vPP_NLofr. 80

Name of function: vPP_shortofr. 81

M_atomPP_ion_functions_KB.f90.. 82

Name of subroutine: read_vPP_ion. 83

Name of subroutine: calculate_vPP_ion. 83

Name of function: psiofr_ion. 84

Name of function: vPP_ion_NLofr. 85

Name of function: vPP_ion_shortofr. 86

M_cells.f90.. 86

Name of Type: T_vector. 87

Name of Subroutine:  make_cell 87

M_integrals_2c.f90.. 88

Name of Type: T_Fdata_cell_2c. 88

Name of Type: T_Fdata_bundle_2c. 89

Name of subroutine: size_Fdata_2c. 90

Name of subroutine: make_munu. 90

Name of subroutine: make_munu_atom.. 91

Name of subroutine: make_munuS. 92

Name of subroutine: make_munuS_atom.. 93

Name of subroutine: evaluate_integral_2: 94

Name of function: zint: 96

Name of function: rescaled_psi 97

Name of function: phunction. 98

Name of function: twopi 99

Name of function: nopi 99

M_neighbors.f90.. 100

Name of Type: T_neighbors. 101

Name of Type: node_neighbor. 101

Name of subroutine: driver_neighbors. 102

Name of subroutine: read_neighbors. 102

Name of subroutine: find_neighbors. 103

Name of subroutine: find_common_max. 103

Name of subroutine: find_common_neighbors. 104

Name of subroutine: writeout_neighbors. 105

Name of subroutine: destroy_neighbors. 105

M_neighbors_PP.f90.. 105

Name of Type: T_neighbors_PP. 107

Name of Type: node_neighbor_PP. 108

Name of subroutine: driver_neighbors_PP. 108

Name of subroutine: read_neighbors_PP. 108

Name of subroutine: find_neighbors_PP. 109

Name of subroutine: find_neighbors_PPx. 109

Name of subroutine: find_neighbors_PPp. 110

Name of subroutine: find_common_PP_max. 110

Name of subroutine: find_common_neighbors_PP. 111

Name of subroutine: writeout_neighbors_PP. 112

Name of subroutine: destroy_neighbors_PP. 113

M_neighbors_vdW_old.f90.. 113

Name of Type: T_neighbors_vdW... 114

Name of Type: node_neighbor_vdW... 114

Name of subroutine: driver_neighbors_vdW... 115

Name of subroutine: read_neighbors. 115

Name of subroutine: find_neighbors_vdW... 116

Name of subroutine: writeout_neighbors_vdW... 116

Name of subroutine: destroy_neighbors_vdW... 117

M_Species.f90.. 117

Name of Type: T_Shell 118

Name of Type: T_Orbitals. 119

Name of Type: T_PPshell 120

Name of Type: T_species. 120

Name of subroutine: read_Fdata_location. 122

Name of subroutine: read_begin. 122

Name of subroutine: read_create. 124

Name of subroutine:  read_info. 125

Name of subroutine:  destroy_species. 125

M_configuraciones.f90.. 126

Name of Type: T_atom.. 127

Name of Type: T_structure. 128

Name of subroutine:  read_positions. 129

Name of subroutine:  read_charges. 130

Name of subroutine:  read_parameters. 130

Name of subroutine:  read_sections. 131

Name of subroutine:  compare_strings. 132

Name of subroutine:  destroy_positions(). 132

write_species.f90.. 133

M_kpoints.f90.. 133

Name of Type: T_kpoint. 134

Name of subroutine: read_kpoints. 134

rotate_PP. 137

Name of subroutine: rotate.PP. 137

M_rotations. 139

Name of subroutine: rotate. 139

Name of subroutine: twister. 140

Name of subroutine: chooser. 142

M_assemble_vxc_McWEDA_spin. 143

Name of subroutine: assemble_vxc_SN_spin. 144

Name of subroutine: lda_ceperley_alder. 144

Name of subroutine: assemble_vxc. 145

Name of subroutine: assemble_vxc_SN.. 146

Name of subroutine: destroy_assemble_vxc_McWEDA.. 147

Name of subroutine: lsdavwn. 147

M_assemble_vxc_McWEDA_Harris. 150

Name of subroutine: assemble_vxc. 150

Name of subroutine: assemble_vxc_SN.. 150

Name of subroutine: assemble_vxc_bond. 151

Name of subroutine: destroy_assemble_vxc_McWEDA.. 152

M_assemble_vxc_McWEDA_DOGS. 153

Name of subroutine: assemble_vxc. 154

Name of subroutine: assemble_vxc_SN.. 155

Name of subroutine: assemble_vxc_bond. 156

Name of subroutine: destroy_assemble_vxc_McWEDA.. 156

M_assemble_rho_McWEDA_usr_DOGS. 158

Name of subroutine: assemble_uee. 158

Name of subroutine: assemble_uxc. 158

M_assemble_rho_McWEDA_usr_Harris. 160

Name of subroutine: assemble_uee. 160

Name of subroutine: assemble_uxc. 160

M_assemble_rho_McWEDA_vdW_Harris. 162

Name of subroutine: assemble_rho_2c. 162

Name of subroutine: assemble_rho_3c. 162

Name of subroutine: assemble_rho_weighted_2c. 163

Name of subroutine: assemble_rho_weighted_3c. 163

Name of subroutine: destroy_assemble_rho. 164

M_assemble_rho_McWEDA_spin. 166

Name of subroutine: assemble_rho_2c. 166

Name of subroutine: assemble_rho_3c. 166

Name of subroutine: assemble_S_weighted. 167

Name of subroutine: assemble_rho_weighted_2c. 167

Name of subroutine: assemble_rho_weighted_3c. 168

Name of subroutine: assemble_rho_average. 169

Name of subroutine: destroy_assemble_rho. 169

M_assemble_rho_McWEDA_Harris. 170

Name of subroutine: assemble_rho_2c. 171

Name of subroutine: assemble_rho_3c. 171

Name of subroutine: assemble_rho_weighted_2c. 172

Name of subroutine: assemble_rho_weighted_3c. 173

Name of subroutine: assemble_rho_weighted_3c. 173

M_assemble_rho_McWEDA DOGS.f90. 175

Name of subroutine: assemble_rho_2c. 175

Name of subroutine: assemble_rho_3c. 176

Name of subroutine: assemble_S_weighted. 176

Name of subroutine: assemble_rho_weighted_2c. 177

Name of subroutine: destroy_assemble_rho. 178

M_assemble_PP_3c.f90.. 179

Name of subroutine: assemble_vnl_3c(). 180

M_assemble_PP_2c.f90.. 181

Name of subroutine: assemble_svnl(). 181

Name of subroutine: assemble_vnl(). 182

Name of subroutine: destroy_assemblePP_2c(). 183

M_assemble_ewald_Harris.f90.. 183

Name of subroutine: assemble_ewaldsr.f90. 184

Name of subroutine: assemble_ewaldlr.f90. 184

Name of subroutine: destroy_assemble_ewaldsr. 185

M_assemble_ewald_DOGS.f90.. 186

Name of subroutine: assemble_ewaldsr.f90. 187

Name of subroutine: assemble_ewaldlr.f90. 187

Name of subroutine: assemble_ewald.f90. 188

Name of subroutine: destroy_assemble_ewaldsr. 189

M_assemble_blocks.f90.. 189

Name of Type: T_assemble_block. 190

Name of Type: T_assemble_neighbors. 190

M_assemble_3c_Harris.f90.. 190

Name of subroutine: assemble_vna_3c. 191

M_assemble_3c_DOGS.f90.. 192

Name of subroutine: assemble_vna_3c (s). 193

M_assemble.f90.. 193

Name of subroutine: Assemble_S. 195

Name of subroutine: assemble_T. 195

Name of subroutine: assemble_dipole_z. 196

Name of subroutine: assemble_vna_2c. 196

M_assemble_2c_DOGS.f90.. 197

Name of subroutine: assemble_S. 198

Name of subroutine: assemble_T. 199

Name of subroutine: assemble_diplole_z.f90. 199

Name of subroutine: assemble_vna_2c.f90. 200

Name of subroutine: destroy_assemble_2c. 200

lda_ceperley_alder. 202

Name of subroutine: lda_ceperley_alder. 202

M_looprc.f90.. 204

Name of subroutine: read_looprc. 204

M_psi.f90.. 205

Name of subroutine: calculate_psi 205

Name of subroutine: integrate_hpsi 206

Name of subroutine: get_psi 207

M_rcatms.f90.. 207

Name of subroutine: rcatms.f90. 208

Name of subroutine: initialize_wf.f90. 208

Name of subroutine: calculate_rcatm.. 209

Name of subroutine: calculate_vconfine. 209

Name of subroutine: report_eigenterms. 209

Name of subroutine: orthagonalize_psi 210

Name of subroutine: report_eigenterms. 211

M_rcatms_Coulomb.f90.. 211

Subroutines: 212

Name of subroutine: calculate_vee. 212

Name of subroutine: calculate_vxc. 212

M_rcatms_Coulomb_DMOL_excited.f90.. 214

Subroutines: 214

Name of subroutine: calculate_vee_ion. 214

Name of subroutine: calculate_vxc_ion. 215

Name of subroutine: calculate_exc_ion. 215

M_Fdata_2c.f90.. 217

Module (Global) Variables: 217

Derived types: 217

Name of Type: T_Fdata_cell_2c. 217

Name of Type: T_Fdata_bundle_2c. 218

Subroutines: 219

Name of subroutine: read_Fdata_2c. 219

Name of subroutine: getMEs_Fdata_2c. 219

Name of subroutine: destroy_Fdata_2c. 220

M_Fdata_3c.f90.. 220

Module (Global) Variables: 221

Derived types: 221

Name of Type: T_Fdata_cell_3c. 221

Name of Type: T_Fdata_bundle_3c. 222

Subroutines: 223

Name of subroutine: read_Fdata_3c. 223

Name of subroutine: getMEs_Fdata_3c. 223

Name of subroutine: addMEs_Fdata_3c. 224

Name of subroutine: destroy_Fdata_3c. 225

M_Fdata_1c_McWEDA_DOGS.f90.. 225

Name of Type: T_vxc_1c. 226

Name of subroutine: read_Fdata_1c. 227

Name of subroutine: destroy_Fdata_1c. 227

M_Fdata_1c_Harris.f90.. 228

Name of Type: T_vxc_1c. 228

Name of subroutine: read_Fdata_1c. 229

Name of subroutine: destroy_Fdata_1c. 229

Name of function: simpson.f90. 230

Name of function:mpairnay.f90. 230

Name of subroutine: invert3x3.f90. 231

Name of function: factorial.f90. 232

Name of function: Dsmoother.f90. 232

Name of function: epsilon.f90. 234

Name of function: clm.f90. 236

Name of function: clebsch_gordan.f90. 236

Name of function: block_slot.f90. 237

Name of function: cross.f90. 238

Name of function: magnitude.f90. 238

Name of subroutine: epsilon.f90. 239

Name of subroutine: Depsilon_2c.f90. 240

             Name of function: block_slot.f90. 240

M_rho_3c_MCWEDA_Harris.f90.. 242

Name of subroutine: initialize_rhoS_3c_Harris. 242

Name of subroutine: rhoS_3c_Harris. 243

Name of subroutine: phiint_rhoS. 243

M_rho_2c_MCWEDA_Harris.f90.. 245

Name of subroutine: initialize_rhoS_2c_Harris. 245

Name of subroutine: rhoS_2c_Harris. 246

Name of subroutine: overlapS. 246

Name of subroutine: rhoS_ontopL_Harris. 247

Name of subroutine: rhoS_ontopR_Harris. 247

Name of subroutine: rhoS_atom_Harris. 248

Name of function: rint_overlapS. 248

Name of function: rint_rho_ontopL. 249

Name of function: rint_rhoS_ontopR. 250

Name of function: rint_rhoS_atom.. 251

Name of function: rint_rhoS_ontopL. 252

M_rho_3c_MCWEDA_Harris.f90.. 252

Name of subroutine: initialize_rho_3c_Harris. 253

Name of subroutine: rho_3c_Harris. 254

Name of subroutine: phiint_rho. 254

M_rho_2c_MCWEDA_Harris.f90.. 255

Name of subroutine: initialize_rho_2c_Harris. 256

Name of subroutine: rho_2c_Harris. 256

Name of subroutine: rho_ontopL_Harris. 257

Name of subroutine: rho_ontopR_Harris. 257

Name of subroutine: rho_atom_Harris. 258

Name of function: rint_rho_ontopL. 258

Name of function: rint_rho_ontopR. 259

Name of function: rint_rho_atom.. 260

M_bcna_3c_Harris.f90.. 261

Name of subroutine: initialize_bcna_3c_Harris. 262

Name of subroutine: bcna_3c_Harris. 263

Name of subroutine: bcna_Harris. 263

Name of subroutine: phiint_bcna. 263

M_charges_Lowdin.f90.. 266

Name of subroutine: calculate_charges. 266

Name of subroutine: writeout_charges. 267

Name of subroutine: destroy_charges. 267

Qmixer_Anderson_DOGS.f90.. 268

Name of subroutine: Qmixer. 268

Qmixer_Anderson_DOGS.f90.. 269

Name of subroutine: Qmixer. 269

M_density_matrix.f90.. 271

Name of subroutine: density_matrix. 271

Name of subroutine: read_fermie. 272

Name of subroutine: fermie. 272

Name of subroutine: writeout_density. 273

Name of subroutine: destroy_denmat. 274

M_diagonalization_Lowdin_gamma.f90.. 274

Name of subroutine: diagonalization_initialize. 275

Name of subroutine: diagonalize_S. 275

Name of subroutine: diagonalize_H_Lowdin. 276

Name of funciton: phase.f90. 276

M_diagonalization_Lowdin_kpoints.f90.. 277


 

A short comment on documentation

 

As can be seen towards the latter part of this book, much work has been applied to documenting all Modules for ease of use. This section outlines the layout of that documentation. The "module.doc" file is freely available so as a developer can write-up their work in the same fashion for other users.

Module Title.

use statement for this module

Short summary of module, what it does, where it comes from, where it “fits in” with the rest.

Dependencies:

·List of each

·other module

·Required by this one

Module (Global) Variables:

Variable

Name   Type  Brief description.

In a table, list name, type, and describe all public variables here.

Derived types:

Name   Type  Brief description.

In a table, list name, type, and describe all derived-type variables here.

Short description of the type, including typical usage such as what it is indexed over or allocated by.

Subroutines:

Name of subroutine:

example call statement

Name and Arguments. . (Implementation example)

Short description of what this does.

Dependencies and globals used:

List all subroutines' dependencies here.

Inputs:

List all input variables here.

Outputs:

List all output variables here.

Functions:

Name of function:

example call statement

Name and Arguments. (Implementation example)

Short description of what this does.

Dependencies and globals used:

Type Structure :: s

Inputs:

List all input variables here.

Outputs:

List all output variables here.

 

In cases of all written functionality, a document of this form must be filled out to assist future users and developers.

 


Fortran features "new" to new Fireball.

 

Within our new Fireball-framework, there are a couple of newer Fortran features that have been used. This section highlights these features and explains their used in Fireball.

Fortran's steering committee has a fairly aggressive update policy currently. There is a upgrade every couple of years with a major upgrade every other release. This started with the release of Fortran90 and there have been releases in 95, 2003 and 2008 since. One big deal is that it is backwards-compatible, this is the first programming language with a rich history after all. For this reason F90 is fully compatible with F77.

Fortran's core focus is to be a modern, efficient language and appropriate to number crunching and high performance computing. At the time of writing, this F2003 is now fully supported by Cray, IBM, PGI and Intel compilers. F2008 is only partially supported currently.

The biggest shift in Fortran was the 90 release, and much of the features that were new in that upgrade are what is used now in new Fireball.

The main features that are used are: Modules, Derived-Types, Pointers,  Advanced Array Manipulation and Explicit Interfaces. Fortran is currently moving more and more towards being fully object-orientated. Which is a very popular methodology, as oppose to more traditional sequential programming. The advantages of object orientated programming is well established, but the learning curve is a little rough. In new Fireball, we use a module orientated approach. Namely we take some of the advantages of object orientated programs, and try to avoid the headaches.

One of the big advantages of the modular approach is when debugging is required. In debugging, the majority of the time is spent locating the bug, not actually fixing it. This is especially difficult to locate if you are using global variables that can therefore have been edited anywhere within the program. By having separate modules, the number of lines of code where the bug could be is reduced to the module and it's dependencies, which is an easier problem to solve.

 

Modules

Modules within Fortran90+ (i.e. Fortran90, 95, 2003 or 2008) are used extensively in new Fireball. To put the concept in context, consider the reasons we use subroutines and functions. Basically, they serve 3 main purposes:

i) reuse of code blocks,

ii) allow us to repeat operations on different data sets,

                                for example,

            call do_this (data1)

            call do_this (data2)

            call do_this (data3)

and iii) hide local variables so that names can be reused.

                                for example,

            subroutine do_this (data)

            integer :: i, j   !Local variables, not

            real :: x, y, z   ! accessible outside of the

                                    ! subroutine.

These are concepts that should be familiar to the reader. Modules are a logical extension of this type of functionality. They're a larger more flexible tool to group content. They can contain many sections and types of code, such as:

·Derived Type declarations (which will be discussed later)

·Variables, Arrays and Structures.

·Subroutines

·Functions

A module is accessed via a use statement in the module that needs to utilize some functionality within the called module. These are used extensively in the new Fireball-framework, as they allow us to encapsulate entire sections of work and use the Makefile to decide what is actually called. For example the DOGS and HARRIS routines are each in their own modules, with the decision of which is used made at compile-time. The "core" functionality of Fireball is also contained within modules that may or may not be required for different simulations.

The one main exception is the driver- e.g., Fireball.f90, which is a program that uses all modules, and not a module itself. Everything else is contained within module files.

Derived Types (a.k.a. structures)

Structures are a magnificent tool for organizing data, and are used wherever possible within the new Fireball programs. Essentially, they are very similar to "structs" in C programming. They allow the programmer to compound different variables into one type.

The nomenclature takes a little getting used to, but the declaration specifies a list of items, thus creating a "derived type" and when a variable of this type is instantiated, it is known as a "structure".

A structure can has the following basic properties:

·Can be allocatable. You can have an array of structures.

·Can contain:

·Variables of simple type (real, integer, logical, character , etc.)

·Arrays, both static and allocatable

·Other derived-types (this is used in the case of, e.g. atom%shell in new Fireball.

By example, this is the declaration of the structure "atom" in new Fireball, which is a structure of type T_atom, and is declared in M_configuraciones.

 

 

 

 

 

 

 

This derived type contains an integer called imass, Q and Q0 which are real numbers, three arrays of dimension (3) and two pointers to two other derived types, a type T_shell called shell and a type of T_species called species.

When this type is instantiated later,

 

 

and then allocated, we can access any variable within the structure with the "%" operator. For example, if I wish to know the imass of atom i, the line would be:

atom(i)%imass

A very useful analogy is to think of structures as being similar to folders on you desktop filesystem. You can keep multiple files and other folders in there, exactly as we do with structures.

Pointers

Pointers, as the name implies, point to something. They can be allocated memory in their own right and then another pointer of the same type can point at that pointer. Clear and simple, right?

More clearly put, a pointer allows us to point at something, this means that we don't need to copy variables for use, thus saving memory, and we can shorten names within the code itself (like aliases), making the code clearer and easier to read.

Pointers are associated with a target via the "=>" operator, such as in this section of code, from M_Dassemble_2c:

 

 

 

 

Now, the pointer, Deriv_pkinetic points at the iatom-th, Deriv_kinetic. This means that whenever I use Deriv_pkinetic%variable in the code, I'm actually looking at Deriv_kinetic(iatom)%variable. The pointer is then pointed at the next iatom when the loop runs again.

In the new Fireball-framework, we use pointers to structures often. An inspection of the code is advised to work with these, they are quite simple to understand when you look at them in action.

Array manipulation

Like pointers, arrays can be allocated memory dynamically as of Fortran90. The big advantage of this is that you can use less memory in runtime by optimising the size of the arrays, this is done in new Create with the get_munu subroutine. A count is carried out of the number of matrix elements required and then the array is allocated that memory. In previous versions of Fireball, you had to make the array big enough, and that was all you could do. This means that you could accidently access a point in the array which has not been given a value, and that the memory was stored on the stack, which is limited in Fortran to 2Gb.

Allocatable arrays are allocated on the heap, which has not got that limit (especially if you use the compile flags for ifort " -mcmodel=large -intel-shared", or equivalent depending on the compiler). And they can be deallocated in runtime also, freeing up memory as the simulation continues.

An allocatable array is declared with a : as a placeholder for each dimension, e.g.:

 

 

 

 

 

 

The first 5 arrays declared above are static, and the second 5 are allocatable in runtime.

Arrays can be summed together directly, without having to make a loop over the indices and add one element at a time as of Fortran90. This is true for basic operators, subtraction, division and multiplication, also.

Explicit interfaces

The last big-deal functionality from Fortran90+ that needs to be discussed is so-called explicit interfaces. This allows us to pass a function as an argument into another function or subroutine. It's used extensively in new Create where the actual loops are all the same with the exception of the actual interaction which is what the final integration is carried over.

If the reader is not familiar with Create, just keep in mind that we can pass a function as an arguement.

An example of this is below, the interface, explaining the functions inputs and outputs, is declared in same part of a subroutine where variables are declared, this is from M_integrals_2c in Create, the subroutine is called "evaluate integral":

 

 

 

 

 

 

 

 

 

 

So in arguments and inputs, there is an interface, describing a function, rint, which takes all of these arguments and outputs a real value, "rint".

Now, when evaluate_integral_2c is called, a function, that takes these arguments, is passed by name. This allows the developed to pass in a different function for each different interaction that is being evaluated, reducing the overall number of lines of code and simplifying debugging.

Conclusions

This chapter sums up, in general, the new Fortran90+ capabilities that are exploited in new Fireball. A fantastic resource to explore these further is the video from Xsede, which is available at:

 http://www.tacc.utexas.edu/user-services/training/course-materials

and is about halfway down the page, the actual online course was held last March 5th, but is held every six months.

 

This document was written by Dr. Barry Haycock on Wednesday, 6th of June 2012. Questions, suggestions for improvement, criticisms and opinions are welcome at barry.haycock@mail.wvu.edu.

It is written to serve as an explanation to a new developer for the Fireball-Lightning / Fireball-Thunder programs. This document was originally written for the Fireball World Conference in Orlando June 18th - 22nd 2012.


Main structures implemented in the new Fireball-framework

 

Using the new Fireball-framework for development should be easier than ever. Previous chapters have shown how various elements of Fortran90+ have been used in a conceptual manner. Here is a list of the main structures (that is, implemented derived-types), and an overview of what data is there to use in your modules.

A more general description of what is in each and every file is in this volume also, that serves as a reference manual, this is an overview, or "quickstart".

The primary structure in the Fireball-framework is the type T_structure, simply called "s", this is an all-encompassing structure so that multiple atomic coordinates can be run via one executible in a high-throuput fashion.

T_structure is declared in M_configuraciones as follows:

All variables within the structure should be clear to anyone with Fireball experience, however, if not, the comments should be clear and there is a breakdown in the section detailing every module.

And is instantiated in the driver, in this case, that's fireball.f90:

 

 

 

A pointer of type T_structure is then pointed at the active structure in the loop over all structures:

Again, this is in the driver file. This means that every subroutine is passed the pointer, s, which contains ALL of the data about the atom configuration being studied, including the atoms, their types and species, positions, etc., for example, from the driver file:

 

 

 

So, for example, in driver_neighbors, in order to get the basisfile name, the command is:

filename = s%basisfile

and all other variables within the s structure can be accessed in a similar way, using the "%" operator.

Most other variables within T_structure are explained by comments, but the types- which are of importance, are discussed herin.

A variable called "atom", of type T_atom is the first of these structures. It's declaration (also in M_configuraciones), is as follows:

and s%atom(:) is instantiated in M_configuraciones/subroutine read_positions right after the number of atoms is read in from the basisfile:

Thus, s%atoms(1) is the atom entry for the first atom in the atomic coordinates being studied and s%atoms(s%natoms)) is the final atom in the molecule.bas file.

As well as coordinates (atoms(:)%ratom) and the other variables in this structure, there are two other derived types. This is a T_species called "species" and a T_shell named "shell".

Type T_species is declared in M_species and is huge, but also contains a Type T_shell named "shell":

 

species contains all of the information about each species, and is made available via the M_species module. The T_shell, T_shell_PP and T_orbitals, which have corresponding instantiation names are declared in M_species also, as described below:

 

species(:) is unique, in that it is allocated in M_species/subroutine read_Fdata, but the atom(:)%species is a pointer to that atom's species. This is clearer by example, so, in  M_species/subroutine read_Fdata, we have:

so, with the line use M_species, any other module can access the species information by species(ispecies)%[variable], where ispecies is some integer corresponding to the species number in the Fdata. However, for the species pointer in atom, we have s%atom(iatom)%species=>species(ispecies) in M_configuracions/subroutine read_positions, which is called as the atomic positions in the .bas file is read in. Thus, species information can also be accessed via the  s%atom(iatom)%species%[variable], for the species information directly about that atom. This costs no more memory but is essential for some purposes during simulation.

The shell, shell_PP and orbital structures are then accessible via both s%atom%species and species in a similar way.

The next structure in the structures structure is the type T_kpoints called kpoints. Declared in M_kpoints:

and instantiated in M_kpoints/subroutine read_kpoints:

Accessing this should be apparant based on the detailed discussion of species and atom.

The type T_transitions in type T_kpoints will not be discussed in this overview.

The final type in the structures structure is the type T_vector, which is used to declare both structures xl and vector_lattice, it takes the form:

and is accessible via the module M_cells. It defines a vector.

Fdata in the new Fireball-framework

The most important aspect of Fireball is the Fdata- where that is stored and how it is accessed. Previous versions of Fireball allocated arrays that were "big enough for whatever we need" and that's that. Which is very inefficient. The new Fireball-framework uses allocated space that is the same size as the number of matrix elements, below is the declaration of the 2c and 3c Fdata structures, the basic unit of which is called T_Fdata_cell_2c or T_Fdata_cell_3c, respecively, these are part of a derived type called T_Fdata_2c_bundle or T_Fdata_3c_bundle:

2c, via M_Fdata_2c:

 

 

and 3c, via M_Fdata_3c:

Access to this data, once it has been read in (Fireball) or generated (Create), is usually done via a pointer, for example, in the M_Fdata_2c/subroutine read_fdata_2c we declare:

Which are then pointed at run time, pFdata_bundle points to the Fdata via indexing over ispecies, jspecies:

and then pFdata_cell points at the cell for that interation using the pointer operator:

where nFdata_cell_2c is the number of actual interaction files in the Fdata and icell is a counter over those.

Block(:,:)

The final important derived type that needs to be discussed here is the  type T_assemble_neighbors and T_assemble_block which replace, for example s_mat on the overlap in the TG code.

Now the types are the same for each interaction, but named accordingly. What is meant by this is that rathar than having an array for the overlap called s_mat, which is indexed over imu, inu, ineigh, iatom, such that:

s_mat(imu,inu,ineigh,iatom)

for the overlap or

t_mat(imu,inu,ineigh,iatom)

for the kinetic is used in TG, the new Fireball-framework uses pointers which will be shown in a minute, of which the form for the overlap is:

pS_neighbors%block instead.

pS_neighbors is of type T_assemble_block, which is a derived type inside type T_assemble_neighbors. These are declared as below, and accessed via M_assemble_blocks:

where block and blocko are to be indexed over imu and inu.

This means that the pointers to these types is taken care of, again in the case of the overlap in M_assemble_2c/subroutine assembleS:

 

and then:

for the iatom/ineighbor combination, then the block can be accessed via:

and similar is done for all other interactions.

 

Conclusions

This chapter is quite conceptual in nature, and care was taken to start off with pointers and derived types that are readily obvious to someone with Fireball experience before building on that to explain how memory is allocated for the Fdata and the MEs in Fireball. It is by no means a complete explanation of how everything in the new Fireball-framework works, but should serve to assist someone in understanding how more specific parts of the source code are constructed and help in coming to terms with the codebase overall.

 

 

This document was written by Dr. Barry Haycock on Wednesday, 6th of June 2012. Questions, suggestions for improvement, criticisms and opinions are welcome at barry.haycock@mail.wvu.edu.

It is written to serve as an explanation to a new developer for the Fireball-Lightning / Fireball-Thunder programs. This document was originally written for the Fireball World Conference in Orlando June 18th - 22nd 2012.

 


General module framework.

 

As mentioned before, the use of "module" files allows us to have self-contained "units" of code that allow us to capture any data that we require without having to modify previously developed modules.

This simplifies both development and debugging. When "core" modules are known to work as specified, then the process of debugging is centralised to the module that is currently being developed. When starting development, one need make a list of what variables are required and then simply add their functionality in whatever number of subroutines and functions that is required to carry out the desired simulation.

The general framework of a "default" blank module file is included here, the next section uses this to show how to make a "hello world" program that is traditionally introduced in any programming language.

All screenshots are generated via eclipse, a common open-source IDE. The general stuff, like the copyright notice and description sections of the module file should be familiar to anyone who has seen the Fireball code, but this is introduced again for those who may not have seen this.

There is a blank module file available in the Fireball repository.

The module file breaks down into a number of standard sections, which are inherited from all previous versions of Fireball, along with some sections that utilize the module capabilities of newer Fortran.

Copyright Notice.

The copyright notice is fairly standard, includes the standard notice as has been in previous versions of Fireball.

Module Description.

The module description is another section of comments that describes what the module is for, how it does what it does, and the contact details of the author(s).

Module Declaration.

In this section, the module itself is declared- that is the module's name is "announced" to the compiler. We also include what other modules this module needs access to- for subroutines or variables.

The "use" statements tell this module to use the data contained in the module(s) declared. In this case that's M_species, M_configurations and M_atom_functions, which are core modules within Fireball.

It has become standard practice to preface every module name with "M_" within the Fireball Framework.

Type Declaration.

Derived Types or simply "Types" are a method of collecting together groups of related variables. These are very similar to structs in the C language. Types are used a lot in Fireball to collect, e.g., atom information. It's helpful to think of them as being like folders in a filesystem.

In this section, the types that are used are declared and comments are  used to describe them and their contents. Type declarations begin with the statement "type [NAME]" and end with the statement "end type [NAME]". It has become standard practice to preface the name of a derived type with "T_".

Module variables.

The module variables are available only to the module and modules that call it via a use statement. For the reader familiar with object orientated programming, these are similar to public variables. They are used in Fireball core modules for derived types like the species data or the atom data.

Care must be taken to remember that the declaration merely declares that we have a derived type, whereas here it is instantiated. The declaration is what a type is, the instantiation is creating a instance of it, and later in the code it will have to be allocated in the case of IncidenceOfExampleBlankPointer, memory is already allocated in the case of IncidenceOfExampleBlankArray, and is a standalone single incidence in the case of IncidenceofExampleBlankOneTime.

It is possible, though ill-advised, to instantiate variables of basic types here, such as a counter, as they are more suited to being declared in the subroutine or function that require them.

Module procedures.

In this section, subroutines and functions are declared and implemented. Within the Fireball Framework, it is typical that the subroutines are declared first, then the functions. It is also typical that the first subroutine is an "initialize_[NAME]", which counts up all the memory that will be required and allocates that to the required pointers, and the final subroutine is called "destroy_[NAME]", which releases the memory used.

This section of the code MUST have the word "contains", to differentiate it to the compiler from the declarations above it.

 

That's literally all this section contains, but it is vitally important.

Subroutine and description.

The subroutine names within the module are each a comment framed above and below by 75 "=" signs.

Below that is a detailed description of what the subroutine does and author information.

Subroutine declaration.

This is fairly self-explanatory, the actual declaration of a subroutine.

This declaration includes an argument, namely the (s) tells the subroutine that when this is called, some variable called "s" will be passed to it. If the subroutine required no passed arguments, the line here would read subroutine initialize_blank ().

One thing to note is the "implicit none" under the subroutine declaration, this is a legacy command in Fortran, telling the compiler to not assume that the first letter in the name of a variable defines its type. It was important when Fortran moved from punchcards to typed code, and needs to be included at all declarations like this.

Argument declaration and description.

In this section, we spell out any passed arguments into the subroutine. In the case of initialize_blank, there is only one argument.

The argument in this case is a target for a pointer. If this were a standard variable the (intent in) modifier would need to be used. Also, if this argument is output-only (intent out) must be in the argument declaration.

Parameters and data declaration.

In some cases, you may need to declare a constant. We reserve this section for this purpose.

For no good reason, this subroutine declares the parameter of pi, typically, we use ALL CAPS for parameter names in Fireball.

Variable declaration and description.

In this section, private variables- that is, variables only used within the subroutine are declared. This includes things like counters, and usually a pointer that will be used to a target via the s derived type.

Allocate arrays.

Arrays that need to be directly allocated before compute-time and local to the current subroutine. In this "blank" module / "blank subroutine, there are none. Usually in an initialization subroutine, there wouldn't be anything here.

Procedure.

The "procedure" section of the subroutine is where the magic happens.  This section is actually the work of the subroutine, whatever algorithm is being implemented.

Because this is an example of an initialize, we count up how much memory is used and allocate the pointer.

We try to make the comments as verbose as possible- this includes using the              "! ***************" shown above to highlight really important parts.

 

 

Deallocate arrays.

The locally-allocated and used arrays are deallocated in this section.

Format statements.

When writing out to a file, it is sometimes useful to use a format statement. The use of which can be found in any basic text on Fortran.

End subroutine.

This simply ends the subroutine.

Other Subroutines.

Other subroutines follow the same form as the "initialize subroutine" that is spelled out above. There is usually at least one subroutine that carries out the actual "work" of the module. In the blank module, this is labelled "do_something_with_blank".

Finally, there must be a a "destroy" subroutine or function that deallocates the arrays allocated by the module.

Functions.

Functions also follow the same form as the subroutines in terms of documentation, comments, arguments and general form. There is some unspoken agreement that this is not as strictly adhered to as in the subroutines. But the description of what the function does and it's inputs and output must be clear.

End module statement.

The end module statement tells the compiler that this is the end of all the module contains.

 

 

This document was written by Dr. Barry Haycock on the 30th of May 2012. Questions, suggestions for improvement, criticisms and opinions are welcome at barry.haycock@mail.wvu.edu.

It is written to serve as an explanation to a new developer for the Fireball-Lightning / Fireball-Thunder programs. The blank module file can be found in the Fireball repository. This document was originally written for the Fireball World Conference in Orlando June 18th - 22nd 2012.

 


List of commonly-used TG variables and their new Fireball equivalent

 

In order to simplify porting, this is a reference for those familiar with the TG Fireball framework, showing commonly used TG variables and their new Fireball counterparts.

 

TG Variable Name

new Fireball Name

Available through:

 

Breakdown by Module:

 

 

 

Barrier not yet implemented.

 

 

 

Bias not yet implemented

 

 

 

 

 

 

 

Module Charges

 

 

 

TG Variable Name

new Fireball Name

Available through:

 

efermi

M_density_matrix/efermi

M_atom_functions

 

nelectron

 

M_atom_functions

 

Qin

s%atom%shell%Qin

M_atom_functions

 

Qneutral

s%atom%shell%Qneutral

M_atom_functions

 

Qout

s%atom%shell%Qout

M_atom_functions

 

dq

s%atom%shell%dQ

M_atom_functions

 

 

 

 

 

Module configuration

 

 

 

TG Variable Name

new Fireball Name

Available through:

 

natoms

s%natoms

M_configuraciones

 

nspecies

s%nspecies

M_configuraciones

 

ratom

s%atom%ratom

M_configuraciones

 

mbeta_max

mbeta_max

M_configuraciones

 

xl

s%xl

M_configuraciones

 

xmass

species%xmass

M_configuraciones

 

a1vec

s%vector_lattice

M_configuraciones

 

a2vec

s%vector_lattice

M_configuraciones

 

a3vec

s%vector_lattice

M_configuraciones

 

symbol

species%symbol

M_configuraciones

 

etotatom

species%etotatom

M_configuraciones

 

rcutoff

species%shell%rcutoff

M_configuraciones

 

xmass

species%xmass

M_configuraciones

 

basisfile

s%basisfile

M_configuraciones

 

lvsfile

s%lvsfile

M_configuraciones

 

 

 

 

 

Module Constants

 

 

 

TG Variable Name

new Fireball Name

Available through:

 

abohr

P_abohr

../constants.h

 

eq2

P_eq2

../constants.h

 

Hartree

P_hartree

../constants.h

 

kb

NOT IMPLEMENTED

../constants.h

 

fovermp

P_fovermp

../constants.h

 

kconvert

P_kconvert

../constants.h

 

pi

P_pi

../constants.h

 

spin

 

../constants.h

 

delk

delk

../constants.h

 

xlevi

xlevi

../constants.h

 

norder1

 

../constants.h

 

amat

amat

../constants.h

 

haveDorbitals

NOT IMPLEMENTED

 

 

 

 

 

 

Module Density

 

 

 

TG Variable Name

new Fireball Name

Available through:

 

bbnkre

kpoints%c

M_kpoints

 

bbnkim

kpoints%c

M_kpoints

 

blowim

kpoints%c_Lowdin

M_kpoints

 

blowre

kpoints%c_Lowdin

M_kpoints

 

rho

denmat

M_density_matrix

 

rhoPP

 

 

 

cape

overlap%neighbors%Dblock

M_DFdata_2c

 

ntheta

P_ntheta

../gridsizes

 

 

 

 

 

Module Energy

 

 

 

TG Variable Name

new Fireball Name

Available through:

 

atomic_energy

species%atomicE

M_species

 

etot

etot

Only in driver .f90

 

ebs

ebs

Only in driver .f90

 

etotnew

etotnew

Only in driver .f90

 

etotold

etotold

Only in driver .f90

 

etotper

etotper

Only in driver .f90

 

etotxc_1c

Not Implemented, yet

Only in driver .f90

 

getot

getot

Only in driver .f90

 

getot_initial

getot_initial

Only in driver .f90

 

getotper

getotper

Only in driver .f90

 

deltaE

d_delta

Only in driver .f90

 

deltaFmax

d_delta_max

Only in driver .f90

 

uiiuee

uiiuee

Only in driver .f90

 

uxcdcc

cdcc

Only in driver .f90

 

uxcdcc_sn

Not implemented, yet

Only in driver .f90

 

uxcdcc_hf

Not implemented, yet

Only in driver .f90

 

uxcdcc_ols

Not implemented, yet

Only in driver .f90

 

 

 

 

 

Module Forces

 

 

 

TG Variable Name

new Fireball Name

Available through:

 

ftot

forces%ftot

M_build_forces

 

ft

forces%kinetic

M_build_forces

 

fana

forces%vna

M_build_forces

 

bcna

vna%block

M_assemble_2c

 

 

 

 

 

Module Interactions

 

 

 

TG Variable Name

new Fireball Name

Available through:

 

norbitals_news%orbitals_new

 

M_configuraciones

 

nbands

s%nbands

M_configuraciones

 

ME2c_max

nME2c_Max

Only in the req'd subroutines in M_integrals and M_Fdata_2c

 

ME2cPP_max

nME2c_Max

Only in the req'd subroutines in M_integrals and M_Fdata_2c

 

lssh

species%shell%lssh

M_atom_functions

 

mu

mu

Only in the req'd subroutines in M_integrals and M_Fdata_2c

 

mvalue

species%shell%mvalue

M_atom_functions

 

nssh

species%shell%nssh

M_atom_functions

 

num_orb

num_orb

Only in the req'd subroutines in M_integrals_2c and M_integrals_3c

 

degelec

block_slot

function from FUNCTIONS/block_slot.f90

 

cp_PP

cl

function from FUNCTIONS/cl.f90

 

h_mat

s%hamiltonian

M_kspace

 

s_mat

s%overlap

M_assemble_2c

 

sm_mat

 

 

 

sVNL

 

 

 

t_mat

s%kinetic

M_assemble_2c

 

vna

s%vna

M_assemble_2c

 

vnl

s%vnl

M_assemble_2c

 

vxc

s%vxc

M_assemble_2c

 

ewald

s%ewald

M_assemble_ewald

 

ewaldlr

s%ewaldlr

M_assemble_ewald

 

ewaldsr

s%ewaldsr

M_assemble_ewald

 

special_k

kpoints

M_kpoints

 

weight_k

kpoints%weight

M_kpoints

 

 

 

 

 

Module neighbor_map

 

 

 

TG Variable Name

new Fireball Name

Available through:

 

neigh_max

neighbors%neighn

M_neighbors

 

neighPP_max

neighborsPP%neighn

M_neighborsPP

 

neigh_b

neighbors%neighb

M_neighbors

 

neigh_j

neighbors%neighj

M_neighbors

 

TG Variable Name

new Fireball Name

Available through:

 

neighn

neighbors%neighn

M_neighbors

 

nPP_b

neighbors_PPp%neighb

M_neighborsPP

 

nPP_j

neighbors_PPp%neighj

M_neighborsPP

 

nPP_map

neighbors_PPp%map

M_neighborsPP

 

nPPn

neighbors_PPp%neighn

M_neighborsPP

 

nPP_self

neighbors_PPp_self

M_neighborsPP

 

nPPx_b

neighbors_PPx%neighb

M_neighborsPP

 

nPPx_j

neighbors_PPx%neighj

M_neighborsPP

 

nPPx_map

neighbors_PPx%map

M_neighborsPP

 

nPPx_point

neighbors_PPx%point

M_neighborsPP

 

nPPxn

neighbors_PPx%neighn

M_neighborsPP

 

nPPx_self

neighbors_PPx_self

M_neighborsPP

 

neighPP_b

neighbors_PP%neighb

M_neighborsPP

 

neighPP_j

neighbors_PP%neighj

M_neighborsPP

 

neighPPn

neighbors_PP%map

M_neighborsPP

 

neigh_comb

neighbors%iatom_common_b

M_neighbors

 

neigh_comj

neighbors%iatom_common_j

M_neighbors

 

neigh_comm

neighbors%jatom_common_b

M_neighbors

 

neigh_comn

neighbors%jatom_common_j

M_neighbors

 

neighPP_comb

neighbors_PP%iatom_common_b

M_neighbors_PP

 

neighPP_comj

neighbors_PP%iatom_common_j

M_neighbors_PP

 

 neighPP_comm

neighbors_PP%jatom_common_b

M_neighbors_PP

 

 

 

 

 

TG Variable Name

new Fireball Name

Available through:

 

neighPP_comn

neighbors_PP%jatom_common_j

M_neighbors_PP

 

neigh_back

 

 

 

neigh_self

neigh_self

M_neighbors

 

neighPP_self

neigh_PP_self

M_neighbors_PP

 

 

 

 

 

Module Options

 

 

 

Options are implemented completely differently- at compile time.

 

 

 

 

Module Outputs

 

 

 

Outputs are implemented differently.

 

 

 

 

Commonly called-upon variables:

TG Variable Name

new Fireball Name

Available through:

 deps

deps

M_Dassemble_2c

 eigen_k

s%kpoints%eigen

M_density_matrix

 eps

eps

M_Dassemble_2c

 etotatom

etotatom

M_atom_functions

 fdataLocation

Not needed

 

 force

forces%ftot

M_build_forces

 iammpi

Not implemented

 

 icluster 

options implemented via input or at compiltime

 

 my_proc

Not yet implemented

 

 natoms

s%natoms

M_configuraciones

 neigh_max

s%neigh_max

M_configuraciones

 neighPP_max

s%neighPP_max

M_configuraciones

 nkpoints

s%nkpoints

M_configuraciones

 nprocs

Not yet implemented

M_configuraciones

 nspecies

s%nspecies

M_configuraciones

 nstepf

 

 

 nstepi

 

 

 num_nonzero

 

 

 numorb_max

 

 

 psi

psi

 

 qstate

qstate

M_density_matrix/subroutine density_matrix

 ratom

s%atom%ratom

M_configuraciones

 symbol

species%symbol

M_species

foccupy

kpoints%foccupy

M_kpoints

iccupy

kpoints%ioccupy

M_kpoints

iammaster

Not yet implemented

 

ioccupy_k

kpoints%ioccupy

 

nkpoints

s%nkpoints

 

norbitals

s%norbitals

 

nspecies

s%nspecies

 

weightk

kpoints%weight

 

 

This document was written by Dr. Barry Haycock on Friday, 8th of June 2012. Questions, suggestions for improvement, criticisms and opinions are welcome at barry.haycock@mail.wvu.edu.

It is written to serve as an explanation to a new developer for the Fireball-Lightning / Fireball-Thunder programs. The blank module file can be found in the Fireball repository. This document was originally written for the Fireball World Conference in Orlando June 18th - 22nd 2012.


Walkthrough- a Fireball "Hello World"

 

Outside of generating a module file, there are a couple of other considerations that need to be addressed when developing a module. The previous chapter, which discussed the Blank Module in detail outlines all of the major parts of a module file.

In this section we are going to start with that blank module, and make a "Hello World", the typical first program anyone learns in any language. The difference here is that we are going to do it within the Fireball framework. This is to show each step.

As an added slight complication, we're going to use a function within the module, this is so as to show the use of functions.

Lets get started...

The first thing we need to do is copy the M_blank_module.f90 and give it some useful name, like M_hello_world.f90, in this case I'm going to make a directory called "Development" and put it in there.

If we now go to that directory and type 'ls' the file is there. We can use any editor we like to edit this file, I'm going to use both Eclipse, as mentioned previously, and vi, which is a command-line editor in Linux, depending on the situation.

Open the new module in your editor and you have exactly what we saw at the end of the last chapter.

The first thing to change is the name in the comments, the description, the declaration and the author name. So, lets do that:

 

We'll take out the use statements because none of that functionality is required in this module.

Next, delete the Type Declarations, we do not need any.

becomes:

Next, we won't be initializing anything, so we can delete the "initialize_blank" subroutine too. Every line from

! ======================================================================

! initialize_blank

! ======================================================================

through to

! End Subroutine

! ======================================================================

        return

        end subroutine initialize_blank

 

can just be deleted.

 

Now, onto the meat- the brand-new subroutine that forms the core of this module. Same as with the module description, we change the name, description, author and declaration:

The next thing to think about is the variables required. This is a very simple program, but lets declare a character string, we have no arguments and no parameters, so:

and then the procedure of this subroutine, which is a simple write out to the std output and to a file:

It's really that simple. The last parts of this subroutine are the deallocate, the format statements, both contain nothing, and the end of the subroutine:

That's the end of the one and only subroutine. Bit more deleting here, and we are ready to go on.

We have no pointer arrays to deallocate, so we can simply delete the destroy_arrays subroutine delete everything from the lines:

through to the lines:

So that this section of the code looks like:

And there you have it! One brand new module file. Truthfully, this is pretty useless in terms of actual functionality, but we've successfully shown how the structure of the Fireball modules work, giving us a firm foundation to build our own modules.

There are a couple of other small considerations. Firstly, we have to update the Makefile to compile this new module into the code- the plan is to make this simpler with modifiers to the Makefile arguments, but for the moment, we will do this manually. Secondly, we have to update the driver file. In the new framework, the driver is simply the program file, for example, the fireball.f90. In previous versions of the code, this file carried the code for a lot of functions. Now it simply contains calls to each subroutine that you need for your calculation, this simplifies reading the code and makes it far easier to add new functionality.

 

The "Driver" program.

 

Outside of generating a module file, the driver is the ONLY other place that code has to be added to Fireball to add functionality. This is because the program has to "call" your current module. It means that other than this one line or so in the driver, your module is entirely self contained.

In the driver, we have to add a use statement for our new module, which just looks like this:

The use statements can be in any order, but we typically label with comments what each one is, again for clarity.

 

The only other thing we have to do is add our subroutine calls. In the case of a "real" module, there may be a few subroutines, as well as the  initialize subroutine and the destroy subroutine. However, in our case, we don't have that. So we just have to choose a place for the subroutine to be called, and put it in. I've decided to just put this call at the start of the program, right after the "welcome" stuff. But with a module this simple, it could go anywhere. With more complex modules, you'll have to decide where your calls go, depending on what they do. So, for example:

And that's all we need do in the driver, in this case I used the fireball.f90, but this could also be create.f90, lightning.f90 or begin.f90, depending on the functionality you are adding.


Editing the Makefile.

 

So, that's the lot. To make our new module compile with the rest of the package, we just have to add it to the Makefile. Again, by convention everything is labelled in the Makefile with comments.

In the Makefile, we'll stick to this convention, and make a new section for the hello world module. Right under the copyright information and the MACHINE file and other platform-specific flags, there is a list of the various sections in the Makefile. This will probably have changed slightly since writing, but it should look something like this:

At the end of this list of sections, we need to add a new section, I am going to call it "HELLO". This is shown by the highlighted text, below:

Then, we have to tell the Makefile that this is part of the "objects" needed to create the executable, this is highlighted below:

So, we've told the Makefile to include this when it generates the executable. The final thing we have to do is tell the Makefile how to make this object. We'll add this to the end of the Makefile, so scroll right down to the end, and add the following lines:

Again, observe the labelling convention, we have sections which are headed with the name of the section to keep everything as clear as possible.

We're done. All that is left is to compile the code, and run it. You should see that Fireball runs exactly as before, but now says "Hello World" at the start and generates the hello.dat file.

Well done, now you know how to do anything you want in Fireball!

 


Walkthrough- from TG-Framework to New Fireball-Framework.

 

As an exercise, the NEB routines from TG were made "New Fireball friendly", this was undertaken to prove that moving to the New Fireball Framework would not mean wasting any of the colossal effort that has gone into TG over the years.

This is my account of that porting from one framework to the other. At the time of writing, forces had not been fully implemented into Fireball, so in many ways this was a waste of time, but I did it on a Sunday morning. In many other ways, this was useful in revealing possible problems in moving NEB, MDET, FIRE, and other features of the TG code across to Fireball.

As done in the "Hello World" tutorial, a directory was made (this time called NEB) and the blank module was copied in and renamed. The copyright was added, and the MODULES/neb.f90 module and NEB directory from TG were read through.

The first step was to check all dependencies of the three files used in TG, which were the NEB module file, MODULES/neb.f90, then NEB/initneb.f90, which is the initialiser and finally, the subroutines and functions used, which are all in NEB/neb.f90

The first call to any NEB-based subroutine in TG is to the initialiser, nebinit.f90, which is a standalone file. Aside from that, and the MODULES/neb.f90 file, which contains the global variables, all other subroutines and functions are in NEB/neb.f90.

The call to NEB/neb.f90 is actually a call to move_neb from main_loop_neb, which is called by the TG-Framework's main_loop. This is obviously after initneb has been called at some earlier point.

Given all of that, the best starting point was to copy in the "global" variables from  MODULES/neb.f90 as module globals in my brand new M_NEB.f90 for the New Fireball-Framework.

The next step is to copy and past in the initneb.f90 contents as a new subroutine, after the "contains" statement in M_NEB.f90. And then copy in the contents of the NEB/neb.f90 file.

Now, the tricky parts.

I needed to go through the new M_NEB.f90 and check all the use statements. Most of the use statements within the subroutines can be deleted and put to the top of the module, right under the module title.

In this case, the TG-NEB required these use statements:

use configuration

use neb

use fragments

use charges

use interactions

use dimensions

use barrier

use options

Some of these were originally in subroutine calls, some at the start of NEB/neb.f90. I copied every one up to the top of the new M_NEB.f90 and went through them one by one:

use configuration   -> use configuraciones

use neb -> No longer required (we copied its contents out of MODULES/NEB.f90 to the header in this file)

use fragments       -> Not implemented yet in New Fireball-Framework

use charges -> EVERYTHING in here is now taken care of by the Type shell, which is inherited from M_species via configuraciones

use interactions -> is now "include ../interactions.h"

use dimensions   -> is now "include ../gridsizes.h"

use barrier                             -> Not implemented yet in New Fireball-Framework

use options      -> Doesn't exist in the new Framwork because you don't                                                    need it.

That was it. The new header looks like this:

I had to fudge a variable from barrier.f90, which is the ratom_final(:), but this was a trivial addition to the global variable declarations.

This was all quite simple so far. The next step is to look for the TG-specific global variables and "translate" them into New Fireball variables. For example, natoms, a global in TG is now s%natoms in New Fireball so as multiple structures can be simulated at the same time.

It's at this moment that I realised we need a huge table of New Fireball equivalences to TG common variables and vice-versa. This will be done by the time you are reading this. A lot of trial-and-error and not having a table I can just search though gave me a bunch of variables whos names needed to be slightly modified in M_NEB.f90. Namely:

natoms                  became                          s%natoms

nzx(ispec)              became                          s%species(ispec)nz

symbol(iatom)     became                                   s%atom(iatoms)%species%symbol

shifter                     became                                   Nothing-it's not needed

ratom(iatom)        became                                   s%atom(iatom)%ratom

natoms                  became                                   s%natoms

nspecies                 became                                   s%nspecies           

imass(iatom)        became                                   s%atom(iatom)%imass     

xmass(iatom)       became                                   s%atom(iatoms)%species%xmass 

These took a while to work out, but a table will be developed to just "look them up" and make porting much simplier.

In the case of the call to initneb (natoms, nspecies, imass, nzx, ratom) every argument was dropped as a result of changing the variable names. It became initneb (s), simlar therefore in style with other new framework subroutines.

This also occured with the move_neb call.

That was it. Literally. I modified the Makefile, putting the new module in there, and I have to modify the driver (fireball.f90) and place initneb with the initializers and move_neb after the scf call.

And, this is what I got:

 

The module description is another section of comments that describes what the module is for, how it does what it does, and the contact

I had already just compiled, this picture just serves as proof it did compile.

At the moment, rudimentary forces are all that is implemented and barrier.f90 or an equivilent has not yet been implemented, but the work around was declaring a global ratom_final() real number under the cut-and-paste from MODULES/NEB.f90. I have also to go through and edit the descriptions and add a destroy_NEB subroutine to deallocate all arrays.

But that was it, it should just run now, if forces were in place.

 

 

This document was written by Dr. Barry Haycock on Sunday, 3rd of June 2012. Questions, suggestions for improvement, criticisms and opinions are welcome at barry.haycock@mail.wvu.edu.

It is written to serve as an explanation to a new developer for the Fireball-Lightning / Fireball-Thunder programs. The blank module file can be found in the Fireball repository. This document was originally written for the Fireball World Conference in Orlando June 18th - 22nd 2012.

 


 

Module Documentation

 

The following pages serve more as "reference documents" with respect to the new Fireball-framework. We have tried to follow the documentation format outlined in the first section of this book so as a developer can look up details about any module, subroutine, function or derived type and structure as quickly as possible.

 

The first page is the subroutine call tree as output using "Understand" which is available at http://www.scitools.com/index.php following that, at the time of compilation all module files and function files from new Fireball. The outlines of modules is subject to change as the codebase grows, and electronic versions of this documentation will be updated as required.

 

 


 

New Fireball Call Tree

 
 

 

 

 

 

 

 


ArchInternalDependencies-DirectoryStructure_Fireball.png

 

 

 

 

 

 

 

 

 

 

 


 

M_atom_functions.f90

use M_atom_functions

 

This is a module containing two subroutines which will read in wavefunctions and interpolate and two other subroutines which will read in the neutral atom potentials and interpolate. The subroutines existing in this module are as following:

 

·         read_wavefunctions

·         psiofr

·         read_napotentials

·         vnaofr

 

Dependencies:

·M_species

 

Module (Global) Variables:

Variable Name

Type

Brief Description

wf

T_data_species

wavefunction information

na

T_data_species

neutral atom information

mesh

int

number of points in file

dr

real

spacing between points

rcutoffA

real

cutoff for this shell (Angtrom)

psitemp

real()

temporary array for storing psi

 

Derived types:

Name of Type: T_data_shell

 

Information about the shell.

 

Variable Name

Type

Brief Description

mesh

int

number of data points

dr

real

distance between mesh points

r

real

value of r at grid point

FofR

real

value of function at grid point

 

Name of Type: T_data_species

 

Information about the species

 

Variable Name

Type

Brief Description

mesh_max

int

maximum mesh size for species

dr_min

real

minimum spacing dr for species

rutoffA_max

real

maximum cutoff for this species

etotatom

real

total energy of the atom

shell_data(:)

T_data_shell

shell data for each shell

 

 

Subroutines:

Name of subroutine: initialize_wf

call initialize_wf ()

 

Sets up the wfmesh grid for BEGIN by calculating the change in radius between wfmesh points and the radius at each wfmesh point

 

Dependencies and globals used:

Type Structure :: species

Inputs: None

Outputs:

Variable Name

Type

Brief Description

wf

T_data_species

wavefunction information

na

T_data_species

neutral atom information

 

Name of subroutine: read_wavefunctions

call read_wavefunctions()

 

This subroutine reads in the wavefunctions of atom.

 

Dependencies and globals used:

include '../constants.h'

Type Structure :: s

Type Structure :: wf

Inputs: None

Outputs:

Variable Name

Type

Brief Description

wf

T_data_species

information about the wavefunction (now allocated)

 

 

Name of subroutine: read_napotentials

call read_napotentials

 

This subroutine reads in the neutral atom potentials of atoms.

 

Really, what we have is the true neutral atom potential in file *.na0 and the coulomb potentials for each wave function state - s, p, d, ..., etc.

 

Note: The potential is already in Angstrom units on the data file. The variable ispecies is a flag which would indicate in the multi-species MD code which species to read.

 rc must be input to this subroutine in abohr units.

 

Dependencies and globals used:

Type Structure :: s

Type T_data_species :: na

Inputs: None

 

Outputs:

Variable Name

Type

Brief Description

na(:)

T_data_species

the neutral atom information

 

Functions:

Name of function: psiofr

psiofr (r, ispecies, jspecies)

 

This function returns the values psiofr(r) for the corresponding shell of the atom described in read_atoms currently in the PSITEMP Variable. This is done so as the Interpolator Adaptive Simpson or other integrator is passed a function that is dependent on 'r' and only 'r'.

 

The radial functions are normalized so that:  int ( psiofr**2  r**2  dr ) = 1.0

The value of r input to this function must be in angstrom units.

 

Dependencies and globals used:

Type Structure :: s

Inputs:

Variable Name

Type

Brief Description