private Dictionary <string, double> GetInternalFactorDefs()
        {   // this is a somewhat simplified implementation, as I think it's an outdated concept and not used (and as such not worth the effort):
            // in the old executable the value of the factor can be a constant (and therewith also an uprating factor defined in the dialog)
            Dictionary <string, double> facDefs = new Dictionary <string, double>(StringComparer.OrdinalIgnoreCase);

            foreach (var group in GetParGroups(DefPar.Uprate.GROUP_FACTOR_DEF).Values)
            {
                ParBase   pName = GetUniqueGroupPar <ParBase>(DefPar.Uprate.Factor_Name, group);
                ParNumber pNum  = GetUniqueGroupPar <ParNumber>(DefPar.Uprate.Factor_Value, group);
                if (pName == null || pNum == null)
                {
                    continue;                                // error (compulsory param missing ...) is issued in the general check
                }
                if (facDefs.ContainsKey(pName.xmlValue))
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = true,
                        message   = $"{description.Get()}: double definition of {DefPar.Uprate.Factor_Name} {pName.xmlValue}"
                    });
                }
                else
                {
                    facDefs.Add(pName.xmlValue, pNum.GetValue());  // as said above, ignore the possibility of a constant
                }
            }
            return(facDefs);
        }
Пример #2
0
        private bool CheckPrePost(ILSpecification ilSpecification, ParBase parPrefix, ParBase parPostfix, bool checkContent = true)
        {
            ilSpecification.prefix  = parPrefix?.xmlValue ?? string.Empty;
            ilSpecification.postfix = parPostfix?.xmlValue ?? string.Empty;
            if (string.IsNullOrEmpty(ilSpecification.prefix) && string.IsNullOrEmpty(ilSpecification.postfix))
            {
                return(true);    // if no prefix or postfix is defined, then all vars match naming by definition.
            }
            if (!checkContent)
            {
                return(true);
            }

            foreach (string v in ParIL.GetILComponents(ilSpecification.ilName, infoStore.operandAdmin))
            {
                if (v.StartsWith(ilSpecification.prefix, StringComparison.OrdinalIgnoreCase) &&
                    v.EndsWith(ilSpecification.postfix, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false,
                    message   = $"{description.Get()}: {ilSpecification.ilName}: contained variables must be named {GetFullVarName("*", ilSpecification)}; " +
                                $"variable {v} does not follow this rule"
                });
                return(false);
            }
            return(true);
        }
        internal override void ProvideIndexInfo()
        {
            ParBase par = GetUniquePar <ParBase>(DefPar.Loop.Loop_Id); if (par == null)

            {
                return;                                                                        // error is issued by standard-check
            }
            loopID = par.xmlValue;
            if (!EM_Helpers.IsValidName(loopID, out string illegal))
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false,
                    message   = $"{par.description.Get()}: usage of illegal character(s): {illegal}"
                });
                return;
            }

            infoStore.operandAdmin.indexLoopIDs.Add(loopID, this); // used by Store-function, for checking if loop exists
            infoStore.operandAdmin.RegisterVar(name: DefVarName.LOOPCOUNT + loopID,
                                               creatorFun: DefFun.Loop,
                                               description: description,
                                               isMonetary: false,
                                               isGlobal: true,     // actually it is not global, as this would not work in parallel evironment
                                                                   // but by setting is Global to true, usage in RunCond is made possible
                                               isWriteable: false, // cannot be used as output-variable
                                               setInitialised: true);
        }
        // this handles the old style syntax which puts the footnote outside the brackets in context with Amount, e.g. {xyz < amount}#1
        // obviously, if the Calculator moves the footnotes inside, it's too late for Amount-replacement,
        // but if this would be the only problem one could think of changing the order
        // however the Calculator would produce {xyz#1 < amount#1} which is in the case I found wrong - there is no footnote for xyz
        // thus this would lead to the incorrect error message "missing footnote for xyz#1"
        // note that for e.g. {xyz < abc}#1, moving in is justified, because the programme never could know which side is meant
        // summarising: treating this as "special" is anyway necessary and thus it is done with this function
        private string HandleOldStyleAmount(string formula, FunBase fun)
        {
            string amount      = DefPar.Value.AMOUNT.ToLower();
            int    amountIndex = formula.IndexOf(amount);

            while (amountIndex >= 0)
            {
                if (amountIndex == 0 || calc.IsSymbol(formula[amountIndex - 1])) // make sure not touching abc_amount
                {
                    int footnoteIndex = formula.Substring(amountIndex).IndexOf("}#");
                    if (footnoteIndex == -1)
                    {
                        return(formula);              // let Calculator catch the error
                    }
                    footnoteIndex += amountIndex + 1; // i.e. the # after the bracket

                    string number = string.Empty;
                    for (int i = footnoteIndex + 1; i < formula.Length; ++i) // start on character after the #
                    {
                        if ((formula[i] >= '0' && formula[i] <= '9') || (formula.ToLower()[i] >= 'a' && formula.ToLower()[i] <= 'z'))
                        {
                            number += formula[i];
                        }
                        else
                        {
                            break;
                        }
                    }

                    ParBase parAmount = fun.GetFootnotePar <ParBase>(DefPar.Footnote.Amount, new List <string>()
                    {
                        number
                    });
                    string replaceBy = "0";
                    if (parAmount != null)
                    {
                        replaceBy = parAmount.xmlValue;
                    }
                    else
                    {
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = false, message = $"{description.Get()}: missing footnote {DefPar.Footnote.Amount}({number})"
                        });
                    }

                    // if there is actually a second footnote (except #_Amount) with the same number, do not delete the footnote
                    // allows for e.g. {yem < amount}#1, with #_Amount(1) = 12000#y and #_Level(1) = tu_whatsoever
                    if (fun.GetFootnoteParCount(number) == 1)
                    {
                        formula = formula.Remove(footnoteIndex, number.Length + 1);
                    }
                    formula = formula.Remove(amountIndex, amount.Length);
                    formula = formula.Insert(amountIndex, replaceBy);
                }
                amountIndex = formula.IndexOf(amount, amountIndex + 1);
            }
            return(formula);
        }
Пример #5
0
        protected override void PrepareNonCommonPar()
        {
            ParBase parFileName = GetUniquePar <ParBase>(DefPar.DefOutput.File);

            if (parFileName != null) // if null the programme is stopped after reading parameters (missing compulsory parameter)
            {
                fileName = Path.Combine(infoStore.runConfig.pathOutput, parFileName.xmlValue);
                if (!fileName.ToLower().EndsWith(".txt"))
                {
                    fileName += ".txt";
                }

                if (infoStore.runConfig.stdOutputFilenameSuffix != string.Empty) // e.g. uk_2017_std -> uk_2017_BTAoff
                {
                    AdaptFileNameForNonStdExtensionSwitches(infoStore.runConfig.stdOutputFilenameSuffix);
                }

                if (infoStore.runConfig.outFileDate != string.Empty) // e.g. hu_2017_std.txt -> hu_2017_std_201805301954.txt
                {
                    fileName = fileName.Insert(fileName.Length - 4, "_" + infoStore.runConfig.outFileDate);
                }

                // * * *   T O D O   * * *
                // check at this point if file is ready for writting, i.e. valid file-name, not used by another file, ...
                // to avoid running the whole thing and then cannot write (probably requires try-catch on attempt to open)
                // also if the file is available, lock it now?
            }

            // in future probably replaced by Scale function, but currently still needed, in particular for PET
            ParFormula parMultipleMonetaryBy = GetUniquePar <ParFormula>(DefPar.DefOutput.MultiplyMonetaryBy);

            if (parMultipleMonetaryBy != null)
            {
                multiplyMonetaryBy = parMultipleMonetaryBy.GetGlobalValue();
            }

            PrepareVarILPar();
            PrepareDefILPar();
            PrepareUnitInfoPar();
            append = GetParBoolValueOrDefault(DefFun.DefOutput, DefPar.DefOutput.Append);
            suppressVoidMessage = GetParBoolValueOrDefault(DefFun.DefOutput, DefPar.DefOutput.Suppress_Void_Message);

            nDecimals      = (int)GetParNumberValueOrDefault(DefFun.DefOutput, DefPar.DefOutput.nDecimals);
            formatDecimals = "0."; for (int i = 0; i < nDecimals; i++)
            {
                formatDecimals += "#";
            }

            parWho     = GetUniquePar <ParCateg>(DefPar.Common.Who_Must_Be_Elig);
            parEligVar = GetUniquePar <ParVar>(DefPar.Common.Elig_Var);

            ParNumber parReplaceUnitLoopVoidBy = GetUniquePar <ParNumber>(DefPar.DefOutput.Replace_Void_By);

            if (parReplaceUnitLoopVoidBy != null)
            {
                doReplaceUnitLoopVoidBy = true;
                replaceUnitLoopVoidBy   = parReplaceUnitLoopVoidBy.GetValue();
            }
        }
        protected void PrepareStartEndPar()
        {
            // assess parameters which define start and end of loop
            loopStart = GetStartEnd(DefPar.Loop.First_Pol, DefPar.Loop.First_Func, DefPar.Loop.Start_After_Pol, DefPar.Loop.Start_After_Func, true);
            loopEnd   = GetStartEnd(DefPar.Loop.Last_Pol, DefPar.Loop.Last_Func, DefPar.Loop.Stop_Before_Pol, DefPar.Loop.Stop_Before_Func, false);

            StartEnd GetStartEnd(string parNamePol, string parNameFun, string parNameNeighbourPol, string parNameNeighbourFun, bool start)
            {
                ParBase parPol          = GetUniquePar <ParBase>(parNamePol);
                ParBase parFun          = GetUniquePar <ParBase>(parNameFun);
                ParBase parNeighbourPol = GetUniquePar <ParBase>(parNameNeighbourPol);
                ParBase parNeighbourFun = GetUniquePar <ParBase>(parNameNeighbourFun);

                StartEnd se = new StartEnd()
                {
                    infoStore = infoStore, description = description, isStart = start
                }; int defCnt = 0;

                if (parPol != null)
                {
                    se.ident = parPol.xmlValue; se.isFun = false; se.isNeighbour = false; ++defCnt;
                }
                if (parFun != null)
                {
                    se.ident = parFun.xmlValue; se.isFun = true; se.isNeighbour = false; ++defCnt;
                }
                if (parNeighbourPol != null)
                {
                    se.ident = parNeighbourPol.xmlValue; se.isFun = false; se.isNeighbour = true; ++defCnt;
                }
                if (parNeighbourFun != null)
                {
                    se.ident = parNeighbourFun.xmlValue; se.isFun = true; se.isNeighbour = true; ++defCnt;
                }

                string sse = parNamePol == DefPar.Loop.First_Pol ? "start" : "end";

                if (defCnt > 1)
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{description.Get()}: over-definition for loop {sse}"
                    });
                }
                if (defCnt == 0)
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{description.Get()}: missing definition for loop {sse}"
                    });
                }
                return(se);
            }
        }
        private bool PreparePostPar()
        {
            ParBase parPostLoop = GetUniquePar <ParBase>(DefPar.Store.PostLoop);
            ParBase parPostFix  = GetUniquePar <ParBase>(DefPar.Store.PostFix);

            if (parPostLoop == null && parPostFix == null)
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false,
                    message   = $"{description.Get()}: neither {DefPar.Store.PostFix} nor {DefPar.Store.PostLoop} defined"
                });
                return(false);
            }
            if (parPostLoop != null && parPostFix != null)
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false,
                    message   = $"{description.Get()}: unclear specification - both {DefPar.Store.PostFix} and {DefPar.Store.PostLoop} defined"
                });
                return(false);
            }
            if (parPostLoop != null)
            {
                post = parPostLoop.xmlValue;
                if (!infoStore.operandAdmin.indexLoopIDs.ContainsKey(post))
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{parPostLoop.description.Get()}: no loop with {DefPar.Loop.Loop_Id} = {post} found"
                    });
                    return(false);
                }
                storeType = infoStore.operandAdmin.indexLoopIDs[post] is FunUnitLoop ? STORETYPE.UNITLOOP : STORETYPE.LOOP;
            }
            else
            {
                post = parPostFix.xmlValue; storeType = STORETYPE.FIX;
                if (!EM_Helpers.IsValidName(post, out string illegal))
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{parPostFix.description.Get()}: usage of illegal character(s): {illegal}"
                    });
                    return(false);
                }
            }
            return(true);
        }
        private bool GetFromTo(ParBase parFromTo, out List <int> iterations) // not activated (see above)
        {
            iterations = new List <int>(); string from = string.Empty, to = string.Empty;
            if (!parFromTo.xmlValue.Contains('-'))
            {
                from = parFromTo.xmlValue;
            }
            else
            {
                string[] ft = parFromTo.xmlValue.Split('-'); if (ft.Count() < 2)
                {
                    return(SyntaxError());
                }
                from = ft[0]; to = ft[1];
            }
            if (!int.TryParse(from, out int f))
            {
                return(SyntaxError());
            }
            int t = f; if (to != string.Empty && !int.TryParse(to, out t))

            {
                return(SyntaxError());
            }

            if (f > t)
            {
                return(SyntaxError($"from ({f}) > to ({t})"));
            }
            if (f <= 0)
            {
                return(SyntaxError($"from ({f}) must not be zero or negative"));
            }
            for (int i = f; i <= t; ++i)
            {
                iterations.Add(i);
            }
            return(true);

            bool SyntaxError(string explanation = "correct syntax: e.g. 1-3")
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false,
                    message   = $"{parFromTo.description.Get()}: invalid range of loop-iterations: {explanation}"
                });
                return(false);
            }
        }
Пример #9
0
        internal override void CheckAndPrepare(FunBase fun, List <string> footnoteNumbers)
        {
            ParBase parDatabase = fun.GetFootnotePar <ParBase>(DefQuery.Par.DataBasename, footnoteNumbers);

            if (parDatabase != null)
            {
                isUsedDB = infoStore.IsUsedDatabase(parDatabase.xmlValue) == true ? 1.0 : 0.0;
            }
            else
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false, message = $"{description.Get()}: compulsory query-parameter {DefQuery.Par.DataBasename} missing"
                });
            }
        }
        private string HandleAmount(string formula, FunBase fun)
        {
            string amount      = DefPar.Value.AMOUNT.ToLower() + "#";
            int    amountIndex = formula.IndexOf(amount);

            while (amountIndex >= 0)
            {
                if (amountIndex == 0 || !calc.IsVarChar(formula[amountIndex - 1])) // make sure not touching abc_amount#1
                {
                    string number = string.Empty;
                    for (int i = amountIndex + amount.Length; i < formula.Length; ++i)
                    {
                        if ((formula[i] >= '0' && formula[i] <= '9') || (formula.ToLower()[i] >= 'a' && formula.ToLower()[i] <= 'z'))
                        {
                            number += formula[i];
                        }
                        else
                        {
                            break;
                        }
                    }

                    ParBase parAmount = fun.GetFootnotePar <ParBase>(DefPar.Footnote.Amount, new List <string>()
                    {
                        number
                    });
                    string replaceBy = "0";
                    if (parAmount != null)
                    {
                        replaceBy = parAmount.xmlValue;
                    }
                    else
                    {
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = false, message = $"{description.Get()}: missing footnote {DefPar.Footnote.Amount}({number})"
                        });
                    }

                    formula = formula.Remove(amountIndex, amount.Length + number.Length);
                    formula = formula.Insert(amountIndex, replaceBy);
                }
                amountIndex = formula.IndexOf(amount, amountIndex + 1);
            }
            return(formula);
        }
Пример #11
0
        private double GetAddMod(ParBase par)
        {
            string addMode = par.xmlValue.Trim(); // i.e. '+' or '-' or '+0.5' or ...

            if (addMode == "+" || addMode == "-")
            {
                addMode += "1";
            }
            if (!double.TryParse(EM_Helpers.AdaptDecimalSign(addMode), out double am))
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false, message = $"{par.description.Get()}: invalid incomelist add-mode: {addMode}"
                });
            }
            return(am);
        }
 protected override void PrepareNonCommonPar()
 {
     updateAll = GetParBoolValueOrDefault(DefFun.UpdateTu, DefPar.UpdateTu.Update_All);
     if (!updateAll)
     {
         ParBase parName = GetUniquePar <ParBase>(DefPar.UpdateTu.Name);
         if (parName != null)
         {
             tuName = parName.xmlValue;
         }
         else
         {
             infoStore.communicator.ReportError(new Communicator.ErrorInfo()
             {
                 isWarning = false, message = $"{description.Get()}: paramter {DefPar.UpdateTu.Name} not defined"
             });
         }
     }
 }
Пример #13
0
        protected override void PreprocessParameters()
        {
            if (GetParGroups(DefPar.DefIl.GROUP_REGEXP).Count == 0)
            {
                return;
            }

            Dictionary <string, double> regExVar = new Dictionary <string, double>();

            foreach (var group in GetParGroups(DefPar.DefIl.GROUP_REGEXP).Values)
            {
                ParBase parDef    = GetUniqueGroupPar <ParBase>(DefPar.DefIl.RegExp_Def, group);
                ParBase parFactor = GetUniqueGroupPar <ParBase>(DefPar.DefIl.RegExp_Factor, group);
                if (parDef == null)
                {
                    continue;
                }
                string pattern = parDef.xmlValue;
                double addMode = parFactor == null ? 1.0 : GetAddMod(parFactor);
                foreach (string matchVar in infoStore.operandAdmin.GetMatchingVar(pattern: pattern, regExpr: true))
                {
                    if (!regExVar.ContainsKey(matchVar))
                    {
                        regExVar.Add(matchVar, addMode);
                    }
                }
            }

            infoStore.operandAdmin.AddRegExVarToILContent(GetUniquePar <ParBase>(DefPar.DefIl.Name).xmlValue, regExVar);

            // note wrt using PreprocessParameters-function instead of ReplaceVarNameByIndex-function (as FunUprate does):
            // the latter comes after CheckAndPrepare, thus ParIL would do its work first and ignore the additional content of the IL
            // thus variables defined after this DefIL (with DefVar) are not taken into account
            //
            // note on differences to "normal" (i.e. placeholder) incomelist entries:
            // - because of the above described, RegExp-entries are evaluted when the DefL appears in spine and not, as "normal" entries, on first usage of the incomelist
            // - only "registered" variables are taken into account, that means if a variable exists in data and is described in the variables file, but not
            //   used by any function before the DefIL, it is ignored (while a "normal" entry would register such a variable)
            //   uprating would however already count as usage (and one anyway gets a warning, if a data-variable is not uprated)
            //   (if this turns out to be a problem, we can improve later)
            //
            // this differnt behaviour can be justified, because this is a different parameter, I guess ...
        }
Пример #14
0
        // note that at this stage parameters are available (via GetxxxPar-functions of FunBase)
        // but not yet prepared, i.e. only xmlValue is available
        internal override void ProvideIndexInfo()
        {
            ParBase parName = GetUniquePar <ParBase>(DefPar.DefIl.Name); if (parName == null)
            {
                return;
            }

            Dictionary <string, double> content = new Dictionary <string, double>();

            foreach (var part in GetPlaceholderPar <ParBase>())
            {
                string varILName = part.Key;
                content.Add(varILName, GetAddMod(part.Value)); // note that vars/ILs are 'registered' (i.e.a.o. checked) in ParIL.CheckAndPrepare (i.e. on 1st use)
            }

            ParBool parWarn      = GetUniquePar <ParBool>(DefPar.DefIl.Warn_If_NonMonetary);
            bool    warnIfNonMon = parWarn == null?DefinitionAdmin.GetParDefault <bool>(DefFun.DefIl, DefPar.DefIl.Warn_If_NonMonetary) :
                                       ParBool.IsTrue(parWarn.xmlValue); // note: GetParBoolValueOrDefault cannot be used as parameter WarnIfNonMon is not yet checked

            infoStore.operandAdmin.RegisterIL(parName.xmlValue, DefFun.DefIl, description, content, warnIfNonMon);
        }
        internal bool IsProspectiveLoopOperand(string operand) // see InfoStore.IsProspectiveStoreOperand for description
        {                                                      // note that this can be called before (or after) PrepareNonCommonPar, therefore one cannot rely on variables (e.g. post, storeType, ...)
          // also note that we are only looking for the "running" operands, e.g. yem_loop, ils_earns_loop (i.e. without an iteration)
            ParBase parPostLoop = GetUniquePar <ParBase>(DefPar.Store.PostLoop);

            if (parPostLoop == null)
            {
                return(false);                     // most likely a PostFix-Store, thus not relevant
            }
            foreach (ParVar par in GetNonUniquePar <ParVar>(DefPar.Store.Var))
            {
                if (ComposeStoreName(par.xmlValue, NOTAP, parPostLoop.xmlValue).ToLower() == operand.ToLower())
                {
                    return(true);
                }
            }

            foreach (ParIL par in GetNonUniquePar <ParIL>(DefPar.Store.IL))
            {
                // first check for IL itself, e.g. ils_earns_loop
                string ili = ComposeStoreName(par.xmlValue, NOTAP, parPostLoop.xmlValue);
                if (ComposeStoreName(par.xmlValue, NOTAP, parPostLoop.xmlValue).ToLower() == operand.ToLower())
                {
                    return(true);
                }
                // then check for the content, e.g. yem_loop, yse_loop
                if (!infoStore.operandAdmin.Exists(par.xmlValue))
                {
                    continue;                                               // only check if il is already registered
                }
                foreach (string ilVar in ParIL.GetILComponents(par.xmlValue, infoStore.operandAdmin))
                {
                    if (ComposeStoreName(ilVar, NOTAP, parPostLoop.xmlValue).ToLower() == operand.ToLower())
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
        public static void PrintParInfo()
        {
            RandColor.WriteLine(Environment.NewLine + "parameter-order (140011-12) or function-order (140011) for analysis, x to exit", colorHeading);
            do
            {
                RandColor.Write("order: ", GetSwapColor()); string o = Console.ReadLine(); if (o == "x")
                {
                    break;
                }
                string fo, parOrder;
                fo       = o.Contains("-") ? o.Substring(0, o.IndexOf('-')) : o;
                parOrder = o.Contains("-") ? o.Substring(o.IndexOf('-')).TrimStart(new char[] { '-' }) : string.Empty;
                if (!double.TryParse(fo, out double funOrder) || !infoStore.spine.ContainsKey(funOrder))
                {
                    continue;
                }
                if (parOrder == string.Empty)
                {
                    foreach (var p in infoStore.spine[funOrder].TestGetAllPar(true))
                    {
                        RandColor.WriteLine($"{p.description.GetParName()} {p.description.par.order}", GetSwapColor());
                    }
                    continue;
                }
                ParBase anaPar = GetPar(funOrder, parOrder);
                if (anaPar != null)
                {
                    PrintParDetails(anaPar);
                }
                RandColor.WriteLine("- - - - - - - - - - - - - - - - - - - - - - - - ", colorHeading);
            } while (true);

            ParBase GetPar(double funOrder, string parOrder)
            {
                return((from p in infoStore.spine[funOrder].TestGetAllPar(true)
                        where p.description.par.order == parOrder
                        select p).FirstOrDefault());
            }
        }
Пример #17
0
        /// <summary>
        /// checks if the standard footnote-parameters, i.e. #_LowLim, #_UpLim, #_Level, are applied on the parameter
        /// if so, stores them in lowLim, upLim and alternativeTU (see above)
        /// also provides the "cleaned" value (e.g. yem#1 -> yem)
        /// note that the footnote-parameters are assessed via the (mother)function (parameter fun)
        /// also note that the only other (not here handled) footnote-parameters are 'amount', which is handled by ParFormula
        /// and query parameters which will not issue a "missing" (see below) but let the query check if it can use the footnote
        /// </summary>
        protected void ExtractStandardFootnotes(string value, out string cleanedValue, FunBase fun)
        {
            List <string> numbers = GetFootnoteNumbers(value, out cleanedValue); // it's unlikely, but yem#1#3 is possible (see GetFootnoteNumbers)

            if (numbers.Count == 0)
            {
                return;                     // no footnotes
            }
            // limits (see remark in _FunInSpineBase_Lim wrt not using a common implementation for limits)
            pLowLim = fun.GetFootnotePar <ParFormula>(DefPar.Footnote.LowLim, numbers);
            if (pLowLim != null)
            {
                if (pLowLim.IsGlobal(true))
                {
                    lowLim = pLowLim.GetGlobalValue(); pLowLim = null;
                }
                else
                {
                    doRunTimeLimCheck = true;
                }
            }

            pUpLim = fun.GetFootnotePar <ParFormula>(DefPar.Footnote.UpLim, numbers);
            if (pUpLim != null)
            {
                if (pUpLim.IsGlobal(true))
                {
                    upLim = pUpLim.GetGlobalValue(); pUpLim = null;
                }
                else
                {
                    doRunTimeLimCheck = true;
                }
            }

            ParCateg pLimpriority = fun.GetFootnotePar <ParCateg>(DefPar.Footnote.LimPriority, numbers);

            if (pLimpriority != null)
            {
                limPri = pLimpriority.GetCateg();
            }

            if (!doRunTimeLimCheck) // both limits available (might be double.MinValue and/or double.MaxValue, but does no harm here)
            {
                CheckLimits(ref lowLim, ref upLim);
            }

            // alternative TU
            ParBase parAltTU = fun.GetFootnotePar <ParBase>(DefPar.Footnote.Level, numbers);

            if (parAltTU != null)
            {
                alternativeTU = parAltTU.xmlValue;
            }

            // if none of the standard footnotes is defined in the function #x points to nowhere ...
            if (GetType() == typeof(ParQuery)) // ... except for queries, which may have own footnotes
            {
                return;                        // (this is slightly negligent, as it accepts e.g. IsMarried#1 without respective footnote-parameter)
            }
            if (pLowLim == null && lowLim == double.MinValue &&
                pUpLim == null && upLim == double.MaxValue &&
                parAltTU == null)
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = true, message = $"{description.Get()}: missing footnote parameter for {value}"
                });
            }
        }
        protected override void PrepareNonCommonPar()
        {
            if (!IsRunCondMet())
            {
                return;
            }

            infoStore.applicableUprateFunctions.Add(description); // to allow for checking if there is no/more than one applicable Uprate

            // get the "function-internal" (rather outdated) factor definitions, i.e. those defined by parameters Factor_Name/Factor_Value
            Dictionary <string, double> internalFactorDefs = GetInternalFactorDefs();

            // check if DBYearVar exists and handle accordingly
            ParVar parDBYearVarPar = GetUniquePar <ParVar>(DefPar.Uprate.DBYearVar);

            isDBYearVarUsed = parDBYearVarPar != null && parDBYearVarPar.name != DefPar.Value.NA;
            if (isDBYearVarUsed)
            {
                if (parDBYearVarPar.name.Trim() != string.Empty)
                {
                    infoStore.operandAdmin.CheckRegistration(name: parDBYearVarPar.name.Trim(), isOutVar: false,
                                                             warnIfNotInit: false, description: parDBYearVarPar.description);
                    if (!infoStore.operandAdmin.GetVarExistsInPersonVarList(parDBYearVarPar.name))
                    {
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = false,
                            message   = $"{parDBYearVarPar.description.Get()}: Parameter {DefPar.Uprate.DBYearVar} was used with value '{parDBYearVarPar.name}', but this variable is not defined"
                        });
                    }
                    else
                    {
                        DBYearVar = parDBYearVarPar.name;
                    }
                }
                else
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{this.description.Get()}: Parameter {DefPar.Uprate.DBYearVar} was used and left empty"
                    });
                }
            }

            // (1) "NORMAL" VARIABLES:
            // an uprating-group consists of the variable to uprate (e.g. yem=$f_cpi) and optionally of a condition (e.g. Factor_Cond={dgn=0})
            foreach (var group in GetParGroups(DefPar.Uprate.GROUP_MAIN).Values)
            {
                // optional condition parameter
                ParCond parCond = GetUniqueGroupPar <ParCond>(DefPar.Uprate.Factor_Condition, group);

                // compulsory var-name/factor-parameter (e.g. yem (in policy-column) / $f_cpi (in system-column))
                // usually this will be one placeholder-parameter but it is possible that one condition applies to several variables
                List <ParBase> listParMain = GetPlaceholderGroupPar <ParBase>(group);
                if (listParMain.Count == 0)
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{parCond.description.Get()}: loose condition {parCond.xmlValue}"
                    });
                    continue;
                }
                foreach (ParBase parMain in listParMain)
                {
                    string upVarName = parMain.description.GetParName(); // get the name of the variable to uprate (e.g. yem)
                                                                         // check for double uprating, but take care of conditions, e.g. twice yem-uprating without condition -> warning, yem-uprating different for men and women -> ok
                    bool exists = ExistsUpVar(upVarName, out bool conditioned);
                    if (exists && (!conditioned || parCond == null))
                    {
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = true, message = $"{parMain.description.Get()}: double uprating of variable {upVarName}"
                        });
                    }
                    Dictionary <double, double> upFactors = GetFactors(internalFactorDefs, parMain);

                    upVars.Add(new UpVar()
                    {
                        varSpec = new VarSpec()
                        {
                            name = upVarName
                        },
                        factors      = upFactors,
                        parCondition = parCond
                    });

                    // the main purpose of this registration is to ensure the variable exists (an error is issued if not)
                    // in fact uprated variables are likely to be registered by usage (why uprate a variable that is not used?)
                    // (it could still be that an uprated but otherwise unused variable should be in the output and would not if VarGroup is used)
                    infoStore.operandAdmin.CheckRegistration(name: upVarName, isOutVar: false,
                                                             warnIfNotInit: false, description: parMain.description);
                }
            }

            // check for double conditioned uprating
            foreach (UpVar condUpVar in from cuv in upVars where cuv.parCondition != null select cuv)
            {
                if ((from cuv in upVars
                     where upVars.IndexOf(cuv) > upVars.IndexOf(condUpVar) && cuv.varSpec.name.ToLower() == condUpVar.varSpec.name.ToLower() &&
                     cuv.parCondition != null && cuv.parCondition.description.GetParGroup() == condUpVar.parCondition.description.GetParGroup()
                     select cuv).Count() > 0)
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = true, message = $"{condUpVar.parCondition.description.Get()}: double uprating of variable {condUpVar.varSpec.name}"
                    });
                }
            }

            // (2) AGGREGATE VARIABLES:
            // the group consists of AggVar_Name (the agg-var to uprate) and a list of AggVar_Part (the vars summing up to the agg-var)
            // and optionally of AggVar_Tolerance (a tolerance for the check if part-vars actually sum up to agg-var)
            foreach (var group in GetParGroups(DefPar.Uprate.GROUP_AGG).Values)
            {
                ParVar parName = GetUniqueGroupPar <ParVar>(DefPar.Uprate.AggVar_Name, group);
                if (parName == null)
                {
                    continue;                  // error is issued by general checking
                }
                if (ExistsUpVar(parName.name, out bool dummy))
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = true, message = $"{parName.description.Get()}: double uprating of variable {parName.name} (aggregate and normally)"
                    });
                }

                ParNumber parTol = GetUniqueGroupPar <ParNumber>(DefPar.Uprate.AggVar_Tolerance, group);

                AggUpVar aggUpVar = new AggUpVar()
                {
                    varSpec = new VarSpec()
                    {
                        name = parName.name
                    }
                };
                if (parTol != null)
                {
                    aggUpVar.tolerance = parTol.GetValue();
                }

                foreach (ParVar parPart in GetNonUniqueGroupPar <ParVar>(DefPar.Uprate.AggVar_Part, group))
                {
                    aggUpVar.parts.Add(new VarSpec()
                    {
                        name = parPart.name
                    });
                }

                if (aggUpVar.parts.Count > 0)
                {
                    aggUpVars.Add(aggUpVar);
                }
            }

            // (3) VARIABLES DEFINED BY REGULAR EXPRESSION (e.g. for updating expenditure variables)
            foreach (var group in GetParGroups(DefPar.Uprate.GROUP_REGEXP).Values)
            {
                ParBase parDef    = GetUniqueGroupPar <ParBase>(DefPar.Uprate.RegExp_Def, group);
                ParBase parFactor = GetUniqueGroupPar <ParBase>(DefPar.Uprate.RegExp_Factor, group);
                if (parDef == null || parFactor == null)
                {
                    continue;
                }
                upRegExp.Add(parDef.xmlValue, GetFactors(internalFactorDefs, parFactor));
            }

            // get default factor ...
            ParBase parDefFac = GetUniquePar <ParBase>(DefPar.Uprate.Def_Factor);

            if (parDefFac != null)
            {
                defaultFactor = GetFactors(internalFactorDefs, parDefFac);
            }

            // ... and the optional parameter WarnIfNoFactor
            warnIfNoFactor = GetParBoolValueOrDefault(DefFun.Uprate, DefPar.Uprate.WarnIfNoFactor);

            // ... and the optional parameter WarnIfNonMonetary
            warnIfNonMonetary = GetParBoolValueOrDefault(DefFun.Uprate, DefPar.Uprate.WarnIfNonMonetary);

            if (zeroFactorSysCollector.Count > 0)
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = true,
                    message   = $"{description.Get()}: uprating-index for system year is 0 for {string.Join(", ", zeroFactorSysCollector)}, resulting in uprating concerned variables by 0."
                });
            }
            if (zeroFactorDataCollector.Count > 0)
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = true,
                    message   = $"{description.Get()}: uprating-index for data year is 0 for {string.Join(", ", zeroFactorDataCollector)}, resulting in setting concerned variables to NaN."
                });
            }
        }
        protected override void PrepareNonCommonPar()
        {
            aggs = GetNonUniquePar <ParVarIL>(DefPar.Totals.Agg);
            if (aggs.Count == 0)
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false, message = $"{description.Get()}: missing required parameter AGG"
                });
                return;
            }

            foreach (string t in new List <string> {
                DefPar.Totals.Varname_Sum, DefPar.Totals.Varname_Mean, DefPar.Totals.Varname_Median,
                DefPar.Totals.Varname_Decile, DefPar.Totals.Varname_Quintile, DefPar.Totals.Varname_Count, DefPar.Totals.Varname_PosCount,
                DefPar.Totals.Varname_NegCount, DefPar.Totals.Varname_Min, DefPar.Totals.Varname_Max
            })
            {
                ParBase par = GetUniquePar <ParBase>(t); if (par == null)
                {
                    continue;
                }

                actions.Add(t);

                foreach (ParVarIL agg in aggs)
                {
                    string aggName = agg.GetName();
                    agg.CheckAndPrepare(this);
                    int n = 1; if (t == DefPar.Totals.Varname_Decile)
                    {
                        n = 9;
                    }
                    if (t == DefPar.Totals.Varname_Quintile)
                    {
                        n = 4;
                    }
                    for (int i = 1; i <= n; ++i)
                    {
                        string counter = t == DefPar.Totals.Varname_Decile || t == DefPar.Totals.Varname_Quintile ? i.ToString() : string.Empty;
                        string varName = $"{par.xmlValue}{counter}_{aggName}";
                        infoStore.operandAdmin.RegisterVar( // generate the variable that will take the total
                            name: varName,
                            creatorFun: DefFun.Totals,
                            description: par.description,
                            isMonetary: false,  // not really clear, but adding over TU does not make sense
                            isGlobal: true,     // equal for each person
                            isWriteable: false, // cannot be use as output-variable
                            setInitialised: true);
                        if (infoStore.operandAdmin.Exists(varName))
                        {
                            totals.Add(t + (n > 1 ? i.ToString() : "") + aggName, new VarSpec()
                            {
                                name = varName
                            });
                        }
                    }
                }
            }

            // setup booleans
            hasMedian = actions.Contains(DefPar.Totals.Varname_Median);
            hasQuint  = actions.Contains(DefPar.Totals.Varname_Quintile);
            hasDec    = actions.Contains(DefPar.Totals.Varname_Decile);
            hasSum    = actions.Contains(DefPar.Totals.Varname_Sum);
            hasMean   = actions.Contains(DefPar.Totals.Varname_Mean);

            // check if there is a condition for inclusion
            ParCond inclCond = GetUniquePar <ParCond>(DefPar.Totals.Incl_Cond);

            if (inclCond != null)
            {
                ParCateg inclWho    = GetUniquePar <ParCateg>(DefPar.Totals.Incl_Cond_Who);
                string   inclWhoVal = (inclWho == null) ? DefPar.Value.WHO_ALL : inclWho.GetCateg();
                include = new Tuple <ParCond, string>(inclCond, inclWhoVal);
            }

            // check if results should be weighted
            useWeights = GetParBoolValueOrDefault(DefFun.Totals, DefPar.Totals.Use_Weights);
            if (useWeights) // get the weight var, if null use dwt
            {
                ParVar dwtPar = GetUniquePar <ParVar>(DefPar.Totals.Weight_Var);
                dwtName = dwtPar != null ? dwtPar.name : DefVarName.DWT;
                infoStore.operandAdmin.CheckRegistration(dwtName, false, false, description);
            }

            //
        }
Пример #20
0
        protected override void PrepareNonCommonPar()
        {
            if (!IsRunCondMet()) // note that this works for info that is clearly available at read-time, e.g. {IsUsedDatabase} or {1}
            {
                return;          // but simply returns true for global variables, which may (in theory) change over run-time
            }
            // to handle the latter IsRunCond is called again in the Run-function (see below)
            // consequently for e.g. {0} the variables are not even generated
            // while for {$Const}, with $Const=0 at the point of request, the variables exist but are set to 0
            // this also reflects the behaviour of the old executable

            ParBase parSysYear = GetUniquePar <ParBase>(isConst ? DefPar.DefConst.Const_SystemYear : DefPar.DefVar.Var_SystemYear);

            if (parSysYear != null && !EM_Helpers.DoesValueMatchPattern(parSysYear.xmlValue, infoStore.country.sys.year))
            {
                return;
            }

            ParBase parDataSet = GetUniquePar <ParBase>(isConst ? DefPar.DefConst.Const_Dataset : DefPar.DefVar.Var_Dataset);

            if (parDataSet != null && !infoStore.IsUsedDatabase(parDataSet.xmlValue))
            {
                return;
            }

            foreach (var g in GetParGroups(isConst ? DefPar.DefConst.THE_ONLY_GROUP : DefPar.DefVar.THE_ONLY_GROUP))
            {
                List <ParBase> group = g.Value;

                // global variables (DefConst) allow for parameter Condition (but there is no reason why it wouldn't work for DefVar as well, thus no check)
                ParCond cond = GetUniqueGroupPar <ParCond>(DefPar.DefConst.Condition, group);

                List <ParFormula> initFormulas = GetPlaceholderGroupPar <ParFormula>(group);

                if (initFormulas.Count == 0) // there can be single Monetary parameters if definition is n/a for this system
                {
                    continue;
                }
                if (cond == null && initFormulas.Count > 1)
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{initFormulas[0].description.Get()}: multiple definition, group {g.Key} is already in use"
                    });
                    continue;
                }

                foreach (ParFormula initFormula in initFormulas)
                {
                    string varName = initFormula.description.GetParName();
                    if (!EM_Helpers.IsValidName(varName, out string illegal))
                    {
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = false,
                            message   = $"{initFormula.description.Get()}: name contains illegal character(s) '{illegal}'"
                        });
                        continue;
                    }

                    if (isConst && cond == null && !initFormula.IsGlobal())
                    {
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = true,
                            message   = $"{initFormula.description.Get()}: trying to initialise global variable with a non-global amount"
                        });
                    }

                    bool isMonetary = false;
                    if (!isConst) // variables defined with DefConst cannot be monetary (more precisely, should not be added over TUs)
                    {
                        // if monetary-parameter is defined, use it, otherwise monetary=true (more precisely, get the default value from lib-def)
                        ParBool parMonetary = GetUniqueGroupPar <ParBool>(DefPar.DefVar.Var_Monetary, group);
                        isMonetary = parMonetary != null?parMonetary.GetBoolValue()
                                         : DefinitionAdmin.GetParDefault <bool>(funName: DefFun.DefVar, parName: DefPar.DefVar.Var_Monetary);
                    }

                    if (!infoStore.operandAdmin.Exists(varName)) // double definition is not illegal (maybe questionable, but handled like this in old exe)
                    {
                        infoStore.operandAdmin.RegisterVar(name: varName, creatorFun: DefFun.DefVar, description: initFormula.description,
                                                           isMonetary: isMonetary,
                                                           isGlobal: isConst && cond == null,
                                                           isWriteable: true,     // DefVar defined variables can be used as output-var (this is a bit lax with DefConst)
                                                           setInitialised: true); // DefVar defined variables always have an initial value -
                                                                                  // if user sets it n/a it does not exist, otherwise she needs to assign a value
                                                                                  // actual initialisation is done in the Run function
                        if (!infoStore.operandAdmin.Exists(varName))
                        {
                            continue;                                          // registration failed
                        }
                    }
                    else if (infoStore.operandAdmin.GetCreatorFun(varName) != DefFun.DefVar && infoStore.operandAdmin.GetCreatorFun(varName) != DefFun.DefConst)
                    {
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = false,
                            message   = $"{description.Get()} {varName}: {DefFun.DefVar}/{DefFun.DefConst} can only overwrite variables created by (another) {DefFun.DefVar}/{DefFun.DefConst}"
                        });
                        continue;
                    }

                    // variable cannot yet be initialised, as at this stage the hh-data does not exist (no formula interpretation possible yet)
                    // note on still setting the variable initialised at this stage, in context with the "not-initialised" warning:
                    // parameters are prepared in the spine-order, thus parameters which are prepared before would get a "not known"
                    // and parameters prepared afterwards are "legal" users
                    if (!varDefs.ContainsKey(varName))
                    {
                        varDefs.Add(varName, new List <VarDef>());                               // see definition of varDefs for reason for Dictionary
                    }
                    varDefs[varName].Add(new VarDef()
                    {
                        varSpec = new VarSpec()
                        {
                            name = varName
                        }, initFormula = initFormula, condition = cond, groupNo = g.Key
                    });
                }
            }

            // a variable can only be defined more than once within one function, if it is conditioned:
            // only one definition can exist without a condition (which will be used as the default fallback value if conditions also exist)
            foreach (List <VarDef> condConstDef in varDefs.Values)
            {
                if (condConstDef.Count > 1 && (from c in condConstDef where c.condition == null select c).Count() > 1)
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{description.Get()}: multiple definitions of {condConstDef[0].varSpec.name} without {DefPar.DefConst.Condition} found"
                    });
                }
            }
        }
        protected override void PrepareNonCommonPar()
        {
            ParBase parPostLoop = GetUniquePar <ParBase>(DefPar.Restore.PostLoop);
            ParBase parPostFix  = GetUniquePar <ParBase>(DefPar.Restore.PostFix);

            if (parPostLoop == null && parPostFix == null)
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false,
                    message   = $"{description.Get()}: neither {DefPar.Restore.PostFix} nor {DefPar.Restore.PostLoop} defined"
                });
                return;
            }
            if (parPostLoop != null && parPostFix != null)
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false,
                    message   = $"{description.Get()}: unclear specification - both {DefPar.Restore.PostFix} and {DefPar.Restore.PostLoop} defined"
                });
                return;
            }

            string post = parPostLoop == null ? parPostFix.xmlValue : parPostLoop.xmlValue;

            if (!infoStore.operandAdmin.indexStoreFuns.ContainsKey(post))
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false,
                    message   = $"{description.Get()}: no related Store-function ({post}) found"
                });
                return;
            }

            relatedStore = infoStore.operandAdmin.indexStoreFuns[post];
            switch (relatedStore.storeType)
            {
            case FunStore.STORETYPE.UNITLOOP: infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false,
                    message   = $"{description.Get()}: restoring UnitLoop values is not possible"
                }); return;

            case FunStore.STORETYPE.FIX: if (parPostFix == null)
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{parPostLoop.description.Get()}: related Store-function concerns {DefPar.Store.PostFix}"
                    }); return;
                }
                break;

            case FunStore.STORETYPE.LOOP: if (parPostLoop == null)
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{parPostFix.description.Get()}: related Store-function concerns {DefPar.Store.PostLoop}"
                    }); return;
                }
                break;
            }

            if (parPostLoop != null)
            {
                ParNumber parIteration = GetUniquePar <ParNumber>(DefPar.Restore.Iteration);
                if (parIteration != null)
                {
                    loopIteration = parIteration.GetValue();
                    if (!EM_Helpers.IsNonNegInteger(loopIteration, false))
                    {
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = false, message = $"{parIteration.description.Get()}: must be a non-negative integer"
                        });
                    }
                    else
                    {
                        relatedStore.RegisterOperands((int)loopIteration);  // see description in FunStore
                    }
                }
                else
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false, message = $"{description.Get()}: parameter {DefPar.Restore.Iteration} missing"
                    });
                }
            }
        }
        private static void PrintParDetails(ParBase par)
        {
            RandColor.WriteLine(par.description.Get(), GetSwapColor());
            RandColor.WriteLine($"xml-value: {par.xmlValue}", GetSwapColor());

            if (infoStore.hhAdmin == null)
            {
                return;
            }
            HH            dummyHH = infoStore.hhAdmin.GetFirstHH();
            List <Person> dummyTU = new List <Person>()
            {
                new Person(0)
            };

            if (par.GetType() == typeof(ParBool))
            {
                RandColor.WriteLine($"value: {(par as ParBool).GetBoolValue()}", GetSwapColor());
            }
            else if (par.GetType() == typeof(ParCateg))
            {
                RandColor.WriteLine($"value: {(par as ParCateg).GetCateg()}", GetSwapColor());
            }
            else if (par.GetType() == typeof(ParNumber))
            {
                RandColor.WriteLine($"value: {(par as ParNumber).GetValue()}", GetSwapColor());
            }
            else if (par.GetType() == typeof(ParTU))
            {
                string tuName = (par as ParTU).name;
                dummyHH.GetTUs(tuName); // that's to "use" the TU, i.e. to create it for the HH
                RandColor.WriteLine($"TU {tuName} has {dummyHH.hhTUs[tuName].Count} unit(s) in 1st HH", GetSwapColor());
            }
            else if (par.GetType() == typeof(ParVar))
            {
                RandColor.WriteLine($"value: {(par as ParVar).GetValue(dummyHH, dummyTU)}", GetSwapColor());
            }
            else if (par.GetType() == typeof(ParOutVar)) // there is actually nothing to check, out-vars just care for registration
            {
                RandColor.WriteLine($"index: {(par as ParOutVar).index}", GetSwapColor());
            }
            else if (par.GetType() == typeof(ParIL))
            {
                RandColor.WriteLine($"value: {(par as ParIL).GetValue(dummyHH, dummyTU)}", GetSwapColor());
            }
            else if (par.GetType() == typeof(ParVarIL))
            {
                RandColor.WriteLine($"value: {(par as ParVarIL).GetValue(dummyHH, dummyTU)}", GetSwapColor());
            }
            else if (par.GetType() == typeof(ParFormula))
            {
                RandColor.WriteLine($"value: {(par as ParFormula).GetValue(dummyHH, dummyTU)}", GetSwapColor());
            }
            else if (par.GetType() == typeof(ParCond))
            {
                RandColor.WriteLine($"ParCond not yet handled", ConsoleColor.DarkMagenta);
            }
            else
            {
                RandColor.WriteLine($"unknow type: {par.GetType()}", GetSwapColor());
            }
        }
Пример #23
0
        /// <summary>
        /// try to identify parameters and, if valid, generate the respective ParXXX and put into respective lists (see above)
        /// </summary>
        private void ClassifyParameters(Dictionary <string, ExeXml.Par> xmlParList, DefinitionAdmin.Fun funDef)
        {
            int dummyGroupNumber = -9999; // this is for placeholder-parameters, see below

            foreach (var xmlPar in xmlParList)
            {
                Description parDescription = new Description(description, xmlPar.Value, xmlPar.Key);
                string      xmlParName     = xmlPar.Value.Name;

                // first check if it is an 'ordinary' parameter ...
                DefinitionAdmin.Par parDef = funDef.GetParDef(xmlParName);
                if (parDef != null)
                {
                    string officialParName = funDef.GetOfficalParName(xmlParName); // is (in contrast to xmlParName) case-sensitive and
                                                                                   // corresponds to constants as defined in Common-library
                                                                                   // generate parameter ...
                    ParBase par = GeneratePar(xmlPar, parDef, parDescription);
                    // ... and put it into the list it belongs too ...
                    if (parDef.isFootnote) // ... footnote-list
                    {
                        if (GetGroupNumber(xmlPar.Value, parDescription, out int dummy))
                        {
                            if (!footnotePar.ContainsKey(xmlPar.Value.Group))
                            {
                                footnotePar.Add(xmlPar.Value.Group, new Dictionary <string, ParBase>());
                            }
                            if (!footnotePar[xmlPar.Value.Group].ContainsKey(officialParName))
                            {
                                footnotePar[xmlPar.Value.Group].Add(officialParName, par);
                            }
                            else
                            {
                                ReportDoubleDef(parDescription);
                            }
                        }
                    }
                    else if (parDef.maxCount == 1) // ... unique-parameter-list
                    {
                        if (!uniquePar.ContainsKey(officialParName))
                        {
                            uniquePar.Add(officialParName, par);
                            if (infoStore.runConfig.warnAboutUselessGroups && !string.IsNullOrEmpty(xmlPar.Value.Group))
                            {
                                ReportUselessGroup(parDescription);
                            }
                        }
                        else
                        {
                            ReportDoubleDef(parDescription);
                        }
                    }
                    else // ... non-unique-parameter-list
                    {
                        if (!nonUniquePar.ContainsKey(officialParName))
                        {
                            nonUniquePar.Add(officialParName, new List <ParBase>());
                        }
                        nonUniquePar[officialParName].Add(par);
                        if (infoStore.runConfig.warnAboutUselessGroups && !string.IsNullOrEmpty(xmlPar.Value.Group))
                        {
                            ReportUselessGroup(parDescription);
                        }
                    }
                    continue;
                }
                // ... if not successuful, check if it is a group parameter ...
                parDef = funDef.GetGroupParDef(xmlParName, out string groupName);
                if (parDef != null)
                {
                    if (GetGroupNumber(xmlPar.Value, parDescription, out int groupNo))
                    {
                        // generate parameter ...
                        ParBase par = GeneratePar(xmlPar, parDef, parDescription);
                        // ... and put it into group-parameter-list
                        if (!groupPar.ContainsKey(groupName))
                        {
                            groupPar.Add(groupName, new SortedList <int, List <ParBase> >());
                        }
                        if (!groupPar[groupName].ContainsKey(groupNo))
                        {
                            groupPar[groupName].Add(groupNo, new List <ParBase>());
                        }
                        if (parDef.maxCount > 1 || GetUniqueGroupPar <ParBase>(xmlPar.Value.Name, groupPar[groupName][groupNo]) == null)
                        {
                            groupPar[groupName][groupNo].Add(par);
                        }
                        else
                        {
                            ReportDoubleDef(parDescription);
                        }
                    }
                    continue;
                }
                // ... if still not successful, it could still be placehoder parameter ...
                if (funDef.AllowsForPlaceholders())
                {
                    parDef = funDef.GetPlaceholderDef(out string phGroupName);
                    ParBase par = GeneratePar(xmlPar, parDef, parDescription, true);
                    if (phGroupName == null) // non-group placeholder, as e.g. in SetDefault, DefIL
                    {
                        if (!placeholderPar.TryAdd(xmlParName, par))
                        {
                            infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                            {
                                isWarning = true, message = $" {parDescription.Get()}: {xmlParName} double definition (is ignored)"
                            });
                        }
                    }
                    else // group placeholder, as e.g. in DefVar (PH, IsGlobal, IsMonetary), Uprate (PH, FactorCond)
                    {
                        GetGroupNumber(xmlPar.Value, parDescription, // note that this returns a dummy-group if the user didn't indicate one
                                       out int groupNo, true); // as placeholders only actually need a group if they are "further specified" (e.g. uprating-factors: factor_condition)
                        if (!groupPar.ContainsKey(phGroupName))
                        {
                            groupPar.Add(phGroupName, new SortedList <int, List <ParBase> >());
                        }
                        if (!groupPar[phGroupName].ContainsKey(groupNo))
                        {
                            groupPar[phGroupName].Add(groupNo, new List <ParBase>());
                        }
                        groupPar[phGroupName][groupNo].Add(par);
                    }
                    continue;
                }
                // ... now we give up
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = true, message = $" {parDescription.Get()}: unknown parameter"
                });
            }

            if (infoStore.runConfig.warnAboutUselessGroups)
            {
                foreach (var groupType in groupPar)
                {
                    if (groupType.Key.ToLower() == DefPar.SchedCalc.Band_XXX.ToLower())
                    {
                        continue;
                    }
                    foreach (var group in groupType.Value)
                    {
                        if (group.Key >= 0 && group.Value.Count == 1)
                        {
                            ReportUselessGroup(group.Value[0].description);
                        }
                    }
                }
            }

            // internal function for generating parameters
            ParBase GeneratePar(KeyValuePair <string, ExeXml.Par> xmlPar, DefinitionAdmin.Par parDef,
                                Description parDescription, bool isPlaceholder = false)
            {
                ParBase par;

                switch (parDef.valueType)
                {
                case DefPar.PAR_TYPE.FORMULA: par = new ParFormula(infoStore); break;

                case DefPar.PAR_TYPE.CONDITION: par = new ParCond(infoStore); break;

                case DefPar.PAR_TYPE.BOOLEAN: par = new ParBool(infoStore); break;

                case DefPar.PAR_TYPE.NUMBER: par = new ParNumber(infoStore); break;

                case DefPar.PAR_TYPE.TEXT: par = new ParBase(infoStore); break;

                case DefPar.PAR_TYPE.VAR: par = new ParVar(infoStore); break;

                case DefPar.PAR_TYPE.OUTVAR: par = new ParOutVar(infoStore); break;

                case DefPar.PAR_TYPE.IL: par = new ParIL(infoStore); break;

                case DefPar.PAR_TYPE.TU: par = new ParTU(infoStore); break;

                case DefPar.PAR_TYPE.VARorIL: par = new ParVarIL(infoStore); break;

                case DefPar.PAR_TYPE.CATEG: par = new ParCateg(infoStore, parDef.categValues); break;

                case DefPar.PAR_TYPE.PLACEHOLDER: par = new ParBase(infoStore); break;

                default: throw new Exception($"Not yet properly implemented parameter value type {parDef.valueType}");
                }
                par.description = parDescription;
                par.xmlValue    = xmlPar.Value.val;
                par.description.isPlaceholder = isPlaceholder;
                return(par);
            }

            bool GetGroupNumber(ExeXml.Par p, Description parDescription, out int groupNumber, bool allowDummy = false)
            {
                groupNumber = dummyGroupNumber++;  // placeholders (e.g.uprating factors) only actually need a group
                if (string.IsNullOrEmpty(p.Group)) // if they are "further specified" (e.g.factor_condition)
                {
                    if (allowDummy)
                    {
                        return(true);
                    }
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false, message = $" {parDescription.Get()}: missing group"
                    });
                    return(false);
                }
                if (int.TryParse(p.Group, out groupNumber))
                {
                    return(true);
                }
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false, message = $" {parDescription.Get()}: invalid group {p.Group} (must be an integer number)"
                });
                return(false);
            }

            void ReportDoubleDef(Description parDescription)
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false, message = $" {parDescription.Get()}: defined more than once"
                });
            }

            void ReportUselessGroup(Description parDescription)
            {
                if (parDescription.GetFunName() != DefFun.Store)    // add a special exception for Store, as it has its own reporting
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = true, message = $" {parDescription.Get()}: group has no use"
                    });
                }
            }
        }
        private Dictionary <double, double> GetFactors(Dictionary <string, double> internalFactorDefs, ParBase parFac)
        {
            Dictionary <double, double> allFactors = new Dictionary <double, double>();
            string upFactorS = parFac.xmlValue; // xmlValue contains the uprating instruction,

            // which may be a number (e.g. 1.4) or the name of a factor (e.g. $f_cpi)
            if (!double.TryParse(EM_Helpers.AdaptDecimalSign(upFactorS), out double upFactor)) // first try if a number ...
            {
                if (internalFactorDefs.ContainsKey(upFactorS))                                 // ... then try if a factor defined by Factor_Name/Factor_Value
                {
                    allFactors.Add(UpVar.ALLYEARS, internalFactorDefs[upFactorS]);
                }
                else if (infoStore.country.upFacs.ContainsKey(upFactorS)) // ... then try if a factor-name defined in dialog
                {
                    if (infoStore.country.upFacs[upFactorS].Get(infoStore.country.sys.year, out double sysInd))
                    {
                        if (sysInd == 0 && !zeroFactorSysCollector.Contains(upFactorS))
                        {
                            zeroFactorSysCollector.Add(upFactorS);
                        }
                        if (isDBYearVarUsed)
                        {
                            // Calculate the uprating factors
                            foreach (KeyValuePair <string, double> facs in infoStore.country.upFacs[upFactorS].GetAll())
                            {
                                if (double.TryParse(facs.Key, out double yr))
                                {
                                    if (facs.Value == 0 && !zeroFactorDataCollector.Contains(facs.Key))
                                    {
                                        zeroFactorDataCollector.Add(facs.Key);
                                    }
                                    allFactors.Add(yr, sysInd / facs.Value);
                                }
                                else
                                {
                                    // This should only happen if a year cannot be parsed - This should NEVER happen!
                                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                                    {
                                        isWarning = false,
                                        message   = $"{parFac.description.Get()}: invalid year '{facs.Key}' found in uprating factors!"
                                    });
                                    return(allFactors);
                                }
                            }
                        }
                        else
                        {
                            if (infoStore.country.upFacs[upFactorS].Get(infoStore.country.data.year, out double dbInd))
                            {
                                if (dbInd == 0 && !zeroFactorDataCollector.Contains(upFactorS))
                                {
                                    zeroFactorDataCollector.Add(upFactorS);
                                }
                                allFactors.Add(UpVar.ALLYEARS, sysInd / dbInd);
                            }
                            else
                            {
                                // Or keep 1 and return warning if any indices are missing
                                string dataInfo = string.IsNullOrEmpty(infoStore.country.data.year)
                                    ? $": income-year is missing for '{infoStore.country.data.Name}'"
                                    : $" for data year '{infoStore.country.data.year}'";
                                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                                {
                                    isWarning = true,
                                    message   = $"{parFac.description.Get()}: insufficient definition of uprating-factor '{parFac.xmlValue}'{dataInfo} (1 is used as default)"
                                });
                            }
                        }
                    }
                    else
                    {
                        // Or keep 1 and return warning if any indices are missing
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = true,
                            message   = $"{parFac.description.Get()}: insufficient definition of uprating-factor '{parFac.xmlValue}' for system year '{infoStore.country.sys.year}' (1 is used as default)"
                        });
                    }
                }
                else
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{parFac.description.Get()}: unknown factor {parFac.xmlValue}"
                    });
                }
            }
            else
            {
                allFactors.Add(UpVar.ALLYEARS, upFactor);
            }
            return(allFactors);
        }