Files
kopalnia_2026/app/Services/WellAssessmentService.php
T
2026-09-03 12:21:17 +02:00

184 lines
7.5 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Services;
/**
* Oceny pracy układu pompowego (port func.php: wellEvaluation4_q / _HfQ_new /
* _Throt / _LineLoss + setRedYellowLimes / setYellowGreenLimes + sprawność).
* Skala m³/h (baza UAT bez ×60 - jak [[use-newest-methods]] / katalog pomp).
*
* Każda ocena zwraca ['zone' => 'green'|'yellow'|'red', 'text' => string]
* albo null gdy nie da się ocenić (brak danych) - jak legacy.
*/
class WellAssessmentService
{
private const T_OPT = 'Praca optymalna';
private const T_Q_YELLOW = 'Praca na granicy przedziału stosowalności';
private const T_Q_RED = 'Praca poza przedziałem stosowalności';
private const T_Q_NODATA = 'Brak danych w systemie';
private const T_HFQ_YELLOW = 'Charakterystyka pompy ulega odkształcaniu, możliwe przecieki na złączach rurociągu';
private const T_HFQ_RED = 'Odkształcona charakterystyka pompy, możliwa utrata szczelności rurociągu';
private const T_THROT_YELLOW = 'Wyraźne dławienie w układzie pompowym';
private const T_THROT_RED = 'Silne dławienie w układzie pompowym';
private const T_LOSS_YELLOW = 'Wyraźne straty liniowe w rurociągu';
private const T_LOSS_RED = 'Wysokie straty liniowe w rurociągu';
/** Przedział Q: porównanie wydajności do nominału. */
public function q(float $qn, ?float $q): ?array
{
if ($q === null || $q <= 0) {
return ['zone' => 'red', 'text' => self::T_Q_NODATA];
}
if (0.7 * $qn <= $q && $q <= 1.22 * $qn) {
return ['zone' => 'green', 'text' => self::T_OPT];
}
if ((0.55 * $qn <= $q && $q < 0.7 * $qn) || (1.22 * $qn < $q && $q <= 1.35 * $qn)) {
return ['zone' => 'yellow', 'text' => self::T_Q_YELLOW];
}
return ['zone' => 'red', 'text' => self::T_Q_RED];
}
/** H=f(Q): odchyłka wysokości podnoszenia ze stacji prób (HPS) od (Pp-Hh). */
public function hfq(?float $hps, ?float $pp, ?float $hh): ?array
{
if (! $pp || $hps === null || $hps == 0.0) {
return null;
}
$dev = ($hps - ($pp - $hh)) / $hps;
if ($dev >= -0.05 && $dev <= 0.05) {
return ['zone' => 'green', 'text' => self::T_OPT];
}
if (($dev < -0.05 && $dev >= -0.07) || ($dev > 0.05 && $dev <= 0.07)) {
return ['zone' => 'yellow', 'text' => self::T_HFQ_YELLOW];
}
return ['zone' => 'red', 'text' => self::T_HFQ_RED];
}
/** Dławienie: spadek P1-P2 na zasuwie dławiącej, progi wg zwierciadła HD. */
public function throttling(?float $hd, ?float $p1, ?float $p2): ?array
{
if ($hd === null || $p1 === null || $p2 === null) {
return null;
}
$hsa = $p1 - $p2;
$green = $this->pick($hd, [[50, 6], [100, 8], [200, 10], [350, 13], [450, 16]]);
$yellow = $this->pick($hd, [[50, 15], [100, 20], [200, 28], [350, 35], [450, 39]]);
if ($green === null) {
return null; // HD poza zakresem - brak oceny (jak legacy)
}
if ($hsa <= $green) {
return ['zone' => 'green', 'text' => self::T_OPT];
}
if ($hsa <= $yellow) {
return ['zone' => 'yellow', 'text' => self::T_THROT_YELLOW];
}
return ['zone' => 'red', 'text' => self::T_THROT_RED];
}
/** Straty liniowe: HSL = Pp - Lp - P1, progi wg średnicy rurociągu DR i Lp. */
public function lineLoss(?float $p1, ?float $pp, ?float $lp, ?float $dr): ?array
{
if (! $pp || $p1 === null || $lp === null || $dr === null) {
return null;
}
$hsl = $pp - $lp - $p1;
// Progi [green, yellow] zależne od DR. Każdy próg to pick() po Lp.
if ($dr > 0.04 && $dr < 0.145) {
$green = $this->pick($lp, [[50, 3.5], [100, 6.4], [200, 10], [300, 18], [450, 25]]);
$yellow = $this->pick($lp, [[50, 4.9], [100, 9.5], [200, 16], [300, 24], [450, 35]]);
// legacy: powyżej "yellow" -> wciąż YELLOW + wymóg weryfikacji p1/p2
$overText = self::T_LOSS_RED.'. Wymagana weryfikacja p1 i p2';
$overZone = 'yellow';
} elseif ($dr > 0.145 && $dr <= 0.160) {
$green = $this->pick($lp, [[50, 2.3], [100, 4.3], [200, 8.6], [300, 12], [450, 21]]);
$yellow = $this->pick($lp, [[50, 4.5], [100, 7.2], [200, 14], [300, 18], [450, 27]]);
$overText = self::T_LOSS_RED;
$overZone = 'red';
} elseif ($dr > 0.195 && $dr <= 0.215) {
$green = $this->pick($lp, [[50, 2], [100, 3], [200, 6.5], [300, 9.5], [450, 12]]);
$yellow = $this->pick($lp, [[50, 3], [100, 5.5], [200, 11], [300, 15], [450, 18]]);
$overText = self::T_LOSS_RED;
$overZone = 'red';
} else {
return null; // DR poza obsługiwanymi zakresami - brak oceny (jak legacy)
}
if ($green === null) {
return null;
}
if ($hsl <= $green) {
return ['zone' => 'green', 'text' => self::T_OPT];
}
if ($hsl <= $yellow) {
return ['zone' => 'yellow', 'text' => self::T_LOSS_YELLOW];
}
return ['zone' => $overZone, 'text' => $overText];
}
/** Granica czerwony/żółty energochłonności w funkcji Q (próg sprawności). */
public function redYellowLimit(float $q): float
{
return match (true) {
$q > 0 && $q <= 25 => 0.00210526315789473 * $q + 0.267368421052632,
$q > 25 && $q <= 40 => 0.00133333333333334 * $q + 0.286666666666667,
$q > 40 && $q <= 60 => 0.000749999999999997 * $q + 0.31,
$q > 60 && $q <= 260 => 0.000225000000000001 * $q + 0.3415,
$q > 260 && $q <= 500 => 4.16666666666662e-5 * $q + 0.389166666666667,
$q > 500 => 1.99999999999997e-5 * $q + 0.4,
default => 0.0,
};
}
/** Granica żółty/zielony energochłonności w funkcji Q. */
public function yellowGreenLimit(float $q): float
{
return match (true) {
$q > 0 && $q <= 8 => 0.00999999999999998 * $q + 0.3,
$q > 8 && $q <= 19 => 0.00545454545454544 * $q + 0.336363636363637,
$q > 19 && $q <= 38 => 0.00210526315789474 * $q + 0.4,
$q > 38 && $q <= 60 => 0.000454545454545451 * $q + 0.462727272727273,
$q > 60 && $q <= 500 => 0.000170454545454545 * $q + 0.479772727272727,
$q > 500 => 9.99999999999959e-6 * $q + 0.560000000000001,
default => 0.0,
};
}
/** Sprawność układu η = Q·(HD+P2) / (367·Pe). Pe<=0 traktujemy jak 1 (jak legacy). */
public function efficiency(?float $q, ?float $hd, ?float $p2, ?float $pe): ?float
{
if ($q === null || $hd === null || $p2 === null) {
return null;
}
$pe = ($pe === null || $pe <= 0) ? 1.0 : $pe;
return ($q * ($hd + $p2)) / (367 * $pe);
}
/** Strefa energochłonności: η>=yg zielona, >=ry żółta, inaczej czerwona. */
public function energyZone(float $eta, float $ry, float $yg): string
{
if ($eta >= $yg) {
return 'green';
}
return $eta >= $ry ? 'yellow' : 'red';
}
/** Wybór progu po przedziałach: [[górna granica wykluczna, wartość], ...]. */
private function pick(float $x, array $bands): ?float
{
foreach ($bands as [$limit, $value]) {
if ($x < $limit) {
return (float) $value;
}
}
return null;
}
}