diff --git a/Modelica/Resources/C-Sources/ModelicaStandardTables.c b/Modelica/Resources/C-Sources/ModelicaStandardTables.c index bc2f7a46b5..7ab0fd8bc3 100644 --- a/Modelica/Resources/C-Sources/ModelicaStandardTables.c +++ b/Modelica/Resources/C-Sources/ModelicaStandardTables.c @@ -1,6 +1,6 @@ /* ModelicaStandardTables.c - External table functions - Copyright (C) 2013-2021, Modelica Association and contributors + Copyright (C) 2013-2022, Modelica Association and contributors All rights reserved. Redistribution and use in source and binary forms, with or without @@ -39,6 +39,14 @@ Modelica.Blocks.Tables.CombiTable2Dv Changelog: + + Jan. 31, 2022: by Hans Olsson, Dassault Systemes + Added better support for one-sided derivatives of CombiTable2D. + The idea is that when we are computing the derivative at a boundary + in the table we should consider the der-value to choose side. + This is less important for 1d-tables and thus ignored in those cases. + (ticket #3893) + Nov. 12, 2021: by Thomas Beutlich Fixed derivatives in CombiTable2D for one-sided extrapolation by constant continuation (ticket #3894) @@ -484,17 +492,28 @@ extern int usertab(char* tableName, int nipo, int dim[], int* colWise, static int isNearlyEqual(double x, double y); /* Compare two floating-point numbers by threshold _EPSILON */ -static size_t findRowIndex(const double* table, size_t nRow, size_t nCol, - size_t last, double x); +static size_t findRowIndex(_In_ const double* table, size_t nRow, size_t nCol, + size_t last, double x) MODELICA_NONNULLATTR; /* Find the row index i using binary search such that * i + 1 < nRow * table[i*nCol] <= x * table[(i + 1)*nCol] > x for i + 2 < nRow */ +static size_t findRowIndex2(_In_ const double* table, size_t nRow, size_t nCol, + size_t last, double x, double dx) MODELICA_NONNULLATTR; + /* Using dx as tie-breaker if table[i*nCol] == x to treat x as x+dx*eps */ + static size_t findColIndex(_In_ const double* table, size_t nCol, size_t last, double x) MODELICA_NONNULLATTR; - /* Same as findRowIndex but works on rows */ + /* Same as findRowIndex but works on columns */ + +static size_t findColIndex2(_In_ const double* table, size_t nCol, size_t last, + double x, double dx) MODELICA_NONNULLATTR; + /* Same as findRowIndex2 but works on columns */ + +static int isLessOrEqualWNegativeSlope(double x, double dx, double val); + /* Check, whether x is less than val, also using dx as tie-breaker */ static int isValidName(_In_z_ const char* name) MODELICA_NONNULLATTR; /* Check, whether a file or table name is valid */ @@ -4237,21 +4256,21 @@ double ModelicaStandardTables_CombiTable2D_getDerValue(void* _tableID, double u1 u2 -= T; } while (u2 > u2Max); } - last2 = findColIndex(&TABLE(0, 1), nCol - 1, - tableID->last2, u2); + last2 = findColIndex2(&TABLE(0, 1), nCol - 1, + tableID->last2, u2, der_u2); tableID->last2 = last2; } - else if (u2 < u2Min) { + else if (isLessOrEqualWNegativeSlope(u2, der_u2, u2Min)) { extrapolate2 = LEFT; last2 = 0; } - else if (u2 > u2Max) { + else if (isLessOrEqualWNegativeSlope(u2Max, -der_u2, u2)) { extrapolate2 = RIGHT; last2 = nCol - 3; } else { - last2 = findColIndex(&TABLE(0, 1), nCol - 1, - tableID->last2, u2); + last2 = findColIndex2(&TABLE(0, 1), nCol - 1, + tableID->last2, u2, der_u2); tableID->last2 = last2; } @@ -4382,21 +4401,21 @@ double ModelicaStandardTables_CombiTable2D_getDerValue(void* _tableID, double u1 u1 -= T; } while (u1 > u1Max); } - last1 = findRowIndex(&TABLE(1, 0), nRow - 1, nCol, - tableID->last1, u1); + last1 = findRowIndex2(&TABLE(1, 0), nRow - 1, nCol, + tableID->last1, u1, der_u1); tableID->last1 = last1; } - else if (u1 < u1Min) { + else if (isLessOrEqualWNegativeSlope(u1, der_u1, u1Min)) { extrapolate1 = LEFT; last1 = 0; } - else if (u1 > u1Max) { + else if (isLessOrEqualWNegativeSlope(u1Max, -der_u1, u1)) { extrapolate1 = RIGHT; last1 = nRow - 3; } else { - last1 = findRowIndex(&TABLE(1, 0), nRow - 1, nCol, - tableID->last1, u1); + last1 = findRowIndex2(&TABLE(1, 0), nRow - 1, nCol, + tableID->last1, u1, der_u1); tableID->last1 = last1; } if (nCol == 2) { @@ -4526,21 +4545,21 @@ double ModelicaStandardTables_CombiTable2D_getDerValue(void* _tableID, double u1 u2 -= T; } while (u2 > u2Max); } - last2 = findColIndex(&TABLE(0, 1), nCol - 1, - tableID->last2, u2); + last2 = findColIndex2(&TABLE(0, 1), nCol - 1, + tableID->last2, u2, der_u2); tableID->last2 = last2; } - else if (u2 < u2Min) { + else if (isLessOrEqualWNegativeSlope(u2, der_u2, u2Min)) { extrapolate2 = LEFT; last2 = 0; } - else if (u2 > u2Max) { + else if (isLessOrEqualWNegativeSlope(u2Max, -der_u2, u2)) { extrapolate2 = RIGHT; last2 = nCol - 3; } else { - last2 = findColIndex(&TABLE(0, 1), nCol - 1, - tableID->last2, u2); + last2 = findColIndex2(&TABLE(0, 1), nCol - 1, + tableID->last2, u2, der_u2); tableID->last2 = last2; } @@ -5158,21 +5177,21 @@ double ModelicaStandardTables_CombiTable2D_getDer2Value(void* _tableID, double u u2 -= T; } while (u2 > u2Max); } - last2 = findColIndex(&TABLE(0, 1), nCol - 1, - tableID->last2, u2); + last2 = findColIndex2(&TABLE(0, 1), nCol - 1, + tableID->last2, u2, der_u2); tableID->last2 = last2; } - else if (u2 < u2Min) { + else if (isLessOrEqualWNegativeSlope(u2, der_u2, u2Min)) { extrapolate2 = LEFT; last2 = 0; } - else if (u2 > u2Max) { + else if (isLessOrEqualWNegativeSlope(u2Max, -der_u2, u2)) { extrapolate2 = RIGHT; last2 = nCol - 3; } else { - last2 = findColIndex(&TABLE(0, 1), nCol - 1, - tableID->last2, u2); + last2 = findColIndex2(&TABLE(0, 1), nCol - 1, + tableID->last2, u2, der_u2); tableID->last2 = last2; } @@ -5304,21 +5323,21 @@ double ModelicaStandardTables_CombiTable2D_getDer2Value(void* _tableID, double u u1 -= T; } while (u1 > u1Max); } - last1 = findRowIndex(&TABLE(1, 0), nRow - 1, nCol, - tableID->last1, u1); + last1 = findRowIndex2(&TABLE(1, 0), nRow - 1, nCol, + tableID->last1, u1, der_u1); tableID->last1 = last1; } - else if (u1 < u1Min) { + else if (isLessOrEqualWNegativeSlope(u1, der_u1, u1Min)) { extrapolate1 = LEFT; last1 = 0; } - else if (u1 > u1Max) { + else if (isLessOrEqualWNegativeSlope(u1Max, -der_u1, u1)) { extrapolate1 = RIGHT; last1 = nRow - 3; } else { - last1 = findRowIndex(&TABLE(1, 0), nRow - 1, nCol, - tableID->last1, u1); + last1 = findRowIndex2(&TABLE(1, 0), nRow - 1, nCol, + tableID->last1, u1, der_u1); tableID->last1 = last1; } if (nCol == 2) { @@ -5449,21 +5468,21 @@ double ModelicaStandardTables_CombiTable2D_getDer2Value(void* _tableID, double u u2 -= T; } while (u2 > u2Max); } - last2 = findColIndex(&TABLE(0, 1), nCol - 1, - tableID->last2, u2); + last2 = findColIndex2(&TABLE(0, 1), nCol - 1, + tableID->last2, u2, der_u2); tableID->last2 = last2; } - else if (u2 < u2Min) { + else if (isLessOrEqualWNegativeSlope(u2, der_u2, u2Min)) { extrapolate2 = LEFT; last2 = 0; } - else if (u2 > u2Max) { + else if (isLessOrEqualWNegativeSlope(u2Max, -der_u2, u2)) { extrapolate2 = RIGHT; last2 = nCol - 3; } else { - last2 = findColIndex(&TABLE(0, 1), nCol - 1, - tableID->last2, u2); + last2 = findColIndex2(&TABLE(0, 1), nCol - 1, + tableID->last2, u2, der_u2); tableID->last2 = last2; } @@ -6168,14 +6187,14 @@ static int isNearlyEqual(double x, double y) { return fabs(y - x) < cmp; } -static size_t findRowIndex(const double* table, size_t nRow, size_t nCol, - size_t last, double x) { +static size_t findRowIndex2(_In_ const double* table, size_t nRow, size_t nCol, + size_t last, double x, double dx) { size_t i0 = 0; size_t i1 = nRow - 1; - if (x < TABLE_COL0(last)) { + if (isLessOrEqualWNegativeSlope(x, dx, TABLE_COL0(last))) { i1 = last; } - else if (x >= TABLE_COL0(last + 1)) { + else if (!isLessOrEqualWNegativeSlope(x, dx, TABLE_COL0(last + 1))) { i0 = last; } else { @@ -6185,7 +6204,7 @@ static size_t findRowIndex(const double* table, size_t nRow, size_t nCol, /* Binary search */ while (i1 > i0 + 1) { const size_t i = (i0 + i1)/2; - if (x < TABLE_COL0(i)) { + if (isLessOrEqualWNegativeSlope(x, dx, TABLE_COL0(i))) { i1 = i; } else { @@ -6195,14 +6214,19 @@ static size_t findRowIndex(const double* table, size_t nRow, size_t nCol, return i0; } -static size_t findColIndex(_In_ const double* table, size_t nCol, size_t last, - double x) { +static size_t findRowIndex(_In_ const double* table, size_t nRow, size_t nCol, + size_t last, double x) { + return findRowIndex2(table, nRow, nCol, last, x, 0.0); +} + +static size_t findColIndex2(_In_ const double* table, size_t nCol, size_t last, + double x, double dx) { size_t i0 = 0; size_t i1 = nCol - 1; - if (x < TABLE_ROW0(last)) { + if (isLessOrEqualWNegativeSlope(x, dx, TABLE_ROW0(last))) { i1 = last; } - else if (x >= TABLE_ROW0(last + 1)) { + else if (!isLessOrEqualWNegativeSlope(x, dx, TABLE_ROW0(last + 1))) { i0 = last; } else { @@ -6212,7 +6236,7 @@ static size_t findColIndex(_In_ const double* table, size_t nCol, size_t last, /* Binary search */ while (i1 > i0 + 1) { const size_t i = (i0 + i1)/2; - if (x < TABLE_ROW0(i)) { + if (isLessOrEqualWNegativeSlope(x, dx, TABLE_ROW0(i))) { i1 = i; } else { @@ -6222,8 +6246,16 @@ static size_t findColIndex(_In_ const double* table, size_t nCol, size_t last, return i0; } +static size_t findColIndex(_In_ const double* table, size_t nCol, size_t last, double x) { + return findColIndex2(table, nCol, last, x, 0.0); +} + /* ----- Internal check functions ----- */ +static int isLessOrEqualWNegativeSlope(double x, double dx, double val) { + return x < val || (x == val && dx < 0); +} + static int isValidName(_In_z_ const char* name) { int isValid = 0; if (NULL != name) { diff --git a/Modelica/Resources/Licenses/LICENSE_ModelicaStandardTables.txt b/Modelica/Resources/Licenses/LICENSE_ModelicaStandardTables.txt index ce519b436d..75336a214a 100644 --- a/Modelica/Resources/Licenses/LICENSE_ModelicaStandardTables.txt +++ b/Modelica/Resources/Licenses/LICENSE_ModelicaStandardTables.txt @@ -1,4 +1,4 @@ -Copyright (C) 2013-2021, Modelica Association and contributors +Copyright (C) 2013-2022, Modelica Association and contributors All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/ModelicaTest/Resources/Reference/ModelicaTest/Tables/CombiTable2Ds/OneSidedDerivative2D/comparisonSignals.txt b/ModelicaTest/Resources/Reference/ModelicaTest/Tables/CombiTable2Ds/OneSidedDerivative2D/comparisonSignals.txt new file mode 100644 index 0000000000..b9fd9b6250 --- /dev/null +++ b/ModelicaTest/Resources/Reference/ModelicaTest/Tables/CombiTable2Ds/OneSidedDerivative2D/comparisonSignals.txt @@ -0,0 +1,5 @@ +time +der1.y +der2.y +der3.y +der4.y diff --git a/ModelicaTest/Resources/Reference/ModelicaTest/Tables/CombiTable2Dv/OneSidedDerivative2D/comparisonSignals.txt b/ModelicaTest/Resources/Reference/ModelicaTest/Tables/CombiTable2Dv/OneSidedDerivative2D/comparisonSignals.txt new file mode 100644 index 0000000000..b9fd9b6250 --- /dev/null +++ b/ModelicaTest/Resources/Reference/ModelicaTest/Tables/CombiTable2Dv/OneSidedDerivative2D/comparisonSignals.txt @@ -0,0 +1,5 @@ +time +der1.y +der2.y +der3.y +der4.y diff --git a/ModelicaTest/Tables/CombiTable2Ds.mo b/ModelicaTest/Tables/CombiTable2Ds.mo index 836d6bcf47..043309a21d 100644 --- a/ModelicaTest/Tables/CombiTable2Ds.mo +++ b/ModelicaTest/Tables/CombiTable2Ds.mo @@ -1125,4 +1125,92 @@ double mydummyfunc(double dummy_in) { points={{-59,-10},{-52,-10},{-52,4},{-42,4}}, color={0,0,127})); annotation (experiment(StartTime=0, StopTime=14)); end Test33; + + model OneSidedDerivative2D "Test of one sided derivatives in 2D-tables (Ticket #3893)" + // We are starting at boundaries of the table + // Case 2 and 4 slide diagonally (from different corners) + // Case 1 and 3 start at the edge of the real table and then leave it top-left + // Interpolating in different ways + extends Modelica.Icons.Example; + parameter Real M0[:,:]=[0,-10,1,2,10; -10,2,2,3,4; 1,2,2,3,3; 2,3,3,4,4; 10,3, + 3,4,4]; + parameter Real M[:,:]=[M0[1:1,1:1],M0[1:1,3:end-1];M0[3:end-1,1],M0[3:end-1,3:end-1]]; + Modelica.Blocks.Sources.Ramp ramp( + height=1, + duration=1, + offset=1) + annotation (Placement(transformation(extent={{-80,40},{-60,60}}))); + Modelica.Blocks.Sources.Ramp ramp1( + height=-1, + duration=1, + offset=2) + annotation (Placement(transformation(extent={{-20,18},{0,38}}))); + Modelica.Blocks.Tables.CombiTable2Ds combiTable2Ds2( + tableOnFile=false, + table=M0, + smoothness=Modelica.Blocks.Types.Smoothness.LinearSegments, + extrapolation=Modelica.Blocks.Types.Extrapolation.LastTwoPoints) + annotation (Placement(transformation(extent={{40,60},{60,80}}))); + Modelica.Blocks.Continuous.Der der2 + annotation (Placement(transformation(extent={{80,60},{100,80}}))); + Modelica.Blocks.Tables.CombiTable2Ds combiTable2Ds4( + tableOnFile=false, + table=M0, + smoothness=Modelica.Blocks.Types.Smoothness.LinearSegments, + extrapolation=Modelica.Blocks.Types.Extrapolation.LastTwoPoints) + annotation (Placement(transformation(extent={{40,0},{60,20}}))); + Modelica.Blocks.Continuous.Der der4 + annotation (Placement(transformation(extent={{80,0},{100,20}}))); + Modelica.Blocks.Sources.Ramp ramp2( + height=-1, + duration=1, + offset=1) + annotation (Placement(transformation(extent={{-80,-80},{-60,-60}}))); + Modelica.Blocks.Tables.CombiTable2Ds combiTable2Ds1( + tableOnFile=false, + table=M0, + smoothness=Modelica.Blocks.Types.Smoothness.LinearSegments, + extrapolation=Modelica.Blocks.Types.Extrapolation.LastTwoPoints) + annotation (Placement(transformation(extent={{-20,-40},{0,-20}}))); + Modelica.Blocks.Continuous.Der der1 + annotation (Placement(transformation(extent={{20,-40},{40,-20}}))); + Modelica.Blocks.Tables.CombiTable2Ds combiTable2Ds3( + tableOnFile=false, + table=M, + smoothness=Modelica.Blocks.Types.Smoothness.LinearSegments, + extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint) + annotation (Placement(transformation(extent={{-20,-80},{0,-60}}))); + Modelica.Blocks.Continuous.Der der3 + annotation (Placement(transformation(extent={{20,-80},{40,-60}}))); + equation + connect(combiTable2Ds2.y, der2.u) + annotation (Line(points={{61,70},{78,70}}, color={0,0,127})); + connect(ramp.y, combiTable2Ds2.u1) annotation (Line(points={{-59,50},{18,50},{ + 18,76},{38,76}}, color={0,0,127})); + connect(ramp1.y, combiTable2Ds2.u2) annotation (Line(points={{1,28},{24,28},{24, + 64},{38,64}}, color={0,0,127})); + connect(combiTable2Ds4.y, der4.u) + annotation (Line(points={{61,10},{78,10}}, color={0,0,127})); + connect(ramp.y, combiTable2Ds4.u2) annotation (Line(points={{-59,50},{-38,50}, + {-38,4},{38,4}}, color={0,0,127})); + connect(combiTable2Ds4.u1, combiTable2Ds2.u2) annotation (Line(points={{38,16}, + {34,16},{34,18},{24,18},{24,64},{38,64}}, color={0,0,127})); + connect(ramp2.y, combiTable2Ds1.u1) annotation (Line(points={{-59,-70},{-30,-70}, + {-30,-24},{-22,-24}}, color={0,0,127})); + connect(ramp2.y, combiTable2Ds1.u2) annotation (Line(points={{-59,-70},{-30,-70}, + {-30,-36},{-22,-36}}, color={0,0,127})); + connect(combiTable2Ds1.y, der1.u) + annotation (Line(points={{1,-30},{18,-30}}, color={0,0,127})); + connect(combiTable2Ds3.u1, combiTable2Ds1.u1) annotation (Line(points={{-22,-64}, + {-26,-64},{-26,-70},{-30,-70},{-30,-24},{-22,-24}}, color={0,0,127})); + connect(combiTable2Ds3.u2, combiTable2Ds1.u1) annotation (Line(points={{-22,-76}, + {-24,-76},{-24,-70},{-30,-70},{-30,-24},{-22,-24}}, color={0,0,127})); + connect(combiTable2Ds3.y, der3.u) + annotation (Line(points={{1,-70},{18,-70}}, color={0,0,127})); + annotation ( + experiment( + StartTime=-1, + StopTime=4)); + end OneSidedDerivative2D; + end CombiTable2Ds; diff --git a/ModelicaTest/Tables/CombiTable2Dv.mo b/ModelicaTest/Tables/CombiTable2Dv.mo index d13412b1f7..82b9255e6e 100644 --- a/ModelicaTest/Tables/CombiTable2Dv.mo +++ b/ModelicaTest/Tables/CombiTable2Dv.mo @@ -950,4 +950,93 @@ double mydummyfunc(double dummy_in) { points={{-59,-10},{-52,-10},{-52,4},{-42,4}}, color={0,0,127})); annotation (experiment(StartTime=0, StopTime=14)); end Test33; + + model OneSidedDerivative2D "Test of one sided derivatives in 2D-tables (Ticket #3893)" + // We are starting at boundaries of the table + // Case 2 and 4 slide diagonally (from different corners) + // Case 1 and 3 start at the edge of the real table and then leave it top-left + // Interpolating in different ways + // Note that compared to the scalar variant 1,2, and 4 have been merged + // into one vector component + // Case 3 is separate. + extends Modelica.Icons.Example; + parameter Real M0[:,:]=[0,-10,1,2,10; -10,2,2,3,4; 1,2,2,3,3; 2,3,3,4,4; 10,3, + 3,4,4]; + parameter Real M[:,:]=[M0[1:1,1:1],M0[1:1,3:end-1];M0[3:end-1,1],M0[3:end-1,3:end-1]]; + Modelica.Blocks.Sources.Ramp ramp( + height=1, + duration=1, + offset=1) + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, origin={-90, + 50}))); + Modelica.Blocks.Sources.Ramp ramp1( + height=-1, + duration=1, + offset=2) + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, origin={-90, + 10}))); + Modelica.Blocks.Tables.CombiTable2Dv combiTable2Dv( + n=3, + tableOnFile=false, + table=M0, + smoothness=Modelica.Blocks.Types.Smoothness.LinearSegments, + extrapolation=Modelica.Blocks.Types.Extrapolation.LastTwoPoints) + annotation (Placement(transformation(extent={{-20,-20},{20,20}}, origin={22,40}))); + Modelica.Blocks.Continuous.Der der2 + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, origin={90,30}))); + Modelica.Blocks.Continuous.Der der4 + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, origin={90,90}))); + Modelica.Blocks.Sources.Ramp ramp2( + height=-1, + duration=1, + offset=1) + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, origin={-90, + -70}))); + Modelica.Blocks.Continuous.Der der1 + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, origin={90,-10}))); + Modelica.Blocks.Tables.CombiTable2Dv combiTable2Dv3( + tableOnFile=false, + table=M, + smoothness=Modelica.Blocks.Types.Smoothness.LinearSegments, + extrapolation=Modelica.Blocks.Types.Extrapolation.HoldLastPoint) + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, origin={-30, + -70}))); + Modelica.Blocks.Continuous.Der der3 + annotation (Placement(transformation(extent={{-10,-10},{10,10}}, origin={30,-70}))); + equation + connect(combiTable2Dv.y[2], der2.u) + annotation (Line(points={{44,40},{72,40},{72,30},{78,30}}, + color={0,0,127})); + connect(ramp.y, combiTable2Dv.u1[2]) annotation (Line(points={{-79,50},{-62,50}, + {-62,52},{-2,52}}, + color={0,0,127})); + connect(ramp1.y, combiTable2Dv.u2[2]) annotation (Line(points={{-79,10},{-58,10}, + {-58,28},{-2,28}}, color={0,0,127})); + connect(combiTable2Dv.y[3], der4.u) + annotation (Line(points={{44,40.6667},{56,40.6667},{56,90},{78,90}}, + color={0,0,127})); + connect(ramp.y, combiTable2Dv.u2[3]) annotation (Line(points={{-79,50},{-62, + 50},{-62,29.3333},{-2,29.3333}}, + color={0,0,127})); + connect(combiTable2Dv.u1[3], combiTable2Dv.u2[2]) annotation (Line(points={{-2, + 53.3333},{-58,53.3333},{-58,28},{-2,28}}, color={0,0,127})); + connect(combiTable2Dv.y[1], der1.u) + annotation (Line(points={{44,39.3333},{50,39.3333},{50,-10},{78,-10}}, + color={0,0,127})); + connect(combiTable2Dv3.y[1], der3.u) + annotation (Line(points={{-19,-70},{18,-70}}, + color={0,0,127})); + connect(ramp2.y, combiTable2Dv3.u1[1]) annotation (Line(points={{-79,-70},{-52, + -70},{-52,-64},{-42,-64}}, color={0,0,127})); + connect(ramp2.y, combiTable2Dv3.u2[1]) annotation (Line(points={{-79,-70},{-52, + -70},{-52,-76},{-42,-76}}, color={0,0,127})); + connect(ramp2.y, combiTable2Dv.u2[1]) annotation (Line(points={{-79,-70},{-52, + -70},{-52,26.6667},{-2,26.6667}}, color={0,0,127})); + connect(ramp2.y, combiTable2Dv.u1[1]) annotation (Line(points={{-79,-70},{-52, + -70},{-52,50.6667},{-2,50.6667}}, color={0,0,127})); + annotation ( + experiment( + StartTime=-1, + StopTime=4)); + end OneSidedDerivative2D; end CombiTable2Dv;