public bool PrepareLoadProfileIfNeeded([NotNull] ProviderParameterDto parameters)
        {
            Module.SetPrint(0);
            //var relevantPotentials = _pvPotentials.Where(x => x.HouseGuid == houseComponent.HouseGuid);
            PvSystemEntry entry = (PvSystemEntry)parameters.HouseComponent;
            int           idx   = 0;

            foreach (var area in entry.PVAreas)
            {
                var key    = MakeKeyFromPVArea(area);
                var keystr = key.GetKey();
                //key has been checked in this run
                if (_checkedKeys.Contains(keystr))
                {
                    continue;
                }

                _checkedKeys.Add(keystr);
                bool isInDb = _saveableEntries.CheckForName(keystr, MyLogger);
                if (isInDb)
                {
                    continue;
                }

                Info("Missing pv profile for " + keystr + ", generating...");
                PVSystemSettings pvs = new PVSystemSettings(key, 1, 1, MyLogger, idx++);
                var profile          = pvs.Run(Services.RunningConfig);
                _saveableEntries.AddRow(profile);
                _saveableEntries.SaveDictionaryToDatabase(MyLogger);
            }

            return(true);
        }
Beispiel #2
0
        protected override void RunActualProcess()
        {
            SqlConnection.RecreateTable <PvSystemEntry>(Stage.Houses, Constants.PresentSlice);
            var dbRaw        = SqlConnection.GetDatabaseConnection(Stage.Raw, Constants.PresentSlice).Database;
            var dbHouses     = SqlConnection.GetDatabaseConnection(Stage.Houses, Constants.PresentSlice).Database;
            var houses       = dbHouses.Fetch <House>();
            var pvanlagen    = dbRaw.Fetch <LocalnetPVAnlage>();
            var pvPotentials = dbHouses.Fetch <PVPotential>();

            dbHouses.BeginTransaction();
            double totalPowerOfIgnoredSystems = 0;

            foreach (var house in houses)
            {
                if (house.ErzeugerIDs.Count == 0)
                {
                    continue;
                }

                foreach (var houseErzeugerID in house.ErzeugerIDs)
                {
                    if (houseErzeugerID.StartsWith("PV"))
                    {
                        var pvl = pvanlagen.FirstOrDefault(x => x.Anlagenummer == houseErzeugerID);
                        if (pvl == null)
                        {
                            continue;
                        }

                        var hausanschlussguid = house.Hausanschluss[0].HausanschlussGuid;
                        var pse   = new PvSystemEntry(house.HouseGuid, Guid.NewGuid().ToString(), hausanschlussguid, house.ComplexName);
                        var areas = pvPotentials.Where(x => x.HouseGuid == house.HouseGuid).ToList();
                        foreach (var area in areas)
                        {
                            pse.PVAreas.Add(new PVSystemArea(area.Ausrichtung, area.Neigung, area.SonnendachStromErtrag));
                        }
                        int dstIdx = Services.Rnd.Next(house.Hausanschluss.Count);
                        pse.HausAnschlussGuid = house.Hausanschluss[dstIdx].HausanschlussGuid;
                        if (pse.PVAreas.Count == 0)
                        {
                            pse.PVAreas.Add(new PVSystemArea(0, 30, pvl.Leistungkwp * 1000));
                            Info("No PV System areas defined: " + house.ComplexName + " Power: " + pvl.Leistungkwp);
                            totalPowerOfIgnoredSystems += pvl.Leistungkwp;
                        }
                        dbHouses.Save(pse);
                    }
                }
            }

            double totalpower = pvanlagen.Sum(x => x.Leistungkwp);

            Info("Total Ignored Power because no Sonnendach data is available:" + totalPowerOfIgnoredSystems + " / " + totalpower);
            dbHouses.CompleteTransaction();
        }
Beispiel #3
0
        public void RunPVProviderTest()
        {
            // ReSharper disable AssignNullToNotNullAttribute
            var dbdto = new DBDto(null, null, null, null, null);
            // ReSharper restore AssignNullToNotNullAttribute
            // ReSharper disable twice AssignNullToNotNullAttribute
            ServiceRepository services = new ServiceRepository(null, null, Logger, Config, new Random(1));
            PVProfileProvider pvp      = new PVProfileProvider(services, Constants.PresentSlice, dbdto);
            PvSystemEntry     pve      = new PvSystemEntry("houseguid", "pvguid", "haguid", "myname", "pv123", 2017);

            pve.PVAreas = new List <PVSystemArea> {
                new PVSystemArea(30, 30, 1000)
            };
            HouseComponentRo     hcro = new HouseComponentRo("myname", "PV", 1, 1, "status", "isns", "standort", 0);
            ProviderParameterDto pp   = new ProviderParameterDto(pve, null, hcro);

            pvp.PrepareLoadProfileIfNeeded(pp);
        }
        protected override Prosumer ProvidePrivateProfile([NotNull] ProviderParameterDto ppdto)
        {
            Module.SetPrint(0);
            //var relevantPotentials = _pvPotentials.Where(x => x.HouseGuid == houseComponent.HouseGuid);
            PvSystemEntry entry = (PvSystemEntry)ppdto.HouseComponent;

            if (_dbDto.Hausanschlusse == null)
            {
                throw new FlaException("hausanschlüsse were not initalized");
            }
            if (_dbDto.Hausanschlusse.Count == 0)
            {
                throw new FlaException("not a single hausanschluss");
            }

            Hausanschluss hausanschluss = _dbDto.Hausanschlusse.FirstOrDefault(x => x.Guid == entry.HausAnschlussGuid);

            if (hausanschluss == null)
            {
                throw new FlaException("No hausanschluss found for guid: " + entry.HausAnschlussGuid);
            }

            if (hausanschluss.ObjectID.ToLower().Contains("leuchte"))
            {
                throw new FlaException("PV anlage an einer leuchte! " + hausanschluss.ObjectID + " - " + entry.Name);
            }
            //TODO: change this to use pv system areas from the pvsystem entry
            Profile sumProf = Profile.MakeConstantProfile(0, ppdto.HouseComponent.Name, Profile.ProfileResolution.QuarterHour);

            if (Math.Abs(entry.PVAreas.Sum(x => x.Energy) - entry.EffectiveEnergyDemand) > 0.1)
            {
                throw new FlaException("Sum of the pv areas did not match pv entry sum");
            }
            foreach (var area in entry.PVAreas)
            {
                var key          = MakeKeyFromPVArea(area);
                var keystr       = key.GetKey();
                var areaProfiles = _saveableEntries.LoadAllOrMatching("Name", keystr);
                if (areaProfiles.Count != 1)
                {
                    throw new FlaException("Invalid count");
                }

                var areaProfile = areaProfiles[0];
                areaProfile.EnergyOrPower = EnergyOrPower.Energy;
                areaProfile = areaProfile.ScaleToTargetSum(area.Energy, entry.Name, out var _);
                sumProf     = sumProf.Add(areaProfile, entry.Name);
            }

            if (Math.Abs(Slice.PVCurtailToXPercent) < 0.00001)
            {
                throw new FlaException("Found curtailment to 0");
            }

            if (sumProf.EnergySum() < 0)
            {
                throw new FlaException("Negative PV Power");
            }

            if (Slice.PVCurtailToXPercent < 1)
            {
                sumProf = sumProf.LimitPositiveToPercentageOfMax(Slice.PVCurtailToXPercent);
            }

            var prosumer = new Prosumer(entry.HouseGuid, entry.Name,
                                        HouseComponentType.Photovoltaik, entry.SourceGuid, entry.FinalIsn, entry.HausAnschlussGuid, hausanschluss.ObjectID,
                                        GenerationOrLoad.Generation,
                                        hausanschluss.Trafokreis, Name, "PV Profile")
            {
                Profile = sumProf
            };

            if (Math.Abs(Slice.PVCurtailToXPercent - 1) < 0.01 && Math.Abs(sumProf.EnergySum() - entry.EffectiveEnergyDemand) > 0.1)
            {
                throw new FlaException("PV Energy result is wrong");
            }
            return(prosumer);
        }
Beispiel #5
0
        // ReSharper disable once FunctionComplexityOverflow
        private static void WriteOneLine([NotNull] ExcelWorksheet ws,
                                         int row,
                                         [NotNull] Dictionary <Column, int> columnNumbers,
                                         [NotNull] House house,
                                         [ItemNotNull][NotNull] List <GwrData> gwr,
                                         [ItemNotNull][NotNull] List <EnergiebedarfsdatenBern> kanton,
                                         [ItemNotNull][NotNull] List <MonthlyElectricityUsePerStandort> complexEnergy,
                                         [NotNull] BuildingComplex mycomplex,
                                         [NotNull] HeatingSystemEntry heatingSystem,
                                         [NotNull][ItemNotNull] List <Occupant> occupants,
                                         [NotNull][ItemNotNull] List <BusinessEntry> businessEntries,
                                         [CanBeNull] PvSystemEntry pvsystem,
                                         [NotNull][ItemNotNull] List <Household> households,
                                         [NotNull][ItemNotNull] List <CarDistanceEntry> carDistances,
                                         [NotNull] HouseComponentRepository hcr)
        {
            ws.Cells[row, columnNumbers[Column.ComplexName]].Value    = house.ComplexName;
            ws.Cells[row, columnNumbers[Column.Adressen]].Value       = mycomplex.AdressesAsJson;
            ws.Cells[row, columnNumbers[Column.EGids]].Value          = CleanJson(mycomplex.EGIDsAsJson);
            ws.Cells[row, columnNumbers[Column.LocalnetISNIds]].Value = CleanJson(mycomplex.GebäudeObjectIDsAsJson);
            ws.Cells[row, columnNumbers[Column.GeoKoordinaten]].Value = CleanJson(mycomplex.GeoCoordsAsJson);
            var gwrs = gwr.Where(x => {
                if (x.EidgGebaeudeidentifikator_EGID == null)
                {
                    throw new FlaException("x.EidgGebaeudeidentifikator_EGID != null");
                }

                return(mycomplex.EGids.Contains((long)x.EidgGebaeudeidentifikator_EGID));
            }).ToList();

            ws.Cells[row, columnNumbers[Column.WG_GWR_GebäudeAnzahl]].Value = gwrs.Count;

            var ebbes = kanton.Where(x => mycomplex.EGids.Contains(x.egid)).ToList();

            ws.Cells[row, columnNumbers[Column.WG_GEAK_Anzahl]].Value      = ebbes.Sum(x => x.has_geak);
            ws.Cells[row, columnNumbers[Column.EBBE_GebäudeTyp]].Value     = CollapseList(ebbes.Select(x => x.upd_gtyp));
            ws.Cells[row, columnNumbers[Column.EBBE_GebäudeTyp]].Value     =
                ws.Cells[row, columnNumbers[Column.GWR_WG]].Value          = gwrs.Sum(x => x.AnzahlWohnungen_GANZWHG);
            ws.Cells[row, columnNumbers[Column.EBBE_GArea]].Value          = ebbes.Sum(x => x.garea);
            ws.Cells[row, columnNumbers[Column.EBBE_EBF_HZ_Updated]].Value = ebbes.Sum(x => x.upd_ebf);
            ws.Cells[row, columnNumbers[Column.EBBE_calc_ehzww]].Value     = ebbes.Sum(x => x.calc_ehzww);
            ws.Cells[row, columnNumbers[Column.EBBE_calc_ehz]].Value       = ebbes.Sum(x => x.calc_ehz);
            ws.Cells[row, columnNumbers[Column.EBBE_calc_eww]].Value       = ebbes.Sum(x => x.calc_eww);

            //energieträger aus ebbe
            var  heizträgerlst = ebbes.Select(x => x.upd_genhz).ToList();
            long heizträger    = 0;

            if (heizträgerlst.Count > 0)
            {
                heizträger = heizträgerlst[0];
            }

            switch (heizträger)
            {
            case 0:
                break;

            case 7200:
                break;

            case 7201:
                ws.Cells[row, columnNumbers[Column.EBHZ_OL]].Value = ebbes.Sum(x => x.calc_ehz);
                break;

            case 7202:
                ws.Cells[row, columnNumbers[Column.EBHZ_KO]].Value = ebbes.Sum(x => x.calc_ehz);
                break;

            case 7203:
                ws.Cells[row, columnNumbers[Column.EBHZ_GZ]].Value = ebbes.Sum(x => x.calc_ehz);
                break;

            case 7204:
                ws.Cells[row, columnNumbers[Column.EBHZ_EL]].Value = ebbes.Sum(x => x.calc_ehz);
                break;

            case 7205:
                ws.Cells[row, columnNumbers[Column.EBHZ_HO]].Value = ebbes.Sum(x => x.calc_ehz);
                break;

            case 7206:
                ws.Cells[row, columnNumbers[Column.EBHZ_WP]].Value = ebbes.Sum(x => x.calc_ehz);
                break;

            case 7207:
                ws.Cells[row, columnNumbers[Column.EBHZ_SO]].Value = ebbes.Sum(x => x.calc_ehz);
                break;

            case 7208:
                ws.Cells[row, columnNumbers[Column.EBHZ_FW]].Value = ebbes.Sum(x => x.calc_ehz);
                break;

            case 7209:
                ws.Cells[row, columnNumbers[Column.EBHZ_A]].Value = ebbes.Sum(x => x.calc_ehz);
                break;

            default: throw new Exception("Unknown Heizungsträger: " + heizträger);
            }

            //warmwasser aus Ebbe
            var  wwträgerlst = ebbes.Select(x => x.upd_genww).ToList();
            long wwträger    = 0;

            if (wwträgerlst.Count > 0)
            {
                wwträger = wwträgerlst[0];
            }

            switch (wwträger)
            {
            case 0:
                break;

            case 7200:
                break;

            case 7201:
                ws.Cells[row, columnNumbers[Column.EBWW_OL]].Value = ebbes.Sum(x => x.calc_eww);
                break;

            case 7202:
                ws.Cells[row, columnNumbers[Column.EBWW_KO]].Value = ebbes.Sum(x => x.calc_eww);
                break;

            case 7203:
                ws.Cells[row, columnNumbers[Column.EBWW_GZ]].Value = ebbes.Sum(x => x.calc_eww);
                break;

            case 7204:
                ws.Cells[row, columnNumbers[Column.EBWW_EL]].Value = ebbes.Sum(x => x.calc_eww);
                break;

            case 7205:
                ws.Cells[row, columnNumbers[Column.EBWW_HO]].Value = ebbes.Sum(x => x.calc_eww);
                break;

            case 7206:
                ws.Cells[row, columnNumbers[Column.EBWW_WP]].Value = ebbes.Sum(x => x.calc_eww);
                break;

            case 7207:
                ws.Cells[row, columnNumbers[Column.EBWW_SO]].Value = ebbes.Sum(x => x.calc_eww);
                break;

            case 7208:
                ws.Cells[row, columnNumbers[Column.EBWW_FW]].Value = ebbes.Sum(x => x.calc_eww);
                break;

            case 7209:
                ws.Cells[row, columnNumbers[Column.EBWW_A]].Value = ebbes.Sum(x => x.calc_eww);
                break;

            default: throw new Exception("Unknown Heizungsträger: " + heizträger);
            }

            ws.Cells[row, columnNumbers[Column.EBBE_EnergieträgerHz]].Value = CollapseList(ebbes.Select(x => x.upd_genhz.ToString()));
            ws.Cells[row, columnNumbers[Column.EBBE_EnergieträgerWW]].Value = CollapseList(ebbes.Select(x => x.upd_genww.ToString()));
            //entries from localnet
            var monthlies = complexEnergy.Where(x => mycomplex.CleanedStandorte.Contains(x.CleanedStandort)).ToList();

            ws.Cells[row, columnNumbers[Column.Localnet_Strom]].Value           = monthlies.Sum(x => x.YearlyElectricityUseNetz);
            ws.Cells[row, columnNumbers[Column.Localnet_Gas]].Value             = monthlies.Sum(x => x.YearlyGasUse);
            ws.Cells[row, columnNumbers[Column.Localnet_Wärme]].Value           = monthlies.Sum(x => x.YearlyFernwaermeUse);
            ws.Cells[row, columnNumbers[Column.BFH_EnergieträgerHeizung]].Value = heatingSystem.SynthesizedHeatingSystemType.ToString();
            ws.Cells[row, columnNumbers[Column.BFH_EnergieBedarfHeizung]].Value = heatingSystem.EffectiveEnergyDemand;
            ws.Cells[row, columnNumbers[Column.BFH_Einwohner]].Value            = occupants.Count;
            var businessTypes   = businessEntries.Select(x => x.BusinessType.ToString()).Distinct().ToList();
            var businessTypeStr = string.Join(",", businessTypes);

            ws.Cells[row, columnNumbers[Column.BFH_Geschäfte]].Value = businessTypeStr;
            if (pvsystem != null)
            {
                ws.Cells[row, columnNumbers[Column.BFH_PVSystemGrösseInKWh]].Value = pvsystem.EffectiveEnergyDemand;
            }

            ws.Cells[row, columnNumbers[Column.BFH_Geschäfte]].Value         = businessTypeStr;
            ws.Cells[row, columnNumbers[Column.BFH_StromHaushalteLow]].Value = households.Sum(x => x.LocalnetLowVoltageYearlyTotalElectricityUse);
            ws.Cells[row, columnNumbers[Column.BFH_StromHaushalteLow]].Value = households.Sum(x => x.LocalnetHighVoltageYearlyTotalElectricityUse);
            ws.Cells[row, columnNumbers[Column.BFH_StromGewerbeLow]].Value   = businessEntries.Sum(x => x.LocalnetLowVoltageYearlyTotalElectricityUse);
            ws.Cells[row, columnNumbers[Column.BFH_StromGewerbeHigh]].Value  =
                businessEntries.Sum(x => x.LocalnetHighVoltageYearlyTotalElectricityUse);
            ws.Cells[row, columnNumbers[Column.FeuerungsstättenArt]].Value            = heatingSystem.FeuerungsstättenType;
            ws.Cells[row, columnNumbers[Column.FeuerungsstättenKesselLeistung]].Value = heatingSystem.FeuerungsstättenPower;
            if (heatingSystem.FeuerungsstättenType == "Gas")
            {
                ws.Cells[row, columnNumbers[Column.FeuerungsstättenJahresEnergie1500hGas]].Value =
                    heatingSystem.EstimatedMinimumEnergyFromFeuerungsStätten;
                ws.Cells[row, columnNumbers[Column.FeuerungsstättenJahresEnergie2200hGas]].Value =
                    heatingSystem.EstimatedMaximumEnergyFromFeuerungsStätten;
            }

            if (heatingSystem.FeuerungsstättenType == "Oel")
            {
                ws.Cells[row, columnNumbers[Column.FeuerungsstättenJahresEnergie1500hOel]].Value =
                    heatingSystem.EstimatedMinimumEnergyFromFeuerungsStätten;
                ws.Cells[row, columnNumbers[Column.FeuerungsstättenJahresEnergie2200hOel]].Value =
                    heatingSystem.EstimatedMaximumEnergyFromFeuerungsStätten;
            }

            ws.Cells[row, columnNumbers[Column.BFH_AnzahlFahrzeuge]].Value         = carDistances.Count;
            ws.Cells[row, columnNumbers[Column.BFH_SummeAutoPendlerdistanz]].Value = carDistances.Sum(x => x.CommutingDistance) * 365;
            ws.Cells[row, columnNumbers[Column.BFH_SummeAutoGesamtdistanz]].Value  = carDistances.Sum(x => x.TotalDistance) * 365;
            ws.Cells[row, columnNumbers[Column.BFH_SonnendachPotential]].Value     = heatingSystem.FeuerungsstättenPower;
            ws.Cells[row, columnNumbers[Column.TrafoKreis]].Value = string.Join(";", house.Hausanschluss.Select(x => x.Trafokreis));
            var houseComponents = house.CollectHouseComponents(hcr);
            Dictionary <HouseComponentType, double> houseComponentSums = new Dictionary <HouseComponentType, double>();

            foreach (var hc in houseComponents)
            {
                if (!houseComponentSums.ContainsKey(hc.HouseComponentType))
                {
                    houseComponentSums.Add(hc.HouseComponentType, 0);
                }

                houseComponentSums[hc.HouseComponentType] += hc.EffectiveEnergyDemand;
            }

            foreach (var entry in houseComponentSums)
            {
                Column mycol = GetColumn(entry.Key);
                ws.Cells[row, columnNumbers[mycol]].Value = entry.Value;
            }
        }
        protected override void RunActualProcess([NotNull] ScenarioSliceParameters parameters)
        {
            Services.SqlConnection.RecreateTable <PvSystemEntry>(Stage.Houses, parameters);
            Services.SqlConnection.RecreateTable <PVPotential>(Stage.Houses, parameters);
            var dbSrcHouses        = Services.SqlConnection.GetDatabaseConnection(Stage.Houses, parameters.PreviousScenarioNotNull).Database;
            var dbDstHouses        = Services.SqlConnection.GetDatabaseConnection(Stage.Houses, parameters).Database;
            var srcHouses          = dbSrcHouses.Fetch <House>();
            var srcPVPotentials    = dbSrcHouses.Fetch <PVPotential>();
            var srcPvSystemEntries = dbSrcHouses.Fetch <PvSystemEntry>();

            dbDstHouses.BeginTransaction();
            foreach (var potential in srcPVPotentials)
            {
                potential.ID = 0;
                dbDstHouses.Save(potential);
            }

            //copy pv systems from previous slice
            HashSet <string>            houseGuidsForSystemsWithPV = new  HashSet <string>();
            Dictionary <string, double> pvPotentialByHouseGuid     = new Dictionary <string, double>();

            foreach (var pvpot in srcPVPotentials)
            {
                if (!houseGuidsForSystemsWithPV.Contains(pvpot.HouseGuid))
                {
                    houseGuidsForSystemsWithPV.Add(pvpot.HouseGuid);
                    pvPotentialByHouseGuid.Add(pvpot.HouseGuid, 0);
                }
                pvPotentialByHouseGuid[pvpot.HouseGuid] += pvpot.SonnendachStromErtrag;
            }
            var potentialhousesForPvSystems = srcHouses.Where(x => houseGuidsForSystemsWithPV.Contains(x.HouseGuid)).ToList();

            foreach (var entry in srcPvSystemEntries)
            {
                var toremove = potentialhousesForPvSystems.FirstOrDefault(x => x.HouseGuid == entry.HouseGuid);
                if (toremove != null)
                {
                    potentialhousesForPvSystems.Remove(toremove);
                }
                if (entry.PVAreas.Count == 0)
                {
                    throw new FlaException("No PV System areas defined.");
                }
                entry.Pvid = 0;
                dbDstHouses.Save(entry);
            }

            var pvToInstallInkWh = parameters.PvPowerToInstallInGwh * 1_000_000;

            while (pvToInstallInkWh > 0)
            {
                //make ranges
                var rangeEntries = SetRanges(potentialhousesForPvSystems, pvPotentialByHouseGuid);
                //randomly pick
                var max        = rangeEntries.Max(x => x.EndRange);
                var pick       = Services.Rnd.NextDouble() * max;
                var rangeEntry = rangeEntries.Single(x => pick >= x.StartRange && pick <= x.EndRange);
                //remove house
                potentialhousesForPvSystems.Remove(rangeEntry.House);
                //save pvsystementry
                var pvPotenial        = pvPotentialByHouseGuid[rangeEntry.House.HouseGuid];
                var hausanschlsusGuid = rangeEntry.House.Hausanschluss[0].HausanschlussGuid;

                var pvSystemEntry = new PvSystemEntry(rangeEntry.House.HouseGuid, Guid.NewGuid().ToString(), hausanschlsusGuid, rangeEntry.House.ComplexName)
                {
                    YearlyPotential = pvPotenial
                };
                var areas = srcPVPotentials.Where(x => x.HouseGuid == rangeEntry.House.HouseGuid).ToList();
                foreach (var area in areas)
                {
                    pvSystemEntry.PVAreas.Add(new PVSystemArea(area.Ausrichtung, area.Neigung, area.SonnendachStromErtrag));
                }

                if (pvSystemEntry.PVAreas.Count == 0)
                {
                    throw new FlaException("No PV System areas defined.");
                }
                pvToInstallInkWh       -= pvSystemEntry.YearlyPotential;
                pvSystemEntry.BuildYear = parameters.DstYear;
                int dstIdx = Services.Rnd.Next(rangeEntry.House.Hausanschluss.Count);
                pvSystemEntry.HausAnschlussGuid = rangeEntry.House.Hausanschluss[dstIdx].HausanschlussGuid;
                dbDstHouses.Save(pvSystemEntry);
                //deduct from pvtoinstall
            }

            dbDstHouses.CompleteTransaction();
        }
Beispiel #7
0
        protected override void RunActualProcess([NotNull] ScenarioSliceParameters slice)
        {
            var dbSrcHouses = Services.SqlConnectionPreparer.GetDatabaseConnection(Stage.Houses, slice.PreviousSliceNotNull);
            var dbDstHouses = Services.SqlConnectionPreparer.GetDatabaseConnection(Stage.Houses, slice);

            dbDstHouses.RecreateTable <PvSystemEntry>();
            dbDstHouses.RecreateTable <PVPotential>();
            var srcHouses          = dbSrcHouses.Fetch <House>();
            var srcPVPotentials    = dbSrcHouses.Fetch <PVPotential>();
            var srcPvSystemEntries = dbSrcHouses.Fetch <PvSystemEntry>();
            var hausanschlusses    = dbDstHouses.Fetch <Hausanschluss>();

            dbDstHouses.BeginTransaction();
            foreach (var potential in srcPVPotentials)
            {
                potential.ID = 0;
                dbDstHouses.Save(potential);
            }

            //copy pv systems from previous slice
            HashSet <string>            houseGuidsForSystemsWithPV = new HashSet <string>();
            Dictionary <string, double> pvPotentialByHouseGuid     = new Dictionary <string, double>();

            foreach (var pvpot in srcPVPotentials)
            {
                if (!houseGuidsForSystemsWithPV.Contains(pvpot.HouseGuid))
                {
                    houseGuidsForSystemsWithPV.Add(pvpot.HouseGuid);
                    pvPotentialByHouseGuid.Add(pvpot.HouseGuid, 0);
                }

                pvPotentialByHouseGuid[pvpot.HouseGuid] += pvpot.SonnendachStromErtrag;
            }

            var potentialhousesForPvSystems = srcHouses.Where(x => houseGuidsForSystemsWithPV.Contains(x.Guid)).ToList();

            foreach (var entry in srcPvSystemEntries)
            {
                var toremove = potentialhousesForPvSystems.FirstOrDefault(x => x.Guid == entry.HouseGuid);
                if (toremove != null)
                {
                    potentialhousesForPvSystems.Remove(toremove);
                }

                if (entry.PVAreas.Count == 0)
                {
                    throw new FlaException("No PV System areas defined.");
                }

                entry.ID = 0;
                dbDstHouses.Save(entry);
            }

            var  pvToInstallInkWh   = slice.PvPowerToInstallInGwh * 1_000_000;
            bool continueAllocation = true;
            int  pvSystemCount      = 0;

            while (pvToInstallInkWh > 0 && continueAllocation)
            {
                //make ranges
                var rangeEntries = SetRanges(potentialhousesForPvSystems, pvPotentialByHouseGuid);
                if (rangeEntries.Count == 0)
                {
                    continueAllocation = false;
                    continue;
                }

                //randomly pick
                var max        = rangeEntries.Max(x => x.EndRange);
                var pick       = Services.Rnd.NextDouble() * max;
                var rangeEntry = rangeEntries.Single(x => pick >= x.StartRange && pick <= x.EndRange);
                //remove house
                potentialhousesForPvSystems.Remove(rangeEntry.House);
                //save pvsystementry
                var pvPotenial = pvPotentialByHouseGuid[rangeEntry.House.Guid];
                pvSystemCount++;
                string erzeugerid    = "PV-" + slice.DstYear + "-" + pvSystemCount;
                var    hausanschlsus = rangeEntry.House.GetHausanschlussByIsn(new List <int>(), erzeugerid, hausanschlusses, MyLogger) ??
                                       throw new FlaException("no hausanschluss");
                if (hausanschlsus.ObjectID.ToLower().Contains("leuchte"))
                {
                    throw new FlaException("pv an leuchte in " + slice.DstYear + " " + hausanschlsus.ObjectID);
                }

                var pvSystemEntry = new PvSystemEntry(rangeEntry.House.Guid,
                                                      Guid.NewGuid().ToString(),
                                                      hausanschlsus.Guid,
                                                      rangeEntry.House.ComplexName,
                                                      erzeugerid,
                                                      slice.DstYear)
                {
                    EffectiveEnergyDemand = pvPotenial
                };
                var areas = srcPVPotentials.Where(x => x.HouseGuid == rangeEntry.House.Guid).ToList();
                foreach (var area in areas)
                {
                    pvSystemEntry.PVAreas.Add(new PVSystemArea(area.Ausrichtung, area.Neigung, area.SonnendachStromErtrag));
                }

                if (pvSystemEntry.PVAreas.Count == 0)
                {
                    throw new FlaException("No PV System areas defined.");
                }

                pvToInstallInkWh       -= pvSystemEntry.EffectiveEnergyDemand;
                pvSystemEntry.BuildYear = slice.DstYear;
                dbDstHouses.Save(pvSystemEntry);
                //deduct from pvtoinstall
            }

            dbDstHouses.CompleteTransaction();
            var           newPVs = dbDstHouses.FetchAsRepo <PvSystemEntry>();
            RowCollection rc     = new RowCollection("pv", "pv");

            foreach (var pv in newPVs)
            {
                foreach (var area in pv.PVAreas)
                {
                    RowBuilder rb = RowBuilder.Start("HA", pv.HausAnschlussGuid);
                    rc.Add(rb);
                    rb.Add("Azimut", area.Azimut);
                    rb.Add("Tilt", area.Tilt);
                    rb.Add("Energy", area.Energy);
                }
            }

            var fn = MakeAndRegisterFullFilename("PVExport.xlsx", slice);

            XlsxDumper.WriteToXlsx(fn, rc);
        }
        protected override void RunActualProcess()
        {
            var dbRaw    = Services.SqlConnectionPreparer.GetDatabaseConnection(Stage.Raw, Constants.PresentSlice);
            var dbHouses = Services.SqlConnectionPreparer.GetDatabaseConnection(Stage.Houses, Constants.PresentSlice);

            dbHouses.RecreateTable <PvSystemEntry>();
            var houses            = dbHouses.Fetch <House>();
            var localnetPVAnlagen = dbRaw.Fetch <LocalnetPVAnlage>();
            var pvPotentials      = dbHouses.Fetch <PVPotential>();
            var hausanschlusses   = dbHouses.Fetch <Hausanschluss>();

            dbHouses.BeginTransaction();
            double totalEnergyOfFakeSystems       = 0;
            double totalEnergyOfSonnendachSystems = 0;

            foreach (var house in houses)
            {
                if (house.ErzeugerIDs.Count == 0)
                {
                    continue;
                }

                foreach (var houseErzeugerID in house.ErzeugerIDs)
                {
                    if (houseErzeugerID.StartsWith("PV"))
                    {
                        var pvl = localnetPVAnlagen.FirstOrDefault(x => x.Anlagenummer == houseErzeugerID);
                        if (pvl == null)
                        {
                            continue;
                        }

                        var hausanschluss = house.GetHausanschlussByIsn(new List <int>(), null, hausanschlusses, MyLogger) ??
                                            throw new FlaException("no hausanschluss");
                        if (hausanschluss.ObjectID.ToLower().Contains("leuchte"))
                        {
                            throw new FlaException("PV anlage an einer leuchte!");
                        }

                        var pse = new PvSystemEntry(house.Guid,
                                                    Guid.NewGuid().ToString(),
                                                    hausanschluss.Guid,
                                                    house.ComplexName,
                                                    houseErzeugerID,
                                                    Constants.PresentSlice.DstYear);
                        var areas = pvPotentials.Where(x => x.HouseGuid == house.Guid).ToList();
                        foreach (var area in areas)
                        {
                            pse.PVAreas.Add(new PVSystemArea(area.Ausrichtung, area.Neigung, area.SonnendachStromErtrag));
                        }

                        double localnetTargetEnergy = pvl.Leistungkwp * 1100;
                        if (pse.PVAreas.Count == 0)
                        {
                            pse.PVAreas.Add(new PVSystemArea(0, 30, localnetTargetEnergy));
                            Debug("No PV System areas defined: " + house.ComplexName + ", setting 30°/south system with power: " + pvl.Leistungkwp);
                            totalEnergyOfFakeSystems += pse.PVAreas.Sum(x => x.Energy);
                        }
                        else
                        {
                            double sonnendachEnergy = pse.PVAreas.Sum(x => x.Energy);
                            if (sonnendachEnergy > localnetTargetEnergy)
                            {
                                //need to
                                var potentialAreas = pse.PVAreas.ToList();
                                if (potentialAreas.Count == 0)
                                {
                                    throw new FlaException("No area?");
                                }

                                potentialAreas.Sort((x, y) => y.Energy.CompareTo(x.Energy));
                                pse.PVAreas.Clear();
                                double sumSoFar = 0;
                                while (potentialAreas[0].Energy + sumSoFar < localnetTargetEnergy)
                                {
                                    pse.PVAreas.Add(potentialAreas[0]);
                                    sumSoFar += potentialAreas[0].Energy;
                                    potentialAreas.RemoveAt(0);
                                }

                                double missingEnergy = localnetTargetEnergy - pse.PVAreas.Sum(x => x.Energy);
                                pse.PVAreas.Add(new PVSystemArea(0, 30, missingEnergy));
                                totalEnergyOfSonnendachSystems += pse.PVAreas.Sum(x => x.Energy);
                            }
                            else
                            {
                                //ignore the sonnendach stuff, since it seems to be wrong
                                pse.PVAreas.Clear();
                                pse.PVAreas.Add(new PVSystemArea(0, 30, localnetTargetEnergy));
                                totalEnergyOfFakeSystems += pse.PVAreas.Sum(x => x.Energy);
                            }
                        }

                        dbHouses.Save(pse);
                    }
                }
            }

            double totalpower = localnetPVAnlagen.Sum(x => x.Leistungkwp) * 1100;

            Info("Total arbitrary south energy because no Sonnendach data is available:" + totalEnergyOfFakeSystems / 1000 + "mwh");
            Info("Total  Sonnendach data is available:" + totalEnergyOfSonnendachSystems / 1000 + "mwh");
            Info("Total energy target: " + totalpower / 1000);
            dbHouses.CompleteTransaction();
        }