The example examples/sim.cpp demonstrates the basic process of running a simulation against an existing sim_type and set of Elements. This is a simplified version of cli.cpp, which is compiled as the run_flame executable.
Most user code will only need base.h and config.h.
Before constructing a Machine it is necessary to register any "sim_type"s to be used. This will typically be the first thing a program does.
Running the simulation with the C++ API begins by populating a Config. This will often by done using the lattice parser (GLPSParser).
Parsing will succeed as long as the file is syntactically correct. For example, "sim_type" and element types are not validated.
Next construct a Machine. It is at this step that "sim_type" and element types are validated.
Now allocate an approprate StateBase based on the "sim_type". More than one StateBase may be allocated and used with a single Machine. The allocated StateBase must only be used with the Machine which allocated it.
This StateBase sub-class is be initialized based a Config. In this example an empty Config is provided, which will leave the state with some "sim_type" specific defaults ("sim_type=Vector" defaults to all zeros). Generally this will only be done when the lattice begins with a "source" element, which will overwrite the state based on its Config.
Alternately, a Config can be provided to Machine::allocState() to provide non-default values.
The Machine::propagate() method is used to run the simulation. When propagate() returns, the StateBase has been modified to reflect the final state.
By default propagate() starts with the first element and continues through the last element.
Before exiting some cleanup may be to clear the registry of "sim_type"s.
The example examples/sim.py demonstrates the basic process of running a simulation using the python API.
Importing "flame" also registers a standard set of "sim_type"s.
Read an parse a lattice file and construct a Machine.
Allocate a State using an empty Config.
Propagate through all elements.
The example defines a new sim_type and two Elements. The simulation itself will be trivial.
The full example can be found in examples/customsim.cpp
The first task is to define the state structure. This contains the variables which define the state of one "bunch". In this case "x" and "xv", which represent a transverse velocity and relative position. In addition the absolute logitudinal StateBase::pos is inherited.
The member variables of State1D are initialized from a Config.
The remainder of State1D is boilerplate which is repeated for each member variable.
Now define the "source" element type. By convention this is an element which simply overwrites it's input state with predefined values (eg. from lattice file). So it is simplest to give this struct it's own internal State1D instance.
Initialization of the element can also initialize this internal State1D from the same Config.
So the same "x" and "xv" used to initialize the state can be given to a source element.
With this lattice file entry, the "x" and "xv" are used to initialize the internal State1D. "L" is used to initialize ElementVoid::length.
Next define the simulated action of this element with its advance() method. This method should modify it's input State1D. In this case, the source element simply overwrites the input state using its internal State1D.
Now define another "generic" element type which transforms the state in a more interesting way.
Here we see that the name given to Config::get need not match a c++ variable name. Also that some calculations can be done once, and the result stored in a class member variable for later re-use.
The advance() function incrementally updates the state.
So far three types have been defined: State1D, Element1DSource, and Element1DGeneric. If nothing further is done there will be no way to make use of this code. As these definitions appear in an anonymous C++ namespace a modern compiler is able to issue a warn that this code is unreachable.
In order for this code to be reachable it must be tied into the FLAME framework in some way. This is accomplished with Machine::registerState and Machine::registerElement.
By convention a function "register...()" is defined, which must be called exactly once before Machine can make use of these definitions.
Now to make use Simple1D we expand on examples/sim.cpp