public RtDecayParam CopyToDecayParam(RtDecayParam param)
 {
     param.EasyRt1         = rt1;
     param.EasyRt2         = rt2;
     param.DaysToOne       = dayIdx;
     param.DecayFactor     = ft1;
     param.DecayFactorNext = ft2;
     return(param);
 }
        public RtDecayParam MakeRtDecayParam(bool bSystem, int idx = -1)
        {
            var param = new RtDecayParam {
                //UseOnForecast = UseOnForecast,
                PostDecayFactorRt2 = getPostDecayFactorRt2(bSystem),
                Fourstep           = DetailSettings && FourstepEnabled,
                StartDate          = getParamStartDate(idx, bSystem)._parseDateTime(),
                StartDateFourstep  = getParamStartDateFourstepStr(idx)._parseDateTime(),
                DaysToOne          = getParamDaysToOne(idx, bSystem),
                DecayFactor        = getParamDecayFactor(idx, bSystem),
                DaysToNext         = getParamDaysToNext(idx, bSystem),
                RtMax           = getParamMaxRt(idx),
                RtMin           = getParamMinRt(idx),
                EasyRt1         = getParamEasyRt1(idx, bSystem),
                EasyRt2         = getParamEasyRt2(idx, bSystem),
                DecayFactorNext = getParamDecayFactorNext(idx, bSystem),
                DaysToRt1       = getParamDaysToRt1(idx),
                Rt1             = getParamRt1(idx),
                DaysToRt2       = getParamDaysToRt2(idx),
                Rt2             = getParamRt2(idx),
                DaysToRt3       = getParamDaysToRt3(idx),
                Rt3             = getParamRt3(idx),
                DaysToRt4       = getParamDaysToRt4(idx),
                Rt4             = getParamRt4(idx),
                DaysToRt5       = getParamDaysToRt5(idx),
                Rt5             = getParamRt5(idx),
                DaysToRt6       = getParamDaysToRt6(idx),
                Rt6             = getParamRt6(idx),
            };

            if ((param.DaysToRt1 + param.DaysToRt2 + param.DaysToRt3 + param.DaysToRt4 + param.DaysToRt5 + param.DaysToRt6) == 0)
            {
                param.DaysToRt1 = 10;
            }
            return(param);
        }
        /// <summary>各種推計値の計算</summary>
        /// <param name="infData"></param>
        /// <param name="rtDecayParam">not null で、書き換えられてもよいデータである必要がある</param>
        /// <param name="skipDays">実データの初めから表示開始日までの日数</param>
        /// <param name="numFullDays">全表示候補日の数(1年間とか)</param>
        /// <param name="extensionDays"></param>
        /// <param name="predStartDt"></param>
        /// <returns></returns>
        public UserPredictData predictValuesEx(InfectData infData, RtDecayParam rtDecayParam, int skipDays, int numFullDays, int extensionDays, DateTime?predStartDt)
        {
            //logger.Trace("ENTER");
            var      firstRealDate = infData.Dates.First();
            DateTime realEndDate   = predStartDt?.AddDays(-1) ?? DateTime.MaxValue;
            DateTime infEndDate    = infData.Dates.Last();

            if (realEndDate > infEndDate)
            {
                realEndDate = infEndDate;
            }
            int realDays  = (realEndDate - firstRealDate).Days + 1;
            int totalDays = skipDays + numFullDays;

            if (rtDecayParam.StartDate > realEndDate)
            {
                rtDecayParam.StartDate = realEndDate;
            }
            if (rtDecayParam.StartDateFourstep > realEndDate)
            {
                rtDecayParam.StartDateFourstep = realEndDate;
            }
            //logger.Debug($"rtDecayParam.StartDate={rtDecayParam.StartDate.ToLongDateString()}, " +
            //    $"StartDateFourstep={rtDecayParam.StartDateFourstep.ToLongDateString()}, " +
            //    $"EffectiveStartDate={rtDecayParam.EffectiveStartDate.ToLongDateString()}");

            const int ExtraDaysForAverage = Constants.EXTRA_DAYS_FOR_AVERAGE;

            // 逆算移動平均
            double[] revAverage = new double[totalDays + ExtraDaysForAverage];
            // 予想実効再生産数
            double[] fullPredRt = new double[totalDays + ExtraDaysForAverage];

            int predStartIdx = (rtDecayParam.EffectiveStartDate - firstRealDate).Days;

            if (predStartIdx < 0 || predStartIdx >= infData.Average.Length)
            {
                logger.Warn($"PredStartIdx({predStartIdx}) is out of range. "
                            + $"rtDecayParam.EffectiveStartDate({rtDecayParam.EffectiveStartDate}) may not be valid. "
                            + $"Use realEndDate={realEndDate} instead");
                predStartIdx = (realEndDate - firstRealDate).Days;
            }
            Array.Copy(infData.Average, revAverage, predStartIdx);
            int predRtLen = rtDecayParam.CalcAndCopyPredictRt(infData.Rt, predStartIdx, fullPredRt, realDays, extensionDays + ExtraDaysForAverage);

            for (int i = 0; i < predRtLen; ++i)
            {
                int idx = predStartIdx + i;
                var rt  = fullPredRt[idx];
                if (idx >= 7 && idx < revAverage.Length && rt > 0)
                {
                    revAverage[idx] = Math.Pow(rt, 7.0 / 5.0) * revAverage[idx - 7];
                }
            }

            predRtLen -= ExtraDaysForAverage;
            double[] revAveAverage = new double[totalDays + ExtraDaysForAverage];   // 逆算移動平均の平均
            for (int i = 3; i < predRtLen; ++i)
            {
                int idx    = predStartIdx + i;
                int margin = i._highLimit(ExtraDaysForAverage - 1);
                int beg    = idx - margin;
                int end    = idx + margin + 1;
                if (beg >= 0 && end <= revAverage.Length)
                {
                    revAveAverage[idx] = revAverage[beg..end].Sum() / (margin * 2 + 1);
 /// <summary>
 /// 各種推計値の計算
 /// </summary>
 /// <param name="rtDecayParam">書き換えられてもよいデータである必要がある</param>
 /// <param name="skipDays">実データの初めから表示開始日までの日数</param>
 /// <param name="numFullDays">全表示候補日の数(1年間とか)</param>
 /// <param name="predStartDt">予測開始日</param>
 /// <returns>(PredictInfectData, 表示開始から予測終了までの日数)</returns>
 public static UserPredictData PredictValuesEx(InfectData infData, RtDecayParam rtDecayParam, int skipDays, int numFullDays, int extensionDays, DateTime?predStartDt = null)
 {
     return(new UserPredictData().predictValuesEx(infData, rtDecayParam, skipDays, numFullDays, extensionDays, predStartDt));
 }