Application Modules =================== Many of the example applications in GridPACK have been converted to modules that can be called from other programs. These modules make it relatively simple to chain different types of calculations together to form larger applications. An example is using power flow or state estimation to initialize a dynamic simulation. The modules are designed to separat the major phases of the calculation into calls so that users have some fine-grained control that allows them to mix different applications together. In most cases, different options for setting up calculations are provided so that once a network has been read in and partitioned, it is not necessary to repeat this process when a new calculation is started based on the results of a previous simulation. Currently, four applications are available as modules within GridPACK. They include power flow, state estimation, dynamic simulation using the full Y-matrix, and electromagnetic transient (EMT) simulation. Each of these modules can be used to create a short, standalone application, but the goal is to enable users to combine modules together in more complicated work flows. These modules can also be used as a starting point for users to create their own applications by modifying the existing code in the modules to create new functionality. Each of the modules is described in more detail below. Example codes that use the modules to implement applications can be found in the ``src/application`` directory. These include powerflow, state estimation, contingency analysis, dynamic simulation, and EMT simulation. These directories also contain sample input networks and input files. Options for different solvers can be found in these files. Most of these applications can use different format PSS/E files for input. The standard format is PSS/E v23 and is specified via the ``networkConfiguration`` field in the input XML file. The v33, v34, v35 and v36 formats can be used by appending ``_v33``, ``_v34``, ``_v35``, or ``v_36`` to the ``networkConfiguration`` field. For example, to include a version 33 network configuration file, modify the network configuration line in the input XML file to :: v33_format.raw Power Flow ---------- The power flow module consists of a collection of function calls that can be used to set up and run power flow calculations. Additional routines are designed to support different types of contingency analysis. The power flow application class is ``PFAppModule`` and belongs to the ``gridpack::powerflow`` namespace. The constructor and destructor for this class are simple and only create the basis power flow object. In particular, the power flow network must be created outside the power flow object and then assigned to the object when the network configuration file is read in. This can be done with the call :: void readNetwork(boost::shared_ptr &network, Configuration *config) The ``Configuation`` object should already be pointing to an open file containing a ``Powerflow`` block. This block contains a ``networkConfiguration`` field that has the name of the PSS/E format file containing the network information. An example powerflow input file is shown below: :: IEEE14.raw 50 1.0e-6 true 3 -ksp_view -ksp_type richardson -pc_type lu -pc_factor_mat_solver_type superlu_dist -ksp_max_it 1 This example specifies the input network configuration, the maximum number of iterations in the non-linear Newton-Raphson solver, the solution tolerance and the properties of the linear solver. The ``qlim`` parameter enables reactive power limit enforcement (default ``true``). When enabled, PV buses whose generator reactive power output exceeds the specified ``Qmax`` or ``Qmin`` limits are switched to PQ buses and the power flow is re-solved. The ``maxQlimIterations`` parameter (default 3) controls the maximum number of outer PV-to-PQ switching iterations. This is a minimal example and more options for the solver can be used. Readers are encouraged to look at the examples that are copied into the powerflow directory as part of the build. The network configuration file is read directly from the input deck by the ``readNetwork`` method. The ``PFNetwork`` is defined in the the ``gridpack.hpp`` header file. The configuration module is usually opened in the main calling program and a pointer to the file can be passed through to power flow module. The ``readNetwork`` routine also partitions the network. Once the network has been read in, the internal indices and exchange buffers can be set up by calling :: void initialize() The power flow application is now ready to be used. To solve the current configuration, the calls :: void solve() void nl_solve() can be used. The first call solves the system uses a hand coded Newton-Raphson iteration loop to solve the system, the second call uses a non-linear solver to solve the power flow equations. Both solvers can be controlled through solver options in the input file. The type of linear solver used in the solve routine is controlled by the parameters in the ``LinearSolver`` block, the non-linear solver is controlled by the properties in the ``NonlinearSolver`` block Output from the power flow solution can be written to an output file or standard out using one of the commands :: void write() void writeBus(const char* signal) void writeBranch(const char* signal) The first command writes out the real and imaginary parts of the complex power for the branches and the voltage magnitude and phase angle for the buses. The second command only writes out bus properties. If no argument is given, the command writes out the voltage magnitude and phase angle for every bus. For buses, the argument ``pq`` writes out the real and imaginary parts of the complex voltage and ``record`` writes out the type of bus, the total active and reactive constant power loads, and the total active and reactive generator power outputs. For branches, ``flow`` writes out the real and imaginary parts of the complex power and “``record``” writes out the values of the resistance, reactance, charging and A, B, C ratings for each line element. Additional information can be written to standard out or a file using the command :: void print(const char* buf) which writes out the contents of the character array ``buf``. This command can be called from all processors, but only one processor actually writes out data. The location of output can be controlled using the commands :: void open(const char* filename) void close() If the write commands or ``print`` are used without calling ``open``, then all output is directed to standard out. If ``open`` is called, then the output is directed to the file specified in filename until the ``close`` command is called, after which all output is again directed towards standard out. If the results of the power flow calculation are needed by another calculation, then the voltage magnitude and phase angle of the bus and the real and imaginary parts of the complex power for each generator can be stored in the ``DataCollection`` objects on each bus using the command :: void saveData() If the network is then copied to a new type of network, this information is carried over to the new network. The voltage magnitude and phase angle is stored in the ``DataCollection`` variables ``BUS_PF_VMAG`` and ``BUS_PF_VANG`` and the generator parameters are stored in the indexed variables ``GENERATOR_PF_PGEN[i]`` and ``GENERATOR_PF_QGEN[i]``, where the index ``i`` runs over all generators on the bus. The power flow module supports ZIP loads, where the total load power is modeled as a combination of constant power (P), constant current (I), and constant admittance (Y) components. The load power at voltage ``V`` is computed as ``P_load = PL + IP*V + YP*V^2`` and ``Q_load = QL + IQ*V - YQ*V^2``, following PSS/E sign conventions. The ZIP load coefficients are read automatically from PSS/E network files when present. Switched shunt devices specified in PSS/E input files are supported. The initial susceptance value (``BINIT``) is absorbed into the fixed bus shunt admittance during network setup, consistent with the behavior of commercial power system tools. The power flow module includes island detection capabilities. The function ``getIslandCount()`` returns the number of electrical islands found in the network after calling ``solve()``. The function ``hasLoneBus()`` identifies isolated buses with no active connections. The function ``checkAndTransferSlack()`` automatically transfers the slack bus role to the bus with the largest online generator capacity if the original slack bus generator goes offline. The output from ``write()`` includes per-bus power injection values (``Pinj`` and ``Qinj``) in addition to voltage magnitude and phase angle. These values reflect the net power injection at each bus including all ZIP load contributions at the solved voltage. The remaining methods in the PFAppModule class support different kinds of contingency applications. Contingencies are defined using the data structure :: struct Contingency { int p_type; std::string p_name; // Line contingencies std::vector p_from; std::vector p_to; std::vector p_ckt; // Status of line before contingency std::vector p_saveLineStatus; // Generator contingencies std::vector p_busid; std::vector p_genid; // Status of generator before contingency std::vector p_saveGenStatus; }; The variable ``p_type`` corresponds to an enumerated type that can have the values ``Generator`` and ``Branch``. The variables ``p_saveLinesStatus`` and ``p_saveGenStatus`` are used internally and do not have to be set by the user. The remaining variables are used to describe the lines and generators that may fail during a contingency event. These variables are all vectors, since a single contingency could theoretically represent the failure of multiple elements. For failures of type ``Branch``, the variables ``p_from`` and ``p_to`` are the original indices of the “from” and “to” bus that identify a branch and the variable ``p_ckt`` is the 2 character identifier of the individual transmission element. For failures of type ``Generator``, ``p_busid`` is the original index of the bus and ``p_genid`` is the 2 character identifier of the generator that fails. An example of how to use this functionality is given in the contingency analysis application that can be found under ``src/applications/contingency_analysis``. This is also a good example of how to use modules. Two calls :: bool setContingency(Contingency &event) bool unSetContingency(Contingency &event) can be used to set or unset a contingency. Both functions return ``true`` if the contingency was successfully applied or removed. The call ``unSetContingency`` should only be called after calling ``setContingency`` and it should use the same ``event`` argument. After calling the ``unSetContingency`` method, the network should have the same configuration as before calling the ``setContingency`` method. After applying a contingency, the network topology should be checked before attempting to solve. The function :: int getIslandCount() returns the number of electrical islands in the network. A value greater than 1 indicates that the contingency has split the network and the power flow solve should be skipped. The function :: bool hasLoneBus() returns ``true`` if any bus has become completely isolated with no active branch connections. If a contingency takes the slack bus generator offline, the slack designation can be transferred using :: bool checkAndTransferSlack() This function transfers the slack bus role to the bus with the largest online generator capacity. It returns ``false`` if no valid slack bus can be found, indicating the system is unsolvable. After unSetting a contingency, the original slack bus can be restored by calling :: void restoreSlack() After solving the post-contingency power flow, the slack bus generation can be validated using :: bool checkSlackCapacity() This returns ``false`` if the slack bus generator output exceeds its ``Pmax`` limit, indicating insufficient generation capacity. The remaining calls in ``PFAppModule`` can be used to determine the status of a network after solving a configuration with a contingency. Voltage limits for violation checking are set using :: void setVoltageLimits(double Vmin, double Vmax) where ``Vmin`` and ``Vmax`` are the minimum and maximum allowable voltage excursions (per unit). The functions :: bool checkVoltageViolations() bool checkVoltageViolations(int area) can then be used to check for voltage violations anywhere in the system or only on buses with the specified value of ``area``. These functions return ``true`` if there are no voltage violations and ``false`` if a violation is found on one or more buses. It frequently turns out that many networks have voltage violations even in the absence of any contingencies and it is often desirable to ignore these violations. This can be accomplished using the function :: void ignoreVoltageViolations() If this function is called after solving the power flow system in the absence of any contingencies, then buses that contain violations will be ignored in subsequent checks of violations. These settings can be undone by calling :: void clearVoltageViolations() Line overload violations can be checked by calling one of the functions :: bool checkLineOverloadViolations() bool checkLineOverloadViolations(int area) bool checkLineOverloadViolations(std::vector &bus1, std::vector &bus2, std::vector &tags, std::vector &violations) The limits on the line are contained in parameters read in from the network configuration file so the first two functions have no arguments describing the line limits. The second function only checks for violations on lines with the specified value of ``area``. The third overload checks a specific set of branches identified by their endpoint buses and circuit tags, and populates a per-branch ``violations`` vector. Like voltage violations, branches that display line overload violations that are present even without contingencies can be ignored in the checks by calling the function :: void ignoreLineOverloadViolations() after running a calculation on the system without contingencies. These settings can be cleared using the function :: void clearLineOverloadViolations() Reactive power limit violations on PV buses can be checked using :: bool checkQlimViolations() bool checkQlimViolations(int area) When a PV bus generator exceeds its reactive power limits, the bus is converted to a PQ bus. After unsetting a contingency, these conversions can be reversed by calling :: void clearQlimViolations() Finally, the internal voltage variables that are used as the solution variables in the power flow calculation can be reset to their original values (specified in the network configuration file) by calling the function :: void resetVoltages() Again, this may be useful in contingency calculations where multiple calculations are run on the same network and it is desirable that they all start with the same initial condition. State Estimation Module ----------------------- The state estimation module can be used to set up and run a state estimation calculation. It does not have the extra functions that the power flow module contains for supporting contingency analysis, so the interface is a bit smaller. In addition to a standard network configuration file, the state estimation calculation needs a second file consisting of measurements. This file has the format :: VM 1 1.0600 0.0050 PIJ 1 2 BL 1.5688 0.0100 QIJ 1 2 BL -0.2040 0.0100 PI 1 2.3240 0.0100 QI 1 -0.1690 0.0100 VA 1 0.0000 0.0100 IIJ 1 2 BL 1.5920 0.0100 IJI 2 1 BL 1.5915 0.0100 The supported measurement types are ``VM`` (voltage magnitude), ``VA`` (voltage angle), ``PI`` (real power injection), ``QI`` (reactive power injection), ``PIJ`` (real power flow), ``QIJ`` (reactive power flow), ``IIJ`` (current magnitude, from-bus direction), and ``IJI`` (current magnitude, to-bus direction). Measurements can appear on any element of the network and multiple measurements are allowed on each element. The state estimation module does not have any error checking ability to determine if there are sufficient measurements to guarantee solvability, if not enough measurements are available then the calculation will simply crash or fail to converge. An example ``State_estimation`` input block is shown below: :: IEEE14.raw IEEE14_meas.xml 20 1.0e-6 1.0 5 3.0 standard false 0.9 1.1 -ksp_type richardson -pc_type lu -pc_factor_mat_solver_type superlu_dist -ksp_max_it 1 The ``dampingFactor`` parameter (default 1.0) scales the Newton-Raphson update step to improve convergence stability. The ``maxBadDataIterations`` and ``badDataThreshold`` parameters control automatic bad data detection and elimination. The ``diagnosticOutputLevel`` can be set to ``basic``, ``standard``, or ``detailed`` to control the verbosity of solver output. The ``useVoltageConstraints`` flag enables virtual voltage limit measurements that constrain bus voltages between ``minVoltage`` (default 0.9) and ``maxVoltage`` (default 1.1) per unit. The state estimation module is represented by the ``SEAppModule`` class which is in the ``gridpack::state_estimation`` namespace. The ``gridpack.hpp`` file contains a definition for the state estimation network ``SENetwork``. After instantiating an ``SEAppModule`` object and a shared pointer to an ``SENetwork``, the state estimation calculation can read in an external network configuration file using the command :: void readNetwork(boost::shared_ptr &network, gridpack::utility::Configuration *config) The ``Configuration`` object should already be pointing at an open file containing a ``State_estimation`` block. Inside the ``State_estimation`` block there should be a ``networkConfiguration`` field containing the name of the network configuration file. The file name is parsed directly inside the ``readNetwork`` method and does not need to be handled by the user. Alternatively, the ``SENetwork`` object may have already been cloned from an existing network and therefore there is no need to read in the configuration from an external file and partition it across processors. In this case, the ``SEAppModule`` can be assigned the network using the command :: void setNetwork(boost::shared_ptr &network, gridpack::utility::Configuration *config) This function just assigns the existing network to an internal pointer, as well as a pointer to the input file. It is much more efficient than reading in the network configuration file, if the network already exists. This can occur when different types of calculations are being chained together. Once a network is in place and has been properly distributed, the measurements can be read in by calling the function :: void readMeasurements() The name of the measurement file is in the input deck and a pointer to this file has already been internally cached in the ``SEAppModule`` when the network was assigned. The measurement file name is stored in the ``measurementList`` field within the ``State_estimation`` block. Alternatively, measurements can be provided programmatically using :: void setMeasurements(std::vector &measurements) where each ``Measurement`` struct contains the type, bus or branch indices, measured value, and standard deviation. This is useful when measurements are generated by another module or read from a non-XML source. The network object can be initialized and the exchange buffers set up by calling the :: void initialize() method followed by :: void solve() to obtain the solution to the system. The solver includes automatic bad data detection. After each Newton-Raphson convergence, a chi-square test is performed on the weighted residuals. If the chi-square test fails, the measurement with the largest normalized residual is identified and removed. The solver then re-converges with the remaining measurements. This process repeats up to ``maxBadDataIterations`` times (default 5). Measurements with normalized residuals exceeding ``badDataThreshold`` (default 3.0) are flagged as bad data. Results can be written out to standard out using the method :: void write() This function will write out the voltage magnitude and phase angle for each bus and the real and imaginary parts of the reactive power for each branch. In addition, it will print out a comparison of the calculated value and the original measured value for all measurements. Finally, the results of the state estimation calculation can be saved to the ``DataCollection`` object assigned to the buses by calling the :: void saveData() method. The voltage magnitude and phase angle are stored as the variables ``BUS_SE_VMAG`` and ``BUS_SE_VANG`` and the generator parameters are stored as the indexed variables ``GENERATOR_SE_PGEN[i]`` and ``GENERATOR_SE_QGEN[i]``, where ``i`` runs over the set of generators on the bus. The convergence status of the most recent solve can be queried using :: bool hasConverged() const This returns ``true`` if the Newton-Raphson iteration converged within the specified tolerance before reaching the maximum number of iterations. Dynamic Simulation Module using Full Y-Matrix --------------------------------------------- GridPACK supplies a dynamic simulation module that integrates the equations of motion using an algorithm based on inversion of the full Y-matrix. This module has been designed to enable the addition of generator models that extend beyond the classical generator. It also supports exciters, governors, power system stabilizers (PSS), relays, dynamic loads, and inverter-based resource (IBR) / renewable energy models. Models that are currently available include Generators: :: GENCLS GENSAL GENROU IBR/Renewable Models: :: REGCA1 REGCB1 REGCC1 GDFORM REECA1 REPCA1 The ``EPRIA1`` model is also available when GridPACK is built with ``ENABLE_EPRI_IBR_MODEL``. Exciters: :: EXDC1 ESST1A IEEET1 SEXS ESST4B Governors: :: WSIEG1 WSHYGP TGOV1 GAST HYGOV GGOV1 Power System Stabilizers: :: PSSSIM Wind Turbine Models: :: WTARA1 WTDTA1 WTPTA1 WTTQA1 Relays: :: LVSHBL FRQTPAT DISTR1 Dynamic Loads: :: ACMTBLU1 IEEL MOTORW CIM6BL The full Y-matrix implementation of dynamic simulation is represented by the ``DSFullApp`` class and the ``DSFullNetwork``, both of which reside in the ``gridpack::dynamic_simulation`` namespace. The dynamic simulation module uses an input deck of the form :: IEEE_145.raw IEEE_145.dyr 30 0.005 true 2.00 2.05 6 7 0.005 60 1 112 1 1 gen_watch.csv -ksp_atol 1.0e-18 -ksp_rtol 1.0e-10 -ksp_monitor -ksp_max_it 200 -ksp_view The input for dynamic simulation module is contained in the ``Dynamic_simulation`` block. The optional ``equilibriumInit`` parameter (default false) enables iterative Norton-equivalent initialization, which eliminates pre-fault drift by rebalancing generator states (Pmech=Telec, Efd=LadIfd) at the network-solved voltage. This is recommended for all simulations. Two features are important, the blocks describing faults and the blocks describing monitored generators. Faults are described in the ``Event``\ s block. The code currently only handles faults on branches. Inside the ``Events`` block are individual faults, described by a ``faultEvent`` block. Multiple ``faultEvent`` blocks can be contained within the ``Events`` block. As will be described below, it is possible for the faults to be listed in a separate file. This can be convenient for describing a task-based calculation that may contain a lot of faults. The parameters describing the fault include the time (in seconds) that the fault is initiated, the time that it is terminated, the timestep used while integrating the fault and the indices of the two buses at either end of the fault branch. When running a dynamic simulation, it is generally desirable to monitor the behavior of a few generators in the system and this can be done by setting generator watch parameters. The ``generatorWatch`` block specifies which generators are to be monitored. Each generator is described within a ``generator`` block that contains the index of the bus that the generator is located on and the character string ID of the generator. The results of monitoring the generator are written to the file listed in the ``generatorWatchFileName`` field and the frequency for storing generator parameters in this file is set in the ``generatorWatchFrequency`` field. This parameter describes the time step interval for writing results (an integer), not the actual time interval. Before using the dynamic simulation module, a network needs to be instantiated outside the ``DSFullApp`` and then passed into the module. If the module itself is going to read and partition a network, then it should use the function :: void readNetwork(boost::shared_ptr &network, gridpack::utility::Configuration *config, const char *otherfile = NULL) The ``Configuration`` object should already be pointing to an input deck with a ``Dynamic_simulation`` block that specifies the network configuration file. The optional ``otherfile`` argument in ``readNetwork`` can be used to overwrite the ``networkConfiguration`` field in the input deck with a different filename. This capability has proven useful in some contingency applications where multiple PSS/E files need to be read. Alternatively, a distributed network may already exist (it may have been cloned from another calculation). In that case, the function :: void setNetwork(boost::shared_ptr &network, gridpack::utility::Configuration *config) can be used to assign an internal pointer to the network. Again, the ``Configuration`` object should already be pointing to an input file. Additional generator parameters can be assigned to the generators by calling the function :: void readGenerators() This function opens the file specified in the ``generatorParameters`` field in the input file and reads the additional generator parameters. The file is assumed to correspond to the PSS/E .dyr format. The devices listed at the start of this section can be included in this file. After setting up the network and reading in generator parameters, the module can be initialized by calling :: void initialize() This sets up internal parameters and initializes the network so that it is ready for calculations. A list of faults can be generated from the input file by calling :: std::vector getEvents(gridpack::utility::Configuration::CursorPtr cursor) If the cursor variable is pointed at a ``Dynamic_simulation`` block inside the input file (as in the example input block above) then this function will return a list of faults from the input deck. However, it is also possible that the cursor could be pointed to the contents of another file. As long as it is pointed to a block containing a ``Events`` block, this function will return a list of faults. This allows users to declare a large list of faults in a separate file and then access the list by including the external file name as a parameter in the input deck of their application. The monitoring of generators specified in the input deck can be set up by calling :: void setGeneratorWatch() This will guarantee that all generators specified in the input deck are monitored and that the results are written out to the specified file. If this function is not called, the generator watch parameters in the input file are ignored. Simulations can be run using the function :: void solve(gridpack::dynamic_simulation::DSFullBranch::Event fault) Some additional results can be written at the end of the simulation using the function :: void write(const char *signal) The signal parameter can be used to control which results are written out. This function currently does not support any output. All output results are controlled using the generator watch parameters. Some additional functions can be used to control where output generated during the course of a simulation is directed. The following two functions can be used to direct output from the ``write`` function to a file :: void open(const char* filename) void close() The function :: void print(const char* buf) can be used to print out a string to standard out. If the ``open`` function has been used to open a file, then the output is directed to the file. This function is equivalent to the ``header`` convenience function in the serial IO classes. Additional functions can be used to stored data from the generator watch variables. These can be used to save the time series data from a simulation in a collection of vectors. The application can then use these series in whatever way it wants. There are four functions that enable this capility. The first is :: void saveTimeSeries(bool flag) This function must be called with the argument set to “true” in order for the time series data to be saved. Otherwise it is only written to output and no data is saved between time steps. The second function can be called after the solve function has been called and the simulation is completed. It returns a vector of time series :: std::vector > getGeneratorTimeSeries() This function returns a vector containing the time series data for all the watched generators located *on this processor* (generators on buses owned by neighboring processors are not included). To find out which variables are actually in the list returned by ``getGeneratorTimeSeries`` requires the remaining two functions. The function :: void getListWatchedGenerators(std::vector &bus_ids, std::vector &gen_ids) returns a list of the bus IDs and 2-character generator tags for all monitored generators. In particular, it assigns and ordering to these generators that is used by function :: std::vector getTimeSeriesMap() This function returns a map between the elements in the list of time series returned by ``getGeneratorTimeSeries`` and the generators that those time series correspond to. For example suppose the time series list has four elements in it that happen to correspond to two generators on processor. There are a total of six monitored generators in the system. The vectors returned by ``getListWatchedGenerators`` have length six, the vector returned by ``getTimeSeriesMap`` has length four. The value in the map vector for the corresponding element in the time series vector points to the location of the bus index and generator tag for that time series variable in the lists returned by ``getListWatchedGenerators``. This still leaves it up to the user to identify the actual variable being watched within the generator. In this example there are four variables that are watched but only two generators. Currently, the generator watch capability only watches the rotor speed and rotor angle of each generator. The first time series is the speed and the second time series is the angle. Recently, a new function was added to the dynamic simulation application module that allows users to update the data collection objects for all branches an buses in the system with current values from the simulation. A call to the function :: void updateData() will take the current values of internal variables and copy them to values in each network component’s data collection object. These values can then be accessed by querying the appropriate data collection object. Variables in the dictionary header files that are updated by the ``updateData`` function have ``_CURRENT`` appended to their names. At present, the following variables are updated by ``updateData`` :: BRANCH_FROM_P_CURRENT BRANCH_FROM_Q_CURRENT BRANCH_TO_P_CURRENT BRANCH_TO_Q_CURRENT BRANCH_IRFLOW_CURRENT BRANCH_IIFLOW_CURRENT BUS_VMAG_CURRENT GENERATOR_PG_CURRENT GENERATOR_QG_CURRENT GENERATOR_VS_CURRENT GENERATOR_NOM_POWER_CURRENT LOAD_PL_CURRENT LOAD_QL_CURRENT Other values can be added as needed. Each of the network components, bus and branch, have an ``updateData`` method that is called by the ``updateData`` method in the ``DSFullApp`` class. This also extends to the base model classes, which all have default implementations that do not do anything. Individual models can overwrite the default implementations to add data to the data collection objects when the update function is called. Kalman Filter ------------- GridPACK includes a Kalman filter module that can be used for dynamic state estimation. The Kalman filter relies heavily on parallel matrix multiplies that are not currently very high performing, so users will probably find this module too slow for large grids. However, we include it for users interested in exploring the use of Kalman filters in smaller applications. We hope to improve performance in future releases. The current implementation of the Kalman filter only supports classical generators. These are described in a PSS/E .dyr formatted file. The network itself can be described using a standard PSS/E .raw file. In addition to the .raw and .dyr files, users need to supply times series data for the voltage magnitude and voltage phase angle on all buses. These are stored as .csv files. The format for both the voltage magnitude and phase angle files is :: t-3001, Bus-1, Bus-2,{\dots} 0.0, -0.001, -0.135,{\dots} 0.1, -0.001, -0.135,{\dots} 0.2, -0.001, -0.135,{\dots} : All entries on the same lines are separated by commas. The first row contains the name of all columns. The first column is time and has a name of the form ``t-xxx,`` where ``xxx`` is an integer representing the number of time steps in the file. The number of rows in the file corresponds to ``xxx+1`` (the extra row is the first line with the column names). The number of columns is equal to the number of buses in the file plus one (the extra column contains the times). After the first column, the remaining names are all of the form ``Bus-xxx``, where ``xxx`` is an integer representing the bus ID. The remaining rows contain the time of the measurement and the value for the measurement on each of the buses. The input file for the Kalman filter module used both for a dynamic simulation as well as input that is unique to the Kalman filter module. The dynamic simulation parameters that are used include :: 3 0.01 1 0 1 1.1 6 7 0.01 The fault used in the simulation is specified using the same ``Events`` block as for dynamic simulation. If the Kalman filter simulation is not being initialized from another calculation, the ``networkConfiguration`` field can also be added. The KnowFault and TimeOffset parameters are unique to the Kalman filter application and control whether the fault is considered to be a know event and whether all the time series data should be used in the analysis. The Kalman filter block consists of the fields :: IEEE14_Kalman_input_ang.csv IEEE14_Kalman_input_mag.csv IEEE14_classicGen.dyr 21 1e-2 1e-4 931316785 3000 -ksp_view -ksp_type richardson -pc_type lu -pc_factor_mat_solver_package superlu_dist -ksp_max_it 1 The ``KalmanAngData`` and ``KalmanMagData`` fields specify the locations of the files containing the time series data for the voltage magnitude and phase angle. The .dyr file containing the generator parameters (classical generators only) is specified in the ``generatorParameters`` field. Additional Kalman filter parameters include #. ``ensembleSize``: The number of random ensembles generated for the Kalman filter calculation. #. ``gaussianWidth``: #. ``noiseScale``: #. ``randomSeed``: This is an arbitrary integer used to seed the GridPACK random number generator. #. ``maxSteps``: this parameter can be used to control the number of steps simulated. If the number of steps is smaller than the number of steps in the time series data files, then only the number of steps set by ``maxSteps`` will be simulated. The Kalman filter also needs to make use of linear solvers and the type of solver and its parameters can be specified in this block as well. The Kalman filter module is represented by the ``KalmanApp`` class and the ``KalmanNetwork``, both of which are in the ``gridpack::kalman_filter`` namespace. At present there are only a few functions in this class, more will probably be added as we develop this module further. Apart from the constructor and destructor, the ``KalmanApp`` class has a method for reading in a network from a PSS/E formatted file and partitioning it among processors :: void readNetwork(boost::shared_ptr &network, gridpack::utility::Configuration *config) If the network already exists, then it can be applied to an existing KalmanApp object using the function :: void readNetwork(boost::shared_ptr &network, gridpack::utility::Configuration *config) The application can be initialized by calling the function :: void initialize() This function will read in the files containing the time series data for the voltage magnitude and phase angles and will set update configure the calculation based on the parameters in the input file. The simulation is run and output generated using :: void solve() The values of the rotor speed and rotor angle for all generators will be written to the files ``omega.dat`` and ``delta.dat`` after this simulation is run. Electromagnetic Transient (EMT) Module --------------------------------------- GridPACK includes an electromagnetic transient (EMT) simulation module that provides detailed modeling of power system components using differential-algebraic equations (DAE). The EMT module is designed for high-fidelity analysis of electromagnetic phenomena in power systems, making it suitable for studying transient behavior, fault analysis, and detailed generator dynamics. The module uses a DAE solver to integrate the system equations and supports both explicit and implicit integration algorithms for machine models. The EMT module is represented by the ``Emt`` class and uses an ``EmtNetwork`` for the network representation. Unlike other GridPACK modules, the EMT class does not use a specific namespace but is designed to work seamlessly with the GridPACK framework. The module requires both a power flow initialization phase and an EMT simulation phase. The EMT module uses an input deck with both ``Powerflow`` and ``EMT`` configuration blocks. An example input file has the form: :: case9_PSCAD.raw 50 1.0e-6 -ksp_type richardson -pc_type lu -pc_factor_mat_solver_package superlu_dist -ksp_max_it 1 false case9_GAST.dyr EXPLICIT 2.0 0.00005 0.5 0.6 9 ThreePhase 0.011 0.0 1 1 2 1 emt_ The ``Powerflow`` block contains standard power flow configuration parameters including the network configuration file and solver options. The ``EMT`` block contains parameters specific to the EMT simulation: #. ``generatorParameters``: PSS/E .dyr format file containing additional generator model parameters for the EMT simulation. #. ``machineIntegrationType``: Integration algorithm for machine models. Can be set to ``EXPLICIT`` or ``IMPLICIT`` (default). #. ``simulationTime``: Total simulation time in seconds. #. ``timeStep``: Integration time step for the EMT simulation. #. ``Events``: Block containing fault events and other disturbances. Currently supports ``BusFault`` events with parameters for fault timing, location, type, and impedance values. #. ``Monitors``: Specifies generators to be monitored during simulation. Output from monitored generators is written to files. #. ``DAESolver``: Configuration parameters for the DAE solver. After instantiating an ``Emt`` object with a communicator, the EMT calculation can be set up using the following sequence of function calls. First, the configuration file must be assigned: :: void setconfigurationfile(const char* configfile) This function assigns the input configuration file to the EMT object. Next, an initial power flow calculation must be performed to establish the system operating point: :: void solvepowerflow() This function reads the network configuration, performs the power flow calculation, and initializes the system state variables. The power flow solution provides the initial conditions for the EMT simulation. After the power flow is complete, the EMT-specific setup can be performed: :: void setup() This function reads the generator parameters from the .dyr file, sets up the EMT network components, initializes the DAE solver, and prepares the system for transient simulation. The setup process includes creating vector and matrix mappers for the DAE system and configuring event handlers for faults and other disturbances. The EMT simulation can then be executed using: :: void solve() This function integrates the DAE system over the specified simulation time, handling events such as faults and writing output for monitored generators. The integration uses the configured time step and machine integration type. The EMT module supports several types of events that can be specified in the input configuration: #. **Bus Faults**: Three-phase faults applied to specified buses with configurable fault resistance and grounding resistance. #. **Generator Monitoring**: Real-time monitoring and output of generator state variables during simulation. The module uses a DAE solver framework that supports various integration algorithms and can handle stiff differential equations typical in power system transient analysis. The solver configuration can be controlled through PETSc options in the ``DAESolver`` block. Output from the EMT simulation includes time series data for monitored generators, which is written to files during the simulation. The output frequency and monitored variables can be controlled through the input configuration. The EMT module is designed to work in conjunction with other GridPACK modules, particularly power flow, to provide comprehensive power system analysis capabilities. The module can be used as a starting point for developing specialized EMT applications or can be integrated into larger multi-physics simulations.