Generated reference › API — ICoreBlocks/ICoreSimulation
kind: generated#api#icoreblocks-icoresimulation

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;
};