API — ICoreBlocks/ICoreSimulation
The public contract of 9 header(s) under src/ICoreBlocks/ICoreSimulation — 9 class/struct definition(s), 129 declaration(s). Each section shows the header's banner and its public (and protected-virtual) surface exactly as the file writes it.
ICoreModelBuild.h#
src/ICoreBlocks/ICoreSimulation/ICoreModelBuild.h
ICoreModelBuild#
ICoreModelBuild.h:11 · class · 10 declaration(s)
class ICoreModelBuild {
public:
static bool buildModel(const ICoreSubsystemTreeNode* topLevelTreeNode = ICoreSubsystemTreeNodeRegistry::getHomeTreeNode());
// static void overwriteSignal(const std::string &key, const ICoreMatrix* value);
static std::vector<ICoreBlock*>& getOrderedBlocks();
static std::vector<double> getAllSamplingRates_unordered();
// static std::pair<double, double> getTwoSmallestSamplings();
// static std::unordered_map<std::string, ICoreMatrix*>& getSignalMap();
static void printOrderedBlocks();
// Code export requires a single-rate subtree: verifies every (already-built) ordered
// block/subsystem shares the source subsystem's sampling time. Logs each offender and
// returns false on any mismatch. Call after buildModel(sourceTreeNode), before parsing.
static bool verifyUniformSamplingTime(const ICoreSubsystemTreeNode* sourceTreeNode);
// Orders one subsystem's blocks for solving. The diagram is a graph whose edges are
// the links; a block's order is one more than the highest order among its sources,
// so a block is always solved after everything it reads -- except around a loop,
// which is opened at the OUTPUT of a block with no direct feedthrough (an
// Integrator, a strictly proper Transfer Function, a Unit Delay: its output at an
// instant is known from its state, so its consumers may run before it and read the
// value it wrote last). A loop with nowhere to open is an ALGEBRAIC LOOP: with
// detectAlgebraicLoops it is reported, naming every block around it, and the call
// fails; without it the loop is opened at an arbitrary edge and the build goes on
// (the first pass of a build, before any block has loaded the parameters its
// feedthrough answer may depend on; and the auto-arrange layout).
static bool assignSolverOrders(const ICoreSubsystemTreeNode *treeNode, const bool& enumerateCommentedOutBlocks = false,
const bool& detectAlgebraicLoops = false);
// The second, decisive ordering pass. Called by the simulator's pre-start logic
// once every block has loaded its config -- the point at which a Transfer
// Function knows whether it is strictly proper -- it re-orders every subsystem
// from Home down with algebraic-loop detection ON and rebuilds the ordered block
// list for the scope buildModel() was given. False, with the loop reported, when
// the diagram has an algebraic loop; the ordered list is then left as the first
// pass made it and the run (or export) must not proceed.
static bool finalizeSolverOrders();
// VARIANT PRUNING (FEATURES_TO_ADD.md BF3.3), the first thing finalizeSolverOrders
// does: every port a variant block marked inactive in its config load
// (ICoreBlock::setInactiveVariantPorts) takes out the blocks it makes inactive,
// and those leave the run as a commented-out block does (isExcludedFromRun).
// R2026a's rule (§F.BF3, BF3.1 (c)): a block goes when EVERY input it has is dead
// (downstream) or EVERY consumer of its outputs is (upstream), or it marked all
// its own outputs inactive; a block with one dead input and one live one stays
// and reads 0 on the dead one. It flows through subsystem gates, and a subsystem
// whose every block went goes with them. The gates of the subsystem being run or
// exported are its interface and are never pruned: an inactive branch reaching one
// carries 0. Returns how many blocks it took out.
static int pruneInactiveVariants();
// Whether the last finalizeSolverOrders() succeeded (false before it ran, and
// after any buildModel()).
[[nodiscard]] static bool solverOrdersFinalized();
// Whether the subsystem `face` runs VIRTUALLY in the finalized order
// (FEATURES_TO_ADD.md BF12.3): a plain subsystem -- not atomic, not Home, not the
// scope the build was given -- has its blocks ordered with its parent's, as
// Simulink's virtual subsystem is, judged port by port through its gates. Its face
// stays in the run but nothing reads through it: its input gates read what feeds
// the face themselves, and a wire from its output is read from the output gate.
[[nodiscard]] static bool runsVirtually(const ICoreBlock* face);
// Whether a block's output at an instant depends on its input at that instant --
// ICoreBlockSolverEnvironment::hasDirectFeedthrough() for an ordinary block; for a
// subsystem block, whether some path inside it runs from an input gate to an
// output gate through feedthrough blocks only (nested subsystems recurse). The
// question the ordering above and the joint scheme's output phase both ask.
[[nodiscard]] static bool blockFeedsThrough(const ICoreBlock* block);
};
};
ICoreModelConfigurator.h#
src/ICoreBlocks/ICoreSimulation/ICoreModelConfigurator.h
ICoreModelConfigurator#
ICoreModelConfigurator.h:4 · class · 69 declaration(s)
class ICoreModelConfigurator {
public:
// ================== Simulation Time
static void setStartTime(const double& newStartTime);
static double getStartTime();
static void setStopTime(const double& newStopTime);
static double getStopTime();
static void setInfiniteSimulation(const bool& newIsInfinite);
static bool getIsInfiniteSimulation();
static void setMaximumConsecutiveTimeBuffer(const double& newBufferTime);
static double getMaximumConsecutiveTimeBuffer();
static void setSlowPaceStepDelay(const double& newSamplingTime);
static std::chrono::milliseconds getSlowPaceStepDelay();
// ================== Solver Type
static void setSolverType(const std::string& newSolverType);
static std::string getSolverType();
static std::vector<std::string> getAvailableSolverTypes();
static bool getIsContinuousSolverType();
static bool getIsDiscreteSolverType();
static void setSteppingType(const std::string& newSteppingType);
static std::string getSteppingType();
static std::vector<std::string> getAvailableSteppingTypes();
static bool getIsFixedTimeStep();
static void setDiscretizationMethod(const std::string &newMethod);
static std::string getDiscretizationMethod();
static bool isDiscretizationMethod_ZOH();
static bool isDiscretizationMethod_FOH();
static bool isDiscretizationMethod_Impulse();
static bool isDiscretizationMethod_Tustin();
static bool isDiscretizationMethod_Matched();
static bool isDiscretizationMethod_BackwardEuler();
static bool isDiscretizationMethod_ForwardEuler();
static std::vector<std::string> getAvailableDiscretizationMethods();
// ================== Solver Type Getters
static bool isSolverType_RK1();
static bool isSolverType_RK2();
static bool isSolverType_RK3();
static bool isSolverType_RK4();
static bool isSolverType_RK45();
static bool isSolverType_RK23();
// Implicit fixed-step methods (stiff models): solved per block by Newton iteration.
static bool isSolverType_BE1();
static bool isSolverType_TR2();
// Implicit variable-step method (stiff models): TR-BDF2 with an embedded error estimate.
static bool isSolverType_TRBDF2();
// ================== Continuous coupling
// How the continuous states of a diagram are advanced under the Continuous
// solver: JOINT integrates every continuous state together, evaluating the
// whole diagram at each stage (feedback among continuous blocks is exact);
// PER_BLOCK integrates each block on its own with its inputs interpolated
// between visits (the scheme every exported code target reproduces).
static void setSolverCoupling(const std::string& newCoupling);
static std::string getSolverCoupling();
static std::vector<std::string> getAvailableSolverCouplings();
static bool isSolverCouplingJoint();
// ================== Continuous time Configuration
static void setMultiRateTolerance(const double& newMultiRateTolerance);
static double getMultiRateTolerance();
// ================== Fixed Stepping Configuration
static void setGlobalSamplingTime(const double& newSamplingTime);
static double getGlobalSamplingTime();
// ================== Variable Stepping Configuration
static void setMaxTimeStep(const double& newMaxTimeStep);
static double getMaxTimeStep();
static void setMinTimeStep(const double& newMinTimeStep);
static double getMinTimeStep();
static void setInitialTimeStep(const double& newInitialTimeStep);
static double getInitialTimeStep();
static void setRelativeTolerance(const double& newRelativeTolerance);
static double getRelativeTolerance();
static void setAbsoluteTolerance(const double& newAbsoluteTolerance);
static double getAbsoluteTolerance();
// ================== Time budget validation
static void setTimeBudgetValidationEnabled(const bool& newTimeBudgetValidationEnabled);
static bool isTimeBudgetValidationEnabled();
static void setTimeBudgetRelativeTolerance(const double& newTimeBudgetRelativeTolerance);
static double getTimeBudgetRelativeTolerance();
static void setTimeBudgetAbsoluteTolerance(const double& newTimeBudgetAbsoluteTolerance);
static double getTimeBudgetAbsoluteTolerance();
// ================== Units on wires
// Simulink's two unit diagnostics (R2026a, measured): UnitsInconsistencyMsg is
// `warning` (default) or `none` -- there is no `error`, so a unit mismatch is never
// refused -- and AllowAutomaticUnitConversions, on by default, makes a gate whose
// unit differs from the one arriving convert the value (m into cm gives 300 for 3).
// ICoreUnits::settle reads both when a model is built.
static void setUnitsInconsistencyMessage(const std::string& newMessage);
static std::string getUnitsInconsistencyMessage();
static std::vector<std::string> getAvailableUnitsInconsistencyMessages();
static bool reportsUnitsInconsistency();
static void setAutomaticUnitConversions(const bool& newAllowed);
static bool getAutomaticUnitConversions();
// Puts every setting back to the value it has at startup. Called when a
// project is opened that carries no solver.ini of its own, so a new or
// pre-sidecar project starts from the documented defaults instead of
// silently inheriting whatever the previously open project was configured
// with. Goes through the setters, so the config panel refreshes with it.
static void resetToDefaults();
// ================== Constants
static const std::string SOLVER_CONTINUOUS;
static const std::string SOLVER_DISCRETE;
static const std::string SOLVER_TYPE_RK1;
static const std::string SOLVER_TYPE_RK2;
static const std::string SOLVER_TYPE_RK3;
static const std::string SOLVER_TYPE_RK4;
static const std::string SOLVER_TYPE_RK45;
static const std::string SOLVER_TYPE_RK23;
static const std::string SOLVER_TYPE_BE1;
static const std::string SOLVER_TYPE_TR2;
static const std::string SOLVER_TYPE_TRBDF2;
static const std::string SOLVER_COUPLING_JOINT;
static const std::string SOLVER_COUPLING_PER_BLOCK;
static const std::string DISCRETE_METHOD_ZOH;
static const std::string DISCRETE_METHOD_FOH;
static const std::string DISCRETE_METHOD_Impulse;
static const std::string DISCRETE_METHOD_Tustin;
static const std::string DISCRETE_METHOD_Matched;
static const std::string DISCRETE_METHOD_BackwardEuler;
static const std::string DISCRETE_METHOD_ForwardEuler;
static const std::string UNITS_MESSAGE_WARNING;
static const std::string UNITS_MESSAGE_NONE;
};
};
ICoreModelSimulatorAPIs.h#
src/ICoreBlocks/ICoreSimulation/ICoreModelSimulatorAPIs.h
False when the build did not complete. Callers driving it from the UI are expected to say so -- the diagnosis log alone leaves a failed build looking like a successful one.
ICoreModelSimulatorAPIs#
ICoreModelSimulatorAPIs.h:5 · class · 6 declaration(s)
class ICoreModelSimulatorAPIs {
public:
// False when the build did not complete. Callers driving it from the UI are expected to
// say so -- the diagnosis log alone leaves a failed build looking like a successful one.
static bool buildProject();
static void runProjectSimulator();
static void runProjectSimulatorInDebugMode();
static void stopProjectSimulator();
static void pauseProjectSimulator();
static void stepProjectSimulator();
};
};
ICoreJointIntegration.h#
src/ICoreBlocks/ICoreSimulation/Core/ICoreJointIntegration.h
ICoreJointIntegration#
ICoreJointIntegration.h:45 · class · nested Linearization, LinearizationPoint · 3 declaration(s)
The continuous coupling "Joint": every block's continuous states form ONE state vector, advanced together by the configured stepping type, with the whole diagram's outputs re-evaluated at every int...
class ICoreJointIntegration {
public:
// True for a discrete-only block that must run its own solve() at tn.
using DiscreteBlockDue = std::function<bool(const ICoreBlockSolverEnvironment*)>;
static void step(const std::vector<ICoreBlock*>& blocks, const double& tn_1, const double& tn,
const DiscreteBlockDue& discreteBlockDue);
// The number of continuous state entries the last step advanced (diagnostics).
static size_t lastStateCount();
// Per block of the ordered list: whether the OUTPUT PHASE evaluates it -- the
// first phase of every sweep and of the commit, before the ordered pass. True for
// a participating block that is a continuous-state block with no direct
// feedthrough (its output is settled by its state alone), and for every
// participating block inside a subsystem that does not feed through (the
// subsystem's outputs are settled by the states inside it, and its gates and the
// chain between must run for the outer consumers to see them). Also the set the
// simulator publishes before the initial visit, so a loop's initial condition
// reaches the blocks solved before its state block.
static std::vector<bool> outputPhaseMask(const std::vector<ICoreBlock*>& blocks);
// THE WHOLE-DIAGRAM LINEARIZATION at the current operating point (FEATURES_TO_ADD.md
// BF17.2, decision D13): dx/dt = A dx + B du, dy = C dx + D du, by central differences
// of the very sweep and derivative a joint step evaluates -- so a loop is closed
// exactly as the run closes it. x is every continuous state of `blocks` (the built
// order), in the joint layout's order, row-major per block; u the elements of the
// `inputs` ports (Simulink's root Inports: their values are SET, and their blocks are
// held out of the sweep) and y those of the `outputs` ports (the root Outports' input
// ports), each row-major, in the order given. Only states that MOVE are states here:
// the 1x1 placeholder a feed-through block (a Gain) registers is left out, as
// Simulink lists no state for it. A numerical Jacobian matches Simulink's
// analytic linmod only to a band (BF17.1 measured linmodv5 ~1e-5 off; central
// differences here land near 1e-9 on smooth models). Every port value is put back
// as it was. False, with the reason, when an input or output is not numeric.
struct Linearization {
ICoreMatrix a, b, c, d;
ICoreMatrix x; // the operating point: states (column)
ICoreMatrix u; // and inputs (column)
std::vector<std::string> stateBlocks; // the block path of each state entry
std::vector<std::string> inputNames; // the port path of each element of u
std::vector<std::string> outputNames; // and of y
double t = 0.0;
};
static bool linearize(const std::vector<ICoreBlock*>& blocks, const double& t, const std::vector<ICorePort*>& inputs,
const std::vector<ICorePort*>& outputs, Linearization& out, std::string* whyNot = nullptr);
// LINEARIZATION ANALYSIS POINTS (FEATURES_TO_ADD.md BF17.3): the same linearization
// between points on links instead of the root ports. A point is an OUTPUT port and
// Simulink's three flags (ICorePort::setLinearizationFlags). At a point the value v
// its block computes is, in this order, MEASURED (an output point: y is v), OPENED
// (an open loop: what the port's consumers see is the operating point's v, so the
// loop through it no longer closes) and PERTURBED (an input point: u is added to
// what the consumers see). u lists the input points' elements and y the output
// points', each in the order given. A port with no flag set is ignored; a point
// on an input port is refused.
struct LinearizationPoint {
ICorePort* port = nullptr;
bool input = false;
bool output = false;
bool openLoop = false;
};
static bool linearize(const std::vector<ICoreBlock*>& blocks, const double& t,
const std::vector<LinearizationPoint>& points, Linearization& out,
std::string* whyNot = nullptr);
// The points `blocks`' output ports carry, ordered by block path, then port number.
static std::vector<LinearizationPoint> linearizationPoints(const std::vector<ICoreBlock*>& blocks);
// Simulink's root ports at `blocks`' top level: the output port of every input gate
// whose subsystem is Home, and the input port of every such output gate, in the order
// the gates were made -- the order a root Inport's port number gives.
static void rootPorts(const std::vector<ICoreBlock*>& blocks, std::vector<ICorePort*>& inputs,
std::vector<ICorePort*>& outputs);
};
};
ICoreModelSimulator.h#
src/ICoreBlocks/ICoreSimulation/Core/ICoreModelSimulator.h
ICoreModelSimulator#
ICoreModelSimulator.h:12 · class · nested CollectedSideTrace, InjectedInput · 22 declaration(s)
class ICoreModelSimulator {
public:
static void runProjectSimulator();
static void runProjectInDebugMode();
static ICoreMatrix runSynchronousAndCollect(
const ICoreSubsystemTreeNode* sourceTreeNode,
const std::vector<ICorePort*>& portsToCollect);
// What a matrix of doubles cannot carry, from the SAME run (T3.5).
//
// A String or Bus port's matrix is a 1x1 placeholder, so it still occupies
// exactly one column of the returned matrix -- every caller's column
// arithmetic is unchanged, and the placeholder zero is what that column
// holds. The value itself is here, one entry per collected port in collect
// order, and it is why the collection is described as "flattening per
// KIND" rather than per size.
struct CollectedSideTrace {
ICorePort* port = nullptr;
std::string typeId;
// String kind: one string per step. Empty for every other kind.
std::vector<std::string> strings;
// Bus kind: one entry per step, each a list of (element name,
// flattened element value) in spec order. A string element's value
// list is empty and its text is in `busStrings` at the same position.
std::vector<std::vector<std::pair<std::string, std::vector<double>>>> buses;
std::vector<std::vector<std::string>> busStrings;
};
// The side traces of the LAST runSynchronousAndCollect. Valid until the
// next one; a caller that keeps them past that is keeping a stale run.
[[nodiscard]] static const std::vector<CollectedSideTrace>& lastCollectedSideTraces();
// One port and the per-step value to force onto its signal at the start of
// every solve (used to inject verification test inputs).
//
// `texts` is the same thing for the kind a matrix cannot hold: a String
// port's matrix is a 1x1 placeholder (T3.2), so injecting a number into it
// feeds the block nothing. Empty for every other kind, and a String port
// whose `texts` is empty is fed the empty string rather than a number --
// which is the state the whole verification path was in before T5.8.
struct InjectedInput {
ICorePort* port = nullptr;
std::vector<ICoreMatrix> values;
std::vector<std::string> texts;
};
using InputInjectionSchedule = std::vector<InjectedInput>;
static ICoreMatrix runSynchronousAndCollect(
const ICoreSubsystemTreeNode* sourceTreeNode,
const std::vector<ICorePort*>& portsToCollect,
const InputInjectionSchedule& inputInjection,
double injectionSampleTimeSeconds);
// Loads every block's config, finalizes the solver order (the pass that opens
// loops at blocks without direct feedthrough and refuses an algebraic loop),
// sets up the sampling times and solves the initial step. False when the run
// must not start -- the reason has been logged and the simulator stopped.
static bool preStartLogic();
// Ends a pre-start that no run follows: a code export, or its verification,
// pre-starts the model to finalize the order and load the configs it emits,
// and then returns without stepping. preStartLogic() hands the model to the
// solver (isSolverStepping()), so without this a re-type -- a Data Type
// Conversion's output type, from its dialog or a recipe -- stayed refused
// "while a simulation is running" after every export until the next run
// (FEATURES_TO_ADD.md BF0.10). Does nothing while a run is live.
static void endPreStartWithoutRun();
static void coreLogic();
static void postEndLogic();
static void stopProjectSimulator();
// Stop the solver if it is running, and JOIN the worker thread.
//
// stopProjectSimulator() is the timeline command -- it means "the user
// pressed stop". This is the LIFETIME command: after it returns, no solver
// thread exists. Safe to call when nothing is running, safe to call twice,
// and a no-op called from the worker thread itself.
//
// A backstop in ICoreModelSimulator.cpp calls this at static destruction,
// so an application that simply exits cannot leave the thread joinable --
// which used to abort the process. See the comment on that backstop.
static void shutdownWorkerThread();
static void pauseSimulation();
static void resumeSimulation();
static void stepSimulation();
// ------------------[ Fast-forward: the pause target ]------------------
//
// A pause target is a time strictly inside the run, (start, stop). The run
// executes EVERY step exactly as it would without one -- nothing is skipped
// and no step is shortened for it -- and on the first solved step whose time
// is at or past the target it pauses, through the same pauseSimulation() the
// Pause button raises, so Run resumes it. Debug mode auto-steps to the target
// instead of waiting for a Step click per step, then goes back to waiting;
// it raises no pause there, because debug mode already stops between steps.
// The target is consumed when reached, and dropped (with a warning) by a run
// that reaches its stop time without a solved step landing on or past it --
// a target inside the last step of a grid that does not end on the stop
// time. One a run is STOPPED before reaching stays set, visibly, for the
// next run, until cleared here.
//
// Set from the time line -- a click ahead of the progress mark -- or before
// a run starts, in which case the next run pauses there. setPauseTarget()
// refuses, leaving any current target as it was: a time that is not strictly
// after the clock (after the start time when no run is live), not strictly
// before the stop time, or a run configured as infinite. preStartLogic()
// drops a target the loaded configuration puts outside the run, with a
// warning in the diagnostics.
static bool setPauseTarget(double time);
static void clearPauseTarget();
static bool hasPauseTarget();
static double getPauseTarget(); // NaN when there is none
// A new value for a block's TUNABLE config while a run is live
// (FEATURES_TO_ADD.md BF11.4; the contract is on ICoreBlockSolverEnvironment::
// refuseTunableWrite). Callable from any thread: the write is queued, and the
// simulator applies the queue at the start of the next solve, so a step never
// sees half of it. A write the block refuses then -- not tunable, a new size,
// its own cross-check -- stops the run with the reason, as Simulink's
// validation does. Returns false, with the reason, when no run is live; a
// queue a run leaves unapplied is dropped when the next run starts.
//
// ⚠ FROM INSIDE A SOLVE THE WRITE LANDS AT ONCE (BF11.6). A block that writes
// another block's parameter as it computes -- a Parameter Writer, whose
// reference config is marked ICoreBlockConfigVariable::setWritesReferencedBlock
// -- is ordered BEFORE that block by the build, so the owner computes with the
// new value in the SAME step, which is where Simulink lands it (BF11.1:
// y = [1 2 3 4 5], not [2 1 2 3 4]). A refusal there returns false and stops
// the run the same way.
static bool writeTunableConfig(ICoreBlock* block, const std::string& configName, const ICoreMatrix& value,
std::string* refusal = nullptr);
// A worker is running or debugging; a paused run counts as live.
//
// ⚠ TRUE FROM THE MOMENT RUN IS CLICKED, WHICH INCLUDES THE BUILD AND THE
// PRE-START. It answers "is there a run in progress?" for the tool bar, the
// time line and setPauseTarget(). It is NOT the question "may the model be
// mutated right now?" -- ask isSolverStepping() for that.
static bool isRunLive();
static bool isSimulationPaused();
// The solver is executing steps: the initial solve of preStartLogic() has
// begun and the run has not ended.
//
// This is the window in which the model is the SOLVER'S, and it is narrower
// than isRunLive() at both ends. The build re-types and re-sizes ports, and
// loadConfigs() applies every block's configured output type (T2.3) -- both
// run on the worker with isRunLive() already true, so a guard written
// against isRunLive() refuses the very work the run is there to do.
//
// Measured, 2026-09-12: a Constant re-applying its own unchanged type id
// during the build was refused "while a simulation is running", and because
// every logError() stops the simulator, the run was torn down from inside
// its own build -- then went on to announce solverStarted() and solve
// nothing, leaving the run controls stuck in their running state with no
// worker left to release them.
static bool isSolverStepping();
static void registerCandidatesNextVariableStepSize(const double& dt_candidate);
static double getCurrentTime();
static double getProgressPercentage();
static bool isSolvingInitialStep();
// How far past the stop time a solve time may land and still count as "at the
// stop time". Every mode uses the same slack, so a fixed grid that ends on the
// stop time (0.1 x 100 = 10) solves its last point and none beyond; variable
// step lands its last step on the stop time exactly. Absolute seconds.
static constexpr double STOP_TIME_SLACK = 1e-9;
};
};
ICoreRunLinearization.h#
src/ICoreBlocks/ICoreSimulation/Core/ICoreRunLinearization.h
ICoreRunLinearization#
ICoreRunLinearization.h:31 · class · 9 declaration(s)
The whole-diagram linearization TAKEN DURING A RUN, as Simulink's Timed-Based and Trigger-Based Linearization blocks take it: at the root Inports and Outports, as linmod does, at the operating po...
class ICoreRunLinearization {
public:
using Deliver = std::function<void(const ICoreJointIntegration::Linearization& result, const std::string& whyNot)>;
static void scheduleAt(const void* owner, const std::vector<double>& times, Deliver deliver);
static void requestAtStepEnd(const void* owner, Deliver deliver);
static void cancel(const void* owner);
static void clear();
// Called by the simulator, on the solver thread: after each step is solved at `t`
// (with `initialStep` for the run's first solve), and when it picks its next step.
static void serviceStep(const std::vector<ICoreBlock*>& blocks, double t, bool initialStep, bool fixedStep,
bool jointCouplingApplies);
[[nodiscard]] static double nextScheduledAfter(double t);
[[nodiscard]] static bool hasWork();
// The result as the variables space holds it (owner decision, 2026-10-01): one
// Record per snapshot -- a, b, c, d, then OperPoint's x, u and t flattened as
// OperPoint_x, OperPoint_u and OperPoint_t, then Ts -- with StateName, OutputName
// and InputName (text cells in Simulink) withheld by name.
static ICoreRecord record(const ICoreJointIntegration::Linearization& result, double sampleTime);
// Simulink's variable for a block: its path with every non-word character as '_'
// (`bfG/My Sub/T L` gives `bfG_My_Sub_T_L`, measured), and snapshot k of a run
// (from 1) as `name`, `name_2`, `name_3`, ...
static std::string variableNameFor(const std::string& blockPath);
static std::string snapshotName(const std::string& variable, std::size_t k);
};
};
ICoreRungeKuttaEstimation.h#
src/ICoreBlocks/ICoreSimulation/Core/ICoreRungeKuttaEstimation.h
Called by the simulator at the start of every run: clears the once-per-run diagnostics (the implicit methods' "did not converge" warning).
ICoreRungeKuttaEstimation#
ICoreRungeKuttaEstimation.h:8 · class · 4 declaration(s)
class ICoreRungeKuttaEstimation {
public:
static ICoreMatrix computeStateEvolution(ICoreBlockSolverEnvironment *block, const ICoreMatrix& xn_1,
const double& tn_1, const double& tn, const double& dt,
const std::vector<ICoreMatrix>& un_1, const std::vector<ICoreMatrix>& un);
// Called by the simulator at the start of every run: clears the once-per-run
// diagnostics (the implicit methods' "did not converge" warning).
static void resetRunState();
// The variable-step controller, shared with the joint scheme so both size the
// step the same way: the scaled RMS error of one state matrix, and the factor
// the next step is scaled by for a given scaled error and error exponent.
[[nodiscard]] static double controllerScaledError(const ICoreMatrix& err, const ICoreMatrix& xOld, const ICoreMatrix& xNew);
[[nodiscard]] static double controllerNextStepFactor(const double& scaledError, const double& exponent);
// Said once per run by the implicit methods' Newton iteration when a step does
// not converge; the joint scheme's Newton reports through the same gate.
static void reportImplicitStepNotConverged(const std::string& where, const double& tn, const double& residual);
};
};
ICoreSimulatorRepeatableWindow.h#
src/ICoreBlocks/ICoreSimulation/Objects/ICoreSimulatorRepeatableWindow.h
ICoreSimulatorRepeatableWindow#
ICoreSimulatorRepeatableWindow.h:9 · class · pImpl · 2 declaration(s)
class ICoreSimulatorRepeatableWindow {
public:
explicit ICoreSimulatorRepeatableWindow(std::map<long long, std::vector<ICoreBlock*>>& orderedBlocksByBandWidth
, long long repeatableWindowWidth);
void fire(double windowStartTime, const double& bandWidthUnitDuration) const;
~ICoreSimulatorRepeatableWindow();
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};
ICoreSimulatorRepeatableWindowSolvingList.h#
src/ICoreBlocks/ICoreSimulation/Objects/ICoreSimulatorRepeatableWindowSolvingList.h
ICoreSimulatorRepeatableWindowSolvingList#
ICoreSimulatorRepeatableWindowSolvingList.h:8 · class · pImpl · 4 declaration(s)
class ICoreSimulatorRepeatableWindowSolvingList {
public:
explicit ICoreSimulatorRepeatableWindowSolvingList(const std::vector<ICoreBlock*>& listOfBlocks);
void fire(const double &windowStartTime, const double &bandWidthUnitDuration, long long &subStep) const;
void increaseNumOfRepeats();
~ICoreSimulatorRepeatableWindowSolvingList();
private:
class Impl; // the two-line residue; state lives here
std::unique_ptr<Impl> impl;
};