Ejemplo n.º 1
0
        internal bool isMonetary = false;       // should this varil be formatted like monetary

        internal override void CheckAndPrepare(FunBase fun)
        {
            GetFootnoteNumbers(xmlValue, out string potentialIL);

            if (infoStore.operandAdmin.Exists(potentialIL) &&
                infoStore.operandAdmin.GetParType(potentialIL) == DefPar.PAR_TYPE.IL)
            {
                parIL = new ParIL(infoStore)
                {
                    xmlValue = xmlValue, description = this.description
                };
                parIL.CheckAndPrepare(fun);
            }
            else
            {
                parVal = new ParVar(infoStore)
                {
                    xmlValue = xmlValue, description = this.description
                };
                parVal.CheckAndPrepare(fun);
            }

            if (infoStore.operandAdmin.GetIsMonetary(GetName()))
            {
                isMonetary = true;
            }
        }
Ejemplo n.º 2
0
        protected override void PrepareNonCommonPar()
        {
            path = GetParBaseValueOrDefault(DefFun.DefInput, DefPar.DefInput.path);     // compulsory
            file = GetParBaseValueOrDefault(DefFun.DefInput, DefPar.DefInput.file);     // compulsory

            ParVar parRowMergeVar = GetUniquePar <ParVar>(DefPar.DefInput.RowMergeVar); // compulsory

            if (parRowMergeVar != null)
            {
                rowMergeVar = new VarSpec()
                {
                    name = parRowMergeVar.name
                }
            }
            ;
            ParVar parColMergeVar = GetUniquePar <ParVar>(DefPar.DefInput.ColMergeVar);

            if (parColMergeVar != null)
            {
                colMergeVar = new VarSpec()
                {
                    name = parColMergeVar.name
                }
            }
            ;
            ParVar parInputVar = GetUniquePar <ParVar>(DefPar.DefInput.InputVar);

            if (parInputVar != null)
            {
                inputVar = new VarSpec()
                {
                    name = parInputVar.name
                }
            }
            ;

            if ((colMergeVar != null && inputVar == null) || (colMergeVar == null && inputVar != null))
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false,
                    message   = $"{description.Get()}: if {DefPar.DefInput.ColMergeVar} is defined {DefPar.DefInput.InputVar} must be defined too, and vice-versa"
                });
            }
            lookUpMode = colMergeVar != null;

            repByEMPath         = GetParBaseValueOrDefault(DefFun.DefInput, DefPar.DefInput.RepByEMPath);
            ignoreNRows         = (int)GetParNumberValueOrDefault(DefFun.DefInput, DefPar.DefInput.IgnoreNRows);
            ignoreNCols         = (int)GetParNumberValueOrDefault(DefFun.DefInput, DefPar.DefInput.IgnoreNCols);
            doRanges            = GetParBoolValueOrDefault(DefFun.DefInput, DefPar.DefInput.DoRanges);
            parDefaultIfNoMatch = GetUniquePar <ParNumber>(DefPar.DefInput.DefaultIfNoMatch);

            // * * *   T O D O   * * *
            // consider parameters that allow defining and initialising variables
            // currently all input-variables need to be defined with DefVar or, if they are defined in variables-file, initialised with SetDefault
        }
Ejemplo n.º 3
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"
                    });
                }
            }
        }
 protected void PrepareEligPar()
 {
     coParWho     = GetUniquePar <ParCateg>(DefPar.Common.Who_Must_Be_Elig);
     coParEligVar = GetUniquePar <ParVar>(DefPar.Common.Elig_Var);
 }
        internal override void CheckAndPrepare(FunBase fun)
        {
            if (FunIlArithOp.HandlesCheckAndPrepare(this))
            {
                return;                                            // IlArithOp has a special handling for the Formula parameter (see FunIlArithOp.cs)
            }
            if (xmlValue.Contains("}#"))
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = true, runTimeErrorId = description.funID, message = $"{description.Get()}: Footnotes should not be placed outside curly brackets! Please make sure that all footnotes are directly applied to a single operand."
                });
            }
            // for optimisation reasons handle #Amount and periods (#y, #w, ...) before parsing the formula:
            // alternatively one could allow for PAR_TYPE.NUMBER in the switch below, which would create a ParNumber that takes care
            // but then e.g. 1200#y*3 would, for each HH, ask for parNumber.GetValue()*3, while with this "preparsing" we just have 300
            string preParsedFormula = PreParse(xmlValue, fun);

            // parse the main formula
            try { parsedExpression = calc.CompileExpression(preParsedFormula); }
            catch (Exception e)
            {
                infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                {
                    isWarning = false, message = $"{description.Get()}: {e.Message}"
                }); return;
            }

            foreach (string op in calc.Variables.Keys)     // parse the formula ...
            {
                ParBase_FormulaComponent opPar = null;     // ... and prepare the operands

                GetFootnoteNumbers(op, out string opName); // temporarily remove potential footnotes to get the pure operand (e.g. yem#1->yem)

                // handle "partner:yem" or "head:yem"
                if (opName.Contains(":"))
                {
                    // this is not allowed outside DefTU!
                    if (description.fun.Name != DefFun.DefTu)
                    {
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = false, message = $"{description.Get()}: invalid use of target outside of a DefTU '{opName}'."
                        });
                    }
                    opName = opName.Substring(opName.IndexOf(":") + 1);
                }

                if (infoStore.operandAdmin.Exists(opName))
                {
                    switch (infoStore.operandAdmin.GetParType(opName))
                    {
                    //case DefPar.PAR_TYPE.NUMBER: opPar = new ParNumber(infoStore); break; // see PreParse above
                    case DefPar.PAR_TYPE.VAR: opPar = new ParVar(infoStore); break;

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

                    case DefPar.PAR_TYPE.QUERY: opPar = new ParQuery(infoStore); break;
                    }
                }
                else
                {
                    opPar = new ParVar(infoStore);  // if not yet in the operand-list, the only (not faulty) option is a data-variable
                }
                opPar.description = description;
                opPar.xmlValue    = op;
                opPar.CheckAndPrepare(fun);
                operands.Add(op, opPar);
            }
        }
        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);
            }

            //
        }
        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()
        {
            ParVar fv = GetUniquePar <ParVar>(DefPar.AddHHMembers.FlagVar);

            if (fv != null)
            {
                flagVar = new VarSpec()
                {
                    name = fv.name
                }
            }
            ;

            foreach (var g in GetParGroups(DefPar.AddHHMembers.GROUP_MAIN))
            {
                var            group = g.Value; int groupNo = g.Key;
                AddInstruction addInstruction = new AddInstruction();

                // first find out whether we are adding children or partners or other persons ...
                ParCateg parWho = GetUniqueGroupPar <ParCateg>(DefPar.AddHHMembers.Add_Who, group); if (parWho == null)
                {
                    continue;                                                                                                    // compulsory parameter, error already issued
                }
                addInstruction.addWho = parWho.GetCateg();

                // ... depending on that, check the add-condition
                ParCond parParent = GetUniqueGroupPar <ParCond>(DefPar.AddHHMembers.ParentCond, group);
                ParCond parPartner = GetUniqueGroupPar <ParCond>(DefPar.AddHHMembers.PartnerCond, group);
                ParCond parOther = GetUniqueGroupPar <ParCond>(DefPar.AddHHMembers.HHCond, group);
                string  missing = string.Empty; string tooMuch = string.Empty;
                switch (addInstruction.addWho)
                {
                case DefPar.Value.ADDHHMEMBERS_CHILD:
                    if (parParent != null)
                    {
                        addInstruction.cond = parParent;
                    }
                    else
                    {
                        missing = DefPar.AddHHMembers.ParentCond;
                    }
                    if (parPartner != null)
                    {
                        tooMuch = DefPar.AddHHMembers.PartnerCond + " ";
                    }
                    if (parOther != null)
                    {
                        tooMuch = DefPar.AddHHMembers.HHCond;
                    }
                    ParBool parIsPP = GetUniqueGroupPar <ParBool>(DefPar.AddHHMembers.IsPartnerParent, group);
                    if (parIsPP != null)
                    {
                        addInstruction.isPartnerParent = parIsPP.GetBoolValue();
                    }
                    break;

                case DefPar.Value.ADDHHMEMBERS_PARTNER:
                    if (parParent != null)
                    {
                        tooMuch = DefPar.AddHHMembers.ParentCond + " ";
                    }
                    if (parPartner != null)
                    {
                        addInstruction.cond = parPartner;
                    }
                    else
                    {
                        missing = DefPar.AddHHMembers.PartnerCond;
                    }
                    if (parOther != null)
                    {
                        tooMuch = DefPar.AddHHMembers.HHCond;
                    }
                    break;

                case DefPar.Value.ADDHHMEMBERS_OTHER:
                    if (parParent != null)
                    {
                        tooMuch = DefPar.AddHHMembers.ParentCond + " ";
                    }
                    if (parPartner != null)
                    {
                        tooMuch = DefPar.AddHHMembers.PartnerCond;
                    }
                    if (parOther != null)
                    {
                        addInstruction.cond = parOther;
                    }
                    else
                    {
                        missing = DefPar.AddHHMembers.HHCond;
                    }
                    break;

                default: continue;     // error is caught by general error handling
                }
                if (missing != string.Empty)
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = false,
                        message   = $"{description.Get()} (group {groupNo}): {DefPar.AddHHMembers.Add_Who}={addInstruction.addWho} requires parameter {missing}"
                    });
                }
                if (tooMuch != string.Empty)
                {
                    infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                    {
                        isWarning = true,
                        message   = $"{description.Get()} (group {groupNo}): {DefPar.AddHHMembers.Add_Who}={addInstruction.addWho} does not require {tooMuch}"
                    });
                }

                // here we are only gathering the variables that are to be set, but do not evaluate whether they exist
                // note: this function does not "register" variables, i.e. if a variable is not used anywhere else, it cannot be set
                foreach (ParFormula parVarDefinition in GetPlaceholderGroupPar <ParFormula>(group))
                {
                    string varName = parVarDefinition.description.GetParName();
                    if (addInstruction.prepVarDefinitions.ContainsKey(varName))
                    {
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = false,
                            message   = $"{parVarDefinition.description.Get()}: double definition of variable {varName}"
                        });
                        continue;
                    }
                    if (varName == DefVarName.IDHH || varName == DefVarName.IDPERSON || varName == DefVarName.DWT || varName == DefVarName.DCT)
                    {
                        infoStore.communicator.ReportError(new Communicator.ErrorInfo()
                        {
                            isWarning = false,
                            message   = $"{parVarDefinition.description.Get()}: variable {varName} is system-set and cannot be changed"
                        });
                        continue;
                    }
                    addInstruction.prepVarDefinitions.Add(varName, parVarDefinition);
                }
                addInstructions.Add(addInstruction);
            }
        }