diff --git a/src/main/java/org/tub/vsp/bvwp/RunLocalRailScraping.java b/src/main/java/org/tub/vsp/bvwp/RunLocalRailScraping.java index bac6472..58c7419 100644 --- a/src/main/java/org/tub/vsp/bvwp/RunLocalRailScraping.java +++ b/src/main/java/org/tub/vsp/bvwp/RunLocalRailScraping.java @@ -3,26 +3,30 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.tub.vsp.bvwp.data.container.analysis.RailAnalysisDataContainer; -import org.tub.vsp.bvwp.io.RailCsvWriter; +import org.tub.vsp.bvwp.io.RailTableCreator; import org.tub.vsp.bvwp.scraping.RailScraper; +import tech.tablesaw.api.Table; +import java.io.IOException; import java.util.List; public class RunLocalRailScraping { private static final Logger logger = LogManager.getLogger(RunLocalRailScraping.class); - public static void main(String[] args) { + public static void main(String[] args) throws IOException { RailScraper scraper = new RailScraper(); logger.info("Starting scraping"); List allRailData = scraper.extractAllLocalBaseData("./data/rail/all", "", "^2.*", "") .stream() + //there is something wrong with the project number of 2-009-V03 + .filter(d -> !d.getProjectInformation().getProjectNumber().equals("2-009-V03")) .map(RailAnalysisDataContainer::new) .toList(); logger.info("Writing csv"); - RailCsvWriter csvWriter = new RailCsvWriter(); - - //TODO + RailTableCreator tableCreator = new RailTableCreator(); + Table table = tableCreator.computeTable(allRailData); + table.write().csv("out.csv"); } } diff --git a/src/main/java/org/tub/vsp/bvwp/computation/ComputationKN.java b/src/main/java/org/tub/vsp/bvwp/computation/ComputationKN.java index 450e471..c82fb46 100644 --- a/src/main/java/org/tub/vsp/bvwp/computation/ComputationKN.java +++ b/src/main/java/org/tub/vsp/bvwp/computation/ComputationKN.java @@ -288,4 +288,19 @@ static Double b_co2(Modifications modifications, Amounts amounts, Benefits benef // Note that this really says nothing about old vs new co2 price, or old vs new addl traffic. That all depends on the settings in "modifications". } + + /** + * @param co2_infra_eur benefit in €/a + * @param co2_betrieb_t emissions in t/a + * @return new nkv + */ + static double nkv_rail(double co2_price, double baukosten, double benefit, double co2_infra_eur, double co2_betrieb_t) { + benefit -= co2_infra_eur; + benefit -= co2_betrieb_t; + + benefit += co2_price / 145. * co2_infra_eur; + benefit += co2_price * co2_betrieb_t; + + return benefit / baukosten; + } } diff --git a/src/main/java/org/tub/vsp/bvwp/computation/Modifications.java b/src/main/java/org/tub/vsp/bvwp/computation/Modifications.java index f509042..f8938fc 100644 --- a/src/main/java/org/tub/vsp/bvwp/computation/Modifications.java +++ b/src/main/java/org/tub/vsp/bvwp/computation/Modifications.java @@ -4,6 +4,8 @@ import org.apache.logging.log4j.Logger; public record Modifications(double co2Price, double mehrFzkm, double constructionCostFactor, double nonCo2BenefitsFactor) { + //TODO nonCo2BenefitsFactor is not used in the codebase + private static final Logger log = LogManager.getLogger(Modifications.class); public static final double co2PriceBVWP = 145.; public static final double co2Price700 = 642.; diff --git a/src/main/java/org/tub/vsp/bvwp/computation/NkvCalculator.java b/src/main/java/org/tub/vsp/bvwp/computation/NkvCalculator.java index ab51bd4..8c24a4d 100644 --- a/src/main/java/org/tub/vsp/bvwp/computation/NkvCalculator.java +++ b/src/main/java/org/tub/vsp/bvwp/computation/NkvCalculator.java @@ -29,6 +29,7 @@ public Double calculateCost_CO2( Modifications modifications ) { } // old static methods beyond: + @Deprecated // use instance approach public static Double calculateNkv(Modifications modifications, StreetBaseDataContainer streetBaseDataContainer) { // log.warn("modifications=" + modifications); Optional a = amountsFromStreetBaseData(streetBaseDataContainer); @@ -93,6 +94,7 @@ private static Optional benefitsFromStreetBaseData(StreetBaseDataConta // @formatter:on } + @Deprecated // use instance approach public static Double calculateCost_CO2( Modifications modifications, StreetBaseDataContainer streetBaseDataContainer ) { log.warn("modifications=" + modifications); Optional a = amountsFromStreetBaseData(streetBaseDataContainer); diff --git a/src/main/java/org/tub/vsp/bvwp/computation/NkvCalculatorRail.java b/src/main/java/org/tub/vsp/bvwp/computation/NkvCalculatorRail.java new file mode 100644 index 0000000..b3d6632 --- /dev/null +++ b/src/main/java/org/tub/vsp/bvwp/computation/NkvCalculatorRail.java @@ -0,0 +1,53 @@ +package org.tub.vsp.bvwp.computation; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.tub.vsp.bvwp.data.container.base.rail.RailBaseDataContainer; +import org.tub.vsp.bvwp.data.type.Emission; + +public class NkvCalculatorRail{ + + private static final Logger log = LogManager.getLogger( NkvCalculatorRail.class ); + private final RailBaseDataContainer railBaseDataContainer; + + // moving towards replacing the stateless static functions by a modifiable instance approach: + public NkvCalculatorRail(RailBaseDataContainer railBaseDataContainer) { + this.railBaseDataContainer = railBaseDataContainer; + } + public Double calculateNkv( Modifications modifications ) { + return calculateNkv( modifications, this.railBaseDataContainer ); + } + + // public Double calculateCost_CO2( Modifications modifications ) { +// return calculateCost_CO2( modifications, this.railBaseDataContainer ); +// } + + // old static methods beyond: + @Deprecated // use instance approach + public static Double calculateNkv(Modifications modifications, RailBaseDataContainer railBaseDataContainer) { + assert modifications.mehrFzkm() == 0; + assert modifications.nonCo2BenefitsFactor() == 1.; + + double baukosten_MioEur = railBaseDataContainer.getCostBenefitAnalysis().getCost().overallCosts() * modifications.constructionCostFactor(); + double benefit_MioEur = railBaseDataContainer.getCostBenefitAnalysis().getOverallBenefit().overall(); + double co2_infra_MioEur = railBaseDataContainer.getCostBenefitAnalysis().getNl().overall(); + double co2_betrieb_t = railBaseDataContainer.getPhysicalEffect().getEmissionsDataContainer().emissions().get(Emission.CO2); + + return ComputationKN.nkv_rail(modifications.co2Price(), baukosten_MioEur * 10e6, benefit_MioEur * 10e6, co2_infra_MioEur * 10e6, + co2_betrieb_t); + } + +// @Deprecated // use instance approach +// public static Double calculateCost_CO2( Modifications modifications, RailBaseDataContainer streetBaseDataContainer ) { +// log.warn("modifications=" + modifications); +// Amounts a = new Amounts(); +// Benefits b = benefitsFromBaseData(streetBaseDataContainer ); +// +// final double co2Costs = -b_co2( modifications, a, b ); +// +// log.warn( TEXT_RED + "project=" + streetBaseDataContainer.getProjectInformation().getProjectNumber() + "; co2Costs=" + co2Costs + +// TEXT_BLACK ); +// +// return co2Costs; +// } +} diff --git a/src/main/java/org/tub/vsp/bvwp/data/container/analysis/RailAnalysisDataContainer.java b/src/main/java/org/tub/vsp/bvwp/data/container/analysis/RailAnalysisDataContainer.java index 84e79ae..5199d1c 100644 --- a/src/main/java/org/tub/vsp/bvwp/data/container/analysis/RailAnalysisDataContainer.java +++ b/src/main/java/org/tub/vsp/bvwp/data/container/analysis/RailAnalysisDataContainer.java @@ -2,16 +2,104 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.tub.vsp.bvwp.computation.ComputationKN; +import org.tub.vsp.bvwp.computation.Modifications; +import org.tub.vsp.bvwp.computation.NkvCalculatorRail; +import org.tub.vsp.bvwp.data.Headers; import org.tub.vsp.bvwp.data.container.base.rail.RailBaseDataContainer; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.SequencedMap; + +import static org.tub.vsp.bvwp.computation.Modifications.NO_CHANGE; +import static org.tub.vsp.bvwp.computation.Modifications.co2Price700; +import static org.tub.vsp.bvwp.data.container.analysis.StreetAnalysisDataContainer.INFLATION_Factor2022to2012; + + public class RailAnalysisDataContainer { Logger logger = LogManager.getLogger(RailAnalysisDataContainer.class); private final RailBaseDataContainer baseDataContainer; - + private double constructionCostFactor = 1; + private final SequencedMap entries = new LinkedHashMap<>(); + private final List remarks = new ArrayList<>(); +// private final double constructionCostTud; public RailAnalysisDataContainer(RailBaseDataContainer baseDataContainer) { this.baseDataContainer = baseDataContainer; + this.addComputations(); } //add analysis stuff here... + private void addComputations() { + + double additionalLaneKm = baseDataContainer.getProjectInformation().getLength() * 2; + // (assumption 2 more lanes) + +// switch( baseDataContainer.getProjectInformation().getBautyp() ){ +// case NB4 -> additionalLaneKm *= 2; +// case NB6 -> additionalLaneKm *= 3; +// case NB4_EW4 -> additionalLaneKm *= 1.5; +// } + +// entries.put(Headers.VERKEHRSBELASTUNG_PLANFALL, baseDataContainer.getProjectInformation().getVerkehrsbelastungPlanfall() ); + + if ( additionalLaneKm==0. ) { + additionalLaneKm = 1.; // Knotenpunkt-Projekte; so that it becomes visible on logplot. kai, mar'24 + } + + entries.put( Headers.ADDTL_LANE_KM, additionalLaneKm ); + + double addtlFzkmFromElasticity03 = additionalLaneKm / ComputationKN.LANE_KM_AB * 0.3 * ComputationKN.FZKM_AB; +// final double addtlFzkmBeyondPrinsEl03 = addtlFzkmFromElasticity03 - baseDataContainer.getPhysicalEffect().getVehicleKilometers().overall(); + // (this is formulated such that addtlFzkmBeyondPrinsEl03=0 means the original additional Fzkm) + + entries.put(Headers.B_PER_KM, baseDataContainer.getCostBenefitAnalysis().getOverallBenefit().overall() / baseDataContainer.getProjectInformation().getLength() ); + + entries.put(Headers.NKV_ORIG, NkvCalculatorRail.calculateNkv( NO_CHANGE, baseDataContainer ) ); + entries.put(Headers.NKV_CO2, NkvCalculatorRail.calculateNkv(new Modifications(co2Price700, 0., 1, 1.), baseDataContainer)); + entries.put(Headers.NKV_CO2_700_EN, NkvCalculatorRail.calculateNkv(new Modifications(co2Price700, 0., 1, 1.), baseDataContainer)); + entries.put(Headers.NKV_CARBON700, NkvCalculatorRail.calculateNkv(new Modifications(co2Price700, 0., 1, 1.), baseDataContainer)); + entries.put(Headers.NKV_CO2_2000_EN, NkvCalculatorRail.calculateNkv( new Modifications( 2000 * INFLATION_Factor2022to2012, 0, 1, 1. ), baseDataContainer ) ); +// entries.put(Headers.NKV_EL03, NkvCalculatorRail.calculateNkv( new Modifications( co2PriceBVWP, addtlFzkmBeyondPrinsEl03, 1, 1. ), baseDataContainer ) ); +// entries.put(Headers.NKV_EL03_CARBON215_INVCOSTTUD, NkvCalculatorRail.calculateNkv( new Modifications( co2Price215, addtlFzkmBeyondPrinsEl03, constructionCostFactor, 1. ), baseDataContainer ) ); +// entries.put(Headers.NKV_EL03_CARBON700tpr0_INVCOSTTUD, NkvCalculatorRail.calculateNkv( new Modifications( co2Price700, addtlFzkmBeyondPrinsEl03, constructionCostFactor, 1.75 ), baseDataContainer ) ); +// entries.put(Headers.NKV_EL03_CARBON700tpr0, NkvCalculatorRail.calculateNkv( new Modifications( co2Price700, addtlFzkmBeyondPrinsEl03, 1., 1.75 ), baseDataContainer ) ); +// entries.put(Headers.NKV_EL03_CO2_INVCOST50, NkvCalculatorRail.calculateNkv( new Modifications( co2Price700, addtlFzkmBeyondPrinsEl03, constructionCostFactor ), baseDataContainer ) ); + + entries.put(Headers.ADDTL_PKWKM_EL03, addtlFzkmFromElasticity03 ); +// entries.put(Headers.CO2_COST_ORIG, Math.max( 1., NkvCalculatorRail.calculateCost_CO2( NO_CHANGE, baseDataContainer ) ) ); +// entries.put(Headers.CO2_COST_EL03, Math.max( 1., NkvCalculatorRail.calculateCost_CO2( new Modifications( co2PriceBVWP, addtlFzkmBeyondPrinsEl03, 1, 1. ), baseDataContainer ) ) ); + // ("max(1,...)" so that they become visible on logplot. find other solution! +// entries.put(Headers.INVCOST_TUD, this.constructionCostTud ); + + double AVERAGE_SPEED_OF_ADDITIONAL_TRAVEL = 50; // km/h +// double addtlFzkmFromTtime = - baseDataContainer.getPhysicalEffect().getVehicleHours().overall() * AVERAGE_SPEED_OF_ADDITIONAL_TRAVEL; +// entries.put( Headers.ADDTL_PKWKM_FROM_TTIME, addtlFzkmFromTtime ); + +// entries.put( Headers.NKV_ELTTIME_CARBON215_INVCOSTTUD, NkvCalculatorRail.calculateNkv( new Modifications( co2Price215, addtlFzkmFromTtime, constructionCostFactor, 1. ), baseDataContainer ) ); +// entries.put( Headers.NKV_ELTTIME_CARBON700TPR0_INVCOSTTUD, NkvCalculatorRail.calculateNkv( new Modifications( co2Price700, addtlFzkmFromTtime, constructionCostFactor, 1.75 ), baseDataContainer ) ); +// +// entries.put( Headers.NKV_ELTTIME_CARBON2000_INVCOSTTUD, NkvCalculatorRail.calculateNkv( new Modifications( 2000 * INFLATION_Factor2022to2012, addtlFzkmFromTtime, constructionCostFactor, 1.75 ), baseDataContainer ) ); + + if ( baseDataContainer.getProjectInformation().getProjectNumber().contains("A1-G50-NI" )) { + this.remarks.add("Eher geringer Benefit pro km ... erzeugt dann ueber die El pro km relativ viel Verkehr " + + "der per co2 stark negativ bewertet wird."); + } + + } + + public RailBaseDataContainer getBaseDataContainer() { + return baseDataContainer; + } + + public SequencedMap getColumns() { + return entries; + } + + public List getRemarks() { + return remarks; + } + } diff --git a/src/main/java/org/tub/vsp/bvwp/data/container/analysis/StreetAnalysisDataContainer.java b/src/main/java/org/tub/vsp/bvwp/data/container/analysis/StreetAnalysisDataContainer.java index d50b2e7..e062503 100644 --- a/src/main/java/org/tub/vsp/bvwp/data/container/analysis/StreetAnalysisDataContainer.java +++ b/src/main/java/org/tub/vsp/bvwp/data/container/analysis/StreetAnalysisDataContainer.java @@ -22,6 +22,7 @@ public class StreetAnalysisDataContainer { private final SequencedMap entries = new LinkedHashMap<>(); private final List remarks = new ArrayList<>(); private final double constructionCostTud; + static final double INFLATION_Factor2022to2012 = 0.917; // Zinse Wert von 2020 auf BVWP Zeitpunkt 2012 ab. public StreetAnalysisDataContainer(StreetBaseDataContainer streetBaseDataContainer, double investmentCostNew ) { this.streetBaseData = streetBaseDataContainer; @@ -56,8 +57,6 @@ private void addComputations() { case NB4_EW4 -> additionalLaneKm *= 1.5; } - final double INFLATION_Factor2022to2012 = 0.917; // Zinse Wert von 2020 auf BVWP Zeitpunkt 2012 ab. - entries.put(Headers.VERKEHRSBELASTUNG_PLANFALL, streetBaseData.getProjectInformation().getVerkehrsbelastungPlanfall() ); if ( additionalLaneKm==0. ) { diff --git a/src/main/java/org/tub/vsp/bvwp/data/container/base/rail/RailBaseDataContainer.java b/src/main/java/org/tub/vsp/bvwp/data/container/base/rail/RailBaseDataContainer.java index 6afa998..b5a2b83 100644 --- a/src/main/java/org/tub/vsp/bvwp/data/container/base/rail/RailBaseDataContainer.java +++ b/src/main/java/org/tub/vsp/bvwp/data/container/base/rail/RailBaseDataContainer.java @@ -6,7 +6,7 @@ public class RailBaseDataContainer { private String url; RailProjectInformationDataContainer projectInformation; - RailPhysicalEffectDataContainer physicalEffect; + RailPhysicalEffectsDataContainer physicalEffect; RailCostBenefitAnalysisDataContainer costBenefitAnalysis; public String getUrl() { @@ -27,11 +27,11 @@ public RailBaseDataContainer setProjectInformation(RailProjectInformationDataCon return this; } - public RailPhysicalEffectDataContainer getPhysicalEffect() { + public RailPhysicalEffectsDataContainer getPhysicalEffect() { return physicalEffect; } - public RailBaseDataContainer setPhysicalEffect(RailPhysicalEffectDataContainer physicalEffect) { + public RailBaseDataContainer setPhysicalEffect( RailPhysicalEffectsDataContainer physicalEffect ) { this.physicalEffect = physicalEffect; return this; } diff --git a/src/main/java/org/tub/vsp/bvwp/data/container/base/rail/RailPhysicalEffectDataContainer.java b/src/main/java/org/tub/vsp/bvwp/data/container/base/rail/RailPhysicalEffectsDataContainer.java similarity index 75% rename from src/main/java/org/tub/vsp/bvwp/data/container/base/rail/RailPhysicalEffectDataContainer.java rename to src/main/java/org/tub/vsp/bvwp/data/container/base/rail/RailPhysicalEffectsDataContainer.java index 396999d..24cc8fe 100644 --- a/src/main/java/org/tub/vsp/bvwp/data/container/base/rail/RailPhysicalEffectDataContainer.java +++ b/src/main/java/org/tub/vsp/bvwp/data/container/base/rail/RailPhysicalEffectsDataContainer.java @@ -2,14 +2,14 @@ import java.util.Objects; -public class RailPhysicalEffectDataContainer { +public class RailPhysicalEffectsDataContainer{ private RailEmissionsDataContainer emissionsDataContainer; public RailEmissionsDataContainer getEmissionsDataContainer() { return emissionsDataContainer; } - public RailPhysicalEffectDataContainer setEmissionsDataContainer(RailEmissionsDataContainer emissionsDataContainer) { + public RailPhysicalEffectsDataContainer setEmissionsDataContainer( RailEmissionsDataContainer emissionsDataContainer ) { this.emissionsDataContainer = emissionsDataContainer; return this; } @@ -23,7 +23,7 @@ public boolean equals(Object o) { return false; } - RailPhysicalEffectDataContainer that = (RailPhysicalEffectDataContainer) o; + RailPhysicalEffectsDataContainer that = (RailPhysicalEffectsDataContainer) o; return Objects.equals(emissionsDataContainer, that.emissionsDataContainer); } diff --git a/src/main/java/org/tub/vsp/bvwp/data/mapper/physicalEffect/RailPhysicalEffectMapper.java b/src/main/java/org/tub/vsp/bvwp/data/mapper/physicalEffect/RailPhysicalEffectMapper.java index 229e240..ac8b2e0 100644 --- a/src/main/java/org/tub/vsp/bvwp/data/mapper/physicalEffect/RailPhysicalEffectMapper.java +++ b/src/main/java/org/tub/vsp/bvwp/data/mapper/physicalEffect/RailPhysicalEffectMapper.java @@ -3,13 +3,15 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jsoup.nodes.Document; -import org.tub.vsp.bvwp.data.container.base.rail.RailPhysicalEffectDataContainer; +import org.tub.vsp.bvwp.data.container.base.rail.RailPhysicalEffectsDataContainer; import org.tub.vsp.bvwp.data.mapper.physicalEffect.emissions.RailEmissionsMapper; public class RailPhysicalEffectMapper { private static final Logger logger = LogManager.getLogger(RailPhysicalEffectMapper.class); - public static RailPhysicalEffectDataContainer mapDocument(Document document) { - return new RailPhysicalEffectDataContainer().setEmissionsDataContainer(RailEmissionsMapper.mapDocument(document)); + public static RailPhysicalEffectsDataContainer mapDocument( Document document ) { + final RailPhysicalEffectsDataContainer physicalDataContainer = new RailPhysicalEffectsDataContainer(); + physicalDataContainer.setEmissionsDataContainer(RailEmissionsMapper.mapDocument(document ) ); + return physicalDataContainer; } } diff --git a/src/main/java/org/tub/vsp/bvwp/io/RailCsvWriter.java b/src/main/java/org/tub/vsp/bvwp/io/RailCsvWriter.java deleted file mode 100644 index 16625c0..0000000 --- a/src/main/java/org/tub/vsp/bvwp/io/RailCsvWriter.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.tub.vsp.bvwp.io; - -public class RailCsvWriter { -} diff --git a/src/main/java/org/tub/vsp/bvwp/io/RailTableCreator.java b/src/main/java/org/tub/vsp/bvwp/io/RailTableCreator.java new file mode 100644 index 0000000..6272d01 --- /dev/null +++ b/src/main/java/org/tub/vsp/bvwp/io/RailTableCreator.java @@ -0,0 +1,175 @@ +package org.tub.vsp.bvwp.io; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.tub.vsp.bvwp.data.Headers; +import org.tub.vsp.bvwp.data.container.analysis.RailAnalysisDataContainer; +import org.tub.vsp.bvwp.data.container.base.rail.RailBaseDataContainer; +import tech.tablesaw.api.DoubleColumn; +import tech.tablesaw.api.Row; +import tech.tablesaw.api.StringColumn; +import tech.tablesaw.api.Table; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class RailTableCreator { + private static final Logger logger = LogManager.getLogger(StreetCsvWriter.class); + + private final Table table; + + public RailTableCreator() { + this.table = Table.create("defaultTable"); + // (I am somewhat abusing this class to also generate a TableSaw Table. Probably would make sense later to + // first genrate the Table object, + // and then csv-write that. kai, feb'24) + } + + public Table computeTable(List analysisDataContainers) { + addHeaders(analysisDataContainers); + + for (RailAnalysisDataContainer analysisDataContainer : analysisDataContainers) { + getCsvRecord(analysisDataContainer, table); + } + return table; + } + + private static class Record { + private final Row row; + private final List record = new ArrayList<>(); + private final Table table; + int ii = 0; + + private Record(Table table) { + this.row = table.appendRow(); + this.table = table; + } + + // private Record add( String str ) { +// row.setString( ii, str ); +// record.add( str ); +// ii++; +// return this; +// } + private Record add(String key, String str) { + +// if ( !table.columnNames().contains( key ) ) { +// table.addColumns( StringColumn.create( key ) ); +// } + // not working (I think) + + row.setString(key, str); + record.add(str); + ii++; + return this; + } + + // private Record add( Double dbl ) { +// if ( dbl != null ){ +// row.setDouble( ii, dbl ); +// } else { +// row.setDouble( ii, Double.NaN ); +// } +// record.add( dbl ); +// ii++; +// return this; +// } + private Record add(String key, Double dbl) { + +// if ( !table.columnNames().contains( key ) ) { +// table.addColumns( DoubleColumn.create( key ) ); +// } + // not working (I think) + + if (dbl != null) { + row.setDouble(key, dbl); + } else { + row.setDouble(key, Double.NaN); + } + record.add(dbl); + ii++; + return this; + } + } + + private static List getCsvRecord( RailAnalysisDataContainer analysisDataContainer, Table table ) { + RailBaseDataContainer baseDataContainer = analysisDataContainer.getBaseDataContainer(); + + Record record = new Record(table); + + //general info + record.add(Headers.PROJECT_NAME, baseDataContainer.getProjectInformation().getProjectNumber()); + record.add(Headers.LINK, baseDataContainer.getUrl()); + record.add(Headers.EINSTUFUNG, baseDataContainer.getProjectInformation().getPriority().name() ); + + record.add(Headers.LENGTH, baseDataContainer.getProjectInformation().getLength()); + + //overall benefit and cost + record.add(Headers.B_OVERALL, baseDataContainer.getCostBenefitAnalysis().getOverallBenefit().overall()); + record.add(Headers.INVCOST_ORIG, baseDataContainer.getCostBenefitAnalysis().getCost().overallCosts()); + + // (yy warum diese aufwändige Syntax? kai, feb'24) + // --> da sowohl getCostBenefitAnalysis, getCost als auch overallCosts null zurückgeben können, wenn die + // Daten nicht vorhanden sind. So spart man sich null checks (paul, feb'24) + + for (Map.Entry entry : analysisDataContainer.getColumns().entrySet()) { + record.add(entry.getKey(), entry.getValue()); + } + + int ii = 0; + for (String remark : analysisDataContainer.getRemarks()) { + record.add("remark_" + ii, "\"" + remark + "\""); + ii++; + } + + return record.record; + } + + private void addHeaders(List analysisDataContainers) { + //assert that all entries of new nkv have the same keys + assert analysisDataContainers.stream() + .allMatch(a -> { + Set thisKeys = a.getColumns().keySet(); + Set firstKeys = analysisDataContainers.getFirst().getColumns() + .keySet(); + return thisKeys.containsAll(firstKeys) && thisKeys.size() == firstKeys.size(); + }) : "Not all nkv have the same keys"; + + table.addColumns(StringColumn.create(Headers.PROJECT_NAME)); + + table.addColumns(StringColumn.create(Headers.LINK)); + table.addColumns(StringColumn.create(Headers.EINSTUFUNG)); + table.addColumns(StringColumn.create(Headers.BAUTYP)); + table.addColumns(DoubleColumn.create(Headers.LENGTH)); + + table.addColumns(DoubleColumn.create(Headers.ADDTL_PKWKM_ORIG)); + table.addColumns(DoubleColumn.create(Headers.ADDTL_PKWKM_INDUZ_ORIG)); + table.addColumns(DoubleColumn.create(Headers.B_FZKM)); + + table.addColumns(DoubleColumn.create(Headers.CO_2_EQUIVALENTS_EMISSIONS)); + // headers.addDoubleColumn( Headers.B_CO_2_EQUIVALENTS_ANNUAL ); + table.addColumns(DoubleColumn.create(Headers.B_CO_2_EQUIVALENTS_ORIG)); + +// for (String colName : EMISSION_COLUMNS.values()) { +// headers.add(colName + "-emissions"); +// headers.add(colName + "-annual"); +// headers.add(colName + "-overall"); +// } + + table.addColumns(DoubleColumn.create(Headers.B_OVERALL)); + table.addColumns(DoubleColumn.create(Headers.INVCOST_ORIG)); + + for (String s : analysisDataContainers.getFirst() + .getColumns() + .keySet()) { + table.addColumns(DoubleColumn.create(s)); + } + + for (int ii = 0; ii < 5; ii++) { + table.addColumns(StringColumn.create("remark_" + ii)); + } + + } +} diff --git a/src/main/java/org/tub/vsp/bvwp/scraping/RailScraper.java b/src/main/java/org/tub/vsp/bvwp/scraping/RailScraper.java index 6ac8b59..f1fe076 100644 --- a/src/main/java/org/tub/vsp/bvwp/scraping/RailScraper.java +++ b/src/main/java/org/tub/vsp/bvwp/scraping/RailScraper.java @@ -3,6 +3,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jsoup.nodes.Document; +import org.tub.vsp.bvwp.JSoupUtils; import org.tub.vsp.bvwp.data.container.base.rail.RailBaseDataContainer; import org.tub.vsp.bvwp.data.mapper.costBenefit.RailCostBenefitMapper; import org.tub.vsp.bvwp.data.mapper.physicalEffect.RailPhysicalEffectMapper; @@ -50,7 +51,8 @@ public List extractAllLocalBaseData(String projectFolder, } private boolean isProjectScrapable(Document doc) { - //if there is only one table, there is no further information to scrape (e.g. https://www.bvwp-projekte.de/schiene/2-034-V01/2-034-V01.html) - return doc.select("table.table_grunddaten").size() > 1; + //if there is no emissions table, there is no further information to scrape (e.g. https://www.bvwp-projekte.de/schiene/2-034-V01/2-034-V01.html) + return JSoupUtils.getTableByKeyAndContainedText(doc, "table.table_webprins", + "Veränderung der Abgasemissionen").isPresent(); } } diff --git a/src/main/java/org/tub/vsp/bvwp/users/kn/RunLocalRailScrapingKN.java b/src/main/java/org/tub/vsp/bvwp/users/kn/RunLocalRailScrapingKN.java new file mode 100644 index 0000000..69b70a4 --- /dev/null +++ b/src/main/java/org/tub/vsp/bvwp/users/kn/RunLocalRailScrapingKN.java @@ -0,0 +1,29 @@ +package org.tub.vsp.bvwp.users.kn; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.tub.vsp.bvwp.data.container.analysis.RailAnalysisDataContainer; +import org.tub.vsp.bvwp.io.RailTableCreator; +import org.tub.vsp.bvwp.scraping.RailScraper; +import tech.tablesaw.api.Table; + +import java.util.List; + +public class RunLocalRailScrapingKN{ + private static final Logger logger = LogManager.getLogger( RunLocalRailScrapingKN.class ); + + public static void main(String[] args) { + RailScraper scraper = new RailScraper(); + + logger.info("Starting scraping"); + List allRailData = scraper.extractAllLocalBaseData("./data/rail/all", "", "^2.*", "") + .stream() + .map(RailAnalysisDataContainer::new) + .toList(); + + logger.info("Writing csv"); + RailTableCreator tableCreator = new RailTableCreator(); + + Table table = tableCreator.computeTable(allRailData); + } +} diff --git a/src/test/java/org/tub/vsp/bvwp/computation/NkvCalculatorRailTest.java b/src/test/java/org/tub/vsp/bvwp/computation/NkvCalculatorRailTest.java new file mode 100644 index 0000000..2e51c68 --- /dev/null +++ b/src/test/java/org/tub/vsp/bvwp/computation/NkvCalculatorRailTest.java @@ -0,0 +1,22 @@ +package org.tub.vsp.bvwp.computation; + +import org.junit.jupiter.api.Test; +import org.tub.vsp.bvwp.data.LocalFileAccessor; +import org.tub.vsp.bvwp.data.container.base.rail.RailBaseDataContainer; +import org.tub.vsp.bvwp.scraping.RailScraper; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class NkvCalculatorRailTest { + @Test + void test_rail() throws IOException { + RailScraper railScraper = new RailScraper(); + RailBaseDataContainer railBaseDataContainer = railScraper.extractBaseData(LocalFileAccessor.getLocalDocument("2-003-v01.html")).orElseThrow(); + + var nkvCalculator = new NkvCalculatorRail(railBaseDataContainer); + Double calculateNkv = nkvCalculator.calculateNkv(Modifications.NO_CHANGE); + assertEquals(2.1593, calculateNkv, 10e-4); + } +} \ No newline at end of file