diff --git a/bootstrap.py b/bootstrap.py index 860474c..f692b3a 100755 --- a/bootstrap.py +++ b/bootstrap.py @@ -36,14 +36,10 @@ "c:/DEV/bld" # avoid long path issues by using a short build path ) - overlay_ports = os.path.abspath( - os.path.join(os.path.dirname(__file__), "deps", "overlay-ports") - ) - if args.clean: vcpkg.clean(triplet=triplet) else: - vcpkg.bootstrap(ports_dir=os.path.join(".", "deps"), triplet=triplet, build_root=build_root, install_root=install_root, overlay_ports=overlay_ports, clean_after_build=args.clean_after_build) + vcpkg.bootstrap(ports_dir=os.path.join(".", "deps"), triplet=triplet, build_root=build_root, install_root=install_root, clean_after_build=args.clean_after_build) except KeyboardInterrupt: print("\nInterrupted") sys.exit(-1) diff --git a/deps/geodynamix b/deps/geodynamix index 0ab6194..7366eff 160000 --- a/deps/geodynamix +++ b/deps/geodynamix @@ -1 +1 @@ -Subproject commit 0ab61942c9f0787541d24f7b165f6cf37eb74b85 +Subproject commit 7366eff9d2b032225d36e5380d6881ef7704080e diff --git a/deps/overlay-ports/fast-cpp-csv-parser/FindFastCppCsvParser.cmake b/deps/overlay-ports/fast-cpp-csv-parser/FindFastCppCsvParser.cmake deleted file mode 100644 index 7ba8809..0000000 --- a/deps/overlay-ports/fast-cpp-csv-parser/FindFastCppCsvParser.cmake +++ /dev/null @@ -1,20 +0,0 @@ -include(FindPackageHandleStandardArgs) - -find_path(FastCppCsvParser_INCLUDE_DIR - NAMES csv.h - HINTS ${FastCppCsvParser_ROOT_DIR}/include ${FastCppCsvParser_INCLUDEDIR} -) - -find_package_handle_standard_args(FastCppCsvParser - FOUND_VAR FastCppCsvParser_FOUND - REQUIRED_VARS FastCppCsvParser_INCLUDE_DIR -) - -mark_as_advanced(FastCppCsvParser_ROOT_DIR FastCppCsvParser_INCLUDE_DIR) - -if(FastCppCsvParser_FOUND AND NOT TARGET FastCppCsvParser::csv) - add_library(FastCppCsvParser::csv INTERFACE IMPORTED) - set_target_properties(FastCppCsvParser::csv PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${FastCppCsvParser_INCLUDE_DIR}" - ) -endif() diff --git a/deps/overlay-ports/fast-cpp-csv-parser/portfile.cmake b/deps/overlay-ports/fast-cpp-csv-parser/portfile.cmake deleted file mode 100644 index 25d840b..0000000 --- a/deps/overlay-ports/fast-cpp-csv-parser/portfile.cmake +++ /dev/null @@ -1,15 +0,0 @@ -# header-only library - -vcpkg_from_github( - OUT_SOURCE_PATH SOURCE_PATH - REPO ben-strasser/fast-cpp-csv-parser - REF 75600d0b77448e6c410893830df0aec1dbacf8e3 - SHA512 aab418e98eb895dabd6369b186b7a55beddb84b89e358395a9f125829074916eff9086d80f9cd342d1bfd91acacc7103875c970a84164b75fff259cc93729285 - HEAD_REF master -) - -file(INSTALL ${SOURCE_PATH}/csv.h DESTINATION ${CURRENT_PACKAGES_DIR}/include) -file(INSTALL ${CMAKE_CURRENT_LIST_DIR}/FindFastCppCsvParser.cmake DESTINATION ${CURRENT_PACKAGES_DIR}/share/cmake) - -# Handle copyright -configure_file(${SOURCE_PATH}/LICENSE ${CURRENT_PACKAGES_DIR}/share/${PORT}/copyright COPYONLY) diff --git a/deps/overlay-ports/fast-cpp-csv-parser/vcpkg.json b/deps/overlay-ports/fast-cpp-csv-parser/vcpkg.json deleted file mode 100644 index 8e2640a..0000000 --- a/deps/overlay-ports/fast-cpp-csv-parser/vcpkg.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "fast-cpp-csv-parser", - "version-string": "2021-01-03", - "port-version": 1, - "description": "A small, easy-to-use and fast header-only library for reading comma separated value (CSV) files", - "homepage": "https://github.com/ben-strasser/fast-cpp-csv-parser" -} diff --git a/deps/vcpkg b/deps/vcpkg index 53238eb..57adc34 160000 --- a/deps/vcpkg +++ b/deps/vcpkg @@ -1 +1 @@ -Subproject commit 53238eb7cdb557aa018585f4b12e288727fc9bdb +Subproject commit 57adc34a5f058ef12ebcba10a78fec9026da9b11 diff --git a/logic/configurationparser.cpp b/logic/configurationparser.cpp index d0ad5e8..4614f67 100644 --- a/logic/configurationparser.cpp +++ b/logic/configurationparser.cpp @@ -14,6 +14,7 @@ namespace emap { using namespace inf; using namespace std::string_view_literals; +namespace gdal = inf::gdal; static EmissionDestination emission_destination_from_string(std::string_view str) { diff --git a/logic/debugtools.cpp b/logic/debugtools.cpp index 76ec229..dbb6a0d 100644 --- a/logic/debugtools.cpp +++ b/logic/debugtools.cpp @@ -18,6 +18,7 @@ namespace emap { using namespace inf; using namespace std::string_literals; +namespace gdal = inf::gdal; class VectorBuilder { diff --git a/logic/emissioninventory.cpp b/logic/emissioninventory.cpp index 004bc33..0f9cdf2 100644 --- a/logic/emissioninventory.cpp +++ b/logic/emissioninventory.cpp @@ -15,6 +15,7 @@ namespace emap { using namespace inf; using namespace date::literals; +namespace gdal = inf::gdal; static fs::path throw_if_not_exists(const fs::path& path) { diff --git a/logic/emissionscollector.cpp b/logic/emissionscollector.cpp index 7587547..ddf66e5 100644 --- a/logic/emissionscollector.cpp +++ b/logic/emissionscollector.cpp @@ -77,9 +77,7 @@ void EmissionsCollector::add_emissions(const CountryCellCoverage& countryInfo, c } for (auto& entry : pointEmissions) { - if (entry.value().amount() > 0.0) { - _outputBuilder->add_point_output_entry(entry); - } + _outputBuilder->add_point_output_entry(entry); } if (diffuseEmissions.empty() && !pointEmissions.empty()) { diff --git a/logic/gridprocessing.cpp b/logic/gridprocessing.cpp index 3bf8621..2ead359 100644 --- a/logic/gridprocessing.cpp +++ b/logic/gridprocessing.cpp @@ -32,6 +32,7 @@ namespace emap { using namespace inf; using namespace std::string_literals; +namespace gdal = inf::gdal; gdal::VectorDataSet transform_vector(const fs::path& vectorPath, const GeoMetadata& destMeta) { diff --git a/logic/include/emap/emissioninventory.h b/logic/include/emap/emissioninventory.h index 690a13b..5e01f11 100644 --- a/logic/include/emap/emissioninventory.h +++ b/logic/include/emap/emissioninventory.h @@ -1,6 +1,7 @@ #pragma once #include "emap/emissions.h" +#include "infra/math.h" namespace emap { @@ -223,6 +224,26 @@ class EmissionCollection throw inf::RuntimeError("No emission found with id: {}", id); } + const TEmission& emission_with_id_at_coordinate(const EmissionIdentifier& id, Coordinate coord) const + { + auto iter = std::find_if(_emissions.begin(), _emissions.end(), [&id, &coord](const TEmission& em) { + if (em.id() == id) { + if (auto coordOpt = em.coordinate(); coordOpt.has_value()) { + return inf::math::approx_equal(coord.x, coordOpt->x, 1e-4) && + inf::math::approx_equal(coord.y, coordOpt->y, 1e-4); + } + } + + return false; + }); + + if (iter == _emissions.end()) { + throw inf::RuntimeError("No emission found with id: {} at coordinate {}", id, coord); + } + + return *iter; + } + std::optional try_emission_with_id(const EmissionIdentifier& id) const noexcept { auto emissionIter = find_sorted(id); @@ -243,6 +264,23 @@ class EmissionCollection return result; } + std::vector emissions_with_id_at_coordinate(const EmissionIdentifier& id, Coordinate coord) const + { + std::vector result; + std::copy_if(_emissions.begin(), _emissions.end(), std::back_inserter(result), [&id, &coord](const TEmission& em) { + if (em.id() == id) { + if (auto coordOpt = em.coordinate(); coordOpt.has_value()) { + return inf::math::approx_equal(coord.x, coordOpt->x, 1e-4) && + inf::math::approx_equal(coord.y, coordOpt->y, 1e-4); + } + } + + return false; + }); + + return result; + } + size_t empty() const noexcept { return _emissions.empty(); diff --git a/logic/include/emap/inputconversion.h b/logic/include/emap/inputconversion.h index f7b42db..3ee75d7 100644 --- a/logic/include/emap/inputconversion.h +++ b/logic/include/emap/inputconversion.h @@ -3,6 +3,7 @@ #include "infra/exception.h" #include "infra/string.h" +#include #include #include #include diff --git a/logic/inputparsers.cpp b/logic/inputparsers.cpp index 5aaccee..ae6eca5 100644 --- a/logic/inputparsers.cpp +++ b/logic/inputparsers.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -25,18 +26,10 @@ #include #include -#if defined(_MSC_VER) -#pragma warning(push) -#pragma warning(disable : 4267 4244) -#endif -#include -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - namespace emap { using namespace inf; +namespace gdal = inf::gdal; static int32_t required_csv_column(const inf::CsvReader& csv, const std::string& columnName) { @@ -209,64 +202,131 @@ SingleEmissions parse_point_sources(const fs::path& emissionsCsv, const RunConfi size_t lineNr = 2; - std::unordered_map pointSourceEmissions; - try { Log::debug("Parse emissions: {}", emissionsCsv); - /* + std::vector pointSources; + std::unordered_map pointSourceEmissions; + +#if 1 using namespace io; - CSVReader<21, trim_chars<' ', '\t'>, no_quote_escape<';'>, throw_on_overflow> in(str::from_u8(emissionsCsv.u8string())); + CSVReader<25, trim_chars<' ', '\t'>, no_quote_escape<';'>, throw_on_overflow> in(file::u8string(emissionsCsv)); + + in.read_header(ignore_missing_column | ignore_extra_column, + "type", + "scenario", + "year", + "reporting_country", + "nfr_sector", + "gnfr_sector", + "pollutant", + "emission", + "unit", + "x", + "y", + "hoogte_m", + "diameter_m", + "temperatuur_C", + "warmteinhoud_MW", + "debiet_Nm3/u", + "Debiet_Nm3/u", + "dv", + "type_emissie", + "EIL_nummer", + "exploitatie_naam", + "EIL_Emissiepunt_Jaar_Naam", + "Activiteit_type", + "subtype", + "pointsource_index"); + + if (!in.has_column("nfr_sector") && !in.has_column("gnfr_sector")) { + throw RuntimeError("Missing nfr_sector or gnfr_sector column"); + } + auto sectorType = in.has_column("nfr_sector") ? EmissionSector::Type::Nfr : EmissionSector::Type::Gnfr; + bool hasSubTypeCol = in.has_column("subtype"); + bool hasDvCol = in.has_column("dv"); + bool hasPointSourceIndexCol = in.has_column("pointsource_index"); + bool hasCoordinates = in.has_column("x") && in.has_column("y"); + + int32_t year = 0, dv = 0; + double value, height, diameter, temp, warmthContents, flowRate; + char *type, *scenario, *countryStr, *nfrSectorName, *gnfrSectorName, *pollutantName, *unit, *emissionType, *eilNr, *explName, *eilYearName, *activityType; + char *subtype = nullptr, *psIndex = nullptr; + char *x = nullptr, *y = nullptr; + while (in.read_row(type, scenario, year, countryStr, nfrSectorName, gnfrSectorName, pollutantName, value, unit, x, y, height, diameter, temp, warmthContents, flowRate, flowRate, dv, emissionType, eilNr, explName, eilYearName, activityType, subtype, psIndex)) { + auto sectorName = std::string_view(sectorType == EmissionSector::Type::Nfr ? nfrSectorName : gnfrSectorName); + const auto country = countryInv.try_country_from_string(countryStr); - int32_t year; - double value, height, diameter, temp, warmthContents, x, y, flowRate; - char *type, *scenario, *countryStr, *sectorName, *pollutantName, *unit, *excType, *eilNr, *explName, *naceCode, *eilYearName, *activityType, *subtype; - while (in.read_row(type, scenario, year, countryStr, sectorName, pollutant, value, x, y, unit, height, diameter, temp, warmthContents, flowRate, excType, eilNr, explName, naceCode, eilYearName, activityType, subtype)) { - if (sectorInv.is_ignored_sector(sectorType, sectorName) || - pollutantInv.is_ignored_pollutant(pollutantName)) { + if (sectorName.empty() || + sectorInv.is_ignored_sector(sectorType, sectorName, *country) || + pollutantInv.is_ignored_pollutant(pollutantName, *country)) { continue; } - double emissionValue = to_giga_gram(to_double(line.get_string(colEmission), lineNr), line.get_string(colUnit)); + double emissionValue = to_giga_gram(value, unit); + if (emissionValue == 0.0) { + continue; + } auto sector = sectorInv.try_sector_from_string(sectorType, sectorName); - auto country = countryInv.try_country_from_string(line.get_string(colCountry)); auto pollutant = pollutantInv.try_pollutant_from_string(pollutantName); - if (sector.has_value() && country.has_value() && pollutant.has_value()) { - EmissionEntry info( - EmissionIdentifier(*country, *sector, *pollutant), - EmissionValue(emissionValue)); - - info.set_height(line.get_double(colHeight).value_or(0.0)); - info.set_diameter(line.get_double(colDiameter).value_or(0.0)); - info.set_temperature(line.get_double(colTemperature).value_or(-9999.0)); - info.set_warmth_contents(line.get_double(colWarmthContents).value_or(0.0)); - info.set_flow_rate(line.get_double(colFlowRate).value_or(0.0)); - - std::string subType = "none"; - if (colSubType.has_value()) { - subType = line.get_string(*colSubType); + + if (sector.has_value() && pollutant.has_value()) { + PointSourceIdentifier ps; + ps.sector = *sector; + ps.country = *country; + ps.pollutant = *pollutant; + ps.height = height; + ps.diameter = diameter; + ps.temperature = temp; + ps.warmthContents = warmthContents; + ps.flowRate = flowRate; + + if (hasSubTypeCol) { + ps.subType = subtype ? subtype : "none"; + } else if (hasPointSourceIndexCol) { + ps.subType = psIndex ? psIndex : "none"; + } else { + ps.subType = "none"; } - info.set_source_id(fmt::format("{}_{}_{}_{}_{}_{}_{}_{}", info.height(), info.diameter(), info.temperature(), info.warmth_contents(), info.flow_rate(), line.get_string(colEilPoint), line.get_string(colEil), subType)); + ps.eilNumber = eilNr; + ps.eilPoint = eilYearName; - if (colX.has_value() && colY.has_value()) { - auto x = line.get_double(*colX); - auto y = line.get_double(*colY); - if (x.has_value() && y.has_value()) { - info.set_coordinate(Coordinate(*x, *y)); + if (hasCoordinates) { + auto xVal = str::to_double(x); + auto yVal = str::to_double(y); + if (xVal.has_value() && yVal.has_value()) { + ps.coordinate = Coordinate(*xVal, *yVal); } else { - throw RuntimeError("Invalid coordinate in point sources: {}", line.get_string(*colX), line.get_string(*colY)); + throw RuntimeError("Invalid coordinate in point sources: x='{}' y='{}'", x, y); } } - result.add_emission(std::move(info)); + if (hasDvCol) { + ps.dv = dv; + } + + if (combineIdentical) { + pointSourceEmissions[ps] += emissionValue; + } else { + pointSources.push_back(ps.to_emission_entry(emissionValue)); + } + } else { + if (!pollutant.has_value()) { + Log::warn("Unknown pollutant name: {}", pollutantName); + } + + if (!sector.has_value()) { + Log::warn("Unknown sector name: {}", sectorName); + } } + ++lineNr; - }*/ + } +#else - SingleEmissions result(cfg.year()); inf::CsvReader csv(emissionsCsv); auto colCountry = required_csv_column(csv, "reporting_country"); @@ -304,6 +364,9 @@ SingleEmissions parse_point_sources(const fs::path& emissionsCsv, const RunConfi } double emissionValue = to_giga_gram(to_double(line.get_string(colEmission), lineNr), line.get_string(colUnit)); + if (emissionValue == 0.0) { + continue; + } auto sector = sectorInv.try_sector_from_string(sectorType, sectorName); auto pollutant = pollutantInv.try_pollutant_from_string(pollutantName); @@ -339,7 +402,7 @@ SingleEmissions parse_point_sources(const fs::path& emissionsCsv, const RunConfi if (combineIdentical) { pointSourceEmissions[ps] += emissionValue; } else { - result.add_emission(ps.to_emission_entry(emissionValue)); + pointSources.push_back(ps.to_emission_entry(emissionValue)); } } else { if (!pollutant.has_value()) { @@ -354,12 +417,16 @@ SingleEmissions parse_point_sources(const fs::path& emissionsCsv, const RunConfi ++lineNr; } +#endif + if (combineIdentical) { for (const auto& [ps, emission] : pointSourceEmissions) { - result.add_emission(ps.to_emission_entry(emission)); + pointSources.push_back(ps.to_emission_entry(emission)); } } + SingleEmissions result(cfg.year()); + result.set_emissions(std::move(pointSources)); return result; } catch (const std::exception& e) { throw RuntimeError("Error parsing {} line {} ({})", emissionsCsv, lineNr, e.what()); diff --git a/logic/modelrun.cpp b/logic/modelrun.cpp index cbaa9d8..eca7760 100644 --- a/logic/modelrun.cpp +++ b/logic/modelrun.cpp @@ -32,6 +32,7 @@ namespace emap { using namespace inf; +namespace gdal = inf::gdal; struct SpatialPatternProcessInfo { @@ -453,4 +454,4 @@ int run_model(const RunConfiguration& cfg, const ModelProgress::Callback& progre return EXIT_FAILURE; } } -} \ No newline at end of file +} diff --git a/logic/outputbuilderfactory.cpp b/logic/outputbuilderfactory.cpp index 385e15c..ea53d8e 100644 --- a/logic/outputbuilderfactory.cpp +++ b/logic/outputbuilderfactory.cpp @@ -13,6 +13,7 @@ namespace emap { using namespace inf; +namespace gdal = inf::gdal; static std::unordered_map parse_chimere_country_mapping(const fs::path& mappingPath, const CountryInventory& countryInv) { @@ -90,4 +91,4 @@ std::unique_ptr make_output_builder(const RunConfiguration& cfg) throw RuntimeError("No known output builder for the specified grid definition"); } -} \ No newline at end of file +} diff --git a/logic/spatialpatterninventory.cpp b/logic/spatialpatterninventory.cpp index 011241c..8172e7c 100644 --- a/logic/spatialpatterninventory.cpp +++ b/logic/spatialpatterninventory.cpp @@ -20,6 +20,7 @@ namespace emap { using namespace inf; +namespace gdal = inf::gdal; static std::set scan_available_years(const fs::path& spatialPatternPath) { diff --git a/logic/test/data/_input/05_model_parameters/code_conversions.xlsx b/logic/test/data/_input/05_model_parameters/code_conversions.xlsx index 1f8f1c6..2a928b1 100644 Binary files a/logic/test/data/_input/05_model_parameters/code_conversions.xlsx and b/logic/test/data/_input/05_model_parameters/code_conversions.xlsx differ diff --git a/logic/test/data/point_sources.csv b/logic/test/data/point_sources.csv new file mode 100644 index 0000000..c9d2467 --- /dev/null +++ b/logic/test/data/point_sources.csv @@ -0,0 +1,19 @@ +type;scenario;year;reporting_country;nfr_sector;pollutant;emission;unit;x;y;hoogte_m;diameter_m;temperatuur_C;warmteinhoud_MW;debiet_Nm3/u;dv;type_emissie;EIL_nummer;exploitatie_naam;EIL_Emissiepunt_Jaar_Naam;Activiteit_type +historic;;2021;BEF;3B1b;NO2;0.360260113;kg/yr;116332.9766;166636.8709;5;0;0;0;0;4;Runderen jonger dan 1 jaar;57978963_57978963_24628802823;57978963_57978963_24628802823;57978963_57978963_24628802823;Vaste mest +historic;;2021;BEF;3B1b;NO2;0;kg/yr;116332.9766;166636.8709;5;0;0;0;0;4;Runderen jonger dan 1 jaar;57978963_57978963_24628802823;57978963_57978963_24628802823;57978963_57978963_24628802823;Mengmest +historic;;2021;BEF;3B1b;NO2;1.489021862;kg/yr;116332.9766;166636.8709;5;0;0;0;0;4;Zoogkoeien;57978963_57978963_24628802823;57978963_57978963_24628802823;57978963_57978963_24628802823;Vaste mest +historic;;2021;BEF;3B1b;NO2;0;kg/yr;116332.9766;166636.8709;5;0;0;0;0;4;Zoogkoeien;57978963_57978963_24628802823;57978963_57978963_24628802823;57978963_57978963_24628802823;Mengmest +historic;;2021;BEF;3B1b;NO2;1.049682095;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Mestkalveren;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Vaste mest +historic;;2021;BEF;3B1b;NO2;0;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Mestkalveren;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Mengmest +historic;;2021;BEF;3B1b;NO2;5.038105693;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Runderen (van 1 tot 2 jaar) ;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Vaste mest +historic;;2021;BEF;3B1b;NO2;0;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Runderen (van 1 tot 2 jaar) ;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Mengmest +historic;;2021;BEF;3B1b;NO2;34.85470149;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Andere runderen;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Vaste mest +historic;;2021;BEF;3B1b;NO2;0;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Andere runderen;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Mengmest +historic;;2021;BEF;3B1b;NO2;42.96467575;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Vervangingsvee (1-2 j.);86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Vaste mest +historic;;2021;BEF;3B1b;NO2;0.015456732;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Vervangingsvee (1-2 j.);86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Mengmest +historic;;2021;BEF;3B1b;NO2;0.842354917;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Runderen jonger dan 1 jaar;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Vaste mest +historic;;2021;BEF;3B1b;NO2;0;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Runderen jonger dan 1 jaar;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Mengmest +historic;;2021;BEF;3B1b;NO2;1.239607175;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Zoogkoeien;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Vaste mest +historic;;2021;BEF;3B1b;NO2;0;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Zoogkoeien;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Mengmest +historic;;2021;BEF;3B1b;NO2;35.77269872;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Vervangingsvee < 1 j.;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Vaste mest +historic;;2021;BEF;3B1b;NO2;0.042744747;kg/yr;95419.65;196533.8;5;0;0;0;0;4;Vervangingsvee < 1 j.;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;86422801341_86422801341_26422801437;Mengmest diff --git a/logic/test/data/point_sources_empty_coord.csv b/logic/test/data/point_sources_empty_coord.csv new file mode 100644 index 0000000..6b316f3 --- /dev/null +++ b/logic/test/data/point_sources_empty_coord.csv @@ -0,0 +1,3 @@ +type;scenario;year;reporting_country;nfr_sector;pollutant;emission;unit;x;y;hoogte_m;diameter_m;temperatuur_C;warmteinhoud_MW;debiet_Nm3/u;dv;type_emissie;EIL_nummer;exploitatie_naam;EIL_Emissiepunt_Jaar_Naam;Activiteit_type +historic;;2021;BEF;3B1b;NO2;0.360260113;kg/yr;116332.9766;166636.8709;5;0;0;0;0;4;Runderen jonger dan 1 jaar;57978963_57978963_24628802823;57978963_57978963_24628802823;57978963_57978963_24628802823;Vaste mest +historic;;2021;BEF;3B1b;NO2;1.489021862;kg/yr;;;5;0;0;0;0;4;Zoogkoeien;57978963_57978963_24628802823;57978963_57978963_24628802823;57978963_57978963_24628802823;Vaste mest diff --git a/logic/test/gridprocessingtest.cpp b/logic/test/gridprocessingtest.cpp index d27a112..95eb95c 100644 --- a/logic/test/gridprocessingtest.cpp +++ b/logic/test/gridprocessingtest.cpp @@ -25,6 +25,7 @@ namespace emap::test { using namespace inf; using namespace doctest; using namespace std::string_view_literals; +namespace gdal = inf::gdal; TEST_CASE("create_geometry_extent") { diff --git a/logic/test/inputparsertest.cpp b/logic/test/inputparsertest.cpp index 82ebf67..d2f8e24 100644 --- a/logic/test/inputparsertest.cpp +++ b/logic/test/inputparsertest.cpp @@ -5,7 +5,9 @@ #include "gdx/algo/sum.h" #include "gdx/rasteriterator.h" #include "infra/algo.h" +#include "infra/chrono.h" #include "infra/test/printsupport.h" +#include "unitconversion.h" #include "testconfig.h" #include "testconstants.h" @@ -75,6 +77,7 @@ TEST_CASE("Input parsers") cfg.set_year(1990_y); auto emissions = parse_emissions(EmissionSector::Type::Gnfr, file::u8path(TEST_DATA_DIR) / "_input" / "01_data_emissions" / "inventory" / "reporting_2021" / "totals" / "gnfr_allyears_2021.txt", cfg.year(), cfg, RespectIgnoreList::Yes); + REQUIRE(emissions.size() == 4); for (auto& em : emissions) { @@ -176,10 +179,10 @@ TEST_CASE("Input parsers") SUBCASE("Load point source emissions") { - cfg.set_combine_identical_point_sources(false); - SUBCASE("nfr sectors") { + cfg.set_combine_identical_point_sources(false); + const auto emissions = parse_point_sources(file::u8path(TEST_DATA_DIR) / "_input" / "01_data_emissions" / "inventory" / "reporting_2021" / "pointsources" / "pointsource_emissions_2021.csv", cfg); REQUIRE(emissions.size() == 4); @@ -190,18 +193,69 @@ TEST_CASE("Input parsers") } { - auto noxEmissions = emissions.emissions_with_id(EmissionIdentifier(country::BEF, EmissionSector(sectors::nfr::Nfr1A1a), pollutants::NOx)); - REQUIRE(noxEmissions.size() == 2); - CHECK(noxEmissions[0].coordinate().value() == Coordinate(148450, 197211)); - CHECK(noxEmissions[1].coordinate().value() == Coordinate(95820, 173080)); + EmissionIdentifier emId(country::BEF, EmissionSector(sectors::nfr::Nfr1A1a), pollutants::NOx); + REQUIRE(emissions.emissions_with_id(emId).size() == 2); + REQUIRE(emissions.emissions_with_id_at_coordinate(emId, Coordinate(148450, 197211)).size() == 1); + REQUIRE(emissions.emissions_with_id_at_coordinate(emId, Coordinate(95820, 173080)).size() == 1); } { - auto nmvocEmissions = emissions.emissions_with_id(EmissionIdentifier(country::BEF, EmissionSector(sectors::nfr::Nfr1A2c), pollutants::NMVOC)); - REQUIRE(nmvocEmissions.size() == 2); - CHECK(nmvocEmissions[0].coordinate().value() == Coordinate(130643, 159190)); - CHECK(nmvocEmissions[1].coordinate().value() == Coordinate(205000, 209000)); + EmissionIdentifier emId(country::BEF, EmissionSector(sectors::nfr::Nfr1A2c), pollutants::NMVOC); + REQUIRE(emissions.emissions_with_id(emId).size() == 2); + REQUIRE(emissions.emissions_with_id_at_coordinate(emId, Coordinate(130643, 159190)).size() == 1); + REQUIRE(emissions.emissions_with_id_at_coordinate(emId, Coordinate(205000, 209000)).size() == 1); + } + } + + SUBCASE("combine point sources") + { + const EmissionIdentifier emissionId(countries::BEF, EmissionSector(sectors::nfr::Nfr3B1b), pollutants::NOx); + + { + cfg.set_combine_identical_point_sources(true); + const auto emissions = parse_point_sources(file::u8path(TEST_DATA_DIR) / "point_sources.csv", cfg); + REQUIRE(emissions.size() == 2); + + CHECK(emissions.emission_with_id_at_coordinate(emissionId, Coordinate(116332.9766, 166636.8709)).value().amount() == Approx(to_giga_gram(1.849281975, "kg/yr"))); + CHECK(emissions.emission_with_id_at_coordinate(emissionId, Coordinate(95419.65, 196533.8)).value().amount() == Approx(to_giga_gram(121.820027319, "kg/yr"))); + } + + { + cfg.set_combine_identical_point_sources(false); + const auto emissions = parse_point_sources(file::u8path(TEST_DATA_DIR) / "point_sources.csv", cfg); + CHECK(emissions.size() == 11); + + CHECK(emissions.emissions_with_id_at_coordinate(emissionId, Coordinate(116332.9766, 166636.8709)).size() == 2); + CHECK(emissions.emissions_with_id_at_coordinate(emissionId, Coordinate(95419.65, 196533.8)).size() == 9); } } + + SUBCASE("point sources empty coordinate") + { + cfg.set_combine_identical_point_sources(true); + chrono::DurationRecorder duration; + CHECK_THROWS_AS(parse_point_sources(file::u8path(TEST_DATA_DIR) / "point_sources_empty_coord.csv", cfg), inf::RuntimeError); + } + + /*SUBCASE("point sources perf") + { + { + cfg.set_combine_identical_point_sources(true); + chrono::DurationRecorder duration; + const auto emissions = parse_point_sources(file::u8path(TEST_DATA_DIR) / "emap_NOx_2021_2024_opslag.csv", cfg); + Log::info("CSV Point source parsing with combining took: {}", duration.elapsed_time_string()); + + REQUIRE(emissions.size() == 28124); + } + + { + cfg.set_combine_identical_point_sources(false); + chrono::DurationRecorder duration; + const auto emissions = parse_point_sources(file::u8path(TEST_DATA_DIR) / "emap_NOx_2021_2024_opslag.csv", cfg); + Log::info("CSV Point source parsing without combining took: {}", duration.elapsed_time_string()); + + REQUIRE(emissions.size() == 89358); + } + }*/ } SUBCASE("Load scaling factors")