#include "TestFixtures.h" #include "core/FlowSolver.h" #include "core/NetworkModel.h" #include #include using namespace diag; class TestSolver : public QObject { Q_OBJECT private slots: void init() { fixtures::fillRegistry(m_reg); delete m_model; m_model = new NetworkModel(&m_reg, this); } void chain_carriesSupplyThrough() { // source(10) -> pump -> consumer(10) const QUuid src = m_model->addNode(QStringLiteral("source"), {0, 0}); const QUuid pump = m_model->addNode(QStringLiteral("pump"), {200, 0}); const QUuid c = m_model->addNode(QStringLiteral("consumer"), {400, 0}); const QUuid e1 = m_model->addEdge(src, "out", pump, "in"); const QUuid e2 = m_model->addEdge(pump, "out", c, "in"); const FlowResult r = FlowSolver::solve(*m_model, QStringLiteral("water")); QVERIFY(r.ok); QVERIFY(qAbs(r.edgeFlow.value(e1) - 10.0) < 1e-6); QVERIFY(qAbs(r.edgeFlow.value(e2) - 10.0) < 1e-6); } void junction_conservesFlow() { // source(10) -> junction -> two consumers (arbitrary demands). const QUuid src = m_model->addNode(QStringLiteral("source"), {0, 0}); const QUuid j = m_model->addNode(QStringLiteral("junction"), {200, 0}); const QUuid c1 = m_model->addNode(QStringLiteral("consumer"), {400, -100}); const QUuid c2 = m_model->addNode(QStringLiteral("consumer"), {400, 100}); m_model->setNodeProperty(c1, "demand", 4.0); m_model->setNodeProperty(c2, "demand", 6.0); const QUuid eIn = m_model->addEdge(src, "out", j, "w"); const QUuid eOut1 = m_model->addEdge(j, "n", c1, "in"); const QUuid eOut2 = m_model->addEdge(j, "s", c2, "in"); const FlowResult r = FlowSolver::solve(*m_model, QStringLiteral("water")); QVERIFY(r.ok); const double in = r.edgeFlow.value(eIn); const double out = r.edgeFlow.value(eOut1) + r.edgeFlow.value(eOut2); QVERIFY(qAbs(in - out) < 1e-6); // Kirchhoff at the junction QVERIFY(qAbs(in - 10.0) < 1e-6); // all supply enters QVERIFY(qAbs(r.edgeFlow.value(eOut1) - 4.0) < 1e-6); QVERIFY(qAbs(r.edgeFlow.value(eOut2) - 6.0) < 1e-6); } void parallelPipes_widerCarriesMore() { // Two parallel pipes between two junctions; DN150 vs DN75. const QUuid src = m_model->addNode(QStringLiteral("source"), {0, 0}); const QUuid j1 = m_model->addNode(QStringLiteral("junction"), {200, 0}); const QUuid j2 = m_model->addNode(QStringLiteral("junction"), {400, 0}); const QUuid c = m_model->addNode(QStringLiteral("consumer"), {600, 0}); m_model->addEdge(src, "out", j1, "w"); const QUuid wide = m_model->addEdge(j1, "n", j2, "n"); const QUuid narrow = m_model->addEdge(j1, "s", j2, "s"); m_model->addEdge(j2, "e", c, "in"); m_model->setEdgeProperty(wide, "diameter", 150.0); m_model->setEdgeProperty(narrow, "diameter", 75.0); const FlowResult r = FlowSolver::solve(*m_model, QStringLiteral("water")); QVERIFY(r.ok); const double fWide = r.edgeFlow.value(wide); const double fNarrow = r.edgeFlow.value(narrow); QVERIFY(fWide > 0 && fNarrow > 0); QVERIFY(qAbs(fWide + fNarrow - 10.0) < 1e-6); // Conductance ~ d^4: ratio (150/75)^4 = 16. QVERIFY(qAbs(fWide / fNarrow - 16.0) < 1e-6); } void unbalancedInjections_areNormalized() { // Supply 10 vs demand 4: imbalance is spread, but flow stays conserved. const QUuid src = m_model->addNode(QStringLiteral("source"), {0, 0}); const QUuid c = m_model->addNode(QStringLiteral("consumer"), {200, 0}); m_model->setNodeProperty(c, "demand", 4.0); const QUuid e = m_model->addEdge(src, "out", c, "in"); const FlowResult r = FlowSolver::solve(*m_model, QStringLiteral("water")); QVERIFY(r.ok); QVERIFY(qAbs(r.edgeFlow.value(e) - 7.0) < 1e-6); // (10 + 4) / 2 } void otherRelation_untouched() { const QUuid src = m_model->addNode(QStringLiteral("source"), {0, 0}); const QUuid c = m_model->addNode(QStringLiteral("consumer"), {200, 0}); m_model->addEdge(src, "out", c, "in"); const FlowResult r = FlowSolver::solve(*m_model, QStringLiteral("power")); QVERIFY(r.ok); QVERIFY(r.edgeFlow.isEmpty()); } void apply_writesFlowsAndSignals() { const QUuid src = m_model->addNode(QStringLiteral("source"), {0, 0}); const QUuid c = m_model->addNode(QStringLiteral("consumer"), {200, 0}); const QUuid e = m_model->addEdge(src, "out", c, "in"); QSignalSpy spy(m_model, &NetworkModel::flowChanged); FlowSolver::apply(*m_model, FlowSolver::solve(*m_model, QStringLiteral("water"))); QCOMPARE(spy.count(), 1); QVERIFY(m_model->edge(e)->flowRate > 0); } private: TypeRegistry m_reg; NetworkModel* m_model = nullptr; }; QTEST_GUILESS_MAIN(TestSolver) #include "tst_solver.moc"