Exemplo n.º 1
0
        /// <summary>
        ///  This method obtains the data from the GAMS file using the low level API
        /// </summary>
        /// <param name="_source"></param>
        /// <param name="file"></param>
        /// <param name="table"></param>
        /// <param name="where"></param>
        /// <returns></returns>
        public static IEnumerable <QvxDataRow> GetGamsDataLowLevel(string _source, string file, QvxTable table, List <string> selectedFields, List <QueryExtractor.WhereCondition> where)
        {
            const int GMS_VAL_LEVEL    = 0;
            const int GMS_VAL_MARGINAL = 1;
            const int GMS_VAL_LOWER    = 2;
            const int GMS_VAL_UPPER    = 3;
            const int GMS_VAL_SCALE    = 4;
            //const int GMS_VAL_MAX = 5;

            string msg = string.Empty, VarName = string.Empty, sText = string.Empty, UelName = string.Empty;
            int    ErrNr = 0, SymNr = 0, SymTyp = 0, ADim = 0, ACount = 0, AUser = 0, NRec = 0, FDim = 0, j = 0, i = 0, IDum = 0;

            using (gdxcs gdx = new gdxcs(ref msg))
            {
                gdx.gdxOpenRead(_source + "\\" + file, ref ErrNr);
                gdx.gdxFindSymbol(table.TableName, ref SymNr);
                gdx.gdxSymbolInfo(SymNr, ref VarName, ref ADim, ref SymTyp);
                gdx.gdxSymbolInfoX(SymNr, ref ACount, ref AUser, ref sText);
                gdx.gdxDataReadRawStart(SymNr, ref NRec);

                Dictionary <int, string>[] dimensionCache = new Dictionary <int, string> [ADim];

                if (where.Count == 0)
                {
                    // No WHERE clause
                    double[] Vals = new double[gamsglobals.val_max];
                    int[]    Keys = new int[gamsglobals.maxdim];
                    while (gdx.gdxDataReadRaw(ref Keys, ref Vals, ref FDim) != 0)
                    {
                        QvxDataRow row = mapRow(Keys, Vals);
                        if (row != null)
                        {
                            yield return(row);
                        }
                    }
                }
                else
                {
                    // WHERE clause
                    string[] strFilter    = Enumerable.Repeat("", table.Fields.Count()).ToArray();
                    var      emptyFilters = new List <QvxField>();
                    foreach (var whereCondition in where)
                    {
                        int m = Array.FindIndex(table.Fields, element => element.FieldName == whereCondition.Field);
                        if (m >= 0)
                        {
                            if (m > (ADim - 1))
                            {
                                // Only dimensions can be filtered
                                throw new QvxPleaseSendReplyException(QvxResult.QVX_UNSUPPORTED_COMMAND, String.Format("Field \"{0}\" is not a dimension and can't be filtered", whereCondition.Field));
                            }
                            else if ("".Equals(whereCondition.Value))
                            {
                                // GAMS API doesn't allow empty filters, so we have to filter them ourselves
                                emptyFilters.Add(table.Fields[m]);
                            }
                            else
                            {
                                strFilter[m] = whereCondition.Value;
                            }
                        }
                        else
                        {
                            throw new QvxPleaseSendReplyException(QvxResult.QVX_FIELD_NOT_FOUND, String.Format("The field \"{0}\" is not valid", whereCondition.Field));
                        }
                    }

                    using (BlockingCollection <QvxDataRow> buffer = new BlockingCollection <QvxDataRow>())
                    {
                        // Start reading thread
                        Exception exception = null;
                        var       readTask  = Task.Run(() =>
                        {
                            try
                            {
                                gdx.gdxDataReadRawFastFilt(SymNr, strFilter, FilterProc);
                            }
                            catch (Exception e)
                            {
                                exception = e;
                            }
                            finally
                            {
                                // Signal the end of the data
                                buffer.CompleteAdding();
                            }
                        });

                        int FilterProc(IntPtr IndxPtr, IntPtr ValsPtr, IntPtr Uptr)
                        {
                            double[] managedArrayVals = new double[gamsglobals.val_max];
                            Marshal.Copy(ValsPtr, managedArrayVals, 0, gamsglobals.val_max);

                            int[] managedArrayIndx = new int[gamsglobals.maxdim];
                            Marshal.Copy(IndxPtr, managedArrayIndx, 0, gamsglobals.maxdim);

                            QvxDataRow row = mapRow(managedArrayIndx, managedArrayVals, emptyFilters);

                            if (row != null)
                            {
                                buffer.Add(row);
                            }
                            return(1);
                        }

                        // Writing process
                        foreach (QvxDataRow row in buffer.GetConsumingEnumerable())
                        {
                            yield return(row);
                        }
                        if (exception != null)
                        {
                            throw exception;
                        }
                    }
                }

                QvxDataRow mapRow(int[] Keys, double[] Vals, List <QvxField> emptyFilters = null)
                {
                    i = 0;
                    var row = new QvxDataRow();

                    // Read the dimensions
                    for (j = 0; j < ADim; j++)
                    {
                        if (dimensionCache[j] == null)
                        {
                            dimensionCache[j] = new Dictionary <int, string>();
                        }

                        UelName = null;
                        if (dimensionCache[j].ContainsKey(Keys[j]))
                        {
                            UelName = dimensionCache[j][Keys[j]];
                        }
                        else
                        {
                            gdx.gdxUMUelGet(Keys[j], ref UelName, ref IDum);
                            dimensionCache[j][Keys[j]] = UelName;
                        }

                        if (UelName != null)
                        {
                            QvxField field = table.Fields[i++];
                            if (selectedFields.Contains(field.FieldName))
                            {
                                row[field] = UelName;
                            }

                            // we check the empty filters, as GAMS API doesn't do it
                            if (emptyFilters != null && emptyFilters.Contains(field) && !string.IsNullOrEmpty(UelName))
                            {
                                return(null);
                            }
                        }
                    }

                    switch (SymTyp)
                    {
                    // SET
                    case gamsglobals.dt_set:
                        if (gdx.gdxGetElemText((int)Vals[GMS_VAL_LEVEL], ref msg, ref IDum) != 0)
                        {
                            QvxField field2 = table.Fields[i++];
                            if (selectedFields.Contains(field2.FieldName))
                            {
                                row[field2] = msg;
                            }
                        }
                        else
                        {
                            QvxField field2 = table.Fields[i++];
                            if (selectedFields.Contains(field2.FieldName))
                            {
                                row[field2] = Y_STRING;
                            }
                        }
                        break;

                    // PARAMETER
                    case gamsglobals.dt_par:
                        // Value
                        readValueField(row, table.Fields[i++], table.Fields[i++], Vals[GMS_VAL_LEVEL]);

                        if (!string.IsNullOrEmpty(sText) && ADim == 0)
                        {
                            QvxField field = table.Fields[i++];
                            if (selectedFields.Contains(field.FieldName))
                            {
                                row[field] = sText;
                            }
                        }
                        break;

                    // EQUATION and VARIABLE
                    case gamsglobals.dt_equ:
                    case gamsglobals.dt_var:
                        int[] gms_values = { GMS_VAL_LEVEL, GMS_VAL_MARGINAL, GMS_VAL_LOWER, GMS_VAL_UPPER, GMS_VAL_SCALE };
                        foreach (int gms_value in gms_values)
                        {
                            // Value
                            readValueField(row, table.Fields[i++], table.Fields[i++], Vals[gms_value]);
                        }
                        break;
                    }
                    return(row);
                }

                /// <summary>This method reads a value separated in two fields, the first with the numeric value and the second with the special value description.</summary>
                void readValueField(QvxDataRow pRow, QvxField numberField, QvxField specialField, double pVal)
                {
                    Boolean isSpecialValue = false;

                    // Value
                    if (selectedFields.Contains(numberField.FieldName))
                    {
                        pRow[numberField] = val2str(pVal, msg, out isSpecialValue, true, false);
                    }
                    // Value (Special)
                    if (selectedFields.Contains(specialField.FieldName))
                    {
                        pRow[specialField] = val2str(pVal, msg, out isSpecialValue, false, true);
                    }
                    else if (isSpecialValue)
                    {
                        // If the value is special, but the "Special value" column is not selected, we throw an error
                        throw new QvxPleaseSendReplyException(QvxResult.QVX_FIELD_NOT_FOUND, String.Format("The field \"{0}\" contains special values, so the field \"{1}\" has to be selected", numberField.FieldName, specialField.FieldName));
                    }
                }

                /// <summary>This method generates the final value of a field, that can be a normal number, an acronym, infinite, ...</summary>
                /// <param name="returnNumber">If true, the value of a number will be returned as a double</param>
                /// <param name="returnSpecial">If true, the value of a special value (infinite, epsilon, acronym, ...) will be returned as a string</param>
                dynamic val2str(double val, string s, out Boolean isSpecial, Boolean returnNumber = true, Boolean returnSpecial = true)
                {
                    string[] gmsSVText = { "UNdef", "NA", "+Inf", "-Inf", "Eps", "0", "AcroN" };
                    int      sv        = 0;

                    if (gdx.gdxAcronymName(val, ref s) != 0)
                    {
                        isSpecial = true;
                        return(returnSpecial ? s : null);
                    }
                    else
                    {
                        gdx.gdxMapValue(val, ref sv);
                        if (gamsglobals.sv_normal != sv)
                        {
                            isSpecial = true;
                            return(returnSpecial ? gmsSVText[sv] : null);
                        }
                        else
                        {
                            isSpecial = false;
                            if (returnNumber)
                            {
                                return(val);
                            }
                            else
                            {
                                return(null);
                            }
                        }
                    }
                }
            }
        }