LINE Solver (C++)
Templated C++ port of the LINE queueing solver
Loading...
Searching...
No Matches
line::fluid Namespace Reference

Namespaces

namespace  petri

Classes

struct  AoiMe
 A matrix-exponential age law: P(age > t) = g exp(A t) h. More...
struct  AoiParams
 The (tau, T) / (sigma, S) pairs and the preemption probability. More...
struct  AoiSolution
 Both age laws of one system, with the policy parameter that produced them. More...
struct  AoiTopology
 What the AoI gate found, when it matches. More...
struct  ClosureValue
 A closure's value and its first two derivatives with respect to the first mean. More...
struct  DiffusionOptions
 Controls of the Euler-Maruyama trajectory. More...
struct  DiffusionResult
 Time-averaged queue lengths of the diffusion trajectory. More...
struct  ExpansionWeight
 How much of the second-order correction the series admits, and d tau / d ratio. More...
struct  FluidAoiResult
 What the AoI branch of mfq returns: the age laws and the metrics beside them. More...
struct  FluidCacheqnSolution
 What the steady analyzer returns: the fluid metrics plus the converged split. More...
struct  FluidCacheqnTranCache
 One cache's transient, the per-cache slice of the reference's 3-D outputs. More...
struct  FluidClosure
 The second moment the drift closes its non-linear terms with, i.e. More...
struct  FluidDaeConservation
 Population conservation, one row per CLOSED chain, in state space. More...
struct  FluidDaeConstraints
 Finite capacity regions as linear admission constraints on the fluid state. More...
struct  FluidDaeGates
 Which events each cap throttles, and what happens to the mass it stops. More...
struct  FluidDaeLegs
 The two legs of every event under the active caps, and the waiting rooms. More...
struct  FluidDaeNewtonInfo
 What the Newton reports about where it stopped. More...
struct  FluidDaeOptions
 Options that only the DAE route reads. More...
struct  FluidDaeStaging
 The waiting room outside a capped region, as fluid coordinates. More...
struct  FluidDaeSwitch
 What a hybrid transient did, beside the trajectory. More...
struct  FluidDaeSystem
 Everything the residual needs, gathered so the Newton can stay generic. More...
struct  FluidEvent
 One event of the drift. More...
struct  FluidImmediateMatrix
 What the matrix-level elimination produced. More...
struct  FluidImmediateResult
 What an elimination attempt produced. More...
struct  FluidJacobian
 The four outputs of @@SolverFLD/getJacobian. More...
struct  FluidKpTransient
 The transient the covariance equation produces, i.e. More...
struct  FluidLayout
 Where each (station, class) block sits in the state vector. More...
struct  FluidLyapunovInfo
 The reference's MException('LINE:FluidNonHyperbolic'), as a type. More...
struct  FluidMatrixSystem
 The assembled matrix-form drift and the maps that read metrics off it. More...
struct  FluidMomentReport
 The second-order results of the moment-closure methods, i.e. More...
struct  FluidMomentTerms
 Port of fluid_moment_terms.m: the event representation of the fluid population process, plus the drift, rate and Jacobian handles the covariance equation needs. More...
class  FluidNonHyperbolicError
 Raised when the moment closure cannot serve this model: the linearization at the fixed point is not hyperbolic, or the drift has left the simplex. More...
struct  FluidOdeSystem
struct  FluidOptions
 Controls, defaulting to SolverOptions('Fluid') in the reference. More...
struct  FluidPassage
 The response-time CDF of one (station, class), sampled on a grid. More...
struct  FluidRateMult
 The assembled drift: the layout, the events, and the per-station schedule. More...
struct  FluidRefineInfo
 What fluid_refine_meanfield reports about the correction it computed. More...
struct  FluidSolution
 What the analyzer returns, in the same shape as the MVA solver's result. More...
struct  FluidStateDepSystem
 Everything the state-dependent drifts read, lowered once to doubles. More...
struct  FluidStiffOptions
 Controls for the stiff arm. More...
struct  FluidSymbolicDrift
 The drift as expression strings, one per state variable, plus their names. More...
struct  FluidSymbolicJacobian
 What @@SolverFLD/getJacobian returns: d f_i / d x_j as expression strings. More...
struct  FluidSymbolicOptions
 Backend selection, mirroring options.config.symbolic and its timeout. More...
struct  FluidSymSystem
 The symbolic system, in whichever of the two forms the method implies. More...
struct  FluidTranPoint
 One point of a transient trajectory: the metrics at time t. More...
struct  KpBlock
 One (station, class) block of the Ko-Pender state vector. More...
struct  KpEvent
struct  MfqPrioResult
 Per-class metrics of the priority queue, indexed by class. More...
struct  MfqResult
 The metrics mfq reports for its single queue. More...
struct  MfqTopology
 What the single-queue gate found, when it matches. More...
struct  ShareValue
 A share closure's value and Jacobian, and the joint-closure covariance. More...
struct  SymFactor
 The state-dependent factor attached to one event's driving variable. More...
struct  TbiOptions
 Controls of the time-based iteration, mirroring options.config.tbi_*. More...

Enumerations

enum class  KpEventKind {
  ArrivalPhase = 1 , Arrival = 2 , ServicePhase = 3 , Departure = 4 ,
  Routed = 5
}
 The five event families of Ko-Pender (3.1)-(3.2). More...
enum class  StateDepKind { StateDep , SoftMin , PNorm }
 Which smoothing the drift applies at a saturated station. More...

Functions

template<class T>
AoiTopology aoi_is_aoi (const qn::NetworkStruct< T > &sn)
 Port of aoi_is_aoi.m.
template<class T>
AoiParams aoi_extract_params (const qn::NetworkStruct< T > &sn, const AoiTopology &top, double preempt_override)
 Port of aoi_extract_params.m.
AoiSolution aoi_solve_bufferless (const std::vector< double > &tau, const Matrix< double > &Tm, const std::vector< double > &sigma, const Matrix< double > &Sm, double p)
 Port of solveBufferless.m: the AoI and PAoI laws of a PH/PH/1/1 system in which an arrival meeting a busy server preempts it with probability p.
AoiSolution aoi_solve_singlebuffer (double lambda, const std::vector< double > &sigma, const Matrix< double > &Sm, double r)
 Port of solveSingleBuffer.m: the AoI and PAoI laws of an M/PH/1/2 system in which a waiting update is replaced by a fresher arrival with probability r.
double aoi_cdf (const AoiMe &me, double t)
 getCdfAoI: F(t) = 1 - S(t) with S the survival function of the age law.
template<class T>
FluidAoiResult fluid_aoi (const qn::NetworkStruct< T > &sn, const AoiTopology &top, double preempt_override)
 Port of solver_mfq_aoi.m.
template<class T>
FluidCacheqnSolution< T > solver_fld_cacheqn_analyzer (const qn::NetworkStruct< T > &sn, const FluidOptions &opt)
 Port of solver_fld_cacheqn_analyzer.m.
template<class T>
std::vector< FluidCacheqnTranCache< T > > solver_fld_cacheqn_tran (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, double t0, double t1, const std::vector< std::vector< T > > &x0cell=std::vector< std::vector< T > >())
 Port of solver_fld_cacheqn_tran.m: the transient counterpart of the analyzer above.
template<class T>
std::vector< double > fluid_initsol (const qn::NetworkStruct< T > &sn, const FluidLayout &L)
 Port of solver_fluid_initsol.m: the ODE's initial condition, in the layout the drift indexes.
template<class T>
std::vector< double > fluid_initsol (const qn::NetworkStruct< T > &sn)
 The same, for a caller that has not built the layout itself.
template<class T>
FluidSolution solver_fluid_closing (const qn::NetworkStruct< T > &sn, const FluidOptions &opt)
 Port of solver_fluid_closing.m: the closing family's entry point.
double closure_normcdf (double z)
 The standard normal cdf, without a statistics library.
double closure_normpdf (double z)
 The standard normal pdf.
ClosureValue fluid_min_closure (double n, double c, double s2, double vc=0.0, double cov_nc=0.0)
 Port of fluid_min_closure.m: E[min(X,Y)] for jointly normal X, Y, and its derivative with respect to E[X].
ClosureValue fluid_lld_scaling (const std::vector< double > &lldrow, double n)
 Port of fluid_lld_scaling.m: the limited load-dependent multiplier alpha at a CONTINUOUS population, by linear interpolation of the integer table.
ClosureValue fluid_capacity_closure (double n, double c, double s2, const std::vector< double > &lldrow, bool is_inf)
 Port of fluid_capacity_closure.m: E[psi(X)] and its derivative, where psi(n) = min(n,c)*alpha(n) at a queueing station and n*alpha(n) at an infinite server.
void fluid_project_rate (std::vector< double > &r, const std::vector< double > &xb, bool capped, double tot)
 Port of local_project_rate in ode_rates_closing_factors.m: project a jointly closed per-coordinate service share onto the set it has to live in, namely r >= 0, r <= xb where that bound applies, and sum(r) = tot.
ExpansionWeight fluid_expansion_weight (double ratio)
 Port of local_expansion_weight in fluid_share_closure.m.
ShareValue fluid_share_closure (const std::vector< double > &x, const std::vector< double > &wv, const Matrix< double > &C, bool want_jac, bool want_cov=false)
 Port of fluid_share_closure.m: E[w_j X_j / sum_m w_m X_m] by the delta method, and its Jacobian at fixed covariance.
ShareValue fluid_gps_share (const std::vector< double > &xk, const std::vector< double > &wk_in, const std::vector< double > &vk, bool want_jac)
 Port of fluid_gps_share.m: the expected capacity share of a GPS station under a normal marginal, and its Jacobian.
template<typename T>
std::vector< std::vector< std::size_t > > fluid_chain_partition (const qn::NetworkStruct< T > &sn, std::size_t K)
 The classes of each chain, as 0-based column indices.
template<typename T>
int fluid_conservation_violation (const qn::NetworkStruct< T > &sn, const FluidLayout &L, const std::vector< double > &x, double tol=kFluidConservationTol)
 The closed chain whose conserved population has drifted past tol, or -1.
double fluid_dae_reach (const std::vector< double > &row, const std::vector< std::size_t > &coord_class, const std::vector< double > &njobs, std::size_t K)
 The largest row x the population can produce, ignoring the coupling.
template<typename T>
FluidDaeConstraints fluid_dae_constraints (const qn::NetworkStruct< T > &sn, const FluidMomentTerms &terms)
template<typename T>
FluidDaeGates fluid_dae_gates (const qn::NetworkStruct< T > &sn, const FluidMomentTerms &t, const FluidDaeConstraints &con)
FluidDaeStaging fluid_dae_staging (const FluidMomentTerms &t, const FluidDaeConstraints &con)
void fluid_dae_extend (FluidDaeConstraints &con, const FluidDaeStaging &stg, const FluidMomentTerms &t)
 Extend every cap to the staging coordinates that hold mass INSIDE it.
FluidDaeLegs fluid_dae_legs (const FluidMomentTerms &t, const FluidDaeGates &gates, const FluidDaeStaging &stg, const FluidDaeConstraints &con, const std::vector< std::size_t > &active, const std::vector< double > &sg, const std::vector< double > &r, const std::vector< double > &mult, bool staged_flow)
 Shared by the steady-state residual and the transient right-hand side so that the two solve the SAME model and not two spellings of it.
template<typename T>
FluidDaeConservation fluid_dae_conservation (const qn::NetworkStruct< T > &sn, const FluidMomentTerms &terms, const FluidDaeStaging &stg)
 The conserved chains as equations.
FluidDaeOptions fluid_dae_options (const FluidOptions &opt, const FluidDaeOptions &dopt)
 The controls the DAE route actually reads: the struct a caller pinned, with whatever options.config set on top of it.
std::vector< std::size_t > fluid_dae_closable (const FluidMomentTerms &t)
 Stations whose variance enters the drift.
std::vector< double > fluid_dae_sigma_from (const Matrix< double > &Sigma, const FluidMomentTerms &t, const std::vector< std::size_t > &cidx)
 Project a state-level covariance onto the per-station variances the drift reads.
Matrix< double > fluid_dae_clamp_tangent (const FluidDaeConstraints &con, const std::vector< std::size_t > &active, const FluidMomentTerms &t)
 Orthogonal projector onto the subspace the CLAMPING caps leave free: I - R'(RR')^-1 R over the covariance coordinates.
bool fluid_dae_residual (const FluidDaeSystem &sysd, const std::vector< double > &u, std::vector< double > &G, std::vector< double > *rates_out, bool rethrow=false, std::vector< double > *fire_out=nullptr)
 The coupled algebraic system, stacked: drift, conservation, closure consistency.
void fluid_dae_project (std::vector< double > &u, std::size_t nfree)
 Onto the feasible box: the state is free, the variances are not.
FluidDaeNewtonInfo fluid_dae_newton (const FluidDaeSystem &sysd, std::vector< double > &u, double tol, std::size_t maxit)
 Damped PROJECTED Newton with a finite-difference Jacobian and an Armijo backtrack on the residual norm.
std::vector< std::vector< double > > fluid_dae_integrate (const FluidMomentTerms &terms, const FluidDaeConservation &cons, const FluidClosure &closure, const std::vector< double > &x0, const std::vector< double > &grid, double tol, bool withcov=false, const std::vector< std::size_t > &closable=std::vector< std::size_t >())
 Integrate the closure as an index-1 DAE, with RODAS, and report the state at every point of grid.
std::vector< double > fluid_dae_hold_multipliers (const FluidMomentTerms &terms, const FluidDaeGates &gates, const FluidDaeStaging &stg, const FluidDaeConstraints &con, const std::vector< std::size_t > &active, const std::vector< double > &x, const std::vector< double > &sg, const FluidClosure &cl, const std::vector< double > &m0, bool &ok)
 The multipliers that hold the active caps at this state, by small Newton.
std::vector< std::vector< double > > fluid_dae_integrate_hybrid (const FluidMomentTerms &terms, const FluidDaeConservation &cons, const FluidDaeConstraints &con, const FluidDaeGates &gates, const FluidDaeStaging &stg, const FluidClosure &closure, const std::vector< double > &x0In, const std::vector< double > &grid, double tol, std::vector< FluidDaeSwitch > *switches=nullptr)
 The transient UNDER CAPS: one index-1 DAE per segment, restarted at every located crossing.
void fluid_dae_metrics (const FluidMomentTerms &terms, const std::vector< double > &x, const FluidClosure &cl, Matrix< double > &QN, Matrix< double > &UN, Matrix< double > &RN, Matrix< double > &TN, const std::vector< double > *rates=nullptr)
 The metrics of one state, read exactly as the steady-state table reads them.
template<class T>
FluidSolution solver_fluid_dae (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, const FluidDaeOptions &dopt_in=FluidDaeOptions())
 solver_fluid_dae.m: the min-normal closure solved as one system.
template<class T>
std::vector< FluidTranPointsolver_fluid_dae_transient (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, double t_end, std::size_t points=101, const std::vector< double > &out_grid=std::vector< double >(), const FluidDaeOptions &dopt_in=FluidDaeOptions())
 @@SolverFLD/getTranAvg for the DAE route: the metrics ALONG the trajectory.
template<class T>
DiffusionResult fluid_diffusion (const qn::NetworkStruct< T > &sn, const DiffusionOptions &opt)
 Run the diffusion approximation of sn.
template<class T>
std::string fluid_export_odes (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, const std::string &notation="scalar", const std::string &model_name="model")
 Render the fluid ODE system of sn as a LaTeX document.
FluidJacobian fluid_jacobian (const FluidSymSystem &sys, const FluidSymbolicOptions &opt=FluidSymbolicOptions())
 Jacobian, drift and equilibria of the mean-field vector field.
template<class T>
FluidSolution solver_fluid_kp_core (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, FluidKpTransient *tran)
 The Ko-Pender solve, returning both the steady table and the covariance trajectory so that neither has to integrate twice.
template<class T>
FluidSolution solver_fluid_kp (const qn::NetworkStruct< T > &sn, const FluidOptions &opt)
 Port of solver_fluid_kp.m: the steady table at the horizon.
template<class T>
FluidKpTransient solver_fluid_tran_avg_var (const qn::NetworkStruct< T > &sn, const FluidOptions &opt)
 Port of @@SolverFLD/getTranAvgVar: the queue-length VARIANCE along the trajectory, per station and class, plus the full state covariance.
template<class T>
FluidMatrixSystem fluid_matrix_system (const qn::NetworkStruct< T > &sn, const std::vector< double > &init_sol, double pstar)
 Assemble the matrix-form drift of sn.
std::function< void(double, const double *, double *)> fluid_matrix_drift (const FluidMatrixSystem &s)
 The drift dx/dt = W' theta(x) + A_lambda.
bool fluid_matrix_degenerate (const FluidMatrixSystem &s, const std::function< void(double, const double *, double *)> &drift, const std::vector< double > &x, std::size_t K)
 Is the returned point one of a CONTINUUM of fixed points?
template<class T>
MfqTopology mfq_is_single_queue (const qn::NetworkStruct< T > &sn)
 Port of fluid_is_single_queue.m: the model must be one open class flowing Source -> Queue -> Sink and nothing else.
template<class T>
MfqResult fluid_mfq (const qn::NetworkStruct< T > &sn, const MfqTopology &top, double tol)
 Solve the single fluid queue of sn.
template<class T>
MfqPrioResult fluid_mfq_prio (const qn::NetworkStruct< T > &sn, const MfqTopology &top, double tol)
 Solve the single priority fluid queue of sn.
FluidClosure fluid_blend_closure (const FluidClosure &a, const FluidClosure &b, double step)
 a + step*(b - a) for a closure, entry by entry.
Matrix< double > fluid_lyapunov (const Matrix< double > &A, const Matrix< double > &Qdiff, const Matrix< double > &D, FluidLyapunovInfo &info, double tol=-1.0)
 Port of fluid_lyapunov.m: the stationary covariance of the linear noise approximation.
bool fluid_coord_eliminated (const FluidMomentTerms &t, std::size_t s)
 True when the immediate reduction folded coordinate s away, so the reduced drift holds no mass there and no event lands on it.
template<class T>
FluidMomentTerms fluid_moment_terms (const qn::NetworkStruct< T > &sn, const FluidOptions &opt)
std::vector< double > fluid_moment_factors (const FluidMomentTerms &t, const std::vector< double > &x, const FluidClosure &cl)
 The rate factors g(x) under a closure: terms.factorFcn.
std::vector< double > fluid_moment_rates (const FluidMomentTerms &t, const std::vector< double > &x, const FluidClosure &cl)
 The event rates r(x) under a closure: terms.ratesFcn.
std::vector< double > fluid_moment_drift (const FluidMomentTerms &t, const std::vector< double > &x, const FluidClosure &cl)
 The drift F(x) = D r(x) under a closure: terms.driftFcn.
Matrix< double > fluid_drift_jacobian (const FluidMomentTerms &t, const std::vector< double > &x, const FluidClosure &cl)
 Port of fluid_drift_jacobian.m: the analytic Jacobian of the fluid drift.
std::vector< std::size_t > fluid_kink_stations (const FluidMomentTerms &t, const std::vector< double > &x, const FluidClosure &cl)
 Every station whose population sits ON the saturation kink n_i = c_i of the first-order rate factor, in increasing order, empty when none does.
std::vector< double > fluid_nudge_off_kink (const FluidMomentTerms &t, const std::vector< double > &x, const std::vector< std::size_t > &kink, double rel)
 A copy of x with every station in kink moved to c_i*(1 + rel), i.e.
Matrix< double > fluid_moment_lyapunov (const FluidMomentTerms &t, const Matrix< double > &A, const std::vector< double > &r, const Matrix< double > *clampT=nullptr)
 local_lyapunov of solver_fluid_moments.m: the covariance on the coordinates that carry a real population, scattered back to full size.
std::vector< double > fluid_refine_meanfield (const FluidMomentTerms &t, const std::vector< double > &x, const FluidClosure &cl, const Matrix< double > &Sigma, FluidRefineInfo &info, double epsrel=1e-4)
 Port of fluid_refine_meanfield.m: the O(1/N) refined mean field correction of Gast (POMACS 2017).
template<class T>
FluidSolution solver_fluid_moments (const qn::NetworkStruct< T > &sn, const FluidOptions &opt)
 Port of solver_fluid_moments.m: the second-order fluid analysis backing minnormal and refined.
double fluid_mvn_rectangle (const std::vector< double > &m, const Matrix< double > &C, const std::vector< double > &a, const std::vector< double > &b, std::size_t npoints=FLUID_MVN_POINTS)
 P(a <= Y <= b) for Y ~ Normal(m, C).
void fluid_interpcols (const std::vector< double > &tg, const Matrix< double > &B, double tt, std::vector< double > &out)
 Port of fluid_interpcols.m: clamped piecewise-linear interpolation of the columns of B at a scalar time, into out.
template<class T>
FluidLayout fluid_layout (const qn::NetworkStruct< T > &sn)
 Port of the layout half of solver_fluid_odes.m.
template<class T>
FluidOdeSystem fluid_ode_system (const qn::NetworkStruct< T > &sn)
 Build the drift of sn: the port of ode_jumps_new and ode_rate_base fused into one pass.
Matrix< double > fluid_jump_matrix (const FluidOdeSystem &sys)
 The reference's dense jump matrix D, (nstates x nevents), rebuilt from the two-index event form this port stores instead.
void fluid_rates_closing_factors (const FluidOdeSystem &sys, const double *x, std::vector< double > &g)
 Port of ode_rates_closing_factors: the state-dependent factor g(x), in place.
void fluid_rates_closing (const FluidOdeSystem &sys, const double *x, std::vector< double > &g)
 The reference's ode_rates_closing name, kept for the first-order callers.
std::function< void(double, const double *, double *)> fluid_drift (const FluidOdeSystem &sys)
 The drift dx/dt, ready to hand to the integrator.
template<class T>
FluidStateDepSystem fluid_statedep_system (const qn::NetworkStruct< T > &sn, StateDepKind kind, double alpha=20.0, double pstar=20.0)
 Assemble what the state-dependent drifts need from sn.
std::function< void(double, const double *, double *)> fluid_drift_statedep (const FluidStateDepSystem &s)
 The drift dx/dt for the state-dependent family.
template<class T>
FluidPassage fluid_passage_time (const qn::NetworkStruct< T > &sn, const std::vector< double > &x_steady, std::size_t ist, std::size_t cls, double tol=1e-4, std::size_t points=201, const FluidClosure &closure=FluidClosure())
 Response-time CDF at station ist for class cls, both 1-based.
template<class T>
FluidPassage fluid_tran_passage_time (const qn::NetworkStruct< T > &sn, std::size_t ist, std::size_t cls, double tol=1e-4, std::size_t points=201)
 Port of @@SolverFLD/getTranCdfPassT: the same passage-time distribution started from the model's INITIAL state rather than from its steady state.
bool fluid_is_time_varying_limit (const std::string &m)
 The three single-station limits that report a TRAJECTORY rather than a stationary point, and so need a finite horizon; ggisgi and tga are stationary and are not among them.
std::string fluid_qsys_horizon_supports (const std::string &method, const FluidOptions &opt)
 The horizon rule the time-varying limits impose, as a public predicate a REPORT can ask: empty when method may be asked for with these options.
template<class T>
FluidSolution solver_fluid_qsys (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, std::vector< FluidTranPoint > *traj=nullptr)
 Solve a single-station model with one of the closed-form fluid limits.
std::vector< std::string > fluid_list_valid_methods ()
 Port of SolverFLD.listValidMethods.
void fluid_check_method (const std::string &method)
 Port of runAnalyzerChecks' method gate: an unlisted method is refused.
template<class T>
FluidSolution solver_fluid_run_analyzer (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, qn::NetworkStruct< T > *sn_out=nullptr, qn::NetworkStruct< T > *refreshed_out=nullptr, solvers::CacheMetrics< T > *cache_out=nullptr)
 Port of @@SolverFLD/runAnalyzer.m: resolve the method, route to the function the reference routes to, correct once.
template<class T>
std::vector< FluidTranPointsolver_fluid_run_transient (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, std::size_t points=101)
 -a tran / @@SolverFLD/getTranAvg with the method HONOURED, which is the one place the reference does not force closing.
template<class T>
std::vector< std::vector< FluidPassage > > solver_fluid_cdf_respt (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, std::size_t points=201)
 Port of @@SolverFLD/getCdfRespT: the response-time law of every (station, class) pair, read off the marked-fluid trajectory started from the steady state.
template<class T>
std::string solver_fluid_export_odes (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, const std::string &notation="scalar", const std::string &model_name="model")
 Port of @@SolverFLD/exportODEs.m at the runner's own method resolution, so the exported system is the one solver_fluid_run_analyzer would integrate.
double fluid_immediate_transition_tol ()
 The reference's two thresholds, which do NOT agree and are not meant to.
double fluid_immediate_state_tol ()
template<class T, class Opt>
bool fluid_hide_immediate (const qn::NetworkStruct< T > &sn, const Opt &opt)
 Stochastic complementation of the INSTANTANEOUS coordinates of a fluid drift, the twin of ode_eliminate_immediate.m.
FluidImmediateResult fluid_eliminate_immediate (const FluidOdeSystem &sys, double imm_tol=fluid_immediate_transition_tol())
template<class T>
FluidImmediateResult fluid_eliminate_immediate (const qn::NetworkStruct< T > &sn, const FluidOdeSystem &sys, double imm_tol=fluid_immediate_transition_tol())
 The same, at the reference's own signature, which carries sn.
template<class T>
FluidImmediateMatrix< T > fluid_eliminate_immediate_matrix (const Matrix< T > &W, double imm_tol=fluid_immediate_state_tol())
 Port of eliminate_immediate_matrix.m: the same elimination on a generator that is already assembled.
OdeSolution< double > fluid_ode_solve_stiff (const std::function< void(double, const double *, double *)> &f, double t0, double t1, const std::vector< double > &y0, const FluidStiffOptions &opt=FluidStiffOptions())
 Port of ode_solve_stiff.m.
LsodaOptions fluid_lsoda (const LsodaOptions &lopt)
 The step budget LSODA gets on a fluid leg before the stiff arm takes over.
std::vector< double > fluid_integrate_leg (const std::function< void(double, const double *, double *)> &f, double t0, double t1, const std::vector< double > &y0, const LsodaOptions &lopt)
 One integration leg, with the reference's retry on a failed solve.
LsodaSolution fluid_integrate_grid (const std::function< void(double, const double *, double *)> &f, const std::vector< double > &y0, const std::vector< double > &grid, const LsodaOptions &lopt)
 The same retry over a whole output grid, for the callers that ask LSODA for a trajectory rather than an endpoint.
template<class T>
FluidSymSystem fluid_symodes (const qn::NetworkStruct< T > &sn, const std::string &method_in, double pstar, const std::vector< double > &init_sol)
 Build the symbolic system of sn under opt.method.
FluidSymbolicDrift fluid_symbolic_drift (const FluidSymSystem &sys)
 Port of @@SolverFLD/getSymbolicDrift: the right-hand side of the mean-field ODE system as expression strings, one per state variable.
FluidSymbolicJacobian fluid_symbolic_jacobian (const FluidSymSystem &sys)
 Port of @@SolverFLD/getJacobian: d f_i / d x_j of the mean-field drift, as expression strings.
template<class T>
std::vector< std::vector< std::size_t > > tbi_partition (const qn::NetworkStruct< T > &sn, std::size_t cellsize=5)
 Port of tbi_partition.m: stations grouped by routing coupling.
std::vector< double > tbi_advance (const FluidOdeSystem &sys, const std::vector< std::vector< std::size_t > > &cells, const std::vector< double > &y0, double t0, double t1, const TbiOptions &topt, const LsodaOptions &lopt)
 Advance the state over [t0, t1] by time-based iteration.
template<class T>
void fluid_closing_metrics (const qn::NetworkStruct< T > &sn, const FluidOdeSystem &sys, const std::string &m, const std::vector< double > &xs, Matrix< double > &Q, Matrix< double > &U, Matrix< double > &R, Matrix< double > &T_)
 Read Q/U/R/T off ONE fluid state, for the closing family.
template<class T>
FluidSolution solver_fluid (const qn::NetworkStruct< T > &sn_in, const FluidOptions &opt, qn::NetworkStruct< T > *sn_out=nullptr)
 Port of solver_fluid_analyzer.m: dispatch on the method, refit the non-exponential FCFS stations the reference refits, then apply the utilization and response-time correction it applies to whatever the branch returned.
template<class T>
std::vector< std::pair< std::size_t, std::size_t > > fluid_detect_nhpp (const qn::NetworkStruct< T > &sn)
 Port of local_detect_nhpp in @@SolverFLD/getTranAvg.m: the (station, class) pairs whose SOURCE carries a rate schedule, 1-based.
template<class T>
std::vector< FluidTranPointsolver_fluid_transient (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, double t_end, std::size_t points=101, const std::vector< double > &out_grid=std::vector< double >())
 Port of @@SolverFLD/getTranAvg: the metrics along the trajectory, not just at the fixed point.
template<class T>
double fluid_default_horizon (const qn::NetworkStruct< T > &sn, const FluidOptions &opt)
 The horizon a transient runs to when the caller gives none.
template<class T>
std::vector< FluidTranPointsolver_fluid_tran_avg (const qn::NetworkStruct< T > &sn, const FluidOptions &opt, std::size_t points=101)
 getTranAvg on the first-order closing drift, over that horizon.
template<class T>
Matrix< double > fluid_jacobian (const qn::NetworkStruct< T > &sn, const std::vector< double > &x)
 The Jacobian of the fluid drift at a state, by central differences.
template<class T>
double fluid_prob_aggr_gaussian (const qn::NetworkStruct< T > &sn, const FluidSolution &sol, std::size_t i, const std::vector< double > &nir, double *logp_out=nullptr)
 The joint probability of the per-class populations at station i (0-based) under the linear noise approximation solved by the moment closure, the local_gaussian_cell of the reference @@SolverFLD/getProbAggr.
template<class T>
double fluid_prob_aggr (const qn::NetworkStruct< T > &sn, const FluidSolution &sol, std::size_t ist, double *logp_out=nullptr)
 Port of @@SolverFLD/getProbAggr: the probability that station ist holds the marginal population of the model's default state.

Variables

constexpr double kFluidConservationTol = 0.1
 Relative population drift that counts as having left the model.
const std::size_t FLUID_MVN_POINTS = 4096
 Lattice points per antithetic pair.

Enumeration Type Documentation

◆ KpEventKind

enum class line::fluid::KpEventKind
strong

The five event families of Ko-Pender (3.1)-(3.2).

Enumerator
ArrivalPhase 

A0: arrival-MAP phase change without an arrival.

Arrival 

A1: phase change WITH an arrival, into a service phase.

ServicePhase 

S: service phase change inside a station.

Departure 

D: completion leaving the network.

Routed 

R: completion routed onward.

Definition at line 98 of file fluid_kp.h.

◆ StateDepKind

enum class line::fluid::StateDepKind
strong

Which smoothing the drift applies at a saturated station.

Enumerator
StateDep 
SoftMin 
PNorm 

Definition at line 65 of file fluid_odes_statedep.h.

Function Documentation

◆ aoi_cdf()

double line::fluid::aoi_cdf ( const AoiMe & me,
double t )
inline

getCdfAoI: F(t) = 1 - S(t) with S the survival function of the age law.

(g, A, h) IS A DENSITY TRIPLE, not a survival one: finish_me normalizes g by -g A^-1 h so that the density f(t) = g exp(A t) h integrates to 1 and the mean is g A^-2 h. The survival function of such a law is S(t) = -g exp(A t) A^-1 h, so F(t) = 1 + g exp(A t) A^-1 h, which is 0 at t = 0 (g A^-1 h = -1) and rises to 1. Subtracting the DENSITY instead – the form all four codebases carried until 2026-07-31 – gives a curve that falls before it rises and is not a distribution function at all.

Definition at line 677 of file fluid_aoi.h.

References aoi_cdf(), and line::expm().

Referenced by aoi_cdf().

◆ aoi_extract_params()

template<class T>
AoiParams line::fluid::aoi_extract_params ( const qn::NetworkStruct< T > & sn,
const AoiTopology & top,
double preempt_override )

◆ aoi_is_aoi()

template<class T>
AoiTopology line::fluid::aoi_is_aoi ( const qn::NetworkStruct< T > & sn)

Port of aoi_is_aoi.m.

Returns the reason rather than throwing, because the reference uses this as a DISPATCH test inside the mfq method: a model that fails it is not an error, it is a model for the ordinary single-queue fluid branch.

Definition at line 102 of file fluid_aoi.h.

References aoi_is_aoi(), line::fluid::AoiTopology::capacity, line::fluid::AoiTopology::cls, line::fluid::AoiTopology::error, line::lang::FCFS, line::lang::LCFS, line::lang::LCFSPR, line::qn::NodeDef::nodetype, line::fluid::AoiTopology::ok, line::fluid::AoiTopology::queue, line::fluid::AoiTopology::sched, and line::fluid::AoiTopology::source.

Referenced by aoi_is_aoi().

◆ aoi_solve_bufferless()

AoiSolution line::fluid::aoi_solve_bufferless ( const std::vector< double > & tau,
const Matrix< double > & Tm,
const std::vector< double > & sigma,
const Matrix< double > & Sm,
double p )
inline

Port of solveBufferless.m: the AoI and PAoI laws of a PH/PH/1/1 system in which an arrival meeting a busy server preempts it with probability p.

Definition at line 413 of file fluid_aoi.h.

References line::fluid::AoiSolution::aoi, aoi_solve_bufferless(), line::Matrix< T >::cols(), line::eye(), line::InputError::InputError(), line::mam::kron(), line::fluid::AoiSolution::paoi, line::fluid::AoiSolution::preemption, and line::fluid::AoiSolution::system_type.

Referenced by aoi_solve_bufferless(), and fluid_aoi().

◆ aoi_solve_singlebuffer()

AoiSolution line::fluid::aoi_solve_singlebuffer ( double lambda,
const std::vector< double > & sigma,
const Matrix< double > & Sm,
double r )
inline

Port of solveSingleBuffer.m: the AoI and PAoI laws of an M/PH/1/2 system in which a waiting update is replaced by a fresher arrival with probability r.

Two fluid queues are solved in sequence. The FIRST gives the waiting-time law of an update that finds the server busy, and needs the SCHUR splitter rather than the Householder one: its drift has two negative states and their invariant subspace is not known a priori. Lemma 1 of the reference then turns that law into a PH pair (beta, B), which drives the SECOND queue – the age process proper – where the split is again explicit.

Definition at line 512 of file fluid_aoi.h.

References line::fluid::AoiSolution::aoi, aoi_solve_singlebuffer(), line::Matrix< T >::cols(), line::eye(), line::InputError::InputError(), line::mam::kron(), line::fluid::AoiSolution::paoi, line::fluid::AoiSolution::preemption, line::schur_decomposition(), line::schur_reorder(), line::solve(), line::fluid::AoiSolution::system_type, line::RealSchur::T, and line::RealSchur::Z.

Referenced by aoi_solve_singlebuffer(), and fluid_aoi().

◆ closure_normcdf()

double line::fluid::closure_normcdf ( double z)
inline

The standard normal cdf, without a statistics library.

Definition at line 61 of file fluid_closures.h.

References closure_normcdf().

Referenced by closure_normcdf(), fluid_gps_share(), and fluid_min_closure().

◆ closure_normpdf()

double line::fluid::closure_normpdf ( double z)
inline

The standard normal pdf.

Definition at line 64 of file fluid_closures.h.

References closure_normpdf().

Referenced by closure_normpdf(), fluid_capacity_closure(), fluid_gps_share(), and fluid_min_closure().

◆ fluid_aoi()

◆ fluid_blend_closure()

FluidClosure line::fluid::fluid_blend_closure ( const FluidClosure & a,
const FluidClosure & b,
double step )
inline

a + step*(b - a) for a closure, entry by entry.

A 0x0 covariance block is read as the zero matrix and stays 0x0 when both sides are. The matrix half of the damped variance step; the twin of the scalar sigma2 blend, so the two stay consistent.

Definition at line 130 of file fluid_moments.h.

References line::Matrix< T >::cols(), line::fluid::FluidClosure::cov, fluid_blend_closure(), line::Matrix< T >::rows(), and line::fluid::FluidClosure::sigma2.

Referenced by fluid_blend_closure(), and solver_fluid_moments().

◆ fluid_capacity_closure()

ClosureValue line::fluid::fluid_capacity_closure ( double n,
double c,
double s2,
const std::vector< double > & lldrow,
bool is_inf )
inline

Port of fluid_capacity_closure.m: E[psi(X)] and its derivative, where psi(n) = min(n,c)*alpha(n) at a queueing station and n*alpha(n) at an infinite server.

THE LOAD-DEPENDENT INTEGRATION IS EXACT AND NOT A QUADRATURE, which matters beyond accuracy: Gauss-Hermite on a fixed node set does not smooth the kinks of a piecewise-linear integrand, it RELOCATES them, and the resulting E[psi] is itself piecewise linear in n. Its second derivative is then zero almost everywhere and fluid_refine_meanfield silently returns a null correction. The segment-wise closed form below is what avoids that.

The zero floor on the no-load-dependence branch is the reference's minimal repair for the normal marginal putting mass below zero, where min(X,c) = X < 0: once n is small against the standard deviation E[min(X,c)] itself goes negative, which is a negative service rate and mass destroyed by the integrator's non-negativity clamp.

Definition at line 267 of file fluid_closures.h.

References closure_normpdf(), line::fluid::ClosureValue::d2h, line::fluid::ClosureValue::dh, fluid_capacity_closure(), fluid_min_closure(), and line::fluid::ClosureValue::h.

Referenced by fluid_capacity_closure(), fluid_closing_metrics(), fluid_drift_jacobian(), and fluid_rates_closing_factors().

◆ fluid_chain_partition()

template<typename T>
std::vector< std::vector< std::size_t > > line::fluid::fluid_chain_partition ( const qn::NetworkStruct< T > & sn,
std::size_t K )
inline

The classes of each chain, as 0-based column indices.

sn.inchain holds them 1-based, one vector per chain. A struct declaring no chains degrades to one chain per class, which is the safe reading rather than a guess: with no chain map there is no class switching to merge classes, so each class IS its own conserved unit.

Definition at line 80 of file fluid_conservation_guard.h.

References fluid_chain_partition().

Referenced by fluid_chain_partition(), and fluid_conservation_violation().

◆ fluid_check_method()

void line::fluid::fluid_check_method ( const std::string & method)
inline

Port of runAnalyzerChecks' method gate: an unlisted method is refused.

Definition at line 101 of file fluid_runner.h.

References fluid_check_method(), fluid_list_valid_methods(), and line::UnsupportedError::UnsupportedError().

Referenced by fluid_check_method(), and solver_fluid_run_analyzer().

◆ fluid_closing_metrics()

template<class T>
void line::fluid::fluid_closing_metrics ( const qn::NetworkStruct< T > & sn,
const FluidOdeSystem & sys,
const std::string & m,
const std::vector< double > & xs,
Matrix< double > & Q,
Matrix< double > & U,
Matrix< double > & R,
Matrix< double > & T_ )

Read Q/U/R/T off ONE fluid state, for the closing family.

Factored out because the transient needs exactly this at every point of the trajectory, and a second copy would drift from the steady-state one. m is the resolved method name: only statedep changes the rules here, and it does so at FCFS stations (see the mean-service-time share below).

Definition at line 738 of file solver_fluid.h.

References line::mam::Map< T >::D0, line::mam::Map< T >::D1, line::lang::DPS, line::fluid::FluidLayout::enabled, line::lang::EXT, line::lang::FCFS, line::lang::GlobalConstants::FineTol, fluid_capacity_closure(), fluid_closing_metrics(), line::fluid::ClosureValue::h, line::lang::INF, line::fluid::FluidLayout::kic, line::fluid::FluidOdeSystem::layout, line::fluid::FluidOdeSystem::lld, line::mam::map_mean(), and line::fluid::FluidLayout::qidx.

Referenced by fluid_closing_metrics(), and solver_fluid_transient().

◆ fluid_conservation_violation()

template<typename T>
int line::fluid::fluid_conservation_violation ( const qn::NetworkStruct< T > & sn,
const FluidLayout & L,
const std::vector< double > & x,
double tol = kFluidConservationTol )

The closed chain whose conserved population has drifted past tol, or -1.

Parameters
snthe network struct, for the chain membership and populations
Lthe state layout, which fixes each (station,class) block
xa state vector of length L.nstates
tolrelative deviation that counts as having left the model

Definition at line 108 of file fluid_conservation_guard.h.

References fluid_chain_partition(), fluid_conservation_violation(), kFluidConservationTol, line::fluid::FluidLayout::kic, and line::fluid::FluidLayout::qidx.

Referenced by fluid_conservation_violation().

◆ fluid_coord_eliminated()

bool line::fluid::fluid_coord_eliminated ( const FluidMomentTerms & t,
std::size_t s )
inline

True when the immediate reduction folded coordinate s away, so the reduced drift holds no mass there and no event lands on it.

absorb is the projector the reduction returns: the identity on a surviving coordinate and the absorption distribution on an eliminated one, so a zero diagonal is exactly the eliminated case. It is empty when nothing was eliminated, where every coordinate survives.

Definition at line 283 of file fluid_moments.h.

References line::fluid::FluidMomentTerms::absorb, fluid_coord_eliminated(), and line::Matrix< T >::rows().

Referenced by fluid_coord_eliminated(), and fluid_dae_constraints().

◆ fluid_dae_clamp_tangent()

Matrix< double > line::fluid::fluid_dae_clamp_tangent ( const FluidDaeConstraints & con,
const std::vector< std::size_t > & active,
const FluidMomentTerms & t )
inline

Orthogonal projector onto the subspace the CLAMPING caps leave free: I - R'(RR')^-1 R over the covariance coordinates.

Empty when no active cap clamps, which is every model without a station buffer and every region model.

Definition at line 975 of file fluid_dae.h.

References line::fluid::FluidDaeConstraints::A, line::fluid::FluidMomentTerms::cov_idx, fluid_dae_clamp_tangent(), and line::fluid::FluidDaeConstraints::staged.

Referenced by fluid_dae_clamp_tangent(), and solver_fluid_dae().

◆ fluid_dae_closable()

std::vector< std::size_t > line::fluid::fluid_dae_closable ( const FluidMomentTerms & t)
inline

Stations whose variance enters the drift.

A delay or a source has no min() to close. A station that cannot fill its servers has min(n,c) = n on its whole support, so closing it is not an improvement but an error (see FLUID_MOMENT_TERMS). Those are held at zero and are not unknowns, which keeps the Newton system as small as the closure is.

Definition at line 919 of file fluid_dae.h.

References fluid_dae_closable(), line::lang::INF, line::fluid::FluidMomentTerms::is_ext, line::fluid::FluidMomentTerms::min_exact, line::fluid::FluidMomentTerms::S, line::fluid::FluidOdeSystem::sched, line::fluid::FluidMomentTerms::station_block, and line::fluid::FluidMomentTerms::sys.

Referenced by fluid_dae_closable(), solver_fluid_dae(), and solver_fluid_dae_transient().

◆ fluid_dae_conservation()

template<typename T>
FluidDaeConservation line::fluid::fluid_dae_conservation ( const qn::NetworkStruct< T > & sn,
const FluidMomentTerms & terms,
const FluidDaeStaging & stg )
inline

The conserved chains as equations.

An open chain has no conserved population and contributes nothing. The EXT coordinates are excluded because the closing representation holds unit mass there as a normalisation constant, not as a job count.

Definition at line 803 of file fluid_dae.h.

References line::fluid::FluidDaeConservation::C, line::fluid::FluidMomentTerms::class_block, fluid_dae_conservation(), line::fluid::FluidMomentTerms::is_ext, line::fluid::FluidDaeStaging::klass, line::fluid::FluidDaeConservation::N, line::fluid::FluidDaeStaging::n, and line::fluid::FluidMomentTerms::nstate.

Referenced by fluid_dae_conservation(), solver_fluid_dae(), and solver_fluid_dae_transient().

◆ fluid_dae_constraints()

◆ fluid_dae_extend()

void line::fluid::fluid_dae_extend ( FluidDaeConstraints & con,
const FluidDaeStaging & stg,
const FluidMomentTerms & t )
inline

Extend every cap to the staging coordinates that hold mass INSIDE it.

A waiting room is outside the region it feeds, which is the whole point of it – but it is not outside every OTHER limit. Where two regions overlap, an admission into the inner one is an INTERNAL move of the outer one: the job leaves a station of the outer region, waits, and re-enters a station of the same outer region, never having left it. Counting only the state coordinates would take that mass out of the outer cap for as long as it waits, and the Newton system that results is inconsistent rather than merely inexact.

Definition at line 643 of file fluid_dae.h.

References line::fluid::FluidDaeConstraints::A, line::fluid::FluidDaeStaging::adm, line::fluid::FluidDaeStaging::adm_stage, line::fluid::FluidDaeConstraints::As, line::fluid::FluidDaeConstraints::b, line::Matrix< T >::cols(), line::fluid::FluidMomentTerms::D, fluid_dae_extend(), line::fluid::FluidDaeConstraints::member, line::fluid::FluidDaeStaging::n, line::fluid::FluidMomentTerms::nstate, and line::fluid::FluidDaeStaging::region.

Referenced by fluid_dae_extend(), solver_fluid_dae(), and solver_fluid_dae_transient().

◆ fluid_dae_gates()

◆ fluid_dae_hold_multipliers()

std::vector< double > line::fluid::fluid_dae_hold_multipliers ( const FluidMomentTerms & terms,
const FluidDaeGates & gates,
const FluidDaeStaging & stg,
const FluidDaeConstraints & con,
const std::vector< std::size_t > & active,
const std::vector< double > & x,
const std::vector< double > & sg,
const FluidClosure & cl,
const std::vector< double > & m0,
bool & ok )
inline

The multipliers that hold the active caps at this state, by small Newton.

Each active cap contributes one equation, d/dt(A x + As s) = 0, and one unknown – a fraction for a cap that holds or loses, an admitted flow for one that stages – so the system is square and small. This is what makes an event RESTART consistent: RODAS needs the algebraic unknowns to satisfy their equations at the initial point of an index-1 DAE. It is also the FEASIBILITY test at an activation: a fraction above one means the cap would have to admit more than arrives, so it is not binding after all.

Definition at line 1669 of file fluid_dae.h.

References line::fluid::FluidDaeConstraints::A, line::fluid::FluidDaeConstraints::As, line::fluid::FluidDaeGates::Dn, line::fluid::FluidDaeGates::DnExt, line::fluid::FluidDaeGates::Dp, line::fluid::FluidDaeLegs::ds, fluid_dae_hold_multipliers(), fluid_dae_legs(), fluid_moment_rates(), line::lstsq(), line::fluid::FluidDaeStaging::n, line::fluid::FluidMomentTerms::nstate, line::fluid::FluidDaeLegs::rin, and line::fluid::FluidDaeLegs::rup.

Referenced by fluid_dae_hold_multipliers(), and fluid_dae_integrate_hybrid().

◆ fluid_dae_integrate()

std::vector< std::vector< double > > line::fluid::fluid_dae_integrate ( const FluidMomentTerms & terms,
const FluidDaeConservation & cons,
const FluidClosure & closure,
const std::vector< double > & x0,
const std::vector< double > & grid,
double tol,
bool withcov = false,
const std::vector< std::size_t > & closable = std::vector<std::size_t>() )
inline

Integrate the closure as an index-1 DAE, with RODAS, and report the state at every point of grid.

One differential equation per closed chain is redundant – the rows of D sum to zero there – so one is REPLACED by the constraint rather than added to it. The row dropped is the one carrying the most mass at t=0, which keeps the algebraic equation away from a coordinate that is identically zero. Chains partition the classes, so no index is claimed twice.

grid must be increasing and end at the horizon; the trajectory comes from RODAS's own dense output (detail::fluid_dae_solout), so the grid costs no extra step. The LAST entry is also the return value of the integration proper, which is what a steady-state caller asking for a single point wants.

Returns
one state vector per grid point, in grid order

Definition at line 1561 of file fluid_dae.h.

References line::fluid::FluidDaeConservation::C, line::fluid::FluidMomentTerms::cov_idx, fluid_dae_integrate(), line::InputError::InputError(), line::fluid::FluidMomentTerms::nstate, line::NumericError::NumericError(), and line::Matrix< T >::rows().

Referenced by fluid_dae_integrate(), solver_fluid_dae(), and solver_fluid_dae_transient().

◆ fluid_dae_integrate_hybrid()

std::vector< std::vector< double > > line::fluid::fluid_dae_integrate_hybrid ( const FluidMomentTerms & terms,
const FluidDaeConservation & cons,
const FluidDaeConstraints & con,
const FluidDaeGates & gates,
const FluidDaeStaging & stg,
const FluidClosure & closure,
const std::vector< double > & x0In,
const std::vector< double > & grid,
double tol,
std::vector< FluidDaeSwitch > * switches = nullptr )
inline

◆ fluid_dae_legs()

FluidDaeLegs line::fluid::fluid_dae_legs ( const FluidMomentTerms & t,
const FluidDaeGates & gates,
const FluidDaeStaging & stg,
const FluidDaeConstraints & con,
const std::vector< std::size_t > & active,
const std::vector< double > & sg,
const std::vector< double > & r,
const std::vector< double > & mult,
bool staged_flow )
inline

Shared by the steady-state residual and the transient right-hand side so that the two solve the SAME model and not two spellings of it.

What differs is only what a STAGED cap's multiplier means: a drain RATE for the steady state, where the room mass is pinned by the cap; the admitted FLOW for the transient, because at the instant a region fills its room is EMPTY and a rate times zero mass cannot hold the cap. The two rules agree at a fixed point, where the room mass is proportional to its inflow.

A held or lost cap composes as a PRODUCT of fractions either way, which is what independent blocking gives and what keeps every active cap present in the Jacobian. Several staged caps gating one room compose HARMONICALLY, because the waits a job serves in turn add.

Definition at line 698 of file fluid_dae.h.

References line::fluid::FluidDaeStaging::adm, line::fluid::FluidDaeStaging::adm_stage, line::fluid::FluidDaeLegs::drain, line::fluid::FluidDaeLegs::ds, fluid_dae_legs(), line::fluid::FluidDaeStaging::gated_by, line::fluid::FluidDaeGates::held, line::fluid::FluidDaeGates::loss, line::fluid::FluidDaeStaging::n, line::fluid::FluidDaeLegs::rin, line::fluid::FluidDaeLegs::rup, and line::fluid::FluidDaeConstraints::staged.

Referenced by fluid_dae_hold_multipliers(), fluid_dae_legs(), fluid_dae_residual(), and solver_fluid_dae().

◆ fluid_dae_metrics()

void line::fluid::fluid_dae_metrics ( const FluidMomentTerms & terms,
const std::vector< double > & x,
const FluidClosure & cl,
Matrix< double > & QN,
Matrix< double > & UN,
Matrix< double > & RN,
Matrix< double > & TN,
const std::vector< double > * rates = nullptr )
inline

The metrics of one state, read exactly as the steady-state table reads them.

Shared by the fixed point and by every point of a trajectory so that the two cannot drift: solver_fluid_transient reuses fluid_closing_metrics for the same reason, and the last point of a long enough run has to reproduce the table or one of them is reading the drift differently.

Definition at line 1995 of file fluid_dae.h.

References line::fluid::FluidMomentTerms::class_block, line::Matrix< T >::empty(), line::fluid::FluidMomentTerms::ev_class, line::fluid::FluidMomentTerms::ev_is_departure, line::fluid::FluidMomentTerms::ev_station, fluid_dae_metrics(), fluid_moment_factors(), fluid_moment_rates(), line::lang::INF, line::fluid::FluidMomentTerms::S, line::fluid::FluidOdeSystem::sched, line::fluid::FluidMomentTerms::station_block, line::fluid::FluidMomentTerms::sys, and line::lang::GlobalConstants::Zero.

Referenced by fluid_dae_metrics(), solver_fluid_dae(), and solver_fluid_dae_transient().

◆ fluid_dae_newton()

FluidDaeNewtonInfo line::fluid::fluid_dae_newton ( const FluidDaeSystem & sysd,
std::vector< double > & u,
double tol,
std::size_t maxit )
inline

Damped PROJECTED Newton with a finite-difference Jacobian and an Armijo backtrack on the residual norm.

The step is solved in least squares: the drift block is rank deficient by exactly the number of conserved chains, and the constraint rows restore that rank, so the stacked system is consistent and overdetermined rather than square.

WHY PROJECTED, AND NOT MERELY CLAMPED. The unknowns past NFREE are variances, which may not go negative, and the residual reads them through max(0,.). Clamping inside the residual alone is a trap: once an iterate goes negative the residual stops depending on it, so the finite-difference column is exactly zero, there is no derivative to climb back on, and the unknown is pinned at the boundary for good. Projecting the ITERATE keeps every evaluation inside the box, where the forward difference across max(0,.) is live even at zero.

Definition at line 1158 of file fluid_dae.h.

References line::fluid::FluidDaeNewtonInfo::converged, fluid_dae_newton(), fluid_dae_project(), fluid_dae_residual(), line::fluid::FluidDaeNewtonInfo::iters, line::lstsq(), line::fluid::FluidDaeSystem::nstate, and line::fluid::FluidDaeNewtonInfo::residual.

Referenced by fluid_dae_newton(), and solver_fluid_dae().

◆ fluid_dae_options()

FluidDaeOptions line::fluid::fluid_dae_options ( const FluidOptions & opt,
const FluidDaeOptions & dopt )
inline

The controls the DAE route actually reads: the struct a caller pinned, with whatever options.config set on top of it.

WHY THIS EXISTS. dae_maxstate and dae_maxcov are options.config entries in MATLAB, the JAR and native Python – they are what a user reaches for to raise a refusal – and they arrive here on FluidOptions, while the route reads FluidDaeOptions. Without this step the fields were unreachable from every ordinary entry point (solver_fluid_run_analyzer hands the defaults), so the two limits were fixed at 100 and 25 whatever the options said. Zero on FluidOptions means NOT SET, so an explicit struct still wins where the options are silent.

THE NEWTON CAP IS NOT A KNOB BUT A DIVERGENCE. max(50, iter_max) is what all three references solve with, and iter_max defaults to 200, so leaving it at 50 here was not a missing option: it was a different solver, one that refuses a fixed point the reference reaches on its 60th step.

Definition at line 902 of file fluid_dae.h.

References fluid_dae_options(), line::fluid::FluidDaeOptions::maxcov, line::fluid::FluidDaeOptions::maxstate, and line::fluid::FluidDaeOptions::newton_max.

Referenced by fluid_dae_options(), solver_fluid_dae(), and solver_fluid_dae_transient().

◆ fluid_dae_project()

void line::fluid::fluid_dae_project ( std::vector< double > & u,
std::size_t nfree )
inline

Onto the feasible box: the state is free, the variances are not.

Definition at line 1130 of file fluid_dae.h.

References fluid_dae_project().

Referenced by fluid_dae_newton(), and fluid_dae_project().

◆ fluid_dae_reach()

double line::fluid::fluid_dae_reach ( const std::vector< double > & row,
const std::vector< std::size_t > & coord_class,
const std::vector< double > & njobs,
std::size_t K )
inline

The largest row x the population can produce, ignoring the coupling.

An upper bound is what is wanted: too loose only costs a constraint that stays inactive, while too tight would discard a cap that does bind. THE BOUND IS PER CLASS, and it has to be – the heaviest weight times the whole population never prunes a PER-CLASS cap set to its own class population, exactly the row the struct refresh derives at every station of every closed model.

Definition at line 136 of file fluid_dae.h.

References fluid_dae_reach().

Referenced by fluid_dae_constraints(), and fluid_dae_reach().

◆ fluid_dae_residual()

bool line::fluid::fluid_dae_residual ( const FluidDaeSystem & sysd,
const std::vector< double > & u,
std::vector< double > & G,
std::vector< double > * rates_out,
bool rethrow = false,
std::vector< double > * fire_out = nullptr )
inline

The coupled algebraic system, stacked: drift, conservation, closure consistency.

Returns false when the closure cannot be evaluated at this iterate – the Lyapunov solve throws on a non-hyperbolic fixed point – so that the line search can back off rather than the whole solve failing.

THE UNKNOWNS ARE [x; staging; sigma2; mult], with MULT one multiplier per ACTIVE cap: a FRACTION of the admissions allowed for a cap that holds the job upstream or loses it, the RATE its waiting room drains at for one that stages it.

Definition at line 1041 of file fluid_dae.h.

References line::fluid::FluidDaeConstraints::A, line::fluid::FluidDaeSystem::active, line::fluid::FluidDaeConstraints::As, line::fluid::FluidDaeConstraints::b, line::fluid::FluidDaeConservation::C, line::fluid::FluidDaeSystem::cidx, line::fluid::FluidDaeSystem::clampT, line::fluid::FluidDaeSystem::con, line::fluid::FluidDaeSystem::cons, line::fluid::FluidClosure::cov, line::fluid::FluidMomentTerms::D, line::fluid::FluidDaeGates::Dn, line::fluid::FluidDaeGates::DnExt, line::fluid::FluidDaeGates::Dp, line::fluid::FluidDaeLegs::ds, fluid_dae_legs(), fluid_dae_residual(), fluid_dae_sigma_from(), fluid_drift_jacobian(), fluid_moment_lyapunov(), fluid_moment_rates(), line::fluid::FluidDaeSystem::gates, line::fluid::FluidDaeGates::has, line::fluid::FluidDaeConservation::N, line::fluid::FluidDaeSystem::nstaging(), line::fluid::FluidDaeSystem::nstate, line::fluid::FluidDaeLegs::rin, line::Matrix< T >::rows(), line::fluid::FluidDaeLegs::rup, line::fluid::FluidClosure::sigma2, line::fluid::FluidMomentTerms::station_block, line::fluid::FluidDaeSystem::stg, and line::fluid::FluidDaeSystem::terms.

Referenced by fluid_dae_newton(), and fluid_dae_residual().

◆ fluid_dae_sigma_from()

std::vector< double > line::fluid::fluid_dae_sigma_from ( const Matrix< double > & Sigma,
const FluidMomentTerms & t,
const std::vector< std::size_t > & cidx )
inline

Project a state-level covariance onto the per-station variances the drift reads.

Definition at line 932 of file fluid_dae.h.

References fluid_dae_sigma_from(), line::Matrix< T >::size(), and line::fluid::FluidMomentTerms::station_block.

Referenced by fluid_dae_residual(), fluid_dae_sigma_from(), and solver_fluid_dae_transient().

◆ fluid_dae_staging()

◆ fluid_default_horizon()

template<class T>
double line::fluid::fluid_default_horizon ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt )

The horizon a transient runs to when the caller gives none.

FACTORED OUT OF solver_fluid_tran_avg because dae has a transient of its own (fluid_dae.h) and must reach it by the SAME rule: a horizon rule that two methods each computed for themselves is a horizon rule that can differ between them, and then two trajectories of one model are read at different times for no stated reason.

options.timespan defaults to [0, Inf] and the reference does NOT integrate to infinity for it. The rule lives in @NetworkSolver/getTranAvg.m, not in the fluid analyzer: an unspecified end time becomes 30/minrate with minrate = min(sn.rates(isfinite(sn.rates))), i.e. thirty mean events of the SLOWEST RATE IN sn.rates – arrival rates included, since the source's rate sits in that same table. That is not the analyzer's own horizon-extension rule (ten mean events of the slowest transition per pass), which governs how far solver_fluid integrates while hunting the fixed point and is invisible to the getter. A caller that sets timespan_end is integrated over exactly that instead.

MATLAB drops NaN (its disabled marker) through isfinite; the port carries a separate disabled flag and stores zero, so the zero is skipped by the flag.

Definition at line 2257 of file solver_fluid.h.

References fluid_default_horizon().

Referenced by fluid_default_horizon(), solver_fluid_run_transient(), and solver_fluid_tran_avg().

◆ fluid_detect_nhpp()

template<class T>
std::vector< std::pair< std::size_t, std::size_t > > line::fluid::fluid_detect_nhpp ( const qn::NetworkStruct< T > & sn)

Port of local_detect_nhpp in @@SolverFLD/getTranAvg.m: the (station, class) pairs whose SOURCE carries a rate schedule, 1-based.

A CALLER OPTS IN, and that is the reference's split rather than a convenience. getTranAvg calls this and puts the result on the options; a steady-state request does not, and is answered at the time-averaged nominal. Both are legitimate readings of the same model, so the decision belongs to the entry point and not to the drift builder.

The reference tests ismethod(proc,'getRateSchedule'), which NHPP, MAPt and PHt all answer; here that is Distrib::has_schedule(), the same three.

Definition at line 2140 of file solver_fluid.h.

References line::lang::EXT, and fluid_detect_nhpp().

Referenced by fluid_detect_nhpp(), and solver_fluid_transient().

◆ fluid_diffusion()

template<class T>
DiffusionResult line::fluid::fluid_diffusion ( const qn::NetworkStruct< T > & sn,
const DiffusionOptions & opt )

Run the diffusion approximation of sn.

Refuses by name every model shape the reference refuses: open classes, a Source, a discipline outside {PS, FCFS, INF, SIRO}, and any finite multiserver station.

Definition at line 74 of file fluid_diffusion.h.

References line::mc::dtmc_stochcomp(), line::lang::EXT, line::lang::FCFS, fluid_diffusion(), line::lang::INF, line::lang::PS, line::fluid::DiffusionResult::QN, line::lang::SIRO, and line::UnsupportedError::UnsupportedError().

Referenced by fluid_diffusion().

◆ fluid_drift()

std::function< void(double, const double *, double *)> line::fluid::fluid_drift ( const FluidOdeSystem & sys)
inline

◆ fluid_drift_jacobian()

Matrix< double > line::fluid::fluid_drift_jacobian ( const FluidMomentTerms & t,
const std::vector< double > & x,
const FluidClosure & cl )
inline

Port of fluid_drift_jacobian.m: the analytic Jacobian of the fluid drift.

IT MUST MIRROR ode_rates_closing_factors BRANCH BY BRANCH. The Jacobian drives the Lyapunov equation and the 1/N refinement, so a branch that exists there and not here linearizes a drift that was never integrated – and any policy with no case there keeps g = x and so contributes the identity here. With sigma2 = 0 the derivative of the occupancy factor is the indicator of the unsaturated region, the a.e. derivative of the first-order closure; with sigma2 > 0 it is the smooth derivative the closure returns.

Definition at line 487 of file fluid_moments.h.

References line::fluid::FluidMomentTerms::class_block, line::fluid::ShareValue::cn, line::fluid::FluidClosure::cov_of(), line::fluid::ClosureValue::d2h, line::fluid::ShareValue::dcn, line::fluid::ClosureValue::dh, line::lang::DPS, line::fluid::ShareValue::ds, line::fluid::FluidLayout::enabled, line::fluid::FluidEvent::event_idx, line::fluid::FluidOdeSystem::events, line::lang::EXT, line::eye(), line::lang::FCFS, line::lang::GlobalConstants::FineTol, fluid_capacity_closure(), fluid_drift_jacobian(), fluid_gps_share(), fluid_lld_scaling(), fluid_share_closure(), line::fluid::FluidClosure::gaussian(), line::lang::GPS, line::fluid::ClosureValue::h, line::lang::INF, line::fluid::FluidLayout::kic, line::fluid::FluidOdeSystem::layout, line::fluid::FluidOdeSystem::lld, line::fluid::FluidEvent::minus, line::fluid::FluidOdeSystem::nservers, line::fluid::FluidMomentTerms::nstate, line::fluid::FluidEvent::plus, line::lang::PS, line::fluid::FluidLayout::qidx, line::fluid::FluidEvent::rate_base, line::fluid::FluidMomentTerms::S, line::fluid::ShareValue::s, line::fluid::FluidOdeSystem::sched, line::fluid::FluidClosure::sigma2_of(), line::Matrix< T >::size(), line::fluid::FluidMomentTerms::station_block, line::fluid::FluidMomentTerms::sys, line::UnsupportedError::UnsupportedError(), and line::fluid::FluidOdeSystem::weight.

Referenced by fluid_dae_residual(), fluid_drift_jacobian(), fluid_refine_meanfield(), solver_fluid_dae(), and solver_fluid_moments().

◆ fluid_drift_statedep()

◆ fluid_eliminate_immediate() [1/2]

◆ fluid_eliminate_immediate() [2/2]

template<class T>
FluidImmediateResult line::fluid::fluid_eliminate_immediate ( const qn::NetworkStruct< T > & sn,
const FluidOdeSystem & sys,
double imm_tol = fluid_immediate_transition_tol() )

The same, at the reference's own signature, which carries sn.

It is here for the arithmetic gate rather than for the struct: the fluid drift is integrated by LSODA and by the Rosenbrock method below, both of which are double by construction, so a non-double model has no business reaching either. The complement ITSELF is field arithmetic and would be exact over the rationals, which is why the gate sits on the entry point that knows what the model is made of and not on the complement.

Definition at line 436 of file fluid_stiff.h.

References fluid_eliminate_immediate(), fluid_immediate_transition_tol(), and line::UnsupportedError::UnsupportedError().

◆ fluid_eliminate_immediate_matrix()

template<class T>
FluidImmediateMatrix< T > line::fluid::fluid_eliminate_immediate_matrix ( const Matrix< T > & W,
double imm_tol = fluid_immediate_state_tol() )

Port of eliminate_immediate_matrix.m: the same elimination on a generator that is already assembled.

It detects immediate STATES directly, by the largest rate on their row, rather than immediate transitions. That is the only rule available once the routing probabilities have been folded in and parallel edges summed, and it catches a case the transition rule misses: an immediate transition taken with probability one half carries rate 5e7, which is nowhere near Immediate but is still seven orders above the rest of the model.

Definition at line 482 of file fluid_stiff.h.

References line::Matrix< T >::cols(), line::mc::ctmc_stochcomp(), line::fluid::FluidImmediateMatrix< T >::eliminated, line::fluid::FluidImmediateMatrix< T >::fallback, fluid_eliminate_immediate_matrix(), fluid_immediate_state_tol(), line::InputError::InputError(), line::Matrix< T >::rows(), line::fluid::FluidImmediateMatrix< T >::state_map, and line::fluid::FluidImmediateMatrix< T >::W.

Referenced by fluid_eliminate_immediate_matrix().

◆ fluid_expansion_weight()

ExpansionWeight line::fluid::fluid_expansion_weight ( double ratio)
inline

Port of local_expansion_weight in fluid_share_closure.m.

Every second-order term of the share closure is a term of the series for E[1/v], whose successive terms are in the ratio Var(v)/v^2, so the truncation is meaningful below 1 and the terms GROW above it. Nothing in the algebra notices: at a near-empty station the corrections come back larger than the quantity they correct, and the drift that follows is not integrable.

One on [0,1], zero from 4 up, and the C^1 smoothstep between. Both ends matter. The lower one has to be EXACTLY one on the whole convergent region, so every model already inside it is bit-identical; the upper one has to be reached with a vanishing derivative, because the drift is integrated and a kink in it is what collapses the step size. The two thresholds are the series, not a tuning: at ratio 1 successive terms stop shrinking, and at ratio 4 the standard deviation of v is twice its mean, where a non-negative v has essentially no mass near the point being expanded about.

Definition at line 405 of file fluid_closures.h.

References line::fluid::ExpansionWeight::dtau, fluid_expansion_weight(), and line::fluid::ExpansionWeight::tau.

Referenced by fluid_expansion_weight(), and fluid_share_closure().

◆ fluid_export_odes()

template<class T>
std::string line::fluid::fluid_export_odes ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
const std::string & notation = "scalar",
const std::string & model_name = "model" )

◆ fluid_gps_share()

ShareValue line::fluid::fluid_gps_share ( const std::vector< double > & xk,
const std::vector< double > & wk_in,
const std::vector< double > & vk,
bool want_jac )
inline

Port of fluid_gps_share.m: the expected capacity share of a GPS station under a normal marginal, and its Jacobian.

GPS divides the server by WEIGHT among the BACKLOGGED classes and then equally among that class's own jobs, so the share is a function of the backlog INDICATOR and not of the populations. The closure is an exact ENUMERATION of the 2^K patterns rather than an expansion: the share is piecewise constant over them, so once the pattern probabilities are given there is no truncation error left. Those probabilities come from the marginals with the continuity correction P(N_k > 1/2), multiplied as if the backlogs were independent – the one approximation here, and not an innocuous one, since a closed network correlates the station coordinates negatively through population conservation.

The shares sum to 1 - P(station empty), not to 1. That is how the idle server is represented: GPS is single-server, the indicator plays the role min(n,c) plays at a PS station, and the caller applies no separate capacity term.

Definition at line 600 of file fluid_closures.h.

References closure_normcdf(), closure_normpdf(), line::fluid::ShareValue::ds, fluid_gps_share(), line::fluid::ShareValue::s, and line::UnsupportedError::UnsupportedError().

Referenced by fluid_drift_jacobian(), fluid_gps_share(), and fluid_rates_closing_factors().

◆ fluid_hide_immediate()

template<class T, class Opt>
bool line::fluid::fluid_hide_immediate ( const qn::NetworkStruct< T > & sn,
const Opt & opt )

Stochastic complementation of the INSTANTANEOUS coordinates of a fluid drift, the twin of ode_eliminate_immediate.m.

A coordinate whose exit rate is GlobalConstants::Immediate is not a fast coordinate, it is an INSTANTANEOUS one: the rate is LINE's stand-in for infinity, written by SolverLN for the branch of an activity that takes no time (an entry called with probability y < 1 carries a second PH phase at InfRate entered with probability 1-y). Integrating it is meaningless work no integrator does well.

THE REDUCTION IS EXACT. The instantaneous coordinates F are absorbed into the timed ones S by the absorption probabilities of the embedded jump chain restricted to F, so the flow that would enter F is routed straight to where F would have sent it.

WHY THIS IS A STRUCTURAL COMPOSITION AND NOT A GENERATOR ROUND TRIP, which is what this function used to be. Every event is a single -1 at event_idx and a single +1 at plus, so a path through F composes to ONE event, -1 at the original source and +1 at the absorbing coordinate, that keeps the original source's GATING. Rebuilding the events from a reduced generator loses that identity – and with it n_departures, which this function used to report as zero because it was "no longer recoverable". It is recoverable: emap(e, o) is the expected number of times the ORIGINAL event o fires per firing of the reduced event e, so a caller maps any per-event quantity with new = emap * old and gets an exact rate accounting. That is what lets the moment-closure methods, which used to refuse the reduction outright, read their throughputs off a reduced event set.

A COMPOSED EVENT CAN BE A DEPARTURE AT TWO STATIONS AT ONCE: a job that leaves a delay, passes through a queue's immediate phase and returns has completed at both, and both throughputs must count it. emap gives it a row with weight on both original events, and the null jump it composes to (-1 and +1 on the same coordinate) correctly contributes nothing to the drift and nothing to the diffusion.

absorb projects an initial condition onto the surviving coordinates: mass parked on an eliminated one would otherwise be frozen there for the whole integration, because nothing moves it any more. Whether this model's fluid drift is built on the stochastic complement of its INSTANTANEOUS coordinates.

Every fluid route that builds its drift from the station/class/phase event set or from the linear generator asks here rather than reading the flag directly, so the answer is the same across matrix, closing, statedep, tbi, minnormal, refined and dae. The flag defaults to TRUE: a coordinate whose exit rate is GlobalConstants::Immediate is LINE's stand-in for infinity, and integrating it is meaningless work no integrator does well.

THE STOCHASTIC PETRI NET ROUTE IS THE ONE EXCEPTION, and it is not a refusal. It carries immediate firings as ALGEBRAIC unknowns of an index-1 DAE, a stronger treatment than absorbing them, and never builds the event set this reduction acts on, so the answer here is simply false.

Definition at line 242 of file fluid_stiff.h.

References fluid_hide_immediate(), and line::lang::Transition.

Referenced by fluid_hide_immediate(), and fluid_moment_terms().

◆ fluid_immediate_state_tol()

double line::fluid::fluid_immediate_state_tol ( )
inline

◆ fluid_immediate_transition_tol()

double line::fluid::fluid_immediate_transition_tol ( )
inline

The reference's two thresholds, which do NOT agree and are not meant to.

ode_eliminate_immediate knows the rates it is looking at are rateBase entries built from an Immediate distribution, so it asks for a rate within 1% of the constant itself. eliminate_immediate_matrix is handed a generator whose entries have already been multiplied by routing probabilities and summed, so it asks only for an order of magnitude below it. A transition routed with probability 0.5 is invisible to the first rule and caught by the second; both are kept as they are, because tightening the first would start eliminating transitions the reference integrates.

Definition at line 93 of file fluid_stiff.h.

References fluid_immediate_transition_tol(), and line::lang::GlobalConstants::Immediate.

Referenced by fluid_eliminate_immediate(), fluid_eliminate_immediate(), and fluid_immediate_transition_tol().

◆ fluid_initsol() [1/2]

template<class T>
std::vector< double > line::fluid::fluid_initsol ( const qn::NetworkStruct< T > & sn)

The same, for a caller that has not built the layout itself.

Definition at line 160 of file fluid_closing.h.

References fluid_initsol(), and fluid_layout().

◆ fluid_initsol() [2/2]

template<class T>
std::vector< double > line::fluid::fluid_initsol ( const qn::NetworkStruct< T > & sn,
const FluidLayout & L )

Port of solver_fluid_initsol.m: the ODE's initial condition, in the layout the drift indexes.

THIS IS THE DISCIPLINE GATE OVER detail::fluid_default_initsol, AND NOT A SECOND CONSTRUCTION OF THE SAME VECTOR. There used to be two: this one synthesized the initDefault marginal, pushed it through from_marginal, took the FIRST row and decoded it back through to_marginal, while the analyzer's own default wrote the population straight into the reference station's phase-one entry. They agreed on a one-phase model and disagreed on every other, so a multi-phase TRANSIENT was integrated from one of two different initial conditions depending on which entry point was called. The closed form is the correct one, for two reasons:

THE ROW WAS THE WRONG ROW. from_marginal enumerates every phase assignment of the jobs in service in multichoose order, whose first row is [0,...,0,n] – all of the mass in the LAST phase. The reference never enumerates: State.fromMarginalAndStarted writes init(1) = si(r) and so always starts its jobs in phase ONE, which is also what its space(end:-1:1,:) reordering exists to guarantee. Seeding an Erlang-2 station's whole population in phase two starts the drift half a service ahead of where the model says the system is.

AND IT WAS PAID FOR IN FACTORIALS. The FCFS branch of from_marginal enumerates the buffer PERMUTATIONS, so decoding the initial state of a closed station holding N jobs cost O(N!) before the first integration step.

What the decode contributes that the closed form does not is the by-name refusal above, which is checked here per station and is the reference's own error arm; it is kept, and is the reason this wrapper exists at all.

Definition at line 146 of file fluid_closing.h.

References line::fluid::FluidLayout::enabled, and fluid_initsol().

Referenced by fluid_initsol(), fluid_initsol(), and solver_fluid_closing().

◆ fluid_integrate_grid()

LsodaSolution line::fluid::fluid_integrate_grid ( const std::function< void(double, const double *, double *)> & f,
const std::vector< double > & y0,
const std::vector< double > & grid,
const LsodaOptions & lopt )
inline

The same retry over a whole output grid, for the callers that ask LSODA for a trajectory rather than an endpoint.

lsoda_integrate stops at the FIRST failed interval and returns the grid it reached, so a caller that reads s.y without reading s.success silently publishes a trajectory that stops short of the horizon. On failure the grid is re-walked one leg at a time through fluid_integrate_leg, which restarts the integrator at every output point – a small accuracy cost paid only where the single-call integration had already given up.

Definition at line 679 of file fluid_stiff.h.

References fluid_integrate_grid(), fluid_integrate_leg(), fluid_lsoda(), line::lsoda_integrate(), line::LsodaSolution::method, line::LsodaSolution::success, line::LsodaSolution::t, and line::LsodaSolution::y.

Referenced by fluid_integrate_grid(), fluid_passage_time(), line::api::infer_fluid_ps_rt_likelihood(), solver_fluid_kp_core(), solver_fluid_transient(), and tbi_advance().

◆ fluid_integrate_leg()

std::vector< double > line::fluid::fluid_integrate_leg ( const std::function< void(double, const double *, double *)> & f,
double t0,
double t1,
const std::vector< double > & y0,
const LsodaOptions & lopt )
inline

One integration leg, with the reference's retry on a failed solve.

WHY A RETRY EXISTS AT ALL. FluidOptions::stiff is false in this port where the reference's options.stiff is true, on the argument that LSODA switches to BDF on its own stiffness detector and so already covers ode15s. That holds on most drifts and NOT on all of them: an LQN layer whose entry carries an Immediate rate has 1e8 in sn.rates, so the drift's Jacobian eigenvalue is -1e8 while the trajectory is otherwise O(1), and LSODA has been measured staying in ADAMS across such a leg – 1e7 accepted steps at h = 5.6e-9, reaching t = 0.056 of a horizon of 20.9 before mxstep stopped it. Adams is stability-limited to h < 2/1e8 there, so no step count would have finished.

WHAT THE FAILURE USED TO COST. Every caller took final_state() regardless: solver_fluid's closing loop broke out and reported the state it happened to reach as the fixed point, while the matrix arm and the transient getter did not read success at all. A layer that never left its initial transient was published as a converged answer, which is the one outcome an integrator failure must not produce.

The reference retries too – solver_fluid_matrix.m re-solves once with hide_immediate toggled, solver_fluid_iteration.m catches the ODE error and re-solves from the default initial state – so retrying is the reference's shape, not an invention. What is retried here is the INTEGRATOR: the same leg, the same tolerances, run by the L-stable Rosenbrock arm above, which is the family ode23s belongs to and is not stability-limited. A leg LSODA completes is untouched, so no result that already converged moves.

Definition at line 653 of file fluid_stiff.h.

References line::fluid::FluidStiffOptions::atol, line::LsodaOptions::atol, line::LsodaSolution::final_state(), line::OdeSolution< T >::final_state(), fluid_integrate_leg(), fluid_lsoda(), fluid_ode_solve_stiff(), line::lsoda_integrate(), line::fluid::FluidStiffOptions::rtol, line::LsodaOptions::rtol, and line::LsodaSolution::success.

Referenced by fluid_integrate_grid(), and fluid_integrate_leg().

◆ fluid_interpcols()

void line::fluid::fluid_interpcols ( const std::vector< double > & tg,
const Matrix< double > & B,
double tt,
std::vector< double > & out )
inline

Port of fluid_interpcols.m: clamped piecewise-linear interpolation of the columns of B at a scalar time, into out.

CLAMPED, not extrapolated: a time outside the grid takes the boundary column (a zero-order hold). A trajectory supplied over [0, T] therefore holds its last value if the integrator steps past T, rather than continuing a linear ramp to a rate the caller never declared.

Definition at line 171 of file fluid_odes.h.

References line::Matrix< T >::cols(), fluid_interpcols(), and line::Matrix< T >::rows().

Referenced by fluid_drift(), and fluid_interpcols().

◆ fluid_is_time_varying_limit()

bool line::fluid::fluid_is_time_varying_limit ( const std::string & m)
inline

The three single-station limits that report a TRAJECTORY rather than a stationary point, and so need a finite horizon; ggisgi and tga are stationary and are not among them.

Parameters
mthe method name, already unqualified
Returns
true when the method integrates over a finite horizon

Definition at line 135 of file fluid_qsys.h.

References fluid_is_time_varying_limit().

Referenced by fluid_is_time_varying_limit(), and fluid_qsys_horizon_supports().

◆ fluid_jacobian() [1/2]

◆ fluid_jacobian() [2/2]

template<class T>
Matrix< double > line::fluid::fluid_jacobian ( const qn::NetworkStruct< T > & sn,
const std::vector< double > & x )

The Jacobian of the fluid drift at a state, by central differences.

The reference's getJacobian builds this SYMBOLICALLY and hands the expression to a SAGE backend over HTTP; there is no symbolic engine here, so this is the numerical counterpart. It is what the symbolic form is used for in practice – local stability of the fixed point, through the eigenvalues of J – and it needs no external service.

Definition at line 2297 of file solver_fluid.h.

References fluid_drift(), fluid_jacobian(), fluid_ode_system(), line::InputError::InputError(), line::fluid::FluidOdeSystem::layout, and line::fluid::FluidLayout::nstates.

◆ fluid_jump_matrix()

Matrix< double > line::fluid::fluid_jump_matrix ( const FluidOdeSystem & sys)
inline

The reference's dense jump matrix D, (nstates x nevents), rebuilt from the two-index event form this port stores instead.

solver_fluid_odes.m discards D once it has composed the right-hand side and the drift never needs it back, which is why the drift does not keep it. The covariance equation of the linear noise approximation does: its diffusion matrix is D*diag(r(x))*D', which cannot be recovered from F alone, and its reachable subspace is range(D). Built on demand, in the event order fluid_ode_system emits, so column e is event e.

Definition at line 456 of file fluid_odes.h.

References line::fluid::FluidOdeSystem::events, fluid_jump_matrix(), line::fluid::FluidOdeSystem::layout, and line::fluid::FluidLayout::nstates.

Referenced by fluid_jump_matrix(), and fluid_moment_terms().

◆ fluid_kink_stations()

std::vector< std::size_t > line::fluid::fluid_kink_stations ( const FluidMomentTerms & t,
const std::vector< double > & x,
const FluidClosure & cl )
inline

Every station whose population sits ON the saturation kink n_i = c_i of the first-order rate factor, in increasing order, empty when none does.

With sigma2 = 0 the occupancy factor is min(n_i, c_i), whose derivative is the indicator of the unsaturated region: slope 1 below c_i, slope 0 above, and NO derivative at c_i itself. fluid_drift_jacobian resolves the tie onto the saturated side, as its MATLAB, python and JAR twins do, so it silently returns one one-sided value there; which side a fixed point lands on is decided by the integrator's rounding residue rather than by the model. Callers that need a differentiable drift consult this instead of trusting the tie-break.

Only the branches that take the indicator derivative can sit on a kink: a positive sigma2 or a load-dependent row makes the closure smooth, and an infinite server never saturates. Twin of FluidRateFactors.driftKinkStations in the JAR.

Definition at line 692 of file fluid_moments.h.

References line::Matrix< T >::empty(), line::lang::EXT, fluid_kink_stations(), line::lang::INF, line::fluid::FluidOdeSystem::lld, line::fluid::FluidMomentTerms::S, line::fluid::FluidOdeSystem::sched, line::fluid::FluidClosure::sigma2, line::Matrix< T >::size(), line::fluid::FluidMomentTerms::station_block, and line::fluid::FluidMomentTerms::sys.

Referenced by fluid_kink_stations(), and solver_fluid_moments().

◆ fluid_layout()

template<class T>
FluidLayout line::fluid::fluid_layout ( const qn::NetworkStruct< T > & sn)

Port of the layout half of solver_fluid_odes.m.

The cumulative index runs even over disabled pairs, which contribute zero phases: the reference records q_indices for them too, so that a later lookup of a disabled pair lands on the next block's start rather than out of range. Reproduced deliberately.

Definition at line 282 of file fluid_odes.h.

References line::fluid::FluidLayout::enabled, fluid_layout(), line::fluid::FluidLayout::kic, line::fluid::FluidLayout::nstates, and line::fluid::FluidLayout::qidx.

Referenced by fluid_export_odes(), fluid_initsol(), fluid_layout(), fluid_matrix_system(), fluid_ode_system(), fluid_statedep_system(), fluid_symodes(), fluid_tran_passage_time(), line::ln::SolverLN< T >::init_from_marginal(), and solver_fluid_closing().

◆ fluid_list_valid_methods()

std::vector< std::string > line::fluid::fluid_list_valid_methods ( )
inline

Port of SolverFLD.listValidMethods.

Every method the dispatch below accepts, INCLUDING the fluid.-qualified spelling of each: the reference's own dispatch took fluid.tbi, fluid.dae and six more while its list named none of them, and native python listed the whole set, so the three lists disagreed. butools (the MFQ backend) and aoi (its age-of-information reading) are aliases of mfq.

Definition at line 74 of file fluid_runner.h.

References fluid_list_valid_methods().

Referenced by line::autosolver::auto_family_methods(), fluid_check_method(), fluid_list_valid_methods(), and line::NetworkSolver::list_valid_methods().

◆ fluid_lld_scaling()

ClosureValue line::fluid::fluid_lld_scaling ( const std::vector< double > & lldrow,
double n )
inline

Port of fluid_lld_scaling.m: the limited load-dependent multiplier alpha at a CONTINUOUS population, by linear interpolation of the integer table.

sn.lldscaling(i,:) is tabulated at populations 1..lldlimit and the discrete solvers read it at min(n, lldlimit). The fluid state is continuous, so the table is interpolated between consecutive entries and clamped to the first entry below n = 1 and to the last above the table end, which is the clamping the CTMC already applies.

Definition at line 142 of file fluid_closures.h.

References line::fluid::ClosureValue::dh, fluid_lld_scaling(), and line::fluid::ClosureValue::h.

Referenced by fluid_drift_jacobian(), fluid_lld_scaling(), and fluid_rates_closing_factors().

◆ fluid_lsoda()

LsodaOptions line::fluid::fluid_lsoda ( const LsodaOptions & lopt)
inline

The step budget LSODA gets on a fluid leg before the stiff arm takes over.

LsodaOptions::max_steps defaults to the JAR's raised mxstep of 1e7, which is a GIVE-UP threshold: nothing follows it, so it is set high enough that a slow-but-finishing integration is not cut off. Here it is a SWITCH threshold instead, because fluid_integrate_leg finishes the leg by another method, and a switch wants to be cheap. A fluid leg that is going to finish takes tens to a few thousand steps (measured: 3 to 121 on the LQN layers of randomLQN), so 1e6 keeps a factor of a thousand in hand while costing a fraction of a second to discover the Adams stability wall instead of the ~20 s that 1e7 cost.

Definition at line 619 of file fluid_stiff.h.

References fluid_lsoda(), and line::LsodaOptions::max_steps.

Referenced by fluid_integrate_grid(), fluid_integrate_leg(), and fluid_lsoda().

◆ fluid_lyapunov()

Matrix< double > line::fluid::fluid_lyapunov ( const Matrix< double > & A,
const Matrix< double > & Qdiff,
const Matrix< double > & D,
FluidLyapunovInfo & info,
double tol = -1.0 )
inline

Port of fluid_lyapunov.m: the stationary covariance of the linear noise approximation.

A IS SINGULAR WHENEVER THE MODEL CONSERVES POPULATION – every closed class contributes a left null vector – so the equation has no unique solution on the full state space. It has one on the reachable subspace, which is exactly range(D): the state moves only along jump directions, so the fluctuation lives there and nowhere else. A = D diag(rateBase) G and Qdiff = D diag(r) D' both map into range(D) as well, so restricting to an orthonormal basis of it is an EXACT reduction and not an approximation, and the reduced equation is nonsingular whenever the fixed point is stable.

Definition at line 177 of file fluid_moments.h.

References line::Matrix< T >::cols(), line::eig_values(), fluid_lyapunov(), line::fluid::FluidNonHyperbolicError::FluidNonHyperbolicError(), line::matmul(), line::fluid::FluidLyapunovInfo::max_real_eig, line::fluid::FluidLyapunovInfo::rank, line::Matrix< T >::rows(), line::fluid::FluidLyapunovInfo::stable, line::sylvester_solve(), and line::Matrix< T >::transpose().

Referenced by fluid_lyapunov(), and fluid_moment_lyapunov().

◆ fluid_matrix_degenerate()

bool line::fluid::fluid_matrix_degenerate ( const FluidMatrixSystem & s,
const std::function< void(double, const double *, double *)> & drift,
const std::vector< double > & x,
std::size_t K )
inline

Is the returned point one of a CONTINUUM of fixed points?

A station whose queue exceeds its server count has theta pinned at the server count, so the drift cannot tell one split of the mass between two such stations from another. The test is direct rather than structural: move a little mass from one station to another along a POPULATION-CONSERVING direction and see whether the drift moves at all. Both directions are tried, because the integrator typically stops on the BOUNDARY of the degenerate set, where one of the two does change the drift.

The DIRECTIONAL DERIVATIVE is the scale-free quantity to threshold: a live direction moves the drift at the station's own service rate (measured 9.99e-01) and a null one only by the FineTol the share carries (measured 1.00e-08), four orders apart. Source and INF states are excluded: neither can be the pinned coordinate. Returns false whenever the point is not a fixed point at all, so a transient run is never repaired.

Definition at line 376 of file fluid_matrix.h.

References fluid_matrix_degenerate(), line::fluid::FluidMatrixSystem::is_inf, line::fluid::FluidMatrixSystem::is_source, line::fluid::FluidMatrixSystem::nstates, line::Matrix< T >::rows(), line::fluid::FluidMatrixSystem::sqc, and line::fluid::FluidMatrixSystem::W.

Referenced by fluid_matrix_degenerate().

◆ fluid_matrix_drift()

std::function< void(double, const double *, double *)> line::fluid::fluid_matrix_drift ( const FluidMatrixSystem & s)
inline

The drift dx/dt = W' theta(x) + A_lambda.

Definition at line 344 of file fluid_matrix.h.

References line::fluid::FluidMatrixSystem::alambda, fluid_matrix_drift(), line::fluid::FluidMatrixSystem::nstates, and line::fluid::FluidMatrixSystem::W.

Referenced by fluid_matrix_drift().

◆ fluid_matrix_system()

◆ fluid_mfq()

◆ fluid_mfq_prio()

◆ fluid_min_closure()

ClosureValue line::fluid::fluid_min_closure ( double n,
double c,
double s2,
double vc = 0.0,
double cov_nc = 0.0 )
inline

Port of fluid_min_closure.m: E[min(X,Y)] for jointly normal X, Y, and its derivative with respect to E[X].

The published closure is Guenther, Stefanek and Bradley (EPEW/UKPEW 2012, LNCS 7587:32-47, eq. 4) in its general two-population form, of which SolverFLD uses only the specialisation Y = c with c the deterministic server count. The general arguments are kept so this IS the published closure rather than one instance of it.

With theta = 0 the expression collapses to min(n,c) and the derivative to 1{n < c}, so the first-order closure shares this code path exactly. The derivative AT the kink is 0, the right derivative of min(), which is the convention the strict inequality of the first-order branch already implies.

Definition at line 83 of file fluid_closures.h.

References closure_normcdf(), closure_normpdf(), line::fluid::ClosureValue::d2h, line::fluid::ClosureValue::dh, line::lang::GlobalConstants::FineTol, fluid_min_closure(), and line::fluid::ClosureValue::h.

Referenced by fluid_capacity_closure(), and fluid_min_closure().

◆ fluid_moment_drift()

std::vector< double > line::fluid::fluid_moment_drift ( const FluidMomentTerms & t,
const std::vector< double > & x,
const FluidClosure & cl )
inline

◆ fluid_moment_factors()

std::vector< double > line::fluid::fluid_moment_factors ( const FluidMomentTerms & t,
const std::vector< double > & x,
const FluidClosure & cl )
inline

◆ fluid_moment_lyapunov()

Matrix< double > line::fluid::fluid_moment_lyapunov ( const FluidMomentTerms & t,
const Matrix< double > & A,
const std::vector< double > & r,
const Matrix< double > * clampT = nullptr )
inline

local_lyapunov of solver_fluid_moments.m: the covariance on the coordinates that carry a real population, scattered back to full size.

For a closed model cov_idx is every coordinate and this is the plain solve. For an open or mixed model it drops the EXT source pool; the zeros left on the dropped rows keep the station and class block indexing unchanged downstream.

Definition at line 743 of file fluid_moments.h.

References line::fluid::FluidMomentTerms::cov_idx, line::fluid::FluidMomentTerms::D, fluid_lyapunov(), fluid_moment_lyapunov(), and line::fluid::FluidMomentTerms::nstate.

Referenced by fluid_dae_residual(), fluid_moment_lyapunov(), solver_fluid_dae(), and solver_fluid_moments().

◆ fluid_moment_rates()

std::vector< double > line::fluid::fluid_moment_rates ( const FluidMomentTerms & t,
const std::vector< double > & x,
const FluidClosure & cl )
inline

◆ fluid_moment_terms()

template<class T>
FluidMomentTerms line::fluid::fluid_moment_terms ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt )

◆ fluid_mvn_rectangle()

double line::fluid::fluid_mvn_rectangle ( const std::vector< double > & m,
const Matrix< double > & C,
const std::vector< double > & a,
const std::vector< double > & b,
std::size_t npoints = FLUID_MVN_POINTS )
inline

P(a <= Y <= b) for Y ~ Normal(m, C).

Parameters
mmean vector
Ccovariance, symmetric positive semi-definite
alower corner, -infinity allowed
bupper corner, +infinity allowed
npointslattice points per antithetic pair

Definition at line 181 of file fluid_mvn_rectangle.h.

References FLUID_MVN_POINTS, fluid_mvn_rectangle(), and line::InputError::InputError().

Referenced by fluid_mvn_rectangle(), and fluid_prob_aggr_gaussian().

◆ fluid_nudge_off_kink()

std::vector< double > line::fluid::fluid_nudge_off_kink ( const FluidMomentTerms & t,
const std::vector< double > & x,
const std::vector< std::size_t > & kink,
double rel )
inline

A copy of x with every station in kink moved to c_i*(1 + rel), i.e.

strictly onto one side of its kink. The station's coordinates are scaled together, so the phase mix and every other station are untouched.

Definition at line 720 of file fluid_moments.h.

References fluid_nudge_off_kink(), line::fluid::FluidMomentTerms::S, line::Matrix< T >::size(), and line::fluid::FluidMomentTerms::station_block.

Referenced by fluid_nudge_off_kink(), and solver_fluid_moments().

◆ fluid_ode_solve_stiff()

OdeSolution< double > line::fluid::fluid_ode_solve_stiff ( const std::function< void(double, const double *, double *)> & f,
double t0,
double t1,
const std::vector< double > & y0,
const FluidStiffOptions & opt = FluidStiffOptions() )
inline

Port of ode_solve_stiff.m.

The reference dispatches through options.odesolvers.*StiffOdeSolver, which are function handles a caller may point at any MATLAB integrator. There is no such registry here and no way to honour an arbitrary one, so a solver asked for BY NAME is refused rather than served by the method that happens to be present under a name it does not have.

THE NONNEGATIVITY IS A PROJECTION, NOT A CONSTRAINT. MATLAB's NonNegative option is enforced by the step controller, which rejects a step that would take a component below zero. Clamping the accepted trajectory afterwards cannot rescue such a step; it prevents a negative mass from feeding back into the drift as a negative rate, which is what solver_fluid.h already does after every integration leg. The difference matters on a drift that is only defined for nonnegative states, and is stated rather than hidden.

Definition at line 570 of file fluid_stiff.h.

References line::OdeOptions< T >::atol, fluid_ode_solve_stiff(), line::InputError::InputError(), line::OdeOptions< T >::max_steps, line::ode_rosenbrock4(), line::OdeOptions< T >::rtol, line::OdeOptions< T >::step_stop, line::OdeOptions< T >::store_trajectory, line::UnsupportedError::UnsupportedError(), and line::OdeSolution< T >::y.

Referenced by fluid_integrate_leg(), and fluid_ode_solve_stiff().

◆ fluid_ode_system()

template<class T>
FluidOdeSystem line::fluid::fluid_ode_system ( const qn::NetworkStruct< T > & sn)

Build the drift of sn: the port of ode_jumps_new and ode_rate_base fused into one pass.

The two reference functions walk the same nested loops in the same order and their outputs are matched element by element, so building them together is the only way to keep them aligned by construction rather than by comment.

rt is read in STATION space, by the STOCHASTIC COMPLEMENT of sn.rt on the station rows. sn.rt is indexed by stateful node, and the reference indexes it with (i-1)*K+c for i over stations, which is the same thing only when every stateful node is a station. Mapping the station index through stateful_of_station is not enough either: it reads the DIRECT station pair and so drops every path that traverses a non-station stateful node. On a cache model that is the whole flow – Think -> Cache -> Queue has a zero direct entry – and the drift then has no outgoing route at all, so the ODE returns its initial condition with every job parked at the reference station. Absorbing those nodes is exact because they hold no jobs.

Definition at line 322 of file fluid_odes.h.

References line::lang::Distrib< T >::D0, line::lang::DPS, line::mc::dtmc_stochcomp(), line::fluid::FluidLayout::enabled, line::fluid::FluidEvent::event_idx, line::fluid::FluidOdeSystem::events, fluid_layout(), fluid_ode_system(), line::lang::GPS, line::fluid::FluidLayout::kic, line::fluid::FluidOdeSystem::layout, line::fluid::FluidOdeSystem::lld, line::fluid::FluidEvent::minus, line::fluid::FluidOdeSystem::n_departures, line::fluid::FluidOdeSystem::nservers, line::fluid::FluidEvent::plus, line::fluid::FluidLayout::qidx, line::fluid::FluidEvent::rate_base, line::fluid::FluidOdeSystem::sched, and line::fluid::FluidOdeSystem::weight.

Referenced by fluid_jacobian(), fluid_moment_terms(), fluid_ode_system(), fluid_passage_time(), line::api::infer_fluid_ps_rt_likelihood(), line::api::infer_fmlps(), and solver_fluid_transient().

◆ fluid_passage_time()

template<class T>
FluidPassage line::fluid::fluid_passage_time ( const qn::NetworkStruct< T > & sn,
const std::vector< double > & x_steady,
std::size_t ist,
std::size_t cls,
double tol = 1e-4,
std::size_t points = 201,
const FluidClosure & closure = FluidClosure() )

Response-time CDF at station ist for class cls, both 1-based.

x_steady is the converged fluid state the marking starts from – the reference passes options.init_sol = odeStateVec, i.e. the steady state, so the distribution is the stationary one.

closure is the variance the mean solve closed its drift at, i.e. FluidSolution::closure. This is a SECOND solve on that solve's fixed point, so it has to be driven by the same drift: closing min(n_i,c_i) at zero variance drains a station the mean solve holds below capacity at full rate, and the distribution then contradicts the mean the same solver reports. A default-constructed closure is the first-order drift, which is what every first-order method wants.

Definition at line 83 of file fluid_passage.h.

References line::LsodaOptions::atol, line::fluid::FluidPassage::cdf, line::fluid::FluidOdeSystem::closure, line::fluid::FluidEvent::event_idx, line::fluid::FluidOdeSystem::events, line::fluid::FluidPassage::fluid0, fluid_integrate_grid(), fluid_ode_system(), fluid_passage_time(), fluid_rates_closing(), line::InputError::InputError(), line::fluid::FluidLayout::kic, line::fluid::FluidOdeSystem::layout, line::fluid::FluidEvent::minus, line::fluid::FluidOdeSystem::n_departures, line::fluid::FluidLayout::nstates, line::fluid::FluidEvent::plus, line::fluid::FluidLayout::qidx, line::fluid::FluidEvent::rate_base, line::LsodaOptions::rtol, line::fluid::FluidClosure::sigma2, line::fluid::FluidPassage::t, line::LsodaSolution::t, and line::LsodaSolution::y.

Referenced by fluid_passage_time(), fluid_tran_passage_time(), and solver_fluid_cdf_respt().

◆ fluid_prob_aggr()

template<class T>
double line::fluid::fluid_prob_aggr ( const qn::NetworkStruct< T > & sn,
const FluidSolution & sol,
std::size_t ist,
double * logp_out = nullptr )

Port of @@SolverFLD/getProbAggr: the probability that station ist holds the marginal population of the model's default state.

The fluid solver has no state space, so the probability is FITTED to the mean queue lengths it does produce: a binomial for each closed class (Schmidt) and, for the open ones, the BCMP marginal – Poisson at an infinite server, multinomial-geometric at a queue. The two contributions are ADDED in log space, which is what lets a mixed model be evaluated at all; the MVA port's version picks one branch because its callers are never mixed.

ist is 1-based, as in the reference.

Definition at line 2397 of file solver_fluid.h.

References line::fluid::FluidMomentReport::class_block, line::lang::EXT, fluid_prob_aggr(), fluid_prob_aggr_gaussian(), line::fluid::FluidSolution::has_moments, line::lang::INF, line::InputError::InputError(), line::fluid::FluidSolution::moments, line::fluid::FluidSolution::QN, and line::fluid::FluidSolution::UN.

Referenced by fluid_prob_aggr().

◆ fluid_prob_aggr_gaussian()

template<class T>
double line::fluid::fluid_prob_aggr_gaussian ( const qn::NetworkStruct< T > & sn,
const FluidSolution & sol,
std::size_t i,
const std::vector< double > & nir,
double * logp_out = nullptr )

The joint probability of the per-class populations at station i (0-based) under the linear noise approximation solved by the moment closure, the local_gaussian_cell of the reference @@SolverFLD/getProbAggr.

The state coordinates of class r at the station are moments.class_block[i][r] (one per service phase), so the class population is their sum: its mean is the reported QN(i,r) and the class-to-class covariance is the sum of the corresponding block of moments.Sigma. The integer count n is then read off the continuous law as the unit cell [n-1/2, n+1/2], with the two ends extended to infinity at the boundaries of the state space, so that the mass the normal puts on negative populations lands on the empty station and the mass above a closed population lands on the full one. Those cells tile the state space, so the probabilities sum to one over the reachable states.

Definition at line 2335 of file solver_fluid.h.

References line::fluid::FluidMomentReport::class_block, fluid_mvn_rectangle(), fluid_prob_aggr_gaussian(), line::fluid::FluidSolution::moments, line::fluid::FluidSolution::QN, and line::fluid::FluidMomentReport::Sigma.

Referenced by fluid_prob_aggr(), and fluid_prob_aggr_gaussian().

◆ fluid_project_rate()

void line::fluid::fluid_project_rate ( std::vector< double > & r,
const std::vector< double > & xb,
bool capped,
double tot )
inline

Port of local_project_rate in ode_rates_closing_factors.m: project a jointly closed per-coordinate service share onto the set it has to live in, namely r >= 0, r <= xb where that bound applies, and sum(r) = tot.

THE JOINT CLOSURE IS AN EXPANSION AND CAN LEAVE THAT SET. r = s*psi + psi'*Cov(S,N) adds a term that sums to ZERO over the coordinates, so it moves mass between them and its entries can push one past either bound; the first-order share x_j/n_i*psi cannot, being x_j scaled by psi/n_i <= 1. Either breach ends the same way, because the integrator holds every coordinate non-negative: r_j > x_j drains coordinate j faster than it holds, the state goes negative and the clamp INJECTS mass.

THE UPPER BOUND HOLDS ONLY WITHOUT LOAD DEPENDENCE, which is what CAPPED selects. r is an expected NUMBER in service so r_j <= x_j, but psi(n) = min(n,c)*alpha(n) folds the load-dependent scaling into the same variable, and with alpha > 1 the first-order share itself exceeds x_j.

Clip, then move the residual onto the coordinates that still have slack in proportion to it, so sum(r) = tot survives and the station still clears what its capacity closure says it clears. It is a NO-OP whenever the expansion stayed inside the set, which is why models already inside it are bit-identical.

Definition at line 342 of file fluid_closures.h.

References fluid_project_rate(), and line::lang::GlobalConstants::Zero.

Referenced by fluid_project_rate(), and fluid_rates_closing_factors().

◆ fluid_qsys_horizon_supports()

std::string line::fluid::fluid_qsys_horizon_supports ( const std::string & method,
const FluidOptions & opt )
inline

The horizon rule the time-varying limits impose, as a public predicate a REPORT can ask: empty when method may be asked for with these options.

solver_fluid_qsys refuses through the same body, so a pair the report offers is a pair the limit runs.

Parameters
methodthe method name, qualified or not
optthe fluid knobs, read for the end of the horizon
Returns
an empty string when the method may run, else the refusal

Definition at line 150 of file fluid_qsys.h.

References fluid_is_time_varying_limit(), and fluid_qsys_horizon_supports().

Referenced by line::autosolver::auto_family_refusal(), and fluid_qsys_horizon_supports().

◆ fluid_rates_closing()

void line::fluid::fluid_rates_closing ( const FluidOdeSystem & sys,
const double * x,
std::vector< double > & g )
inline

The reference's ode_rates_closing name, kept for the first-order callers.

Definition at line 646 of file fluid_odes.h.

References fluid_rates_closing(), and fluid_rates_closing_factors().

Referenced by fluid_drift(), fluid_passage_time(), fluid_rates_closing(), line::api::infer_fluid_ps_rt_likelihood(), and tbi_advance().

◆ fluid_rates_closing_factors()

void line::fluid::fluid_rates_closing_factors ( const FluidOdeSystem & sys,
const double * x,
std::vector< double > & g )
inline

Port of ode_rates_closing_factors: the state-dependent factor g(x), in place.

g must already be a copy of x on entry, which is the reference's rates = x and is what makes INF and every under-loaded station correct with no work.

THE CLOSURE VARIANCE IS READ FROM THE SYSTEM, not passed separately, because fluid_drift closes over the system alone and LSODA holds that callback for the whole integration; a closure supplied beside it would have to be captured somewhere else and could then disagree with the Jacobian, which reads it from here.

WHAT THE gaussian FLAG IS. The reference's any(sigma2 > 0) is GLOBAL over the stations, not per station, so one station carrying a variance sends every PS/FCFS station down the closure branch – with its own sigma2(i), which may be zero, in which case fluid_capacity_closure returns min(n_i,c) and the branch reproduces the first-order value. Reproduced as the same global flag so that the one place the two differ, the zero floor on a negative E[min], is reached on the same models as in the reference.

Definition at line 486 of file fluid_odes.h.

References line::fluid::FluidOdeSystem::closure, line::fluid::ShareValue::cn, line::fluid::FluidClosure::cov_of(), line::fluid::ClosureValue::dh, line::lang::DPS, line::fluid::FluidLayout::enabled, line::lang::EXT, line::lang::FCFS, fluid_capacity_closure(), fluid_gps_share(), fluid_lld_scaling(), fluid_project_rate(), fluid_rates_closing_factors(), fluid_share_closure(), line::fluid::FluidClosure::gaussian(), line::lang::GPS, line::fluid::ClosureValue::h, line::lang::INF, line::fluid::FluidLayout::kic, line::fluid::FluidOdeSystem::layout, line::fluid::FluidOdeSystem::lld, line::fluid::FluidOdeSystem::nservers, line::lang::PS, line::fluid::FluidLayout::qidx, line::fluid::ShareValue::s, line::fluid::FluidOdeSystem::sched, line::fluid::FluidClosure::sigma2_of(), line::UnsupportedError::UnsupportedError(), and line::fluid::FluidOdeSystem::weight.

Referenced by fluid_moment_factors(), fluid_rates_closing(), and fluid_rates_closing_factors().

◆ fluid_refine_meanfield()

std::vector< double > line::fluid::fluid_refine_meanfield ( const FluidMomentTerms & t,
const std::vector< double > & x,
const FluidClosure & cl,
const Matrix< double > & Sigma,
FluidRefineInfo & info,
double epsrel = 1e-4 )
inline

Port of fluid_refine_meanfield.m: the O(1/N) refined mean field correction of Gast (POMACS 2017).

The correction V solves A V + (1/2) sum_{jk} Sigma_jk d2F/dx_j dx_k = 0. The Hessian contraction is evaluated WITHOUT forming the tensor: with Sigma = sum_m lam_m v_m v_m', the contraction is sum_m lam_m d2F/dv_m^2 and each directional second derivative is one central second difference, so the cost is O(rank(Sigma)) drift evaluations rather than O(n^2). Because Sigma scales with the population, V is the O(1/N) term written directly in job counts and no explicit density rescaling is needed.

THE DRIFT MUST BE TWICE DIFFERENTIABLE. The first-order closure is only piecewise linear – second derivative zero away from the kink and a delta at it – so a zero variance is REFUSED rather than silently returning a null correction.

Definition at line 810 of file fluid_moments.h.

References line::Matrix< T >::cols(), line::fluid::FluidRefineInfo::condition, line::fluid::FluidMomentTerms::D, fluid_drift_jacobian(), fluid_moment_drift(), fluid_refine_meanfield(), line::fluid::FluidNonHyperbolicError::FluidNonHyperbolicError(), line::fluid::FluidClosure::gaussian(), line::InputError::InputError(), line::inverse(), line::matmul(), line::fluid::FluidRefineInfo::rank, line::fluid::FluidRefineInfo::residual, line::SvdFactors::s, line::fluid::FluidRefineInfo::stepsize, line::svd_full(), line::svd_values(), line::Matrix< T >::transpose(), and line::SvdFactors::U.

Referenced by fluid_refine_meanfield(), and solver_fluid_moments().

◆ fluid_share_closure()

ShareValue line::fluid::fluid_share_closure ( const std::vector< double > & x,
const std::vector< double > & wv,
const Matrix< double > & C,
bool want_jac,
bool want_cov = false )
inline

Port of fluid_share_closure.m: E[w_j X_j / sum_m w_m X_m] by the delta method, and its Jacobian at fixed covariance.

THE INVARIANT TO CHECK ON ANY CHANGE HERE is that the shares sum to one. The correction is exactly capacity conserving because sum_j Cov(u_j,v) = Var(v), so the two correction terms cancel in the sum; a work-conserving discipline that lost that identity would leak or invent capacity.

The expansion is local and fails where v is small against its own standard deviation, the exact expectation there being a Cauchy-like integral with no finite mean. A raw share can come out negative; it is clipped at zero and the survivors renormalised, which preserves the identity.

Definition at line 436 of file fluid_closures.h.

References line::fluid::ShareValue::cn, line::Matrix< T >::cols(), line::fluid::ShareValue::dcn, line::fluid::ShareValue::ds, line::fluid::ExpansionWeight::dtau, fluid_expansion_weight(), fluid_share_closure(), line::Matrix< T >::rows(), line::fluid::ShareValue::s, line::fluid::ExpansionWeight::tau, and line::lang::GlobalConstants::Zero.

Referenced by fluid_drift_jacobian(), fluid_rates_closing_factors(), and fluid_share_closure().

◆ fluid_statedep_system()

◆ fluid_symbolic_drift()

FluidSymbolicDrift line::fluid::fluid_symbolic_drift ( const FluidSymSystem & sys)
inline

Port of @@SolverFLD/getSymbolicDrift: the right-hand side of the mean-field ODE system as expression strings, one per state variable.

This is the input a computer-algebra backend needs to produce a Jacobian or an equilibrium, and it is the same system fluid_symodes describes and fluid_export_odes typesets, written out variable by variable instead of in matrix form.

ONLY SMOOTH DRIFTS ARE EXPORTED. The default, matrix, closing and statedep methods scale rates by min(n_i, S_i), which is not differentiable at n_i = S_i, so their Jacobian does not exist there; emitting a one-sided derivative would be a silent lie exactly at the regime switch that matters. The p-norm smoothing (pstar, methods matrix or pnorm) and the softmin method are smooth everywhere, and everything else is refused BY THE FACTOR TYPE that carries the kink rather than by method name, so a new non-smooth branch cannot slip through.

Definition at line 472 of file fluid_symodes.h.

References line::fluid::FluidSymSystem::alambda, line::fluid::FluidSymSystem::alpha, line::fluid::FluidSymSystem::coeff, line::fluid::FluidSymSystem::event_var, line::fluid::FluidSymSystem::factor, line::lang::GlobalConstants::FineTol, fluid_symbolic_drift(), line::fluid::FluidSymSystem::form, line::fluid::FluidSymSystem::is_inf, line::fluid::FluidSymSystem::is_source, line::fluid::FluidSymSystem::J, line::fluid::FluidSymSystem::nevents, line::fluid::FluidSymSystem::nstates, line::fluid::SymFactor::others, line::fluid::FluidSymSystem::pstar, line::fluid::FluidSymbolicDrift::rhs, line::fluid::FluidSymSystem::S, line::fluid::FluidSymSystem::smoothing, line::fluid::FluidSymSystem::state_station, line::fluid::SymFactor::station, line::fluid::SymFactor::type, line::UnsupportedError::UnsupportedError(), line::fluid::FluidSymbolicDrift::vars, and line::fluid::FluidSymSystem::W.

Referenced by fluid_jacobian(), fluid_symbolic_drift(), and fluid_symbolic_jacobian().

◆ fluid_symbolic_jacobian()

FluidSymbolicJacobian line::fluid::fluid_symbolic_jacobian ( const FluidSymSystem & sys)
inline

Port of @@SolverFLD/getJacobian: d f_i / d x_j of the mean-field drift, as expression strings.

IT IS DIFFERENTIATED HERE, NOT SENT AWAY. The reference hands the drift strings to the line-sage-rest backend over HTTP and returns what SAGE gives back. This port has no symbolic engine and no HTTP client – the CTMC port makes the same refusal for its own symbolic getters – but the drift is not an opaque expression here: FluidSymSystem carries it STRUCTURALLY, as a jump matrix times per-event rates whose state dependence is one of a closed set of typed factors. Each of those factors has a derivative that can be written down once, so the Jacobian is produced exactly, by the chain rule over the structure, rather than by parsing the strings the drift printer emitted.

The smoothness gate is the SAME one fluid_symbolic_drift applies, and for the same reason: min(n_i, S_i) has no derivative at n_i = S_i, and a one-sided value there would be a silent lie exactly at the regime switch. The refusal is by FACTOR TYPE, so a new non-smooth branch cannot slip through.

equilibria, the reference's fourth output, is NOT produced here: solving f(x) = 0 in closed form needs a computer-algebra solver, which differentiating does not. It lives in fluid_jacobian (fluid_jacobian.h), which resolves the same line-sage-rest backend the reference uses and asks it; this function stays backend-free so that the Jacobian alone never needs one.

Definition at line 671 of file fluid_symodes.h.

References line::fluid::FluidSymSystem::alpha, line::fluid::FluidSymSystem::coeff, line::fluid::FluidSymSystem::event_var, line::fluid::FluidSymSystem::factor, line::fluid::FluidSymSystem::fcfs_phase_w, line::lang::GlobalConstants::FineTol, fluid_symbolic_drift(), fluid_symbolic_jacobian(), line::fluid::FluidSymSystem::form, line::fluid::FluidSymSystem::is_inf, line::fluid::FluidSymSystem::is_source, line::fluid::FluidSymbolicJacobian::J, line::fluid::FluidSymSystem::J, line::fluid::FluidSymSystem::nevents, line::fluid::FluidSymSystem::nstates, line::fluid::SymFactor::others, line::fluid::FluidSymSystem::pstar, line::fluid::FluidSymbolicDrift::rhs, line::fluid::FluidSymbolicJacobian::rhs, line::fluid::FluidSymSystem::S, line::fluid::FluidSymSystem::state_station, line::fluid::SymFactor::station, line::fluid::SymFactor::type, line::UnsupportedError::UnsupportedError(), line::fluid::FluidSymbolicDrift::vars, line::fluid::FluidSymbolicJacobian::vars, and line::fluid::FluidSymSystem::W.

Referenced by fluid_jacobian(), and fluid_symbolic_jacobian().

◆ fluid_symodes()

template<class T>
FluidSymSystem line::fluid::fluid_symodes ( const qn::NetworkStruct< T > & sn,
const std::string & method_in,
double pstar,
const std::vector< double > & init_sol )

Build the symbolic system of sn under opt.method.

init_sol is the initial condition to report; empty takes the solver's default, as build_x0 in the reference does through solver_fluid_initsol.

Definition at line 169 of file fluid_symodes.h.

References line::fluid::FluidMatrixSystem::alambda, line::fluid::FluidSymSystem::alambda, line::fluid::FluidSymSystem::alpha, line::fluid::FluidSymSystem::class_names, line::fluid::FluidSymSystem::coeff, line::lang::DPS, line::fluid::FluidSymSystem::dpsw, line::fluid::FluidLayout::enabled, line::fluid::FluidSymSystem::event_var, line::lang::EXT, line::fluid::FluidSymSystem::factor, line::lang::FCFS, line::fluid::FluidSymSystem::fcfs_phase_w, fluid_layout(), fluid_matrix_system(), fluid_symodes(), line::fluid::FluidSymSystem::form, line::lang::INF, line::fluid::FluidMatrixSystem::is_inf, line::fluid::FluidSymSystem::is_inf, line::fluid::FluidMatrixSystem::is_source, line::fluid::FluidSymSystem::is_source, line::fluid::FluidSymSystem::J, line::fluid::FluidLayout::kic, line::fluid::FluidSymSystem::method, line::fluid::FluidSymSystem::nevents, line::fluid::FluidLayout::nstates, line::fluid::FluidMatrixSystem::nstates, line::fluid::FluidSymSystem::nstates, line::NumericError::NumericError(), line::fluid::FluidSymSystem::pstar, line::fluid::FluidLayout::qidx, line::fluid::FluidSymSystem::S, line::fluid::FluidSymSystem::sched, line::fluid::FluidSymSystem::sched_names, line::lang::sched_to_text(), line::fluid::FluidSymSystem::smoothing, line::fluid::FluidSymSystem::state_class, line::fluid::FluidSymSystem::state_phase, line::fluid::FluidSymSystem::state_station, line::fluid::FluidSymSystem::station_names, line::UnsupportedError::UnsupportedError(), line::fluid::FluidMatrixSystem::W, line::fluid::FluidSymSystem::W, line::fluid::FluidMatrixSystem::x0, and line::fluid::FluidSymSystem::x0.

Referenced by fluid_export_odes(), and fluid_symodes().

◆ fluid_tran_passage_time()

template<class T>
FluidPassage line::fluid::fluid_tran_passage_time ( const qn::NetworkStruct< T > & sn,
std::size_t ist,
std::size_t cls,
double tol = 1e-4,
std::size_t points = 201 )

Port of @@SolverFLD/getTranCdfPassT: the same passage-time distribution started from the model's INITIAL state rather than from its steady state.

IT IS THE SAME ALGORITHM AT A DIFFERENT STARTING POINT, which is exactly what the reference is: getCdfRespT passes the converged odeStateVec, getTranCdfPassT passes solver_fluid_initsol(sn, options). The two are kept as separate named entry points because the quantity differs – one is the stationary response-time law, the other the law seen by a job marked while the system is still where the model says it starts – and a caller that had to assemble the second by hand would have to know that, which is what a name is for.

WHAT IS NOT REPRODUCED, and it is a MODEL-LAYER restriction rather than an algorithmic one: the reference first collapses sn.state to the first row of its prior and ERRORS when more than one initial state carries non-zero prior mass, because a passage time from a mixture of starting states is not one distribution. fluid_default_initsol is the closed form of the single-state decode (see fluid_closing.h) and there is no prior to collapse here, so the refusal has no input in this port.

Definition at line 321 of file fluid_passage.h.

References fluid_layout(), fluid_passage_time(), and fluid_tran_passage_time().

Referenced by fluid_tran_passage_time().

◆ mfq_is_single_queue()

template<class T>
MfqTopology line::fluid::mfq_is_single_queue ( const qn::NetworkStruct< T > & sn)

Port of fluid_is_single_queue.m: the model must be one open class flowing Source -> Queue -> Sink and nothing else.

Definition at line 67 of file fluid_mfq.h.

References line::fluid::MfqTopology::cls, mfq_is_single_queue(), line::fluid::MfqTopology::ok, line::fluid::MfqTopology::open_classes, line::fluid::MfqTopology::queue, and line::fluid::MfqTopology::source.

Referenced by mfq_is_single_queue().

◆ solver_fld_cacheqn_analyzer()

template<class T>
FluidCacheqnSolution< T > line::fluid::solver_fld_cacheqn_analyzer ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt )

Port of solver_fld_cacheqn_analyzer.m.

Returns the branch result BEFORE solver_fluid's analyzer-level utilization and response-time correction, exactly as the reference's branch returns what solver_fluid_matrix gave it and lets solver_fluid_analyzer correct once after the method switch. Applying the correction here as well would apply it twice, and it is not idempotent (it rescales U by a share computed from the U it is given).

Definition at line 268 of file fluid_cacheqn.h.

References line::mva::MvaSolution< T >::C, line::fluid::FluidSolution::CN, line::da::da_cacheqn(), line::da::CacheqnResult< T >::hitprob, line::fluid::FluidCacheqnSolution< T >::hitprob, line::fluid::FluidOptions::init_sol, line::InputError::InputError(), line::da::CacheqnResult< T >::iter, line::fluid::FluidCacheqnSolution< T >::iter, line::mva::MvaSolution< T >::iter, line::mva::MvaOptions::iter_max, line::fluid::FluidSolution::iters, line::fluid::FluidOptions::method, line::fluid::FluidSolution::method, line::mva::MvaSolution< T >::method, line::da::CacheqnResult< T >::missprob, line::fluid::FluidCacheqnSolution< T >::missprob, line::NumericError::NumericError(), line::mva::MvaSolution< T >::Q, line::fluid::FluidSolution::QN, line::mva::MvaSolution< T >::R, line::fluid::FluidCacheqnSolution< T >::refreshed, line::fluid::FluidSolution::RN, line::Matrix< T >::size(), line::fluid::FluidCacheqnSolution< T >::sol, solver_fld_cacheqn_analyzer(), solver_fluid_moments(), line::fluid::FluidSolution::TN, line::mva::MvaOptions::tol, line::mva::MvaSolution< T >::Tp, line::mva::MvaSolution< T >::U, line::fluid::FluidSolution::UN, line::UnsupportedError::UnsupportedError(), line::mva::MvaSolution< T >::X, and line::fluid::FluidSolution::XN.

Referenced by solver_fld_cacheqn_analyzer(), and solver_fluid_run_analyzer().

◆ solver_fld_cacheqn_tran()

template<class T>
std::vector< FluidCacheqnTranCache< T > > line::fluid::solver_fld_cacheqn_tran ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
double t0,
double t1,
const std::vector< std::vector< T > > & x0cell = std::vector<std::vector<T> >() )

Port of solver_fld_cacheqn_tran.m: the transient counterpart of the analyzer above.

The steady solver drives the cache drift to its fixed point; this integrates the SAME drift over [t0,t1] from a given occupancy. The decomposition still runs first and in full, because the drift is parameterised by the converged per-class arrival rates – a transient computed at the offered rates would be the trajectory of a cache the network does not feed.

x0cell[c], when present and non-empty, seeds cache c with a flat DDPP state of length nitems*(h+1); otherwise the reference default is used.

WHY THE TIME GRID IS PER CACHE. The reference builds one tcache from the FIRST cache and writes every other cache's trajectory into a slice of that width. The grids come from an adaptive integrator on different drifts, so they agree in length only by accident; keeping each cache's own grid is the same information without the coincidence.

Definition at line 395 of file fluid_cacheqn.h.

References line::qn::CacheParam< T >::accost, line::fluid::FluidCacheqnTranCache< T >::arate, line::mva::MvaSolution< T >::C, line::cache::cache_miss_fifo_rmf_transient(), line::cache::cache_miss_rmf_transient(), line::cache::cache_miss_sfifo_rmf_transient(), line::fluid::FluidSolution::CN, line::Matrix< T >::cols(), line::da::da_cacheqn(), line::lang::FIFO, line::fluid::FluidCacheqnTranCache< T >::hitprob_t, line::da::CacheqnResult< T >::info, line::fluid::FluidOptions::init_sol, line::InputError::InputError(), line::mva::MvaOptions::iter_max, line::Matrix< T >::Matrix(), line::fluid::FluidOptions::method, line::fluid::FluidCacheqnTranCache< T >::missprob_t, line::fluid::FluidCacheqnTranCache< T >::node, line::mva::MvaSolution< T >::Q, line::fluid::FluidSolution::QN, line::mva::MvaSolution< T >::R, line::qn::CacheParam< T >::replacestrat, line::fluid::FluidSolution::RN, line::Matrix< T >::rows(), line::lang::SFIFO, line::Matrix< T >::size(), solver_fld_cacheqn_tran(), line::fluid::FluidCacheqnTranCache< T >::t, line::fluid::FluidSolution::TN, line::mva::MvaOptions::tol, line::mva::MvaSolution< T >::Tp, line::mva::MvaSolution< T >::U, line::fluid::FluidSolution::UN, line::UnsupportedError::UnsupportedError(), line::mva::MvaSolution< T >::X, line::fluid::FluidSolution::XN, and line::fluid::FluidCacheqnTranCache< T >::xocc.

Referenced by solver_fld_cacheqn_tran().

◆ solver_fluid()

template<class T>
FluidSolution line::fluid::solver_fluid ( const qn::NetworkStruct< T > & sn_in,
const FluidOptions & opt,
qn::NetworkStruct< T > * sn_out = nullptr )

Port of solver_fluid_analyzer.m: dispatch on the method, refit the non-exponential FCFS stations the reference refits, then apply the utilization and response-time correction it applies to whatever the branch returned.

Definition at line 2094 of file solver_fluid.h.

References line::api::NonmarkovOptions::order, line::api::Ph, line::api::NonmarkovOptions::phfit, line::fluid::FluidSolution::QN, line::fluid::FluidSolution::RN, line::api::sn_has_nonmarkov(), line::api::sn_nonmarkov_toph(), solver_fluid(), line::fluid::FluidSolution::TN, and line::fluid::FluidSolution::UN.

Referenced by solver_fluid(), and solver_fluid_run_analyzer().

◆ solver_fluid_cdf_respt()

template<class T>
std::vector< std::vector< FluidPassage > > line::fluid::solver_fluid_cdf_respt ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
std::size_t points = 201 )

Port of @@SolverFLD/getCdfRespT: the response-time law of every (station, class) pair, read off the marked-fluid trajectory started from the steady state.

THE SOLVE COMES FIRST AND IS NOT THE CALLER'S. The reference clears its cached result, re-runs getAvg to fill odeStateVec, and hands the passage time BOTH that vector and result.solverSpecific.sn – the struct the FCFS refit may have re-fitted – because the vector is laid out by the phase counts of that struct and not of the model's. Bundling the two here is what keeps a caller from pairing a state vector with the wrong struct, which would be a length error at best and a law of the wrong model at worst.

A Source has no response time and is left empty, as is a pair whose class the station does not serve; an empty entry is an ABSENT law, never a degenerate one.

Definition at line 908 of file fluid_runner.h.

References line::fluid::FluidSolution::closure, line::qn::NetworkStruct< T >::disabled, fluid_passage_time(), line::fluid::FluidSolution::method, line::qn::NetworkStruct< T >::nclasses, line::qn::NetworkStruct< T >::nstations, solver_fluid_cdf_respt(), solver_fluid_run_analyzer(), line::qn::NetworkStruct< T >::stations, line::UnsupportedError::UnsupportedError(), and line::fluid::FluidSolution::xvec.

Referenced by line::SolverFLD::cdf_respt(), and solver_fluid_cdf_respt().

◆ solver_fluid_closing()

template<class T>
FluidSolution line::fluid::solver_fluid_closing ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt )

Port of solver_fluid_closing.m: the closing family's entry point.

IT RETURNS THE UNCORRECTED TABLE, as the reference function does. The utilization and response time that reach a user go through fluid_analyzer_correct, which solver_fluid_analyzer.m applies AFTER the method switch and to every branch alike; applying it here as well would either double it or fork it. Callers who want the analyzer's answer call solver_fluid, which is that function.

The method is gated rather than forwarded because the analyzer's switch sends only these names here; matrix and pnorm are a different drift and mfq, diffusion and rmf are different solvers entirely, and answering for them under this name would report one method's number as another's.

Definition at line 180 of file fluid_closing.h.

References fluid_initsol(), fluid_layout(), line::fluid::FluidOptions::init_sol, line::fluid::FluidOptions::method, solver_fluid_closing(), and line::UnsupportedError::UnsupportedError().

Referenced by solver_fluid_closing(), and solver_fluid_run_analyzer().

◆ solver_fluid_dae()

template<class T>
FluidSolution line::fluid::solver_fluid_dae ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
const FluidDaeOptions & dopt_in = FluidDaeOptions() )

solver_fluid_dae.m: the min-normal closure solved as one system.

Backs options.method = "dae". The answer is the same closure minnormal computes; what differs is that the mean and the variance are solved simultaneously rather than alternated, and that population conservation is an equation rather than a consequence of the drift.

Definition at line 2069 of file fluid_dae.h.

References line::fluid::FluidDaeConstraints::A, line::fluid::FluidDaeSystem::active, line::fluid::FluidDaeConstraints::As, line::fluid::FluidDaeConstraints::b, line::fluid::FluidDaeConservation::C, line::fluid::FluidDaeSystem::cidx, line::fluid::FluidDaeSystem::clampT, line::fluid::FluidMomentReport::class_block, line::fluid::FluidMomentTerms::class_block, line::fluid::FluidOptions::closure, line::fluid::FluidSolution::closure, line::fluid::FluidSolution::CN, line::Matrix< T >::cols(), line::fluid::FluidDaeSystem::con, line::fluid::FluidDaeSystem::cons, line::fluid::FluidDaeNewtonInfo::converged, line::fluid::FluidClosure::cov, line::fluid::FluidMomentTerms::D, line::lang::DPS, line::fluid::FluidDaeConstraints::empty(), fluid_dae_clamp_tangent(), fluid_dae_closable(), fluid_dae_conservation(), fluid_dae_constraints(), fluid_dae_extend(), fluid_dae_gates(), fluid_dae_integrate(), fluid_dae_integrate_hybrid(), fluid_dae_legs(), fluid_dae_metrics(), fluid_dae_newton(), fluid_dae_options(), fluid_dae_staging(), fluid_drift_jacobian(), fluid_moment_lyapunov(), fluid_moment_rates(), fluid_moment_terms(), line::fluid::FluidNonHyperbolicError::FluidNonHyperbolicError(), line::fluid::FluidDaeStaging::gated_by, line::fluid::FluidDaeSystem::gates, line::lang::GPS, line::fluid::FluidSolution::has_moments, line::lang::INF, line::fluid::FluidMomentTerms::is_ext, line::fluid::FluidDaeNewtonInfo::iters, line::fluid::FluidSolution::iters, line::fluid::FluidDaeOptions::maxstate, line::fluid::FluidOptions::method, line::fluid::FluidSolution::method, line::fluid::FluidSolution::moments, line::fluid::FluidDaeStaging::n, line::fluid::FluidDaeOptions::newton_max, line::fluid::FluidDaeSystem::nstate, line::fluid::FluidMomentTerms::nstate, line::NumericError::NumericError(), line::fluid::FluidMomentReport::outer_iters, line::fluid::FluidSolution::QN, line::fluid::FluidMomentReport::QStd, line::fluid::FluidMomentReport::QVar, line::fluid::FluidDaeLegs::rin, line::fluid::FluidSolution::RN, line::Matrix< T >::rows(), line::fluid::FluidDaeLegs::rup, line::fluid::FluidMomentTerms::S, line::fluid::FluidOdeSystem::sched, line::fluid::FluidMomentReport::Sigma, line::fluid::FluidClosure::sigma2, line::fluid::FluidMomentReport::sigma2, line::Matrix< T >::size(), solver_fluid_dae(), line::fluid::FluidDaeConstraints::staged, line::fluid::FluidMomentTerms::station_block, line::fluid::FluidDaeSystem::stg, line::fluid::FluidMomentTerms::sys, line::fluid::FluidDaeSystem::terms, line::fluid::FluidOptions::timespan_end, line::fluid::FluidSolution::TN, line::fluid::FluidSolution::UN, line::UnsupportedError::UnsupportedError(), line::fluid::FluidSolution::XN, and line::fluid::FluidSolution::xvec.

Referenced by solver_fluid_dae(), solver_fluid_dae_transient(), and solver_fluid_run_analyzer().

◆ solver_fluid_dae_transient()

template<class T>
std::vector< FluidTranPoint > line::fluid::solver_fluid_dae_transient ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
double t_end,
std::size_t points = 101,
const std::vector< double > & out_grid = std::vector<double>(),
const FluidDaeOptions & dopt_in = FluidDaeOptions() )

@@SolverFLD/getTranAvg for the DAE route: the metrics ALONG the trajectory.

The counterpart of solver_fluid_transient (solver_fluid.h), and different from it in exactly the way this method is different. That one forces the method to closing – the reference does the same, because matrix and the smoothed variants are steady-state devices – and integrates y' = f with LSODA, so population conservation holds only to integrator tolerance. This integrates M y' = f with a SINGULAR M, so conservation is an algebraic equation satisfied at every reported point rather than a quantity that drifts.

THE VARIANCE IS HELD AT ITS STATIONARY VALUE, which is the narrowing the port makes against solver_fluid_dae.m. The reference integrates the covariance alongside the mean when the closable state is small enough (nc <= dae_maxcov) and holds it above that; this always holds it. What is held is the variance the steady-state Newton converged to, so the trajectory and the table are read off ONE drift – and a held variance is what minnormal uses for the whole of its own transient anyway, so this is the reference's own fallback, not a different closure.

The steady state is solved FIRST and is not optional: it is where that variance comes from. A caller that wants only the trajectory still pays for the fixed point.

Definition at line 2527 of file fluid_dae.h.

References line::fluid::FluidMomentTerms::class_block, line::fluid::FluidSolution::closure, line::fluid::FluidClosure::cov, line::fluid::FluidMomentTerms::cov_idx, line::fluid::FluidDaeConstraints::empty(), fluid_dae_closable(), fluid_dae_conservation(), fluid_dae_constraints(), fluid_dae_extend(), fluid_dae_gates(), fluid_dae_integrate(), fluid_dae_integrate_hybrid(), fluid_dae_metrics(), fluid_dae_options(), fluid_dae_sigma_from(), fluid_dae_staging(), fluid_moment_terms(), line::InputError::InputError(), line::fluid::FluidDaeOptions::maxcov, line::fluid::FluidMomentTerms::nstate, line::fluid::FluidTranPoint::QN, line::fluid::FluidTranPoint::QVar, line::fluid::FluidClosure::sigma2, line::Matrix< T >::size(), solver_fluid_dae(), solver_fluid_dae_transient(), line::fluid::FluidMomentTerms::station_block, line::fluid::FluidTranPoint::t, line::fluid::FluidOptions::timespan_end, line::fluid::FluidTranPoint::TN, and line::fluid::FluidTranPoint::UN.

Referenced by solver_fluid_dae_transient(), and solver_fluid_run_transient().

◆ solver_fluid_export_odes()

template<class T>
std::string line::fluid::solver_fluid_export_odes ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
const std::string & notation = "scalar",
const std::string & model_name = "model" )

Port of @@SolverFLD/exportODEs.m at the runner's own method resolution, so the exported system is the one solver_fluid_run_analyzer would integrate.

rmf has no single exported drift – the cache decomposition rewrites the routing between passes, so there is one fluid system per sweep and none of them is "the" model's – and is refused by name rather than exported at the routing of whichever sweep happened to be last.

Definition at line 940 of file fluid_runner.h.

References fluid_export_odes(), line::fluid::FluidOptions::method, solver_fluid_export_odes(), and line::UnsupportedError::UnsupportedError().

Referenced by solver_fluid_export_odes().

◆ solver_fluid_kp()

template<class T>
FluidSolution line::fluid::solver_fluid_kp ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt )

Port of solver_fluid_kp.m: the steady table at the horizon.

Definition at line 894 of file fluid_kp.h.

References solver_fluid_kp(), and solver_fluid_kp_core().

Referenced by solver_fluid_kp(), and solver_fluid_run_analyzer().

◆ solver_fluid_kp_core()

template<class T>
FluidSolution line::fluid::solver_fluid_kp_core ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
FluidKpTransient * tran )

The Ko-Pender solve, returning both the steady table and the covariance trajectory so that neither has to integrate twice.

Definition at line 274 of file fluid_kp.h.

References Arrival, ArrivalPhase, line::LsodaOptions::atol, line::sn::ScheduleNominal< T >::breakpoints, line::fluid::KpEvent::c, line::fluid::KpBlock::cls, line::fluid::FluidSolution::CN, line::sn::ScheduleNominal< T >::cyclic, Departure, line::lang::EXT, line::LsodaSolution::final_state(), fluid_integrate_grid(), line::LsodaOptions::h_max, line::fluid::FluidSolution::has_moments, line::fluid::KpEvent::i, line::lang::INF, line::InputError::InputError(), line::fluid::KpEvent::ip, line::fluid::FluidSolution::iters, line::fluid::KpEvent::j, line::fluid::KpEvent::k, line::fluid::KpEvent::kind, line::fluid::KpEvent::l, line::fluid::FluidSolution::method, line::fluid::KpEvent::minus, line::fluid::FluidSolution::moments, line::fluid::KpEvent::n, line::fluid::KpBlock::nphases, line::fluid::KpEvent::off_dst, line::fluid::KpEvent::off_src, line::fluid::KpBlock::offset, line::fluid::FluidMomentReport::outer_iters, line::fluid::KpEvent::plus, line::fluid::FluidKpTransient::q, line::fluid::FluidSolution::QN, line::fluid::FluidMomentReport::QStd, line::fluid::FluidKpTransient::QVar, line::fluid::FluidMomentReport::QVar, line::fluid::FluidSolution::RN, Routed, line::LsodaOptions::rtol, line::sn::ScheduleNominal< T >::segD0, line::sn::ScheduleNominal< T >::segD1, ServicePhase, line::fluid::FluidKpTransient::Sigma, line::fluid::FluidMomentReport::Sigma, line::sn::sn_has_schedule(), line::sn::sn_schedule_nominal(), solver_fluid_kp_core(), line::fluid::KpBlock::station, line::fluid::FluidKpTransient::t, line::LsodaSolution::t, line::fluid::FluidSolution::TN, line::fluid::FluidSolution::UN, line::UnsupportedError::UnsupportedError(), line::fluid::KpEvent::weight, line::fluid::FluidSolution::XN, line::fluid::FluidSolution::xvec, line::LsodaSolution::y, and line::lang::GlobalConstants::Zero.

Referenced by solver_fluid_kp(), solver_fluid_kp_core(), and solver_fluid_tran_avg_var().

◆ solver_fluid_moments()

template<class T>
FluidSolution line::fluid::solver_fluid_moments ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt )

Port of solver_fluid_moments.m: the second-order fluid analysis backing minnormal and refined.

THE OUTER FIXED POINT IS OVER THE VARIANCE, not over the mean. Each sweep solves the mean at the current closure variance – through the ordinary closing integration, which is why the closure travels on FluidOptions – then solves the Lyapunov equation at that mean and reads a new variance off the covariance blocks. sigma2 alone is not enough to iterate on: the DPS and PS capacity share is a RATIO of coordinates, so closing it needs the covariance BETWEEN them, and the blocks are carried through the same fixed point and compared in the same convergence test – a block sum can converge while the off-diagonals the share closure reads are still moving.

THE METRICS ARE READ AT THE VARIANCE THE MEAN SOLVE USED, not at the variance that solve produced. Using the latter evaluates the rate functions away from their own fixed point and throughput stops balancing: with the variance held at zero for the mean solve, Tput came back 2.000000 at the delay against 1.949745 at the queue on Delay -> Queue(PS,c=2), N=6, a 2.5% gap in a closed cycle where the two must be equal. The two differ only within the outer tolerance once the fixed point has converged.

A DELAY'S VARIANCE IS KEPT FOR REPORTING AND EXCLUDED FROM THE DRIFT: there is no min() to close at an infinite server, so letting it in would perturb a term that is exactly linear.

Definition at line 947 of file fluid_moments.h.

References line::fluid::FluidMomentReport::class_block, line::fluid::FluidMomentTerms::class_block, line::fluid::FluidOptions::closure, line::fluid::FluidSolution::closure, line::fluid::FluidSolution::CN, line::fluid::FluidClosure::cov, line::lang::DPS, line::fluid::FluidMomentTerms::emap, line::Matrix< T >::empty(), line::fluid::FluidMomentTerms::ev_class, line::fluid::FluidMomentTerms::ev_is_departure, line::fluid::FluidMomentTerms::ev_station, line::lang::EXT, line::lang::FCFS, fluid_blend_closure(), fluid_drift_jacobian(), fluid_kink_stations(), fluid_moment_factors(), fluid_moment_lyapunov(), fluid_moment_rates(), fluid_moment_terms(), fluid_nudge_off_kink(), fluid_refine_meanfield(), line::fluid::FluidNonHyperbolicError::FluidNonHyperbolicError(), line::lang::GPS, line::fluid::FluidSolution::has_moments, line::lang::INF, line::util::LineConsole::iter(), line::fluid::FluidSolution::iters, line::fluid::FluidOdeSystem::lld, line::util::LineConsole::loop(), line::fluid::FluidOptions::method, line::fluid::FluidSolution::method, line::fluid::FluidMomentTerms::min_exact, line::fluid::FluidSolution::moments, line::fluid::FluidMomentTerms::nstate, line::fluid::FluidMomentReport::outer_iters, line::lang::PS, line::fluid::FluidSolution::QN, line::fluid::FluidMomentReport::QStd, line::fluid::FluidMomentReport::QVar, line::fluid::FluidMomentReport::refinement, line::fluid::FluidSolution::RN, line::Matrix< T >::rows(), line::fluid::FluidMomentTerms::S, line::fluid::FluidOdeSystem::sched, line::fluid::FluidMomentReport::Sigma, line::fluid::FluidClosure::sigma2, line::fluid::FluidMomentReport::sigma2, line::Matrix< T >::size(), solver_fluid_moments(), line::fluid::FluidMomentTerms::station_block, line::fluid::FluidMomentTerms::sys, line::fluid::FluidSolution::TN, line::fluid::FluidSolution::UN, line::UnsupportedError::UnsupportedError(), line::fluid::FluidSolution::XN, line::fluid::FluidSolution::xvec, and line::lang::GlobalConstants::Zero.

Referenced by solver_fld_cacheqn_analyzer(), solver_fluid_moments(), and solver_fluid_run_analyzer().

◆ solver_fluid_qsys()

template<class T>
FluidSolution line::fluid::solver_fluid_qsys ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
std::vector< FluidTranPoint > * traj = nullptr )

Solve a single-station model with one of the closed-form fluid limits.

The steady-state row of a TIME-VARYING model is the TIME AVERAGE over the horizon, which is what a stationary reader of a periodic system measures; the trajectory itself is available from solver_fluid_qsys_transient.

Definition at line 172 of file fluid_qsys.h.

References line::qsys::QsysMolResult< T >::arrivalRate, line::qsys::QsysMtginfResult< T >::arrivalRate, line::qsys::QsysTvFluidResult< T >::arrivalRate, line::qsys::QsysTvFluidResult< T >::B, line::api::PatienceHandles< T >::ccdf, line::fluid::FluidSolution::CN, line::lang::dist_to_map(), line::lang::Distrib< T >::has_map(), line::fluid::FluidSolution::iters, line::api::ArrivalRateFun< T >::lambda, line::mam::map_cdf(), line::qsys::QsysMolResult< T >::meanBusyMOL, line::qsys::QsysFluidAbandonResult< T >::meanNumber, line::qsys::QsysMtginfResult< T >::meanNumber, line::qsys::QsysTgaResult< T >::meanNumber, line::qsys::QsysTgaResult< T >::meanNumberInService, line::fluid::FluidSolution::method, line::api::PatienceHandles< T >::pdf, line::qsys::TvFluidOptions< T >::pdf, line::api::PatienceHandles< T >::present, line::qsys::QsysTgaResult< T >::probAbandon, line::fluid::FluidSolution::QN, line::fluid::FluidTranPoint::QN, line::qsys::qsys_ggingi_tga(), line::qsys::qsys_ggisgi_fluid(), line::qsys::qsys_gtmtst_fluid(), line::qsys::qsys_mtginf(), line::qsys::qsys_mtgs0_mol(), line::fluid::FluidSolution::RN, line::api::sn_arrival_rate_fun(), line::api::sn_patience_handles(), solver_fluid_qsys(), line::fluid::FluidTranPoint::t, line::qsys::QsysFluidAbandonResult< T >::throughput, line::qsys::QsysMolResult< T >::times, line::qsys::QsysMtginfResult< T >::times, line::qsys::QsysTvFluidResult< T >::times, line::fluid::FluidSolution::TN, line::fluid::FluidTranPoint::TN, line::fluid::FluidSolution::UN, line::fluid::FluidTranPoint::UN, line::UnsupportedError::UnsupportedError(), line::qsys::QsysFluidAbandonResult< T >::utilization, line::qsys::QsysTvFluidResult< T >::utilization, line::qsys::QsysTvFluidResult< T >::X, and line::fluid::FluidSolution::XN.

Referenced by solver_fluid_qsys(), solver_fluid_run_analyzer(), and solver_fluid_run_transient().

◆ solver_fluid_run_analyzer()

template<class T>
FluidSolution line::fluid::solver_fluid_run_analyzer ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
qn::NetworkStruct< T > * sn_out = nullptr,
qn::NetworkStruct< T > * refreshed_out = nullptr,
solvers::CacheMetrics< T > * cache_out = nullptr )

Port of @@SolverFLD/runAnalyzer.m: resolve the method, route to the function the reference routes to, correct once.

This is what a host should call. solver_fluid remains the port of solver_fluid_analyzer.m alone and stays reachable for a caller that wants one named method and no model-dependent resolution.

sn_out, when given, receives result.solverSpecific.sn: the struct the returned table was integrated on, which the FCFS refit may have re-fitted to a different phase count. Anything that reads FluidSolution::xvec afterwards must be handed THAT struct, because the vector is laid out by its phases.

refreshed_out, when given, receives the cache decomposition's own struct: the base one with the cache self-switch renormalized at the CONVERGED hit and miss split. It is DELIBERATELY NOT sn_out: that one is the inner, relabeled struct the ODE ran on and it lays out xvec, whereas this one is the caller's own topology carrying a solved quantity. Left untouched on every model with no cache, and on the cache branches that report no split.

cache_out, when given, receives the SAME split as a CacheMetrics, which is the form every other solver states it in (mva::AvgResult::cache). The refreshed struct alone is not enough for a caller: a host that solves through the CLI reads the hit and miss fractions back onto its own Cache node from that block, and MATLAB's CPPLINE.restoreCacheResults CLEARS the node when it is absent – which is how -s fluid came to report link()'s offered 1/2-1/2 on cache_replc_rr for a split it had converged to 0.5623/0.4377.

Definition at line 696 of file fluid_runner.h.

References line::solvers::cache_metrics_of_matrix(), line::qn::feature_gate(), fluid_check_method(), line::qn::fluid_feature_set(), line::fluid::FluidCacheqnSolution< T >::hitprob, line::fluid::FluidOptions::method, line::fluid::FluidCacheqnSolution< T >::missprob, line::fluid::FluidSolution::QN, line::fluid::FluidCacheqnSolution< T >::refreshed, line::fluid::FluidSolution::RN, line::fluid::FluidCacheqnSolution< T >::sol, solver_fld_cacheqn_analyzer(), solver_fluid(), solver_fluid_closing(), solver_fluid_dae(), solver_fluid_kp(), solver_fluid_moments(), solver_fluid_qsys(), solver_fluid_run_analyzer(), line::fluid::FluidSolution::TN, and line::fluid::FluidSolution::UN.

Referenced by line::NetworkSolver::avg_table(), solver_fluid_cdf_respt(), solver_fluid_run_analyzer(), and line::uq::uq_stage_solver().

◆ solver_fluid_run_transient()

template<class T>
std::vector< FluidTranPoint > line::fluid::solver_fluid_run_transient ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
std::size_t points = 101 )

-a tran / @@SolverFLD/getTranAvg with the method HONOURED, which is the one place the reference does not force closing.

solver_fluid_tran_avg integrates the first-order closing drift whatever opt.method says, and that IS the reference's rule for every steady-state device – matrix, pnorm, softmin and the rest have no trajectory of their own, so the reference substitutes one and warns. dae is the exception (getTranAvg.m:155-166): it integrates the closure itself, with conservation as an algebraic equation, so substituting the first-order drift for it would hand back a DIFFERENT method's trajectory under this method's name.

Every other method keeps the byte-identical path it had, gate included – this routes, it does not re-gate.

Definition at line 868 of file fluid_runner.h.

References line::qn::feature_gate(), fluid_default_horizon(), line::qn::fluid_feature_set(), line::fluid::FluidOptions::method, solver_fluid_dae_transient(), solver_fluid_qsys(), solver_fluid_run_transient(), and solver_fluid_tran_avg().

Referenced by solver_fluid_run_transient().

◆ solver_fluid_tran_avg()

template<class T>
std::vector< FluidTranPoint > line::fluid::solver_fluid_tran_avg ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
std::size_t points = 101 )

getTranAvg on the first-order closing drift, over that horizon.

THE METHOD IS NOT CONSULTED, as it is not in the reference: matrix, pnorm and the smoothed variants are steady-state devices with no trajectory of their own, so getTranAvg.m substitutes closing for them and warns. dae is the exception the reference itself makes, and solver_fluid_run_transient (fluid_runner.h) is where that routing lives – it cannot live here, because this header is below fluid_dae.h in the include order.

Definition at line 2281 of file solver_fluid.h.

References fluid_default_horizon(), solver_fluid_tran_avg(), and solver_fluid_transient().

Referenced by solver_fluid_run_transient(), solver_fluid_tran_avg(), and line::SolverFLD::tran_avg().

◆ solver_fluid_tran_avg_var()

template<class T>
FluidKpTransient line::fluid::solver_fluid_tran_avg_var ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt )

Port of @@SolverFLD/getTranAvgVar: the queue-length VARIANCE along the trajectory, per station and class, plus the full state covariance.

ONLY kp HAS THIS. Every other fluid method integrates the mean alone and carries no second moment, so asking them for one is an error rather than a misleading zero – and minnormal's covariance is STATIONARY, so it is not this quantity either. A caller that left the horizon unbounded gets one resolved the way getTranAvg resolves it, from the slowest rate in the model.

Definition at line 909 of file fluid_kp.h.

References line::fluid::FluidOptions::method, solver_fluid_kp_core(), solver_fluid_tran_avg_var(), and line::UnsupportedError::UnsupportedError().

Referenced by solver_fluid_tran_avg_var().

◆ solver_fluid_transient()

template<class T>
std::vector< FluidTranPoint > line::fluid::solver_fluid_transient ( const qn::NetworkStruct< T > & sn,
const FluidOptions & opt,
double t_end,
std::size_t points = 101,
const std::vector< double > & out_grid = std::vector<double>() )

Port of @@SolverFLD/getTranAvg: the metrics along the trajectory, not just at the fixed point.

The reference forces the method to closing for a transient (matrix and the smoothed variants are steady-state devices), and so does this. The drift is integrated once over [0, t_end] with the output grid handed to LSODA, and every point is passed through the SAME extraction the steady state uses, so the last point of a long enough run reproduces solver_fluid exactly.

A transient is only meaningful from a KNOWN starting state, so the default initial condition is used unless the caller supplies init_sol.

THE RATE SCHEDULE IS DETECTED HERE, as getTranAvg.m:76 detects it: a transient of a model with a non-homogeneous source follows the intensity exactly rather than its time average. A caller that has already filled opt.nhpp_sched keeps its own list, so the nominal can still be asked for.

out_grid REPLACES the uniform grid when a caller needs the trajectory at points of its own choosing. It exists because interpolating a trajectory cannot recover resolution it never had: SolverENV sums an exit average against a sojourn CDF, and over a horizon of 1e3 read through an Exp(1) clock a uniform 1001-point grid carries six samples where the whole weight lives. LSODA takes an arbitrary increasing output vector, so asking for the points that matter costs nothing and removes the interpolation entirely.

Definition at line 2179 of file solver_fluid.h.

References line::LsodaOptions::atol, fluid_closing_metrics(), fluid_detect_nhpp(), fluid_drift(), fluid_integrate_grid(), fluid_ode_system(), line::fluid::FluidOptions::init_sol, line::InputError::InputError(), line::fluid::FluidOdeSystem::layout, line::fluid::FluidOptions::nhpp_sched, line::fluid::FluidLayout::nstates, line::fluid::FluidTranPoint::QN, line::fluid::FluidOdeSystem::ratemult, line::LsodaOptions::rtol, solver_fluid_transient(), line::fluid::FluidTranPoint::t, line::LsodaSolution::t, line::fluid::FluidTranPoint::TN, line::fluid::FluidOptions::tol, line::fluid::FluidTranPoint::UN, line::UnsupportedError::UnsupportedError(), and line::LsodaSolution::y.

Referenced by solver_fluid_tran_avg(), and solver_fluid_transient().

◆ tbi_advance()

std::vector< double > line::fluid::tbi_advance ( const FluidOdeSystem & sys,
const std::vector< std::vector< std::size_t > > & cells,
const std::vector< double > & y0,
double t0,
double t1,
const TbiOptions & topt,
const LsodaOptions & lopt )
inline

◆ tbi_partition()

template<class T>
std::vector< std::vector< std::size_t > > line::fluid::tbi_partition ( const qn::NetworkStruct< T > & sn,
std::size_t cellsize = 5 )

Port of tbi_partition.m: stations grouped by routing coupling.

Definition at line 80 of file fluid_tbi.h.

References tbi_partition().

Referenced by tbi_partition().

Variable Documentation

◆ FLUID_MVN_POINTS

const std::size_t line::fluid::FLUID_MVN_POINTS = 4096

Lattice points per antithetic pair.

Definition at line 170 of file fluid_mvn_rectangle.h.

Referenced by fluid_mvn_rectangle().

◆ kFluidConservationTol

double line::fluid::kFluidConservationTol = 0.1
inlineconstexpr

Relative population drift that counts as having left the model.

Definition at line 62 of file fluid_conservation_guard.h.

Referenced by fluid_conservation_violation().