forked from Warwick-Plasma/EPOCH_manuals
-
Notifications
You must be signed in to change notification settings - Fork 0
/
epoch_dev.tex
3908 lines (3578 loc) · 176 KB
/
epoch_dev.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\include{epoch_head}
\externaldocument{epoch_user}
\begin{document}
\includepdf{images/title_page_dev}
{
\fontfamily{phv}\selectfont\input{epoch_dev_title}
}
\fontfamily{garamond}\selectfont%
\tableofcontents%
\newpage%
\DefineShortVerb{\#}
\fvset{formatcom=\color{warwickred}}
\section{{\EPOCH} developers manual}
This section of the manual is aimed at people who intend to edit the {\EPOCH}
source code to extend or modify existing features, add new diagnostics or
develop new physics packages. It is expected that anyone reading this part of
the manual will be familiar with the material covered in the main manual,
particularly the notices about the layout of particle, particle\_list and
particle\_species structures in \sect{partrep} of the user manual.
A quick note: Some files have the normal Fortran file extension .f90, while
some have the slightly unusual .F90. The difference is that files with the
.F90 extension are passed through the preprocessor before they are compiled
allowing the use of precompiler directives (the \#ifdef commands).
\scaledcapimage{./images/coreblock}{coreblock}{Block diagram of the core
routines in {\EPOCH}}{0.5}
\section{General layout of the {\EPOCH} code}
The names of the source files in {\EPOCH} are fairly self explanatory but, for
clarity, they are explained here.
\subsection{Directories}
All source files are contained in the \inlinecode{src} directory and its
subdirectories. There is a stylistic reason for the layout of the files, which
is explained here
\begin{itemize}
\item \inlinecode{src} - Files in this directory are the core files for the
basic {\EPOCH} code, such as the field solvers, the particle pusher, the
boundary conditions and the lasers.
\item \inlinecode{src/deck} - Files in this directory are responsible for
dealing with the permanent input deck parser and include the core parts of
the deck handler, and also the routines which deal with the blocks in the
input deck files.
\item \inlinecode{src/housekeeping} - Files in this directory deal with those
parts of the code operation which are not physics; including the load
balancer, the MPI setup routines and the moving window.
\item \inlinecode{src/include} - This directory contains the shape function
code fragments which are inserted into the particle push at compile time.
\item \inlinecode{src/io} - The files involved in all I/O activities, including
the distribution functions and the particle probes.
\item \inlinecode{src/parser} - The files for the maths expression parser are
in this directory, including both the core implementation of the shunting yard
algorithm and the routines for implementing the permanent functions,
constants and operators for the input deck.
\item \inlinecode{src/physics\_packages} - Contains routines which implement
additional physics for the code.
\item \inlinecode{src/user\_interaction} - Contains any Fortran routines which
a user has to modify to use the code with internal initial conditions, or to
temporarily extend the maths parser or the input deck.
\end{itemize}
\subsection{The files in \inlinecode{src}}
\begin{itemize}
\item\inlinecode{boundary.f90} - Includes all boundary conditions except laser
and transmissive boundaries; including field and particle MPI boundaries, and
field and particle domain boundaries.
\item\inlinecode{epoch\{n\}d.F90} - Main driver for the code. Reading this
routine gives the basic layout of the code flow.
\item\inlinecode{fields.f90} - The Maxwell field solver.
\item\inlinecode{laser.f90} - Includes laser and transmissive boundary
conditions for each boundary and also the housekeeping routines for the laser
objects.
\item\inlinecode{particles.F90} - The particle pusher.
\item\inlinecode{shared\_data.F90} - This file includes all the global variable
and type definitions. Usually new variables should be defined in this file.
\item\inlinecode{gen\_commit\_string} - This is a script used to generate an ID
string when compiling the code.
\item\inlinecode{gen\_src\_module} - This is a script which is used at build
time to generate a Fortran module containing the source code. This is used for
embedding the {\EPOCH} source code into restart dumps.
\end{itemize}
\subsection{The files in \inlinecode{src/deck}}
\label{sec:src_deck}
\begin{itemize}
\item\inlinecode{deck.F90} - The main input deck routines. Deals with opening
files, reading data and MPI distribution of the data to all processes. Also
includes the routines which deal with calling the right reader routines to
deal with a given block.
\item\inlinecode{deck\_boundaries\_block.f90} - Reader routine for the
``boundaries'' block of the input deck.
\item\inlinecode{deck\_constant\_block.f90} - Reader routine for ``constants''
blocks in the input deck.
\item\inlinecode{deck\_control\_block.f90} - Reader routine for ``control''
block in the input deck.
\item\inlinecode{deck\_dist\_fn\_block.f90} - Reader routine for ``dist\_fn''
blocks in the input deck.
\item\inlinecode{deck\_fields\_block.f90} - Reader routine for ``fields''
blocks in the input deck.
\item\inlinecode{deck\_io\_block.F90} - Reader routine for the ``io'' block in
the input deck.
\item\inlinecode{deck\_laser\_block.f90} - Reader routine for ``laser'' blocks
in the input deck.
\item\inlinecode{deck\_particle\_probe\_block.F90} - Reader routine for
``particle\_probe'' blocks in the input deck.
\item\inlinecode{deck\_species\_block.F90} - Reader routine for ``species''
blocks in the input deck.
\item\inlinecode{deck\_window\_block.f90} - Reader routine for the ``window''
block in the input deck.
\item\inlinecode{strings.f90} - Basic string handling routines such as
``str\_cmp'' and routines for converting strings to numbers WITHOUT using the
maths parser are covered in this routine.
\item\inlinecode{strings\_advanced.f90} - The routines which pass maths along
to the maths parser routines are here.
\end{itemize}
\subsection{The files in \inlinecode{src/housekeeping}}
\begin{itemize}
\item\inlinecode{balance.F90} - Contains the routines for the load balancer
and related routines.
\item\inlinecode{current\_smooth.F90} - Contains the current smoothing routines.
\item\inlinecode{dummy\_encoded\_source.f90} - A dummy module used when the
code is being built without the ability to write the source code into restart
dumps.
\item\inlinecode{mpi\_routines.F90} - Contains the routines dealing with the
setup of the MPI layer and the creation of the communicator. Also allocates
all arrays for the first time before load balancing.
\item\inlinecode{mpi\_subtype\_control.f90} - Contains the routines that setup
the mpi types required by the I/O subsystem.
\item\inlinecode{particle\_pointer\_advance.f90} - Contains subroutines which
walk through the lists of particles and species for I/O purposes.
\item\inlinecode{partlist.F90} - Contains the routines which deal with the
particle lists which are used for inter-processor communication of particles.
\item\inlinecode{random\_generator.f90} - Contains the random number generator
routines.
\item\inlinecode{setup.F90} - Deals with the setup of the grids and domains and
restarting from previous output dumps.
\item\inlinecode{shape\_functions.F90} - Contain the particle shape functions
used for calculating the particle weighting.
\item\inlinecode{split\_particle.F90} - Is the implementation of a
demonstration of particle splitting routines.
\item\inlinecode{utilities.f90} - Contains growable arrays used by the species
block parser.
\item\inlinecode{version\_data.F90} - Contains version information for the
current {\EPOCH} code.
\item\inlinecode{welcome.F90} - The routine which prints the banner message and
compiler options info.
\item\inlinecode{window.F90} - The routines which deal with the moving window.
\end{itemize}
\subsection{The files in \inlinecode{src/io}}
\begin{itemize}
\item\inlinecode{calc\_df.F90} - Despite the slightly confusing name, this
subroutine deals with derived functions like number density, charge density
and mass density.
\item\inlinecode{diagnostics.F90} - Contains the routines which actually dump
the data, decide what to dump and also the routine to calculate the timestep.
\item\inlinecode{dist\_fn.F90} - Contains the routines to calculate the
distribution functions, and also the routines handling the requests for
distribution functions.
\item\inlinecode{iterators.F90} - Contains the iterator functions used to write
particle data into SDF files.
\item\inlinecode{probes.F90} - Contains the routines which write the data from
the particle probes. Also includes the routines which deal with user requests
to add new particle probes.
\item\inlinecode{sdf\_common.f90} - Core part of the SDF file format. Contains
constants and definitions needed by the SDF format. If attempting to
implement a SDF reader then look here for values of named constants.
\item\inlinecode{sdf\_control.f90} - Core part of the SDF file format. Contains
the routines needed to open and close files etc.
\item\inlinecode{sdf.f90} - Module interface for the SDF file format. This file
specifies the application interface to the SDF library.
\item\inlinecode{sdf\_input.f90} - Core part of the SDF file format. Contains
the general routines needed for reading data from SDF files.
\item\inlinecode{sdf\_input\_cartesian.f90} - Core part of the SDF file format.
Contains the routines needed to read Cartesian meshes and variables from SDF
files.
\item\inlinecode{sdf\_input\_functions.f90} - Core part of the SDF file format.
Contains the routines needed to traverse the block structure of a SDF file
without reading any block specific metadata.
\item\inlinecode{sdf\_input\_point.f90} - Core part of the SDF file format.
Contains the routines needed to read particles meshes and variables from SDF
files.
\item\inlinecode{sdf\_input\_util.f90} - Core part of the SDF file format.
Contains general routines for reading the block structure of SDF files.
\item\inlinecode{sdf\_job\_info.f90} - Contains routines for generating a
unique job-id for each simulation run.
\item\inlinecode{sdf\_output.f90} - Core part of the SDF file format. Contains
the basic routines needed to write data to a SDF file.
\item\inlinecode{sdf\_output\_cartesian.f90} - Core part of the SDF file
format. Contains the routines needed to write Cartesian meshes and variables.
\item\inlinecode{sdf\_output\_point.f90} - Core part of the SDF file format.
Contains the routines needed to write particles meshes and variables.
\item\inlinecode{sdf\_output\_util.f90} - Core part of the SDF file format.
Contains general routines for writing the block structure of SDF files.
\item\inlinecode{simple\_io.f90} - Contains routines for performing the simple
binary I/O required by species\_external and fields\_external blocks.
\end{itemize}
\subsection{The files in \inlinecode{src/parser}}
\begin{itemize}
\item\inlinecode{evaluate.f90} - Contains the routines which actually evaluate
a tokenized expression. The core of this is a simple implementation of an
RPN calculator.
\item\inlinecode{evaluator\_blocks.f90} - Contains the routines which evaluate
a given token into a numerical values. Actually implements the functions,
constants and operators in {\EPOCH}'s maths parser.
\item\inlinecode{shunt.F90} - {\EPOCH}'s implementation of the
``shunting yard'' algorithm used to simultaneously tokenize the input and
convert it from infix notation to RPN.
\item\inlinecode{stack.f90} - Deals with routines for pushing onto and popping
off stacks.
\item\inlinecode{tokenizer\_blocks.f90} - Deal with converting strings found
in a string being tokenized into tokens. Essentially a large collection of
``str\_cmp'' commands testing a string against a known name.
\end{itemize}
\subsection{The files in \inlinecode{src/physics\_packages}}
\begin{itemize}
\item\inlinecode{TABLES} - Subdirectory containing tables
for QED emissions.
\item\inlinecode{numerics.f90} - Some additional numerics
routines, primarily for the photons (QED) package.
\item\inlinecode{ionise.F90} - Physics package dealing with field ionisation.
Field ionisation consists of three distinct regimes; multiphoton in which
ionisation is best described as absorption of multiple photons, tunnelling
in which deformation of the atomic Coulomb potential is the dominant factor,
and barrier suppression ionisation in which the electric field is strong enough
for an electron to escape classically. It is possible to turn off multiphoton or
barrier suppression ionisation through the input deck.
\item\inlinecode{collisions.F90} - Physics package handling particle collisions
and collisional ionisation. See
\url{http://iopscience.iop.org/article/10.1088/0741-3335/57/11/113001/pdf}
for details.
\item\inlinecode{injectors.F90} - Package dealing with particle injection through
a boundary. Currently this handles drifting and non-drifting Maxwellian and
flux-Maxwellian distributions.
\item\inlinecode{photons.F90} - Package for some QED effects.
EPOCH can model QED pair production, synchrotron emission and radiation
reaction as described in Duclous et al
\url{http://iopscience.iop.org/article/10.1088/0741-3335/53/1/015009} and
Ridgers et al.
\url{https://www.sciencedirect.com/science/article/pii/S0021999113008061?via}
\end{itemize}
\subsection{The files in \inlinecode{src/user\_interaction}}
\begin{itemize}
\item\inlinecode{custom\_deck.f90} - This file is where and end user can
temporarily extend the input deck. Described in the
``\nameref{sec:customising}'' section.
\item\inlinecode{custom\_laser.f90} - The file where an end user specifies
laser time profiles without using the input deck.
\item\inlinecode{custom\_parser.f90} - The file where an end user can
temporarily add new functions and constants to the input deck. It is
described in the ``\nameref{sec:customising}'' section of this manual.
\item\inlinecode{helper.F90} - This file contains all the internal workings of
the autoloader. This is in user\_interaction for historical reasons, since
early versions of the code required the end user to modify some parts of the
functions contained in this file. As the autoloader has increased in
complexity, this has ceased to be the case, so it is likely that soon this
file will be move to ``housekeeping''.
\item\inlinecode{ic\_module.f90} - This file is where the internal and manual
initial conditions are set.
\item\inlinecode{particle\_temperature.F90} - Contains the routines for
thermally loading a particle species.
\end{itemize}
\section{{\EPOCH} makefile}
The makefile supplied with {\EPOCH} is a standard GNU make makefile, which must
be user modified to allow a developer to add new files to the code. {\EPOCH}'s
makefile is quite large, so an explanation of how to add new files and new
directories is given below.
\subsection{Adding a new file to be compiled with {\EPOCH}}
There are three things that must be done to cause {\EPOCH} to compile a new
file and link it into the final code. Assume that you're adding a file called
``newfile.F90''. First, find the line which sets the environment variable
\inlinecode{SRCFILES} and add a new parameter which reads\\
\\
newfile.F90\\
\\ This tells the makefile to compile the final code using your new file, the
next thing to do is to add a line which tells the code about the dependencies
for your file. Lower down in the makefile, you'll find a section with lines
which look like:
\begin{boxverbatim}
balance.o: balance.F90 boundary.o mpi_subtype_control.o partlist.o
\end{boxverbatim}
Add a new line for describing all the FILES (NOT modules) which are used by
your new file. If you USE shared\_data, mpi\_subtype\_control and stack in
your file then the line would look like:
\begin{boxverbatim}
newfile.o: newfile.F90 shared_data.o mpi_subtype_control.o stack.o
\end{boxverbatim}
Note the structure of the line with ONLY the source file for the new file
specified, all other used files specify the intermediate .o files. The
remaining element of the makefile which needs to be modified is to add your
new file as a dependency to all the files which USE modules contained in your
new file. This is achieved very simply by adding ``newfile.o'' to the dependency
list for those files which USE your modules. For example if you've written new
boundary conditions and USE your modules in boundary.f90, you'd just change
the line for boundary.f90 from:
\begin{boxverbatim}
boundary.o: boundary.f90 deck_io_block.o particle_temperature.o partlist.o
\end{boxverbatim}
to
\begin{boxverbatim}
boundary.o: boundary.f90 deck_io_block.o particle_temperature.o partlist.o \
newfile.o
\end{boxverbatim}
Note that the backslash characters are line continuation marks in makefiles.
\subsection{Adding new directories to {\EPOCH}'s makefile}
If you want to add an entire new directory to the {\EPOCH} compile path then
you need to add it to the definition of the variable \inlinecode{VPATH}.
Remember to use the variable \inlinecode{\$(SRCDIR)} rather than hard-coding
\inlinecode{src} into the path.
\section{{\EPOCH} core programming}
{\EPOCH} is designed so that it can fairly easily be extended while still being
written in (more or less) standard Fortran90 and MPI1.2. This section details
in increasing complexity what a programmer needs to know to extend {\EPOCH} with
new diagnostics, new physics or even new core solvers. The first few entries
in this section range between style points and explanations of fairly trivial
parts of the {\EPOCH} code, but the end of this section gives an overview of how
one would perform major changes to the complete {\EPOCH} core solver.
\subsection{Physical constants}
In order to ensure that different parts of the code run at the same precision
common physical constants are defined in \inlinecode{shared\_data.F90} and any
new physical constants required by extensions to the code should be placed in
the same location. The constants available in the code are
\begin{itemize}
\item pi - Ratio of a circle's circumference to its diameter.
\item q0 - Charge on electron.
\item m0 - Rest mass of electron.
\item c - Speed of light in vacuum.
\item kb - Boltzmann's constant.
\item mu0 - Permeability of free space.
\item epsilon0 - Permittivity of free space.
\item h\_planck - Plank's constant.
\item ev - The value of an electron volt.
\end{itemize}
Any new constants required should be specified in the same place in
\inlinecode{shared\_data.F90}.
\subsection{Important variables, arrays and array length}
As well as the physical constants, there are some important variables which
you will have to use to do any development with {\EPOCH}. As a general note,
since {\EPOCH} is written with separate 1D, 2D and 3D versions, definitions will
be given for the 3D version of the code and irrelevant dimensions should just
be left out.
\subsubsection{Shape and size variables}
\begin{itemize}
\item #INTEGER :: nx, ny, nz# - The number of gridpoints on the current
processor in each direction. This may change when the load balancer
activates, so always use these variables rather than local copies.
\item #INTEGER :: nx_global, ny_global, nz_global# - The number of gridpoints
in each direction of the whole domain. These numbers will never change and
will be the numbers read in from the input deck.
\item #INTEGER(KIND=8) :: npart_global# - The global number of particles
specified in the input deck. This is not updated as particles leave the
domain through boundaries etc. so it is not guaranteed to be accurate.
\item #INTEGER :: n_species# - The number of species of particles specified.
\item #INTEGER :: nsteps# - The maximum number of steps that the core solver
should take.
\setlength{\emergencystretch}{3em}
\item #INTEGER, DIMENSION(1:nproc{x,y,z}), ALLOCATABLE :: cell_{x,y,z}_min,#
\linebreak#cell_{x,y,z}_max# - The variables #cell_{x,y,z}_min# and
#cell_{x,y,z}_max# represent the part of a global array which is held by the
current processor. Since {\EPOCH} is an MPI code, there doesn't exist a
single copy of any of the global arrays anywhere, but if there did then each
processor would be responsible for the slice which runs
(cell\_x\_min(rank):cell\_x\_max(rank),
cell\_y\_min(rank):cell\_y\_max(rank))
in 2D. These variables are used internally in the load balancer, where it is
updated, but is also used when calculating distribution functions. Here it is
used to define the extents of the MPI type which is used to write the
distribution function to disk.
\end{itemize}
\subsubsection{Input deck variables}
\begin{itemize}
\item #CHARACTER(LEN=entry_length) :: blank# - A special string which the input
deck parser uses to indicate that it's passing a blank string rather than a
string read from the deck which just happens to be blank.
\item #INTEGER :: deck_state# - An integer determining the current sweep of
the input deck by the deck parser.
\item #INTEGER, PARAMETER :: num_vars_to_dump# - A variable describing the
number of variables which should be selectable in the input deck as possible
variables to dump.
\item #CHARACTER(LEN=entry_length) :: extended_error_string# - String used by
some error codes in the deck parser to give more user friendly error
messages.
\item #INTEGER :: data_dir_max_length# - The maximum number of characters in
the name of the output directory.
\item #INTEGER :: n_zeros# - The number of leading zeros in the output filenames
from {\EPOCH}.
\end{itemize}
\subsubsection{Initial conditions (autoloader) variables}
Initial conditions for the autoloader for a given species are described in
{\EPOCH} by the Fortran TYPE \inlinecode{initial\_conditions\_block}. The
definition (in 3D) is:
\begin{boxverbatim}
TYPE initial_condition_block
REAL(num), DIMENSION(:,:,:), POINTER :: density
REAL(num), DIMENSION(:,:,:,:), POINTER :: temp
REAL(num), DIMENSION(:,:,:,:), POINTER :: drift
REAL(num) :: density_min
REAL(num) :: density_max
END TYPE initial_condition_block
\end{boxverbatim}
In 2D, the arrays have one fewer index, and in 1D they have two fewer.
\begin{itemize}
\item #REAL(num) :: density# - Number density for the particles in the species.
When defined runs (-2:nx+3,-2:ny+3,-2:nz+3).
\item #REAL(num) :: temp# - Temperature in Kelvin of the species in space. When
defined runs (-2:nx+3,-2:ny+3,-2:nz+3,1:3). The final index of the array
is a direction index, used to give anisotropic thermal distributions.
\item #REAL(num) :: drift# - Velocity drift in $m/s$ of the species in space.
When defined runs (-2:nx+3,-2:ny+3,-2:nz+3,1:3). The final index of the array
is the velocity direction component.
\item #density_min# - The minimum density below which the autoloader
should not load particles.
\item #density_max# - The maximum density above which the autoloader
should clip the density function.
\end{itemize}
The initial conditions themselves are in the variable
\begin{boxverbatim}
TYPE(initial_condition_block), DIMENSION(:), ALLOCATABLE :: initial_conditions
\end{boxverbatim}
which is allocated to an array of size \inlinecode{1:n\_species}.
\subsubsection{Linked Lists}
Linked lists are a standard computer programming technique which is still
slightly unusual in Fortran, and may well be unfamiliar to many Fortran
programmers. They effectively allow you to have an array of arbitrary length,
although this comes with various trade-offs about memory locality and speed of
accessing elements. The general concept is that of a chain where each link in
the chain only knows about the previous link in the chain and the next link in
the chain. Although there are schemes for doing this in languages which don't
have pointers, the normal method of implementing linked lists is to use
pointers to point to previous and next elements in the list, and this is how
they are implemented in {\EPOCH}. Since both linked lists and Fortran pointers
are slightly esoteric concepts, while being key to the operation of {\EPOCH} a
brief overview of them is presented here.\\
The simplest possible form of a linked list element would be a TYPE which
looks like:
\begin{boxverbatim}
TYPE linked_list
TYPE(linked_list), POINTER :: next
TYPE(linked_list), POINTER :: prev
END TYPE linked_list
\end{boxverbatim}
You also have to have a pointer to the start of the list, and to speed up
adding new elements to the list, you normally also keep a pointer to the
last element of the list. Therefore, you would also have variables which look
like:
\begin{boxverbatim}
TYPE(linked_list) :: head, tail
\end{boxverbatim}
Since Fortran pointers are not initialised in any particular state, you have
to remember to set the head and tail pointers to explicitly point nowhere
(normally called a null pointer by analogy with the older C style
pointers). This is done using the nullify command.
\begin{boxverbatim}
NULLIFY(head)
NULLIFY(tail)
\end{boxverbatim}
The same thing is important when creating a new linked list element, so you
would normally have a creation function for linked list elements.
\begin{boxverbatim}
SUBROUTINE create_element(element)
TYPE(linked_list), POINTER :: element
ALLOCATE(element)
NULLIFY(element%next)
NULLIFY(element%prev)
END SUBROUTINE create_element
\end{boxverbatim}
Note that the allocate function can be used on pointers in the same way that
it can be used with variables which have the allocatable attribute. However,
there is one important difference between a pointer and an allocatable
variable. If you attempt to allocate an already allocated variable which has
the allocatable attribute then the code will fail, whereas allocating an
already allocated pointer is perfectly valid, and will allocate the new
variable and point the pointer to it. This does not deallocate the memory that
the pointer previously pointed to, and Fortran does not have a ``garbage
collector'' which deallocates memory no longer accessible. So if you
allocate a pointer which already points to a variable, it is very important
that you have another pointer somewhere which points to the same memory. Once
you no longer have a pointer to an area of memory, that area of memory is
completely inaccessible and cannot even be deallocated. This is termed a
memory leak and for programs which run for many cycles and have a memory leak
on each cycle, the entire memory can very quickly be used up.
So, to add a new element to the list you would have a subroutine which looks
like:
\begin{boxverbatim}
SUBROUTINE add_element(element)
TYPE(linked_list), POINTER :: element
IF (.NOT. ASSOCIATED(head)) THEN
! Adding first element to list, so just set
! both head and tail to the element
head=>element
tail=>element
RETURN
ENDIF
tail%next=>element
element%prev=>tail
tail=>element
END SUBROUTINE add_element
\end{boxverbatim}
This subroutine adds the new Fortran operator of ``$=>$'' which means ``points
to''. Unlike C or similar languages, Fortran pointers try to be partially
transparent to the end user, so the following code would fail:
\begin{boxverbatim}
PROGRAM test
REAL, TARGET :: a = 10.0
REAL, POINTER :: b
b = a
END PROGRAM test
\end{boxverbatim}
This happens because Fortran will try to copy the value of ``a'' into ``b''.
However, ``b'' is a pointer which hasn't been initialised, so the code will
crash when it tries to copy the data in (in theory, the code may not crash if
the uninitialised ``b'' pointer happens to point somewhere in memory which is
a valid target, but this is very unlikely). Note also that ``a'' has the
attribute ``TARGET''. The target attribute means that it is possible to point
a pointer to this variable. You can only point a pointer to a variable which
is either a pointer itself or has the target attribute. This is to try and
keep Fortran pointers ``safer'' than C style pointers. The correct code would
use \inlinecode{b$=>$a}, at which point ``b'' is set to point to ``a'' and
can then be used everywhere in place of ``a''.
So, to set up a linked list of n elements, you would use the following code:
\begin{boxverbatim}
TYPE(linked_list), POINTER :: new
NULLIFY(new)
DO i = 1,n
CALL create_element(new)
CALL add_element(new)
ENDDO
\end{boxverbatim}
To then run through the elements of your newly created linked list, you would
use code like:
\begin{boxverbatim}
TYPE(linked_list), POINTER :: current
current=>head
DO WHILE(ASSOCIATED(current))
! Do stuff
current=>current%next
ENDDO
\end{boxverbatim}
This code snippet introduces one new function ``ASSOCIATED'', which tells you
whether a pointer is a null pointer or not (this is why it is so important to
nullify new pointers, because ASSOCIATED on its own doesn't check whether a
pointer is valid, just whether or not it is a null pointer). You can also use
ASSOCIATED to check whether a pointer points to a particular object or not, in
which case the syntax is #RESULT = ASSOCIATED(b, TARGET=a)#, which
returns true if ``b'' points to ``a'', or false if it doesn't, even if ``b''
is a valid pointer pointing to something else. It also introduces the way in
which you must use linked lists in {\EPOCH}. The execution flow is as follows
\begin{itemize}
\item Point current to the current element to the start of the linked list
(head).
\item Iterate while current points to a valid element.
\item Perform whatever actions you want on current.
\item Point current to the next element in the chain.
\end{itemize}
This leads to the slightly counter intuitive behaviour where even though the
loop only acts on the variable named ``current'', all of the elements in the
list are operated on. Although there are many tricks which can be performed
with linked lists, the only other aspect which needs to be explained is how
to delete elements. A subroutine to remove a single element from a linked list
would look like:
\begin{boxverbatim}
SUBROUTINE remove_element(element)
TYPE(linked_list), POINTER :: element
IF (ASSOCIATED(element%prev)) THEN
! Previous element exists
element%prev%next=>element%next
ELSE
! Previous element does not exist therefore element is the head. When
! element is removed the head is the element after the one being removed
head=>element%next
ENDIF
IF (ASSOCIATED(element%next)) THEN
! next element exists
element%next%prev=>element%prev
ELSE
! next element does not exists therefore element is the tail. When element
! is removed the head is the element before the one being removed
tail=>element%prev
ENDIF
END SUBROUTINE remove_element
\end{boxverbatim}
Once again, this code looks slightly counter-intuitive, but if you go through
step by step, it's fairly simple. In the following discussion the element
being removed is called ``C'', the element before ``C'' (if it exists) is
called ``P'' and the element after ``C'' (if it exists) is called ``N''
\begin{itemize}
\item Check whether \inlinecode{C}'s prev element exists, this means that
\inlinecode{P} exists.
\item If \inlinecode{P} exists then the element to be removed isn't at the
start of the chain. When \inlinecode{C} is removed, we need
\inlinecode{P}\%next to point to \inlinecode{C}\%next. This leads to the odd
looking element\%prev\%next$=>$ element\%next syntax.
\item If \inlinecode{P} does not exist then \inlinecode{C} is at the the start
of the chain. In order to not leave the chain orphaned when \inlinecode{C}
is removed, we need head to point to \inlinecode{C}\%next.
\item Exactly the same logic applies for updating the element after
\inlinecode{C}.
\item Check whether \inlinecode{C}'s next element exists, this means that
\inlinecode{N} exists.
\item If \inlinecode{N} exists then the element to be removed isn't at the end
of the chain. When \inlinecode{C} is removed, we need \inlinecode{N}\%prev
to point to \inlinecode{C}\%prev.
\item If \inlinecode{P} does not exist then \inlinecode{C} is at the the start
of the chain. In order to not leave the chain orphaned when \inlinecode{C}
is removed, we need head to point to \inlinecode{C}\%next.
\end{itemize}
Therefore, code to remove some elements from a linked list would look like:
\begin{boxverbatim}
TYPE(linked_list), POINTER :: current, next
current=>head
DO WHILE(ASSOCIATED(current))
next=>current%next
IF (dealloc) THEN
CALL remove_element(current)
DEALLOCATE(current)
ENDIF
current=>next
ENDDO
\end{boxverbatim}
Note that ``current'' must be deallocated explicitly even after it has been
removed from the linked list to prevent a memory leak. Note also that the
pointer to the ``next'' element is saved before ``current'' is deallocated.
This is not necessary but means that there is only one IF statement rather
than the two otherwise required.
\subsubsection{Particles and particle species}
Particles are represented as linked lists of Fortran TYPES. The definition of
the particle type is:
\begin{boxverbatim}
TYPE particle
REAL(num), DIMENSION(3) :: part_p
REAL(num), DIMENSION(c_ndims) :: part_pos
#ifdef PER_PARTICLE_WEIGHT
REAL(num) :: weight
#endif
#ifdef PER_PARTICLE_CHARGE_MASS
REAL(num) :: charge
REAL(num) :: mass
#endif
TYPE(particle), POINTER :: next, prev
#ifdef PARTICLE_DEBUG
INTEGER :: processor
INTEGER :: processor_at_t0
#endif
END TYPE particle
\end{boxverbatim}
And the descriptions are
\begin{itemize}
\item #REAL(num) :: part_p(3)# - The particle momentum. Always dimension 3 even
in 1D and 2D codes.
\item #REAL(num) :: part_pos(ndims)# - The particle position. Has
the same dimensions as that of the code.
\item #REAL(num) :: weight# - The particle weight if the code is running with
per particle weighting.
\item #REAL(num) :: charge# - The particle charge in Coulombs if the code is
running with per particle charge.
\item #REAL(nun) :: mass# - The particle mass in kilograms if the code is
running with per particle mass.
\item #TYPE(particle), POINTER :: next, prev# - The pointers to the next and
previous elements of the linked list.
\item #INTEGER :: processor# - The rank of the processor that the particle
thinks it is on. Used for debugging.
\item #INTEGER :: processor_at_t0# - The rank of the processor that the
particle started on. Used for debugging.
\end{itemize}
Simply adding a new parameter to the definition of the particle type is NOT
sufficient to extend the particle type, since the communications when the
particle crosses a processor boundary do not know about the new parameter and
it will not be transmitted with the particle. How to add new properties to the
particle communication layer is described later.\\
The entire linked list of particles is encapsulated in another Fortran TYPE,
called \inlinecode{particle\_list}, which is defined as:
\begin{boxverbatim}
TYPE particle_list
TYPE(particle), POINTER :: head
TYPE(particle), POINTER :: tail
INTEGER(KIND=8) :: count
! Pointer is safe if the particles in it are all unambiguously linked
LOGICAL :: safe
TYPE(particle_list), POINTER :: next, prev
END TYPE particle_list
\end{boxverbatim}
And its properties are:
\begin{itemize}
\item #TYPE(particle), POINTER :: head# - The first particle in the linked list.
\item #TYPE(particle), POINTER :: tail# - The last particle in the linked
list. New particles added to the end of the list are added onto the end of
the tail element, and the new last particle becomes the new tail element.
\setlength{\emergencystretch}{3em}
\item #INTEGER(KIND=8) :: count# - The number of particles in this particle
list. Note that the \inlinecode{particle\_list} type is not
directly MPI aware, so this is literally the number of particles in
{\it this} particle list, not the number of particles of this species on all
processors.
\item #LOGICAL :: safe# - A particle list is {\it safe} if the particles in it
are unambiguously linked. That is that the \inlinecode{count}th particle is
guaranteed to have its \inlinecode{next} property be null. Most particle
lists within {\EPOCH} are safe, but sometimes it is useful to be able to have
particle lists which are subsets of longer particles lists, and these
particle lists are not {\it safe}.
\item #TYPE(particle_list), POINTER :: next, prev# - At present, {\EPOCH} does
not use these pointers, which are intended to allow multiple particle lists to
be attached together. Certain parts of {\EPOCH}, such as the I/O system are
aware of these pointers and will automatically use them if they are ever
set. They are reserved for future use.
\end{itemize}
The \inlinecode{particle\_list} objects are used to abstract all the functions
of the linked list, including adding and removing particles and transporting
particles between processors.\\
\\
The particle species are represented by yet another Fortran TYPE, this time
called \inlinecode{particle\_species}, which is defined as:
\begin{boxverbatim}
TYPE particle_species
! Core properties
CHARACTER(string_length) :: name
TYPE(particle_species), POINTER :: next, prev
INTEGER :: id
INTEGER :: dumpmask
REAL(num) :: charge
REAL(num) :: mass
REAL(num) :: weight
INTEGER(KIND=8) :: count
TYPE(particle_list) :: attached_list
#ifdef TRACER_PARTICLES
LOGICAL :: tracer
#endif
! particle cell division
#ifdef SPLIT_PARTICLES_AFTER_PUSH
INTEGER(KIND=8) :: global_count
LOGICAL :: split
INTEGER(KIND=8) :: npart_max
! Secondary list
TYPE(particle_list), DIMENSION(:,:), POINTER :: secondary_list
#endif
! Injection of particles
INTEGER(KIND=8) :: npart_per_cell
REAL(num), DIMENSION(:), POINTER :: density
REAL(num), DIMENSION(:,:), POINTER :: temperature
! Species_ionisation
#ifdef PARTICLE_IONISE
LOGICAL :: ionise
INTEGER :: ionise_to_species
INTEGER :: release_species
REAL(num) :: critical_field
REAL(num) :: ionisation_energy
#endif
! Attached probes for this species
#ifdef PARTICLE_PROBES
TYPE(particle_probe), POINTER :: attached_probes
#endif
END TYPE particle_species
\end{boxverbatim}
Again, most of these properties are self explanatory, but they are detailed
below.
\begin{itemize}
\item #CHARACTER(LEN=entry_length) :: name# - The name of the particle
species. Used when constructing things like ``ekbar\_electron'' and similar
names.
\item #TYPE(particle_species), POINTER :: next, prev# - Particle species are
connected to each other as a linked list using pointers as well as being
available through a simple array. These pointers are used behind the scenes
in the I/O.
\item #INTEGER :: id# - The number of the species, so for the species
\inlinecode{species\_list(1)}, the id field would be 1. For
\inlinecode{species\_list(2)}, the id field would be 2 etc.
\item #INTEGER :: dumpmask# - Bitmask to determine when this species should be
dumped in diagnostic output.
\item #REAL(num) :: charge# - The charge on a single particle of the species in
Coulombs.
\item #REAL(num) :: mass# - The mass of a single particle of the species in
kilograms.
\item #REAL(num) :: weight# - The per-species particle weight.
\item #INTEGER(KIND=8) :: count# - The number of particles of this species on
all processors. NOTE that this is only accurate if the code is compiled with
the correct preprocessor options. Without the correct preprocessor options,
this will be accurate at the start of the code runtime, but will not be if
any particles enter or leave the domain. This is mainly a debugging
parameter.
\setlength{\emergencystretch}{3em}
\item #TYPE(particle_list) :: attached_list# - This is the
\inlinecode{particle\_list} object which holds the particles assigned to this
species on this processor. Particles are attached to this list at all
times EXCEPT when they are explicitly split when the code is compiled with
the \inlinecode{SPLIT\_PARTICLES\_AFTER\_PUSH} option. When the
code is compiled with this option, the particles are attached to
\inlinecode{attached\_list} except between the calls to
\inlinecode{reorder\_particles\_to\_grid} and
\inlinecode{reattach\_particles\_to\_mainlist} in
\inlinecode{epoch{\it n}d.F90} where the particles are instead attached to
\inlinecode{secondary\_list}. This is explained later.
\item #LOGICAL :: tracer# - Whether or not this species is a tracer particle. If
a species is a tracer species then it moves under the fields as normal for a
particle with its mass and charge but contributes no current.
\item #LOGICAL :: split# - {\EPOCH} includes a very early version of a particle
splitting operator. It works mechanically but has undesirable properties at
present. If this flag is true then the code attempts to split the particles
when the pseudoparticle number density drops too low.
\item #INTEGER(KIND=8) :: npart_max# - Used with the particle splitting
operator. When the total number of particles equals this number, further
particle splitting is suppressed.
\item #TYPE(particle_list), DIMENSION(:,:,:), POINTER :: secondary_list# - When
the code is compiled with the \inlinecode{-DSPLIT\_PARTICLES\_AFTER\_PUSH}
option, the code allocates
\inlinecode{secondary\_list(0:nx+1,0:ny+1,0:nz+1)} and then loops over all
particles. It calculates the cell in which each particle is and moves the
particle from \inlinecode{attached\_list} to the correct element of
\inlinecode{secondary\_list} for that cell. This means the particles which
are nearby in space are now linked together in an array of linked lists.
This allows things such as collision operators which require direct
interaction between nearby particles.
\item #INTEGER(KIND=8) :: npart_per_cell# - The number of pseudoparticles per
cell in the initial conditions. This is used with the moving window function
to ensure that the same number of particles per cell are used for the new
material introduced at the leading edge of the window.
\item #REAL(num), DIMENSION(:,:), POINTER :: density# - The density of the
plasma at the leading edge of the window at the start of the simulation. This
is used to structure the density of the new material introduced at the leading
edge of the plasma.
\item #REAL(num), DIMENSION(:,:,:), POINTER :: temperature# - The temperature
in of the plasma at the leading edge of a moving window at the start of the
simulation. The final index of the array is the direction in which the
temperature is set (1=x, 2=y, 3=z).
\item #LOGICAL :: ionise# - If the ionisation model is activated then this
species should ionise.
\item #INTEGER :: ionise_to_species# - The species number for the next ionised
state of this species.
\item #INTEGER :: release_species# - Specifies what type of particle should be
released when this species ionises (i.e. which species is the electron).
\item #REAL(num) :: ionisation_energy# - The ionisation energy for the next
ionisation of this species.
\item #TYPE(particle_probe), POINTER :: attached_probes# - A pointer pointing to
the head of an attached linked list of particle probe diagnostics.
\end{itemize}
\subsubsection{EM Fields}
There are nine variables which are used in updating the EM field solver. These
are
\begin{itemize}
\item ex - Electric field in the X direction.
\item ey - Electric field in the Y direction.
\item ez - Electric field in the Z direction.
\item bx - Magnetic field in the X direction.
\item by - Magnetic field in the Y direction.
\item bz - Magnetic field in the Z direction.
\item jx - Current in the X direction.
\item jy - Current in the Y direction.
\item jz - Current in the Z direction.
\end{itemize}
The EM fields in {\EPOCH} are simple allocatable arrays, which are of size
(-2:nx+3,-2:ny+3,-2:nz+3), although this includes the ghost cells. The length of
the core domain is different for each variable due to the grid stagger.
The {\EPOCH} field solver is a Yee staggered 2nd order FDTD scheme, directly
based on the scheme in the PSC by Hartmut Ruhl and is contained in the file
\inlinecode{fields.f90}. To locate a variable on the grid there is a simple
rule.
\begin{itemize}
\item Start at the cell centre.
\item For an $E$ field component, move the field half a grid point in the
direction that the field points if possible.
\item For a $B$ field component, move the field half a grid point in all
directions {\it except} the one it points.
\end{itemize}
This is illustrated in Figure~\ref{yeegrid} for the 2D case.\\
\captionedimage{./images/stagger}{yeegrid}{The Yee grid in 2D}
The grid stagger means that you have to be careful with boundary conditions
since some variables are defined on the domain boundaries whereas others are
defined on either side of a domain boundary. This is handled automatically by
the built in boundary routines, but must be understood if developing other
boundary conditions. To explain it, consider only the left/right boundary in 1D
and consider $E_x$ and $B_x$.\\
$E_x$ is defined on the cell boundary, so \inlinecode{ex(0)} is the value of
$E_x$ on the left boundary and similarly \inlinecode{ex(nx)} is the
value on the right boundary. Conversely, in the 1D code $B_x$ is cell centred
(in reality, $B_x$ is never used in the field update and is unimportant since
any gradients in $B_x$ in 1D automatically break the solenoidal condition, but
this is still a useful example.). This means that \inlinecode{bx(1)} is the
centre of the first cell in the domain, and \inlinecode{bx(0)} is the value at
the centre of the first left hand ghost cell. This means the you must do
different things as boundary conditions for the two fields for some boundary
conditions.\\
For example, if you want to clamp the value of $E_x$ to be zero on the
boundary, then just set \inlinecode{ex(0) = 0.0\_num} since \inlinecode{ex(0)}
lies on the boundary. To do the same for $B_x$ on the boundary you have to
set \inlinecode{bx(0) = -bx(1)}. This is because if you use a linear
reconstruction of $B_x$ (i.e second order) then the point between
\inlinecode{bx(0)} and \inlinecode{bx(1)} has the value
$B_x(1/2) = \left(B_x(1)+B_x(0)\right)/2$. Similarly, if you want to set zero
gradient on the boundary then for $E_x$ you set \inlinecode{ex(-1) = ex(1)},
whereas for $B_x$ you would set \inlinecode{bx(0) = bx(1)}. This is explained
in more detail in \sect{bcs}.
In the particle pusher, time centred field variables are needed for second
order accuracy, so an FDTD scheme is used to advance the fields. This looks
like
\begin{itemize}
\item $\vec{E}^{n+\frac{1}{2}} = \vec{E}^n + \frac{\Delta t}{2} \left( c^2
\nabla \wedge \vec{B}^{n} -\vec{j}^{n} \right)$
\item $\vec{B}^{n+\frac{1}{2}} = \vec{B}^n - \frac{\Delta t}{2} \left( \nabla
\wedge \vec{E}^{n+\frac{1}{2}} \right)$
\item Call particle pusher which calculates $j^{n+1}$ currents
\item $\vec{B}^{n+1} = \vec{B}^{n+\frac{1}{2}} - \frac{\Delta t}{2} \left(
\nabla \wedge \vec{E}^{n+\frac{1}{2}} \right)$
\item $\vec{E}^{n+1} = \vec{E}^{n+\frac{1}{2}} + \frac{\Delta t}{2} \left( c^2
\nabla \wedge \vec{B} ^{n+1} - \vec{j}^{n+1} \right)$
\end{itemize}
Note that all spatial derivatives are calculated using the staggered grid, so
the final derivatives in the code appear one sided. However, this is not the
case, and all spatial derivatives are second order accurate. Higher order
spatial derivatives schemes for {\EPOCH} are being developed to improve the
dispersion properties of the code when resolving small timescales.
\subsection{The particle pusher}
{\EPOCH}'s particle pusher is based on the one from the PSC by Hartmut Ruhl, and
is a Birdsall and Landon type PIC scheme using Villasenor and Buneman current
weighting. It is contained in the file \inlinecode{particles.F90}. The
operation of the particle pusher is fairly simple, but there are a few elements
which need some clarification.
\begin{itemize}
\item The update to the particle momenta etc. does not explicitly include the
particle weight function. This means that the pseudoparticle momenta etc. are
the momentum for a single real particle of the collection of real particles
represented by that pseudoparticle, NOT the momentum of the whole collection
of real particles.
\item \inlinecode{gamma} - The variable gamma which appears in various places
is the relativistic $\gamma$ which is needed to convert the particle momentum
into the particle velocity using the relation $\vec{p} = \gamma m \vec{v}$.
Here, $\vec{p}$ is the particle momentum, $\vec{v}$ is the particle