From 83221794da81b2144a192defdfd74ba6be9ef7da Mon Sep 17 00:00:00 2001
From: Even Solbraa <41290109+EvenSol@users.noreply.github.com>
Date: Sun, 17 Nov 2024 18:19:16 +0000
Subject: [PATCH 1/2] add extrapolate curve
---
.../equipment/compressor/Compressor.java | 6 +-
.../CompressorChartAlternativeMapLookup.java | 131 ++++++++++--------
...rChartAlternativeMapLookupExtrapolate.java | 84 +++++++++++
.../compressor/CompressorInterface.java | 15 ++
.../compressor/CompressorChartTest.java | 5 +-
5 files changed, 178 insertions(+), 63 deletions(-)
create mode 100644 src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookupExtrapolate.java
diff --git a/src/main/java/neqsim/process/equipment/compressor/Compressor.java b/src/main/java/neqsim/process/equipment/compressor/Compressor.java
index 8da288cc0..ac78022d0 100644
--- a/src/main/java/neqsim/process/equipment/compressor/Compressor.java
+++ b/src/main/java/neqsim/process/equipment/compressor/Compressor.java
@@ -1475,8 +1475,12 @@ public double getActualCompressionRatio() {
public void setCompressorChartType(String type) {
if (type.equals("simple")) {
compressorChart = new CompressorChart();
- } else {
+ } else if (type.equals("interpolate")) {
compressorChart = new CompressorChartAlternativeMapLookup();
+ } else if (type.equals("interpolate and extrapolate")) {
+ compressorChart = new CompressorChartAlternativeMapLookupExtrapolate();
+ } else {
+ compressorChart = new CompressorChart();
}
}
}
diff --git a/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookup.java b/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookup.java
index 7e4895eb5..72b983f1d 100644
--- a/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookup.java
+++ b/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookup.java
@@ -13,8 +13,10 @@
import neqsim.thermo.system.SystemSrkEos;
/**
- * This class is an implementation of the compressor chart class that uses Fan laws and "double"
- * interpolation to navigate the compressor map (as opposed to the standard class using reduced
+ * This class is an implementation of the compressor chart class that uses Fan
+ * laws and "double"
+ * interpolation to navigate the compressor map (as opposed to the standard
+ * class using reduced
* variables according to Fan laws).
*
* @author asmund
@@ -54,7 +56,8 @@ public class CompressorChartAlternativeMapLookup
* Constructor for CompressorChartAlternativeMapLookup.
*
*/
- public CompressorChartAlternativeMapLookup() {}
+ public CompressorChartAlternativeMapLookup() {
+ }
/** {@inheritDoc} */
@Override
@@ -128,8 +131,7 @@ public double getPolytropicHead(double flow, double speed) {
for (int i = 0; i < closestRefSpeeds.size(); i++) {
s = closestRefSpeeds.get(i);
// speedRatio = speed * gearRatio / s;
- PolynomialSplineFunction psf =
- asi.interpolate(getCurveAtRefSpeed(s).flow, getCurveAtRefSpeed(s).head);
+ PolynomialSplineFunction psf = asi.interpolate(getCurveAtRefSpeed(s).flow, getCurveAtRefSpeed(s).head);
tempHeads.add(psf.value(flow));
}
@@ -151,8 +153,8 @@ public double getPolytropicEfficiency(double flow, double speed) {
for (int i = 0; i < closestRefSpeeds.size(); i++) {
s = closestRefSpeeds.get(i);
- PolynomialSplineFunction psf =
- asi.interpolate(getCurveAtRefSpeed(s).flow, getCurveAtRefSpeed(s).polytropicEfficiency);
+ PolynomialSplineFunction psf = asi.interpolate(getCurveAtRefSpeed(s).flow,
+ getCurveAtRefSpeed(s).polytropicEfficiency);
tempEffs.add(psf.value(flow));
}
@@ -222,7 +224,7 @@ public void setGearRatio(double GR) {
* polytropicEfficiency.
*
*
- * @param flow a double
+ * @param flow a double
* @param speed a double
* @return a double
*/
@@ -273,7 +275,7 @@ public boolean checkSurge1(double flow, double head) {
* checkSurge2.
*
*
- * @param flow a double
+ * @param flow a double
* @param speed a double
* @return a boolean
*/
@@ -286,7 +288,7 @@ public boolean checkSurge2(double flow, double speed) {
* checkStoneWall.
*
*
- * @param flow a double
+ * @param flow a double
* @param speed a double
* @return a boolean
*/
@@ -366,53 +368,58 @@ public static void main(String[] args) {
// comp1.getAntiSurge().setActive(true);
comp1.setSpeed(11918);
- double[] chartConditions = new double[] {0.3, 1.0, 1.0, 1.0};
+ double[] chartConditions = new double[] { 0.3, 1.0, 1.0, 1.0 };
/*
- * double[] speed = new double[] { 1000.0, 2000.0, 3000.0, 4000.0 }; double[][] flow = new
- * double[][] { { 453.2, 600.0, 750.0, 800.0 }, { 453.2, 600.0, 750.0, 800.0 }, { 453.2, 600.0,
- * 750.0, 800.0 }, { 453.2, 600.0, 750.0, 800.0 } }; double[][] head = new double[][] { {
- * 10000.0, 9000.0, 8000.0, 7500.0 }, { 10000.0, 9000.0, 8000.0, 7500.0 }, { 10000.0, 9000.0,
- * 8000.0, 7500.0 }, { 10000.0, 9000.0, 8000.0, 7500.0 } }; double[][] polyEff = new double[][]
- * { { 90.0, 91.0, 89.0, 88.0 }, { 90.0, 91.0, 89.0, 88.0 }, { 90.0, 91.0, 89.0, 88.1 }, { 90.0,
+ * double[] speed = new double[] { 1000.0, 2000.0, 3000.0, 4000.0 }; double[][]
+ * flow = new
+ * double[][] { { 453.2, 600.0, 750.0, 800.0 }, { 453.2, 600.0, 750.0, 800.0 },
+ * { 453.2, 600.0,
+ * 750.0, 800.0 }, { 453.2, 600.0, 750.0, 800.0 } }; double[][] head = new
+ * double[][] { {
+ * 10000.0, 9000.0, 8000.0, 7500.0 }, { 10000.0, 9000.0, 8000.0, 7500.0 }, {
+ * 10000.0, 9000.0,
+ * 8000.0, 7500.0 }, { 10000.0, 9000.0, 8000.0, 7500.0 } }; double[][] polyEff =
+ * new double[][]
+ * { { 90.0, 91.0, 89.0, 88.0 }, { 90.0, 91.0, 89.0, 88.0 }, { 90.0, 91.0, 89.0,
+ * 88.1 }, { 90.0,
* 91.0, 89.0, 88.1 } };
*/
- double[] speed = new double[] {12913, 12298, 11683, 11098, 10453, 9224, 8609, 8200};
+ double[] speed = new double[] { 12913, 12298, 11683, 11098, 10453, 9224, 8609, 8200 };
double[][] flow = new double[][] {
- {2789.1285, 3174.0375, 3689.2288, 4179.4503, 4570.2768, 4954.7728, 5246.0329, 5661.0331},
- {2571.1753, 2943.7254, 3440.2675, 3837.4448, 4253.0898, 4668.6643, 4997.1926, 5387.4952},
- {2415.3793, 2763.0706, 3141.7095, 3594.7436, 4047.6467, 4494.1889, 4853.7353, 5138.7858},
- {2247.2043, 2799.7342, 3178.3428, 3656.1551, 4102.778, 4394.1591, 4648.3224, 4840.4998},
- {2072.8397, 2463.9483, 2836.4078, 3202.5266, 3599.6333, 3978.0203, 4257.0022, 4517.345},
- {1835.9552, 2208.455, 2618.1322, 2940.8034, 3244.7852, 3530.1279, 3753.3738, 3895.9746},
- {1711.3386, 1965.8848, 2356.9431, 2685.9247, 3008.5154, 3337.2855, 3591.5092},
- {1636.5807, 2002.8708, 2338.0319, 2642.1245, 2896.4894, 3113.6264, 3274.8764, 3411.2977}};
- double[][] head =
- new double[][] {{80.0375, 78.8934, 76.2142, 71.8678, 67.0062, 60.6061, 53.0499, 39.728},
- {72.2122, 71.8369, 68.9009, 65.8341, 60.7167, 54.702, 47.2749, 35.7471},
- {65.1576, 64.5253, 62.6118, 59.1619, 54.0455, 47.0059, 39.195, 31.6387},
- {58.6154, 56.9627, 54.6647, 50.4462, 44.4322, 38.4144, 32.9084, 28.8109},
- {52.3295, 51.0573, 49.5283, 46.3326, 42.3685, 37.2502, 31.4884, 25.598},
- {40.6578, 39.6416, 37.6008, 34.6603, 30.9503, 27.1116, 23.2713, 20.4546},
- {35.2705, 34.6359, 32.7228, 31.0645, 27.0985, 22.7482, 18.0113},
- {32.192, 31.1756, 29.1329, 26.833, 23.8909, 21.3324, 18.7726, 16.3403}};
+ { 2789.1285, 3174.0375, 3689.2288, 4179.4503, 4570.2768, 4954.7728, 5246.0329, 5661.0331 },
+ { 2571.1753, 2943.7254, 3440.2675, 3837.4448, 4253.0898, 4668.6643, 4997.1926, 5387.4952 },
+ { 2415.3793, 2763.0706, 3141.7095, 3594.7436, 4047.6467, 4494.1889, 4853.7353, 5138.7858 },
+ { 2247.2043, 2799.7342, 3178.3428, 3656.1551, 4102.778, 4394.1591, 4648.3224, 4840.4998 },
+ { 2072.8397, 2463.9483, 2836.4078, 3202.5266, 3599.6333, 3978.0203, 4257.0022, 4517.345 },
+ { 1835.9552, 2208.455, 2618.1322, 2940.8034, 3244.7852, 3530.1279, 3753.3738, 3895.9746 },
+ { 1711.3386, 1965.8848, 2356.9431, 2685.9247, 3008.5154, 3337.2855, 3591.5092 },
+ { 1636.5807, 2002.8708, 2338.0319, 2642.1245, 2896.4894, 3113.6264, 3274.8764, 3411.2977 } };
+ double[][] head = new double[][] { { 80.0375, 78.8934, 76.2142, 71.8678, 67.0062, 60.6061, 53.0499, 39.728 },
+ { 72.2122, 71.8369, 68.9009, 65.8341, 60.7167, 54.702, 47.2749, 35.7471 },
+ { 65.1576, 64.5253, 62.6118, 59.1619, 54.0455, 47.0059, 39.195, 31.6387 },
+ { 58.6154, 56.9627, 54.6647, 50.4462, 44.4322, 38.4144, 32.9084, 28.8109 },
+ { 52.3295, 51.0573, 49.5283, 46.3326, 42.3685, 37.2502, 31.4884, 25.598 },
+ { 40.6578, 39.6416, 37.6008, 34.6603, 30.9503, 27.1116, 23.2713, 20.4546 },
+ { 35.2705, 34.6359, 32.7228, 31.0645, 27.0985, 22.7482, 18.0113 },
+ { 32.192, 31.1756, 29.1329, 26.833, 23.8909, 21.3324, 18.7726, 16.3403 } };
double[][] polyEff = new double[][] {
- {77.2452238409573, 79.4154186459363, 80.737960012489, 80.5229826589649, 79.2210931638144,
- 75.4719133864634, 69.6034181197298, 58.7322388482707},
- {77.0107837113504, 79.3069974136389, 80.8941189021135, 80.7190194665918, 79.5313242980328,
- 75.5912622896367, 69.6846136362097, 60.0043057990909},
- {77.0043065299874, 79.1690958847856, 80.8038169975675, 80.6543975614197, 78.8532389102705,
- 73.6664774270613, 66.2735600426727, 57.671664571658},
- {77.0716623789093, 80.4629750233093, 81.1390811169072, 79.6374242667478, 75.380928428817,
- 69.5332969549779, 63.7997587622339, 58.8120614497758},
- {76.9705872525642, 79.8335492585324, 80.9468133671171, 80.5806471927835, 78.0462158225426,
- 73.0403707523258, 66.5572286338589, 59.8624822515064},
- {77.5063036680357, 80.2056198362559, 81.0339108025933, 79.6085962687939, 76.3814534404405,
- 70.8027503005902, 64.6437367160571, 60.5299349982342},
- {77.8175271586685, 80.065165942218, 81.0631362122632, 79.8955051771299, 76.1983240929369,
- 69.289982774309, 60.8567149372229},
- {78.0924334304045, 80.9353551568667, 80.7904437766234, 78.8639325223295, 75.2170936751143,
- 70.3105081673411, 65.5507568533569, 61.0391468300337}};
+ { 77.2452238409573, 79.4154186459363, 80.737960012489, 80.5229826589649, 79.2210931638144,
+ 75.4719133864634, 69.6034181197298, 58.7322388482707 },
+ { 77.0107837113504, 79.3069974136389, 80.8941189021135, 80.7190194665918, 79.5313242980328,
+ 75.5912622896367, 69.6846136362097, 60.0043057990909 },
+ { 77.0043065299874, 79.1690958847856, 80.8038169975675, 80.6543975614197, 78.8532389102705,
+ 73.6664774270613, 66.2735600426727, 57.671664571658 },
+ { 77.0716623789093, 80.4629750233093, 81.1390811169072, 79.6374242667478, 75.380928428817,
+ 69.5332969549779, 63.7997587622339, 58.8120614497758 },
+ { 76.9705872525642, 79.8335492585324, 80.9468133671171, 80.5806471927835, 78.0462158225426,
+ 73.0403707523258, 66.5572286338589, 59.8624822515064 },
+ { 77.5063036680357, 80.2056198362559, 81.0339108025933, 79.6085962687939, 76.3814534404405,
+ 70.8027503005902, 64.6437367160571, 60.5299349982342 },
+ { 77.8175271586685, 80.065165942218, 81.0631362122632, 79.8955051771299, 76.1983240929369,
+ 69.289982774309, 60.8567149372229 },
+ { 78.0924334304045, 80.9353551568667, 80.7904437766234, 78.8639325223295, 75.2170936751143,
+ 70.3105081673411, 65.5507568533569, 61.0391468300337 } };
// double[] chartConditions = new double[] { 0.3, 1.0, 1.0, 1.0 };
// double[] speed = new double[] { 13402.0 };
@@ -423,17 +430,20 @@ public static void main(String[] args) {
comp1.getCompressorChart().setCurves(chartConditions, speed, flow, head, polyEff);
// comp1.getCompressorChart().setHeadUnit("kJ/kg");
/*
- * double[] surgeflow = new double[] { 453.2, 550.0, 700.0, 800.0 }; double[] surgehead = new
+ * double[] surgeflow = new double[] { 453.2, 550.0, 700.0, 800.0 }; double[]
+ * surgehead = new
* double[] { 6000.0, 7000.0, 8000.0, 10000.0 };
- * comp1.getCompressorChart().getSurgeCurve().setCurve(chartConditions, surgeflow, surgehead);
+ * comp1.getCompressorChart().getSurgeCurve().setCurve(chartConditions,
+ * surgeflow, surgehead);
*
- * double[] stoneWallflow = new double[] { 923.2, 950.0, 980.0, 1000.0 }; double[] stoneWallHead
+ * double[] stoneWallflow = new double[] { 923.2, 950.0, 980.0, 1000.0 };
+ * double[] stoneWallHead
* = new double[] { 6000.0, 7000.0, 8000.0, 10000.0 };
- * comp1.getCompressorChart().getStoneWallCurve().setCurve(chartConditions, stoneWallflow,
+ * comp1.getCompressorChart().getStoneWallCurve().setCurve(chartConditions,
+ * stoneWallflow,
* stoneWallHead);
*/
- neqsim.process.processmodel.ProcessSystem operations =
- new neqsim.process.processmodel.ProcessSystem();
+ neqsim.process.processmodel.ProcessSystem operations = new neqsim.process.processmodel.ProcessSystem();
operations.add(stream_1);
operations.add(comp1);
operations.run();
@@ -506,8 +516,8 @@ public static int bisect_left(Double[] A, double x) {
* bisect_left.
*
*
- * @param A an array of {@link java.lang.Double} objects
- * @param x a double
+ * @param A an array of {@link java.lang.Double} objects
+ * @param x a double
* @param lo a int
* @param hi a int
* @return a int
@@ -538,7 +548,8 @@ public static int bisect_left(Double[] A, double x, int lo, int hi) {
/** {@inheritDoc} */
@Override
- public void plot() {}
+ public void plot() {
+ }
/** {@inheritDoc} */
@Override
diff --git a/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookupExtrapolate.java b/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookupExtrapolate.java
new file mode 100644
index 000000000..02f422d65
--- /dev/null
+++ b/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookupExtrapolate.java
@@ -0,0 +1,84 @@
+package neqsim.process.equipment.compressor;
+
+import java.util.ArrayList;
+import org.apache.commons.math3.analysis.interpolation.SplineInterpolator;
+import org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+/**
+ * This class is an implementation of the compressor chart class that uses Fan laws and "double"
+ * interpolation to navigate the compressor map (as opposed to the standard class using reduced
+ * variables according to Fan laws).
+ *
+ * @author asmund
+ * @version $Id: $Id
+ */
+public class CompressorChartAlternativeMapLookupExtrapolate
+ extends CompressorChartAlternativeMapLookup {
+ private static final long serialVersionUID = 1000;
+ static Logger logger = LogManager.getLogger(CompressorChartAlternativeMapLookupExtrapolate.class);
+
+
+ /**
+ *
+ * Constructor for CompressorChartAlternativeMapLookupExtrapolate.
+ *
+ */
+ public CompressorChartAlternativeMapLookupExtrapolate() {}
+
+ @Override
+ public double getPolytropicHead(double flow, double speed) {
+ ArrayList closestRefSpeeds = getClosestRefSpeeds(speed);
+ SplineInterpolator interpolator = new SplineInterpolator();
+ ArrayList interpolatedHeads = new ArrayList<>();
+
+ for (double refSpeed : closestRefSpeeds) {
+ CompressorCurve curve = getCurveAtRefSpeed(refSpeed);
+ PolynomialSplineFunction spline = interpolator.interpolate(curve.flow, curve.head);
+
+ double headValue = extrapolateOrInterpolate(flow, curve.flow, curve.head, spline);
+ interpolatedHeads.add(headValue);
+ }
+
+ return interpolatedHeads.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
+ }
+
+ @Override
+ public double getPolytropicEfficiency(double flow, double speed) {
+ ArrayList closestRefSpeeds = getClosestRefSpeeds(speed);
+ SplineInterpolator interpolator = new SplineInterpolator();
+ ArrayList interpolatedEfficiencies = new ArrayList<>();
+
+ for (double refSpeed : closestRefSpeeds) {
+ CompressorCurve curve = getCurveAtRefSpeed(refSpeed);
+ PolynomialSplineFunction spline =
+ interpolator.interpolate(curve.flow, curve.polytropicEfficiency);
+
+ double efficiencyValue =
+ extrapolateOrInterpolate(flow, curve.flow, curve.polytropicEfficiency, spline);
+ interpolatedEfficiencies.add(efficiencyValue);
+ }
+
+ return interpolatedEfficiencies.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
+ }
+
+ private double extrapolateOrInterpolate(double flow, double[] flowData, double[] valueData,
+ PolynomialSplineFunction spline) {
+ double[] knots = spline.getKnots();
+ if (flow < knots[0]) {
+ // Linear extrapolation below range using the first two points
+ double slope = (valueData[1] - valueData[0]) / (flowData[1] - flowData[0]);
+ return valueData[0] + slope * (flow - flowData[0]);
+ } else if (flow > knots[knots.length - 1]) {
+ // Linear extrapolation above range using the last two points
+ int last = flowData.length - 1;
+ double slope =
+ (valueData[last] - valueData[last - 1]) / (flowData[last] - flowData[last - 1]);
+ return valueData[last] + slope * (flow - flowData[last]);
+ }
+ // Interpolate within the range
+ return spline.value(flow);
+ }
+
+}
diff --git a/src/main/java/neqsim/process/equipment/compressor/CompressorInterface.java b/src/main/java/neqsim/process/equipment/compressor/CompressorInterface.java
index 184862452..103bd51e2 100644
--- a/src/main/java/neqsim/process/equipment/compressor/CompressorInterface.java
+++ b/src/main/java/neqsim/process/equipment/compressor/CompressorInterface.java
@@ -142,4 +142,19 @@ public interface CompressorInterface extends ProcessEquipmentInterface, TwoPortI
*
*/
public void setCompressorChartType(String type);
+
+ /**
+ *
+ * isSurge.
+ *
+ *
+ * @return a boolean
+ */
+ default boolean isSurge() {
+ if (getDistanceToSurge() < 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
}
diff --git a/src/test/java/neqsim/process/equipment/compressor/CompressorChartTest.java b/src/test/java/neqsim/process/equipment/compressor/CompressorChartTest.java
index e0c0b8c9b..e07867f55 100644
--- a/src/test/java/neqsim/process/equipment/compressor/CompressorChartTest.java
+++ b/src/test/java/neqsim/process/equipment/compressor/CompressorChartTest.java
@@ -199,7 +199,7 @@ public void runCurveTest() {
testFluid.setTemperature(29.96, "C");
testFluid.setPressure(75.73, "bara");
- testFluid.setTotalFlowRate(559401.418270102, "kg/hr");
+ testFluid.setTotalFlowRate(359401.418270102, "kg/hr");
Stream stream_1 = new Stream("Stream1", testFluid);
stream_1.run();
@@ -207,7 +207,7 @@ public void runCurveTest() {
stream_1.getFluid().prettyPrint();
Compressor comp1 = new Compressor("compressor 1", stream_1);
- //comp1.setCompressorChartType("interpolate");
+ comp1.setCompressorChartType("interpolate and extrapolate");
comp1.setUsePolytropicCalc(true);
comp1.setSpeed(8765);
@@ -262,6 +262,7 @@ public void runCurveTest() {
System.out.println("surge flow rate margin " + comp1.getSurgeFlowRateMargin());
System.out.println("surge flow rate " + comp1.getSurgeFlowRate());
System.out.println("duty " + comp1.getPower("MW"));
+ System.out.println("surge " + comp1.isSurge());
}
}
From 0b5d7e638b85c7e0b0b32be1c37560125040be74 Mon Sep 17 00:00:00 2001
From: Even Solbraa <41290109+EvenSol@users.noreply.github.com>
Date: Sun, 17 Nov 2024 20:16:12 +0000
Subject: [PATCH 2/2] update test
---
.../CompressorChartAlternativeMapLookup.java | 277 +++++++++++++-----
...rChartAlternativeMapLookupExtrapolate.java | 169 +++++++++--
.../compressor/CompressorChartTest.java | 27 +-
3 files changed, 371 insertions(+), 102 deletions(-)
diff --git a/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookup.java b/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookup.java
index 72b983f1d..8aa221c57 100644
--- a/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookup.java
+++ b/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookup.java
@@ -13,12 +13,115 @@
import neqsim.thermo.system.SystemSrkEos;
/**
- * This class is an implementation of the compressor chart class that uses Fan
- * laws and "double"
- * interpolation to navigate the compressor map (as opposed to the standard
- * class using reduced
+ * This class is an implementation of the compressor chart class that uses Fan laws and "double"
+ * interpolation to navigate the compressor map (as opposed to the standard class using reduced
* variables according to Fan laws).
- *
+ *
+ *
+ * The class provides methods to add compressor curves, set reference conditions, and calculate
+ * polytropic head and efficiency based on flow and speed. It also includes methods to check surge
+ * and stone wall conditions.
+ *
+ *
+ *
+ * The main method demonstrates the usage of the class by creating a test fluid, setting up a
+ * compressor, and running a process system.
+ *
+ *
+ *
+ * The class implements the CompressorChartInterface and is Serializable.
+ *
+ *
+ *
+ * Fields:
+ *
+ *
+ * - serialVersionUID: A unique identifier for serialization.
+ * - logger: Logger instance for logging.
+ * - chartValues: List of compressor curves.
+ * - chartSpeeds: List of chart speeds.
+ * - surgeCurve: Surge curve instance.
+ * - stoneWallCurve: Stone wall curve instance.
+ * - isSurge: Flag indicating if the compressor is in surge condition.
+ * - isStoneWall: Flag indicating if the compressor is in stone wall condition.
+ * - refMW: Reference molecular weight.
+ * - headUnit: Unit of the head (default is "meter").
+ * - useCompressorChart: Flag indicating if the compressor chart is used.
+ * - refTemperature: Reference temperature.
+ * - refPressure: Reference pressure.
+ * - referenceSpeed: Reference speed (default is 1000.0).
+ * - refZ: Reference compressibility factor.
+ * - useRealKappa: Flag indicating if real kappa is used.
+ * - chartConditions: Array of chart conditions.
+ * - reducedHeadFitter: Weighted observed points for reduced head fitting.
+ * - reducedFlowFitter: Weighted observed points for reduced flow fitting.
+ * - fanLawCorrectionFitter: Weighted observed points for fan law correction fitting.
+ * - reducedPolytropicEfficiencyFitter: Weighted observed points for reduced polytropic efficiency
+ * fitting.
+ * - reducedHeadFitterFunc: Polynomial function for reduced head fitting.
+ * - reducedPolytropicEfficiencyFunc: Polynomial function for reduced polytropic efficiency
+ * fitting.
+ * - fanLawCorrectionFunc: Polynomial function for fan law correction fitting.
+ * - gearRatio: Gear ratio (default is 1.0).
+ *
+ *
+ *
+ * Methods:
+ *
+ *
+ * - addCurve: Adds a compressor curve.
+ * - setCurves: Sets multiple compressor curves.
+ * - getClosestRefSpeeds: Gets the closest reference speeds to a given speed.
+ * - getPolytropicHead: Calculates the polytropic head based on flow and speed.
+ * - getPolytropicEfficiency: Calculates the polytropic efficiency based on flow and speed.
+ * - addSurgeCurve: Adds a surge curve.
+ * - getCurveAtRefSpeed: Gets the compressor curve at a given reference speed.
+ * - getGearRatio: Gets the gear ratio.
+ * - setGearRatio: Sets the gear ratio.
+ * - polytropicEfficiency: Calculates the polytropic efficiency (returns a constant value of
+ * 100.0).
+ * - getSpeed: Calculates the speed based on flow and head.
+ * - checkSurge1: Checks if the compressor is in surge condition (method 1).
+ * - checkSurge2: Checks if the compressor is in surge condition (method 2).
+ * - checkStoneWall: Checks if the compressor is in stone wall condition.
+ * - setReferenceConditions: Sets the reference conditions.
+ * - getSurgeCurve: Gets the surge curve.
+ * - setSurgeCurve: Sets the surge curve.
+ * - getStoneWallCurve: Gets the stone wall curve.
+ * - setStoneWallCurve: Sets the stone wall curve.
+ * - main: Main method demonstrating the usage of the class.
+ * - isUseCompressorChart: Checks if the compressor chart is used.
+ * - setUseCompressorChart: Sets the flag indicating if the compressor chart is used.
+ * - getHeadUnit: Gets the unit of the head.
+ * - setHeadUnit: Sets the unit of the head.
+ * - useRealKappa: Checks if real kappa is used.
+ * - setUseRealKappa: Sets the flag indicating if real kappa is used.
+ * - bisect_left: Helper method for binary search (overloaded).
+ * - plot: Placeholder method for plotting (not implemented).
+ * - getFlow: Placeholder method for getting flow (not implemented).
+ *
+ *
+ *
+ * Exceptions:
+ *
+ *
+ * - RuntimeException: Thrown for invalid input or unsupported head unit value.
+ *
+ *
+ * @see neqsim.process.equipment.compressor.CompressorChartInterface
+ * @see java.io.Serializable
+ * @see org.apache.commons.math3.analysis.interpolation.SplineInterpolator
+ * @see org.apache.commons.math3.analysis.polynomials.PolynomialFunction
+ * @see org.apache.commons.math3.analysis.polynomials.PolynomialSplineFunction
+ * @see org.apache.commons.math3.fitting.WeightedObservedPoints
+ * @see org.apache.logging.log4j.LogManager
+ * @see org.apache.logging.log4j.Logger
+ * @see neqsim.process.equipment.stream.Stream
+ * @see neqsim.thermo.system.SystemInterface
+ * @see neqsim.thermo.system.SystemSrkEos
+ */
+
+/**
* @author asmund
* @version $Id: $Id
*/
@@ -56,8 +159,7 @@ public class CompressorChartAlternativeMapLookup
* Constructor for CompressorChartAlternativeMapLookup.
*
*/
- public CompressorChartAlternativeMapLookup() {
- }
+ public CompressorChartAlternativeMapLookup() {}
/** {@inheritDoc} */
@Override
@@ -68,6 +170,16 @@ public void addCurve(double speed, double[] flow, double[] head, double[] polytr
}
/** {@inheritDoc} */
+ /**
+ * Sets the compressor curves based on the provided chart conditions, speed, flow, head, and
+ * polytropic efficiency values.
+ *
+ * @param chartConditions an array of chart conditions (not used in this method)
+ * @param speed an array of speed values for the compressor
+ * @param flow a 2D array of flow values corresponding to each speed
+ * @param head a 2D array of head values corresponding to each speed
+ * @param polyEff a 2D array of polytropic efficiency values corresponding to each speed
+ */
@Override
public void setCurves(double[] chartConditions, double[] speed, double[][] flow, double[][] head,
double[][] polyEff) {
@@ -88,6 +200,16 @@ public void setCurves(double[] chartConditions, double[] speed, double[][] flow,
* @param speed a double
* @return a {@link java.util.ArrayList} object
*/
+ /**
+ * Returns a list of the closest reference speeds to the given speed. If the given speed matches a
+ * reference speed, only that speed is returned. If the given speed is between two reference
+ * speeds, both are returned. If the given speed is lower than the lowest reference speed, the
+ * lowest reference speed is returned. If the given speed is higher than the highest reference
+ * speed, the highest reference speed is returned.
+ *
+ * @param speed the speed to find the closest reference speeds for
+ * @return an ArrayList of the closest reference speeds
+ */
public ArrayList getClosestRefSpeeds(double speed) {
ArrayList closestRefSpeeds = new ArrayList();
Double[] speedArray = new Double[chartSpeeds.size()];
@@ -119,6 +241,16 @@ public ArrayList getClosestRefSpeeds(double speed) {
}
/** {@inheritDoc} */
+ /**
+ * Calculates the polytropic head for a given flow and speed.
+ *
+ * This method interpolates the polytropic head values from reference speeds closest to the given
+ * speed and averages them to estimate the polytropic head at the specified flow and speed.
+ *
+ * @param flow the flow rate for which the polytropic head is to be calculated
+ * @param speed the speed at which the polytropic head is to be calculated
+ * @return the calculated polytropic head
+ */
@Override
public double getPolytropicHead(double flow, double speed) {
ArrayList closestRefSpeeds = new ArrayList();
@@ -131,7 +263,8 @@ public double getPolytropicHead(double flow, double speed) {
for (int i = 0; i < closestRefSpeeds.size(); i++) {
s = closestRefSpeeds.get(i);
// speedRatio = speed * gearRatio / s;
- PolynomialSplineFunction psf = asi.interpolate(getCurveAtRefSpeed(s).flow, getCurveAtRefSpeed(s).head);
+ PolynomialSplineFunction psf =
+ asi.interpolate(getCurveAtRefSpeed(s).flow, getCurveAtRefSpeed(s).head);
tempHeads.add(psf.value(flow));
}
@@ -143,6 +276,15 @@ public double getPolytropicHead(double flow, double speed) {
}
/** {@inheritDoc} */
+ /**
+ * Calculates the polytropic efficiency of the compressor for a given flow and speed. The method
+ * interpolates the efficiency values from reference speed curves and averages them to estimate
+ * the efficiency at the specified conditions.
+ *
+ * @param flow the flow rate through the compressor
+ * @param speed the rotational speed of the compressor
+ * @return the polytropic efficiency at the specified flow and speed
+ */
@Override
public double getPolytropicEfficiency(double flow, double speed) {
ArrayList closestRefSpeeds = new ArrayList();
@@ -153,8 +295,8 @@ public double getPolytropicEfficiency(double flow, double speed) {
for (int i = 0; i < closestRefSpeeds.size(); i++) {
s = closestRefSpeeds.get(i);
- PolynomialSplineFunction psf = asi.interpolate(getCurveAtRefSpeed(s).flow,
- getCurveAtRefSpeed(s).polytropicEfficiency);
+ PolynomialSplineFunction psf =
+ asi.interpolate(getCurveAtRefSpeed(s).flow, getCurveAtRefSpeed(s).polytropicEfficiency);
tempEffs.add(psf.value(flow));
}
@@ -224,7 +366,7 @@ public void setGearRatio(double GR) {
* polytropicEfficiency.
*
*
- * @param flow a double
+ * @param flow a double
* @param speed a double
* @return a double
*/
@@ -275,7 +417,7 @@ public boolean checkSurge1(double flow, double head) {
* checkSurge2.
*
*
- * @param flow a double
+ * @param flow a double
* @param speed a double
* @return a boolean
*/
@@ -288,7 +430,7 @@ public boolean checkSurge2(double flow, double speed) {
* checkStoneWall.
*
*
- * @param flow a double
+ * @param flow a double
* @param speed a double
* @return a boolean
*/
@@ -368,58 +510,53 @@ public static void main(String[] args) {
// comp1.getAntiSurge().setActive(true);
comp1.setSpeed(11918);
- double[] chartConditions = new double[] { 0.3, 1.0, 1.0, 1.0 };
+ double[] chartConditions = new double[] {0.3, 1.0, 1.0, 1.0};
/*
- * double[] speed = new double[] { 1000.0, 2000.0, 3000.0, 4000.0 }; double[][]
- * flow = new
- * double[][] { { 453.2, 600.0, 750.0, 800.0 }, { 453.2, 600.0, 750.0, 800.0 },
- * { 453.2, 600.0,
- * 750.0, 800.0 }, { 453.2, 600.0, 750.0, 800.0 } }; double[][] head = new
- * double[][] { {
- * 10000.0, 9000.0, 8000.0, 7500.0 }, { 10000.0, 9000.0, 8000.0, 7500.0 }, {
- * 10000.0, 9000.0,
- * 8000.0, 7500.0 }, { 10000.0, 9000.0, 8000.0, 7500.0 } }; double[][] polyEff =
- * new double[][]
- * { { 90.0, 91.0, 89.0, 88.0 }, { 90.0, 91.0, 89.0, 88.0 }, { 90.0, 91.0, 89.0,
- * 88.1 }, { 90.0,
+ * double[] speed = new double[] { 1000.0, 2000.0, 3000.0, 4000.0 }; double[][] flow = new
+ * double[][] { { 453.2, 600.0, 750.0, 800.0 }, { 453.2, 600.0, 750.0, 800.0 }, { 453.2, 600.0,
+ * 750.0, 800.0 }, { 453.2, 600.0, 750.0, 800.0 } }; double[][] head = new double[][] { {
+ * 10000.0, 9000.0, 8000.0, 7500.0 }, { 10000.0, 9000.0, 8000.0, 7500.0 }, { 10000.0, 9000.0,
+ * 8000.0, 7500.0 }, { 10000.0, 9000.0, 8000.0, 7500.0 } }; double[][] polyEff = new double[][]
+ * { { 90.0, 91.0, 89.0, 88.0 }, { 90.0, 91.0, 89.0, 88.0 }, { 90.0, 91.0, 89.0, 88.1 }, { 90.0,
* 91.0, 89.0, 88.1 } };
*/
- double[] speed = new double[] { 12913, 12298, 11683, 11098, 10453, 9224, 8609, 8200 };
+ double[] speed = new double[] {12913, 12298, 11683, 11098, 10453, 9224, 8609, 8200};
double[][] flow = new double[][] {
- { 2789.1285, 3174.0375, 3689.2288, 4179.4503, 4570.2768, 4954.7728, 5246.0329, 5661.0331 },
- { 2571.1753, 2943.7254, 3440.2675, 3837.4448, 4253.0898, 4668.6643, 4997.1926, 5387.4952 },
- { 2415.3793, 2763.0706, 3141.7095, 3594.7436, 4047.6467, 4494.1889, 4853.7353, 5138.7858 },
- { 2247.2043, 2799.7342, 3178.3428, 3656.1551, 4102.778, 4394.1591, 4648.3224, 4840.4998 },
- { 2072.8397, 2463.9483, 2836.4078, 3202.5266, 3599.6333, 3978.0203, 4257.0022, 4517.345 },
- { 1835.9552, 2208.455, 2618.1322, 2940.8034, 3244.7852, 3530.1279, 3753.3738, 3895.9746 },
- { 1711.3386, 1965.8848, 2356.9431, 2685.9247, 3008.5154, 3337.2855, 3591.5092 },
- { 1636.5807, 2002.8708, 2338.0319, 2642.1245, 2896.4894, 3113.6264, 3274.8764, 3411.2977 } };
- double[][] head = new double[][] { { 80.0375, 78.8934, 76.2142, 71.8678, 67.0062, 60.6061, 53.0499, 39.728 },
- { 72.2122, 71.8369, 68.9009, 65.8341, 60.7167, 54.702, 47.2749, 35.7471 },
- { 65.1576, 64.5253, 62.6118, 59.1619, 54.0455, 47.0059, 39.195, 31.6387 },
- { 58.6154, 56.9627, 54.6647, 50.4462, 44.4322, 38.4144, 32.9084, 28.8109 },
- { 52.3295, 51.0573, 49.5283, 46.3326, 42.3685, 37.2502, 31.4884, 25.598 },
- { 40.6578, 39.6416, 37.6008, 34.6603, 30.9503, 27.1116, 23.2713, 20.4546 },
- { 35.2705, 34.6359, 32.7228, 31.0645, 27.0985, 22.7482, 18.0113 },
- { 32.192, 31.1756, 29.1329, 26.833, 23.8909, 21.3324, 18.7726, 16.3403 } };
+ {2789.1285, 3174.0375, 3689.2288, 4179.4503, 4570.2768, 4954.7728, 5246.0329, 5661.0331},
+ {2571.1753, 2943.7254, 3440.2675, 3837.4448, 4253.0898, 4668.6643, 4997.1926, 5387.4952},
+ {2415.3793, 2763.0706, 3141.7095, 3594.7436, 4047.6467, 4494.1889, 4853.7353, 5138.7858},
+ {2247.2043, 2799.7342, 3178.3428, 3656.1551, 4102.778, 4394.1591, 4648.3224, 4840.4998},
+ {2072.8397, 2463.9483, 2836.4078, 3202.5266, 3599.6333, 3978.0203, 4257.0022, 4517.345},
+ {1835.9552, 2208.455, 2618.1322, 2940.8034, 3244.7852, 3530.1279, 3753.3738, 3895.9746},
+ {1711.3386, 1965.8848, 2356.9431, 2685.9247, 3008.5154, 3337.2855, 3591.5092},
+ {1636.5807, 2002.8708, 2338.0319, 2642.1245, 2896.4894, 3113.6264, 3274.8764, 3411.2977}};
+ double[][] head =
+ new double[][] {{80.0375, 78.8934, 76.2142, 71.8678, 67.0062, 60.6061, 53.0499, 39.728},
+ {72.2122, 71.8369, 68.9009, 65.8341, 60.7167, 54.702, 47.2749, 35.7471},
+ {65.1576, 64.5253, 62.6118, 59.1619, 54.0455, 47.0059, 39.195, 31.6387},
+ {58.6154, 56.9627, 54.6647, 50.4462, 44.4322, 38.4144, 32.9084, 28.8109},
+ {52.3295, 51.0573, 49.5283, 46.3326, 42.3685, 37.2502, 31.4884, 25.598},
+ {40.6578, 39.6416, 37.6008, 34.6603, 30.9503, 27.1116, 23.2713, 20.4546},
+ {35.2705, 34.6359, 32.7228, 31.0645, 27.0985, 22.7482, 18.0113},
+ {32.192, 31.1756, 29.1329, 26.833, 23.8909, 21.3324, 18.7726, 16.3403}};
double[][] polyEff = new double[][] {
- { 77.2452238409573, 79.4154186459363, 80.737960012489, 80.5229826589649, 79.2210931638144,
- 75.4719133864634, 69.6034181197298, 58.7322388482707 },
- { 77.0107837113504, 79.3069974136389, 80.8941189021135, 80.7190194665918, 79.5313242980328,
- 75.5912622896367, 69.6846136362097, 60.0043057990909 },
- { 77.0043065299874, 79.1690958847856, 80.8038169975675, 80.6543975614197, 78.8532389102705,
- 73.6664774270613, 66.2735600426727, 57.671664571658 },
- { 77.0716623789093, 80.4629750233093, 81.1390811169072, 79.6374242667478, 75.380928428817,
- 69.5332969549779, 63.7997587622339, 58.8120614497758 },
- { 76.9705872525642, 79.8335492585324, 80.9468133671171, 80.5806471927835, 78.0462158225426,
- 73.0403707523258, 66.5572286338589, 59.8624822515064 },
- { 77.5063036680357, 80.2056198362559, 81.0339108025933, 79.6085962687939, 76.3814534404405,
- 70.8027503005902, 64.6437367160571, 60.5299349982342 },
- { 77.8175271586685, 80.065165942218, 81.0631362122632, 79.8955051771299, 76.1983240929369,
- 69.289982774309, 60.8567149372229 },
- { 78.0924334304045, 80.9353551568667, 80.7904437766234, 78.8639325223295, 75.2170936751143,
- 70.3105081673411, 65.5507568533569, 61.0391468300337 } };
+ {77.2452238409573, 79.4154186459363, 80.737960012489, 80.5229826589649, 79.2210931638144,
+ 75.4719133864634, 69.6034181197298, 58.7322388482707},
+ {77.0107837113504, 79.3069974136389, 80.8941189021135, 80.7190194665918, 79.5313242980328,
+ 75.5912622896367, 69.6846136362097, 60.0043057990909},
+ {77.0043065299874, 79.1690958847856, 80.8038169975675, 80.6543975614197, 78.8532389102705,
+ 73.6664774270613, 66.2735600426727, 57.671664571658},
+ {77.0716623789093, 80.4629750233093, 81.1390811169072, 79.6374242667478, 75.380928428817,
+ 69.5332969549779, 63.7997587622339, 58.8120614497758},
+ {76.9705872525642, 79.8335492585324, 80.9468133671171, 80.5806471927835, 78.0462158225426,
+ 73.0403707523258, 66.5572286338589, 59.8624822515064},
+ {77.5063036680357, 80.2056198362559, 81.0339108025933, 79.6085962687939, 76.3814534404405,
+ 70.8027503005902, 64.6437367160571, 60.5299349982342},
+ {77.8175271586685, 80.065165942218, 81.0631362122632, 79.8955051771299, 76.1983240929369,
+ 69.289982774309, 60.8567149372229},
+ {78.0924334304045, 80.9353551568667, 80.7904437766234, 78.8639325223295, 75.2170936751143,
+ 70.3105081673411, 65.5507568533569, 61.0391468300337}};
// double[] chartConditions = new double[] { 0.3, 1.0, 1.0, 1.0 };
// double[] speed = new double[] { 13402.0 };
@@ -430,20 +567,17 @@ public static void main(String[] args) {
comp1.getCompressorChart().setCurves(chartConditions, speed, flow, head, polyEff);
// comp1.getCompressorChart().setHeadUnit("kJ/kg");
/*
- * double[] surgeflow = new double[] { 453.2, 550.0, 700.0, 800.0 }; double[]
- * surgehead = new
+ * double[] surgeflow = new double[] { 453.2, 550.0, 700.0, 800.0 }; double[] surgehead = new
* double[] { 6000.0, 7000.0, 8000.0, 10000.0 };
- * comp1.getCompressorChart().getSurgeCurve().setCurve(chartConditions,
- * surgeflow, surgehead);
+ * comp1.getCompressorChart().getSurgeCurve().setCurve(chartConditions, surgeflow, surgehead);
*
- * double[] stoneWallflow = new double[] { 923.2, 950.0, 980.0, 1000.0 };
- * double[] stoneWallHead
+ * double[] stoneWallflow = new double[] { 923.2, 950.0, 980.0, 1000.0 }; double[] stoneWallHead
* = new double[] { 6000.0, 7000.0, 8000.0, 10000.0 };
- * comp1.getCompressorChart().getStoneWallCurve().setCurve(chartConditions,
- * stoneWallflow,
+ * comp1.getCompressorChart().getStoneWallCurve().setCurve(chartConditions, stoneWallflow,
* stoneWallHead);
*/
- neqsim.process.processmodel.ProcessSystem operations = new neqsim.process.processmodel.ProcessSystem();
+ neqsim.process.processmodel.ProcessSystem operations =
+ new neqsim.process.processmodel.ProcessSystem();
operations.add(stream_1);
operations.add(comp1);
operations.run();
@@ -516,8 +650,8 @@ public static int bisect_left(Double[] A, double x) {
* bisect_left.
*
*
- * @param A an array of {@link java.lang.Double} objects
- * @param x a double
+ * @param A an array of {@link java.lang.Double} objects
+ * @param x a double
* @param lo a int
* @param hi a int
* @return a int
@@ -548,8 +682,7 @@ public static int bisect_left(Double[] A, double x, int lo, int hi) {
/** {@inheritDoc} */
@Override
- public void plot() {
- }
+ public void plot() {}
/** {@inheritDoc} */
@Override
diff --git a/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookupExtrapolate.java b/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookupExtrapolate.java
index 02f422d65..01ab16f5d 100644
--- a/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookupExtrapolate.java
+++ b/src/main/java/neqsim/process/equipment/compressor/CompressorChartAlternativeMapLookupExtrapolate.java
@@ -6,14 +6,6 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
-/**
- * This class is an implementation of the compressor chart class that uses Fan laws and "double"
- * interpolation to navigate the compressor map (as opposed to the standard class using reduced
- * variables according to Fan laws).
- *
- * @author asmund
- * @version $Id: $Id
- */
public class CompressorChartAlternativeMapLookupExtrapolate
extends CompressorChartAlternativeMapLookup {
private static final long serialVersionUID = 1000;
@@ -21,17 +13,65 @@ public class CompressorChartAlternativeMapLookupExtrapolate
/**
- *
- * Constructor for CompressorChartAlternativeMapLookupExtrapolate.
- *
+ * Retrieves the closest reference speeds to the given speed from the compressor chart values. The
+ * method returns a list containing one or two speeds: - If the given speed matches a reference
+ * speed, the list contains only that speed. - If the given speed is between two reference speeds,
+ * the list contains both speeds. - If the given speed is less than the lowest reference speed,
+ * the list contains the lowest reference speed. - If the given speed is greater than the highest
+ * reference speed, the list contains the highest reference speed.
+ *
+ * @param speed the speed to find the closest reference speeds for.
+ * @return a list of the closest reference speeds.
+ * @throws IllegalStateException if no reference speeds are available in the chart values.
*/
- public CompressorChartAlternativeMapLookupExtrapolate() {}
+ @Override
+ public ArrayList getClosestRefSpeeds(double speed) {
+ ArrayList closestSpeeds = new ArrayList<>();
+ for (CompressorCurve curve : chartValues) {
+ closestSpeeds.add(curve.speed);
+ }
+
+ if (closestSpeeds.isEmpty()) {
+ throw new IllegalStateException(
+ "No reference speeds available. Ensure chartValues is populated.");
+ }
+
+ closestSpeeds.sort(Double::compareTo);
+ ArrayList result = new ArrayList<>();
+ for (int i = 0; i < closestSpeeds.size(); i++) {
+ if (speed == closestSpeeds.get(i)) {
+ result.add(speed);
+ return result;
+ }
+ if (speed < closestSpeeds.get(i)) {
+ if (i > 0) {
+ result.add(closestSpeeds.get(i - 1));
+ }
+ result.add(closestSpeeds.get(i));
+ return result;
+ }
+ }
+
+ // Speed is greater than the highest reference speed
+ result.add(closestSpeeds.get(closestSpeeds.size() - 1));
+ return result;
+ }
+
+ /**
+ * Calculates the polytropic head for a given flow and speed by interpolating or extrapolating
+ * between reference compressor curves.
+ *
+ * @param flow the flow rate for which the polytropic head is to be calculated
+ * @param speed the speed at which the compressor is operating
+ * @return the polytropic head corresponding to the given flow and speed
+ */
@Override
public double getPolytropicHead(double flow, double speed) {
ArrayList closestRefSpeeds = getClosestRefSpeeds(speed);
SplineInterpolator interpolator = new SplineInterpolator();
ArrayList interpolatedHeads = new ArrayList<>();
+ ArrayList speeds = new ArrayList<>();
for (double refSpeed : closestRefSpeeds) {
CompressorCurve curve = getCurveAtRefSpeed(refSpeed);
@@ -39,46 +79,139 @@ public double getPolytropicHead(double flow, double speed) {
double headValue = extrapolateOrInterpolate(flow, curve.flow, curve.head, spline);
interpolatedHeads.add(headValue);
+ speeds.add(refSpeed);
+ }
+
+ if (interpolatedHeads.size() == 1) {
+ return interpolatedHeads.get(0);
}
- return interpolatedHeads.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
+ double speed1 = speeds.get(0);
+ double speed2 = speeds.get(1);
+ double head1 = interpolatedHeads.get(0);
+ double head2 = interpolatedHeads.get(1);
+
+ return extrapolateOrInterpolateSpeed(speed, speed1, speed2, head1, head2);
}
+ /**
+ * Calculates the polytropic efficiency for a given flow and speed by interpolating or
+ * extrapolating between reference compressor curves.
+ *
+ * @param flow the flow rate for which the polytropic efficiency is to be calculated
+ * @param speed the speed at which the compressor is operating
+ * @return the polytropic efficiency at the given flow and speed
+ * @throws IllegalArgumentException if no valid reference speeds are found for the given speed or
+ * if the curve data for a reference speed is invalid
+ */
@Override
public double getPolytropicEfficiency(double flow, double speed) {
ArrayList closestRefSpeeds = getClosestRefSpeeds(speed);
+
+ if (closestRefSpeeds.isEmpty()) {
+ throw new IllegalArgumentException(
+ "No valid reference speeds found for the given speed: " + speed);
+ }
+
SplineInterpolator interpolator = new SplineInterpolator();
ArrayList interpolatedEfficiencies = new ArrayList<>();
+ ArrayList speeds = new ArrayList<>();
for (double refSpeed : closestRefSpeeds) {
CompressorCurve curve = getCurveAtRefSpeed(refSpeed);
+
+ if (curve.flow.length == 0 || curve.polytropicEfficiency.length == 0) {
+ throw new IllegalArgumentException("Invalid curve data for speed: " + refSpeed);
+ }
+
PolynomialSplineFunction spline =
interpolator.interpolate(curve.flow, curve.polytropicEfficiency);
-
double efficiencyValue =
extrapolateOrInterpolate(flow, curve.flow, curve.polytropicEfficiency, spline);
interpolatedEfficiencies.add(efficiencyValue);
+ speeds.add(refSpeed);
+ }
+
+ if (interpolatedEfficiencies.size() == 1) {
+ return interpolatedEfficiencies.get(0);
}
- return interpolatedEfficiencies.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
+ double speed1 = speeds.get(0);
+ double speed2 = speeds.get(1);
+ double eff1 = interpolatedEfficiencies.get(0);
+ double eff2 = interpolatedEfficiencies.get(1);
+
+ return extrapolateOrInterpolateSpeed(speed, speed1, speed2, eff1, eff2);
}
+ /**
+ * Extrapolates or interpolates a value based on the given flow using the provided flow data,
+ * value data, and polynomial spline function.
+ *
+ * @param flow the flow value for which the corresponding value needs to be determined
+ * @param flowData an array of flow data points
+ * @param valueData an array of value data points corresponding to the flow data points
+ * @param spline a polynomial spline function created from the flow and value data points
+ * @return the extrapolated or interpolated value corresponding to the given flow
+ */
private double extrapolateOrInterpolate(double flow, double[] flowData, double[] valueData,
PolynomialSplineFunction spline) {
double[] knots = spline.getKnots();
+
if (flow < knots[0]) {
- // Linear extrapolation below range using the first two points
+ logger.debug("Extrapolating below range: flow={}, knots[0]={}", flow, knots[0]);
double slope = (valueData[1] - valueData[0]) / (flowData[1] - flowData[0]);
return valueData[0] + slope * (flow - flowData[0]);
} else if (flow > knots[knots.length - 1]) {
- // Linear extrapolation above range using the last two points
+ logger.debug("Extrapolating above range: flow={}, knots[last]={}", flow,
+ knots[knots.length - 1]);
int last = flowData.length - 1;
double slope =
(valueData[last] - valueData[last - 1]) / (flowData[last] - flowData[last - 1]);
return valueData[last] + slope * (flow - flowData[last]);
}
- // Interpolate within the range
+
+ logger.debug("Interpolating within range: flow={}", flow);
return spline.value(flow);
}
+ /**
+ * Extrapolates or interpolates a value based on the given speed and two reference speeds with
+ * their corresponding values.
+ *
+ * @param speed the speed at which to extrapolate or interpolate the value
+ * @param speed1 the first reference speed
+ * @param speed2 the second reference speed
+ * @param value1 the value corresponding to the first reference speed
+ * @param value2 the value corresponding to the second reference speed
+ * @return the extrapolated or interpolated value at the given speed
+ */
+ private double extrapolateOrInterpolateSpeed(double speed, double speed1, double speed2,
+ double value1, double value2) {
+ if (speed < speed1) {
+ // Extrapolate below the range
+ double slope = (value2 - value1) / (speed2 - speed1);
+ return value1 + slope * (speed - speed1);
+ } else if (speed > speed2) {
+ // Extrapolate above the range
+ double slope = (value2 - value1) / (speed2 - speed1);
+ return value2 + slope * (speed - speed2);
+ }
+ return linearInterpolate(speed, speed1, speed2, value1, value2); // Interpolate within the range
+ }
+
+ /**
+ * Performs linear interpolation to estimate the value of y at a given x, based on two known
+ * points (x1, y1) and (x2, y2).
+ *
+ * @param x the x-value at which to interpolate
+ * @param x1 the x-value of the first known point
+ * @param x2 the x-value of the second known point
+ * @param y1 the y-value of the first known point
+ * @param y2 the y-value of the second known point
+ * @return the interpolated y-value at the given x
+ */
+ private double linearInterpolate(double x, double x1, double x2, double y1, double y2) {
+ return y1 + (y2 - y1) * (x - x1) / (x2 - x1);
+ }
}
diff --git a/src/test/java/neqsim/process/equipment/compressor/CompressorChartTest.java b/src/test/java/neqsim/process/equipment/compressor/CompressorChartTest.java
index e07867f55..0896e75de 100644
--- a/src/test/java/neqsim/process/equipment/compressor/CompressorChartTest.java
+++ b/src/test/java/neqsim/process/equipment/compressor/CompressorChartTest.java
@@ -199,7 +199,7 @@ public void runCurveTest() {
testFluid.setTemperature(29.96, "C");
testFluid.setPressure(75.73, "bara");
- testFluid.setTotalFlowRate(359401.418270102, "kg/hr");
+ testFluid.setTotalFlowRate(559401.418270102, "kg/hr");
Stream stream_1 = new Stream("Stream1", testFluid);
stream_1.run();
@@ -210,6 +210,7 @@ public void runCurveTest() {
comp1.setCompressorChartType("interpolate and extrapolate");
comp1.setUsePolytropicCalc(true);
comp1.setSpeed(8765);
+ comp1.setUseGERG2008(false);
double[] chartConditions = new double[] {0.3, 1.0, 1.0, 1.0};
@@ -252,17 +253,19 @@ public void runCurveTest() {
comp1.getAntiSurge().setSurgeControlFactor(1.0);
comp1.run();
- System.out.println("speed " + comp1.getSpeed());
- System.out.println("out pres " + comp1.getOutletPressure());
- System.out.println("out temp " + (comp1.getOutTemperature() - 273.15));
- System.out.println("feed flow " + (comp1.getInletStream().getFlowRate("m3/hr")));
- System.out.println("polytropic head " + comp1.getPolytropicFluidHead());
- System.out.println("polytropic efficiency " + comp1.getPolytropicEfficiency());
- System.out.println("dist to surge " + comp1.getDistanceToSurge());
- System.out.println("surge flow rate margin " + comp1.getSurgeFlowRateMargin());
- System.out.println("surge flow rate " + comp1.getSurgeFlowRate());
- System.out.println("duty " + comp1.getPower("MW"));
- System.out.println("surge " + comp1.isSurge());
+ org.apache.logging.log4j.LogManager.getLogger(CompressorChartTest.class).debug("speed " + comp1.getSpeed());
+ org.apache.logging.log4j.LogManager.getLogger(CompressorChartTest.class).debug("out pres " + comp1.getOutletPressure());
+ org.apache.logging.log4j.LogManager.getLogger(CompressorChartTest.class).debug("out temp " + (comp1.getOutTemperature() - 273.15));
+ org.apache.logging.log4j.LogManager.getLogger(CompressorChartTest.class).debug("feed flow " + (comp1.getInletStream().getFlowRate("m3/hr")));
+ org.apache.logging.log4j.LogManager.getLogger(CompressorChartTest.class).debug("polytropic head " + comp1.getPolytropicFluidHead());
+ org.apache.logging.log4j.LogManager.getLogger(CompressorChartTest.class).debug("polytropic efficiency " + comp1.getPolytropicEfficiency());
+ org.apache.logging.log4j.LogManager.getLogger(CompressorChartTest.class).debug("dist to surge " + comp1.getDistanceToSurge());
+ org.apache.logging.log4j.LogManager.getLogger(CompressorChartTest.class).debug("surge flow rate margin " + comp1.getSurgeFlowRateMargin());
+ org.apache.logging.log4j.LogManager.getLogger(CompressorChartTest.class).debug("surge flow rate " + comp1.getSurgeFlowRate());
+ org.apache.logging.log4j.LogManager.getLogger(CompressorChartTest.class).debug("duty " + comp1.getPower("MW"));
+ org.apache.logging.log4j.LogManager.getLogger(CompressorChartTest.class).debug("surge " + comp1.isSurge());
+ Assertions.assertTrue(comp1.isSurge() == false);
+ Assertions.assertEquals(158.7732888, comp1.getOutletPressure(), 1e-3);
}
}