2.2. Support of Novice User Experience
It is expected that SCONE will be mainly used by UK’s postgraduate students in Nuclear Engineering. Thus, it is reasonable to assume that upon a first introduction to the framework, a student will be already familiar with basic programming concepts and aware but not fully comfortable with more advanced ideas such as inheritance or polymorphism. Therefore, the initial contact with the framework will be challenging to students as they will be required not only to understand the specifics of SCONE, but also become comfortable with object-orientation and relevant design patterns [
4]. Fortunately there is a large number of steps that can be taken to improve the initial user experience. They will be outlined in the following paragraphs.
The simplest enhancement of new user experience is the organisation of the source code directory into a folder structure, such that functionally related source files are kept in the same folder. In SCONE the folder structure tries to convey the architecture. Starting from the root directory, each major component of the code has an associated folder, e.g., “NuclearData” or “Geometry”. Then each such folder contains source files that specify the abstract classes and data structures, that serve as an interface for this section of the code. A more specific interfaces (abstract classes that inherit from the main interface class) as well as implementations of the interfaces are places in sub-folders. Thus, a folder tree follows the inheritance hierarchy. The main benefit of this approach is that it makes navigating source code easy. A new user, instead of being presented with hundreds of files sorted alphabetically, can see the high-level decomposition of the code into different abstractions from the beginning.
Another decision to improve the readability of SCONE source code was to keep the size of the source files small. At the time of writing only 4 source files out of 279 have more then 1000 lines (which includes comments). The mean size of the file is 221.4 lines. Each source file contains a single Fortran module or program. To avoid confusion, each source file has the same name as the module it contains (e.g., module “RNG_class” is in file “RNG_class.f90”). To improve clarity, no functions or types are used implicitly. Every object or procedure needs to be explicitly imported using the Fortran “use..., only: ...” construct. This rule makes certain that it is straightforward to identify origin of every component that is being used in a module. The exception from this rule is allowed when importing modules that contain only large number of constants (e.g., ENDF MT numbers). The content of every module is indicated by a suffix in its name: “_class” for class, “_inter” for abstract class, “_func” for library of procedures and _mod”: for module acting as an object (Singleton Design Pattern [
4]).
The fact that the expected new user of SCONE will have a limited programming experience makes the selection of Fortran as a programming language beneficial. Because the student, will have to learn both the unfamiliar Monte Carlo techniques and the programming language at the same time, it is important that all the relevant concepts are not obfuscated by syntax. The Fortran use of verbose attributes such as “pointer” or “allocatable” communicate the meaning clearly even to people who are not well-acquainted with Fortran syntax. It is also important that the MATLAB language shares many features with Fortran, such as array syntax and column major order for indexing. This makes transition to Fortran easier for engineering students who often have extensive experience with MATLAB.
Consistent and exhaustive documentation of classes and procedures allows the user to quickly determine the purpose and functionality of any given component. In SCONE, documentation is based on the Google docstring style for Python code. A comment is placed before the declaration of a derived-type or a procedure. In all cases it contains the name of the component and a short paragraph that details it purpose. In a case of a procedure (including class methods), the comment contains three sections. “Args” section provides the description and intent (in, out or inout) of arguments as well as any preconditions they must meet (e.g., an array of numbers may need to be sorted). “Errors” section lists the behaviour of the procedure for invalid input or edge-cases. A function also contains “Result” section that describes the output. Documentation comment for classes contains “Public Members” and “Private Members” sections that provide short description of each class member. In addition “Interface” section is included which lists all available public methods with short description of their purpose. When documenting class, inheritance poses a threat to the consistency of documentation if methods in each sub-class have their own full documentation comment. Because, the same information about the specification of the method would be replicated in multiple places, any change would need to be propagated to all instances. This would make it likely that due to mistakes and omissions, with time the descriptions of the same method would diverge. To prevent it, if the method is overriding a super-class method only reduced documentation comment is provided with basic information about the purpose of the method, name of a module that contains full documentation comment and perhaps some sub-class specific information. Full comment is provided only for the top-level declaration of the procedure.
The use of object-oriented architecture should help new users to learn the code. SCONE is based on a plug-in architecture with every major code component such as geometry or nuclear data being associated with an abstract class, which deferred (virtual) methods provide access to all required functionality. The code components are also associated with abstractions, which are simplified mental models of the sections of the code. Every abstraction specifies how the section should behave under interaction through procedure calls. Within this arrangement it is easy to provide multiple implementations of the same functionality using the idea of polymorphism. All implementations are associated with a sub-class of the abstract class and as long as all of them conform to the abstraction they are completely interchangeable from the user perspective. In practical terms it means that it is sufficient for a student to learn only the abstraction and the interface of the abstract class in order to be able to use all implementations. Furthermore it is not necessary to know anything about the details of the implementation. This significantly reduces mental burden when learning the code. The plug-in architecture also makes the code modification easier if the change can be made without changing the abstractions, because there is no need to consider the interaction with all the other sections of the code. It is sufficient that the modified version also implements the abstraction. However, plug-ins can also have a detrimental effect and make the modification much more difficult if it is necessary to make a change in an abstraction. Then it is necessary to ensure that all existing implementation will conform to the new specification of the abstraction, which can require a significant amount of work if the code is mature and multiple implementations are already created. For that reason the design of the SCONE abstraction is crucial for the code usefulness as a research tool. Furthermore, the reliance on abstract classes have a significant performance penalty due to dynamic dispatch on procedure calls.
2.3. Tallies Module
In order to illustrate the principles followed in the design of SCONE, the architecture of tallies will be discussed in detail. Their main purpose in the Monte Carlo particle transport calculation is to calculate statistical estimates of the useful quantities from the samples of various events obtained from the Sampler. This provides a natural interface that can reduce dependency of the tallies on the rest of the code. The tally subroutines need only to interact with a number of defined reports about certain events and require no knowledge about how the reports were generated. In the extreme case it is even possible that the generation of the reports and their processing may be performed by completely different programs as was the case for 05R code [
5]. However, in practice, some degree of interaction between transport routine and tallies is required.
Figure 2 shows a sketch of class diagram of SCONE tallies section. Ordinary arrows represent association, white diamond aggregation, black diamond composition and white arrow generalisation (inheritance). The main goal of this arrangement was to contain all the code that governs how event reports are converted into useful results inside a single class (and thus single source file) of tallyClerk. The role of the interface for all tally functionality is served by the tallyAdmin. Sampler send reports about the events by calling the methods of the tallyAdmin, which then routes the reports to all tallyClerks that require them. Furthermore, it is the responsibility of a tallyAdmin to allocate and release memory for all clerks. Each tally admin contains a single instance of scoreMemory, which is a class responsible for management of space for storing results and performing normalisation and batching. The reason why the scoring logic contained in tallyClerks was decoupled from storage space was to simplify the implementation of operations on all results such as archiving into a file. Each tallyClerk is assigned with a contiguous section of scoreMemory for its results by a tallyAdmin that provides the clerk with an address. Following types of reports are available to a clerk to generate results:
reportCycleStart: Event that indicates the beginning of a cycle. A reference to a particle population with all normalisations applied that is to be transported over the course of the cycle is provided as an argument.
reportInColl: Event associated with a particle entering collision.
reportOutColl: Event associated with the particle exiting collision. Argument list contains cosine of scattering angle in LAB frame and MT number of the reaction the particle has underwent.
reportPath: Report that provides a path a particle has moved within confines of a single material or cell with unique ID. Argument list contains the length of the path.
reportTrans: Report that indicates a transfer of a particle between collisions along a straight line. Collision with a boundary condition is interpreted as a collision.
reportHist: Report that indicates the end of a particle history. It includes an integer flag that provides information about the fate of the particle (leaked, absorbed or lost).
reportCycleEnd: Event that indicates the end of a particle transport cycle. A reference to a particle population that is to be transported in the next cycle without any population normalisation is provided. It also includes the value used to adjust secondary particles generation rate.
Each report contains information about the particle together with its global position in phase-space at key moments (e.g., start of history). It needs to be noted that the tally architecture was created with batch statistics in mind. ScoreMemory is responsible for the control over the batching process and it also contains the number of cycles in each batch. Clerks that require non-standard normalisation (e.g., Fission Matrix tally) can enquire whether the cycle currently ending requires accumulation of results using the “lastCycle” method of scoreMemory. The coupling with the Sampler is achieved by using a family of tallyResult classes. In “getResult” method each clerk may allocate provided allocatable argument (an unique pointer) to a derived type created to store the clerk’s data. For example, tallyResult for k-eff clerks store only two numbers related to expectancy and standard deviation, while tallyResult for a Fission Matrix Clerk contains a matrix. By default, clerks that do not implement coupling allocate tallyResult to a special null type called noResult. This approach has a drawback of a significant overhead that may be associated with the allocation of memory whenever result is requested.
In order to avoid needless reimplementation of common functionality, three class families are available to every Clerk. tallyMap is responsible for mapping a particle global position in phase-space to a bin. It contain method “map” that returns an index given a particle state. If the particle state falls outside a range of a map, index 0 is returned. Even though the results are mapped to a single index, maps can have multiple dimensions. Information about the shape can be obtained from a tallyMap with “binArrayShape()” method. Maps are represented in column-major order following Fortran convention. The existence of tallyFilter, which given a particle state accepts or rejects the event, may be considered redundant given that its functionality can be implemented using a tallyMap composed of a single bin. However it can be used to restrict range of the accepted events without changing the rank of a result array in output file and any scripts written for results post-processing. For this reason it may prove useful during classroom demonstrations or when investigating a new phenomena.