## 2 Numerical Model
### Software Structure  
This section provides a description of the structure and variable handling of FLARE. The code is designed for flexibility, while keeping a consistent organization of the settings, regardless of the solver chosen by the user. Let us consider one of the simplest possible problems, computing the electric potential on a uniformly charged unit disk. The basic structure of a simulation is provided in Figure 2. One starts by generating the computational mesh used to perform the calculation. This can be done by either loading a file that has been previously generated by Gmsh or by calling (from MATLAB(r)) the Python Gmsh APIs. In the first case, if the mesh from a.geo file called, e.g.,.unit_circle.geo has been exported in.n format, the information can be loaded via a single command, e.g.,  
unit_circle; % importmesh file ndom = num_regions(msh); % countnumber of regions (domains)  
Using the Python Gmsh APIs allows dynamically providing instructions to Gmsh from FLARE, and it is advised when the mesh must be updated during the simulations, such as when geometry optimizations are performed. In both cases, a msh MATLAB(r) structure file is generated, containing the information on the computational mesh. This is one of the two inputs to the fesolve function used to obtain the solution. The next phase (settings) involves filling several fields of the structure opts, which will be passed to the solver. Here is an example of the considered electrostatic problem on the unit disk:  
opts.tag_boundary = 1; % setdomain boundary onedges marked with tag=1 in msh [opts.materials] = set_materials('mesh_unit_circle',ndom); % definematerial properties  
Figure 1: Example of a triangular mesh with two elements and four nodes. opts.ProblemKind = 'Electrostatic'; % [Electrostatic][ Magnetostatic][QMagnetostaticSin][MagTimeDependent] % set the kind of problemotbesolved opts.source = 1; % unitchargedensity,uniformlydistributed The set_materials function requires a string containing the test case name--for example'mesh_unit_circle'--and returns a string array named materials, containing the material for each region of the domain: function[material] = set_materials(flag,ndom) switchflag case ('mesh_unit_circle') material(1) = 'air';... The properties of the material 'air' are stored in a separate function called MatLib: function[Mprop] = MatLib(MatKind) % prop(1) = material relativepermittivity [Adim] % prop(2) = material relativepermeability [Adim] % prop(3) = materialelectricconductivity [S/m] switchMatKind case \"air\" Mprop = [1, 1, 0];... While the source term in the above code snippet has been set to 1, FLARE easily allows for more sophisticated source terms that can vary over time and depend on the given mesh region. One may indeed write a standalone MATLAB(r) function in a separate file and pass a function handle to FLARE. Figure 2 shows an example of this method for a source term representing a lightning current. Regardless of the selected solver, one always calls the same function to obtain the solution, which is essentially a driver making a series of subcalls depending on the selected options:  
[out] = resolve(msh,opts); % setup and computes solution When a stationary solver is called, out file structure has only two fields, named field and scal. These store information about the field variables, such as the MVP \(A_{z}\) or the current density \(I_{z}\), or scalar variables, such as the current of each region (surface integral of \(J_{z}\)). When a transient solver is selected, the two former fields only store the information computed at the latest time instant, and out is populated with more fields. The field tm,  
Figure 2: Structure of a typical FLARE simulation. which stands for time measurement, stores the cumulative computation time spent during several key processes, such as the matrix assembly or the linear system solution. Variables saved over time are stored in a dedicated field called sv. Finally, the user has two options regarding visualization.