diff --git a/bdtopo/src/main/groovy/org/orbisgis/geoclimate/bdtopo/AbstractBDTopoWorkflow.groovy b/bdtopo/src/main/groovy/org/orbisgis/geoclimate/bdtopo/AbstractBDTopoWorkflow.groovy index a3976981f3..b4e3120d19 100644 --- a/bdtopo/src/main/groovy/org/orbisgis/geoclimate/bdtopo/AbstractBDTopoWorkflow.groovy +++ b/bdtopo/src/main/groovy/org/orbisgis/geoclimate/bdtopo/AbstractBDTopoWorkflow.groovy @@ -491,13 +491,18 @@ abstract class AbstractBDTopoWorkflow extends BDTopoUtils { } //Check for rsu indicators def rsu_indicators = processing_parameters.rsu_indicators + def target_grid_indicators =false if (rsu_indicators) { def indicatorUseP = rsu_indicators.indicatorUse if (indicatorUseP && indicatorUseP in List) { - def allowed_rsu_indicators = ["LCZ", "UTRF", "TEB"] + def allowed_rsu_indicators = ["LCZ", "UTRF", "TEB", "TARGET"] def allowedOutputRSUIndicators = allowed_rsu_indicators.intersect(indicatorUseP*.toUpperCase()) if (allowedOutputRSUIndicators) { rsu_indicators_default.indicatorUse = indicatorUseP + //We must update the grid indicators for TARGET schema + if(indicatorUseP*.toUpperCase().contains("TARGET")){ + target_grid_indicators = true + } } else { throw new Exception("Please set a valid list of RSU indicator names in ${allowedOutputRSUIndicators}".toString()) } @@ -541,7 +546,24 @@ abstract class AbstractBDTopoWorkflow extends BDTopoUtils { //Check for grid indicators def grid_indicators = processing_parameters.grid_indicators - if (grid_indicators) { + if(target_grid_indicators && !grid_indicators){ + def grid_indicators_tmp = [ + "x_size" : 100, + "y_size" : 100, + "output" : "fgb", + "rowCol" : false, + "indicators": ["BUILDING_FRACTION", + "BUILDING_HEIGHT", + "WATER_FRACTION", + "ROAD_FRACTION", + "IMPERVIOUS_FRACTION", + "STREET_WIDTH" , + "IMPERVIOUS_FRACTION", + "VEGETATION_FRACTION"] + ] + defaultParameters.put("grid_indicators", grid_indicators_tmp) + } + else if (grid_indicators) { def x_size = grid_indicators.x_size def y_size = grid_indicators.y_size def list_indicators = grid_indicators.indicators @@ -569,6 +591,17 @@ abstract class AbstractBDTopoWorkflow extends BDTopoUtils { rsu_indicators.indicatorUse << "UTRF" } } + //Update the GRID indicators list if TARGET output is specified + if(target_grid_indicators){ + allowedOutputIndicators.addAll(["BUILDING_FRACTION", + "BUILDING_HEIGHT", + "WATER_FRACTION", + "ROAD_FRACTION", + "IMPERVIOUS_FRACTION", + "STREET_WIDTH" , + "IMPERVIOUS_FRACTION", + "VEGETATION_FRACTION"]) + } def grid_indicators_tmp = [ "x_size" : x_size, "y_size" : y_size, @@ -650,7 +683,8 @@ abstract class AbstractBDTopoWorkflow extends BDTopoUtils { "population", "ground_acoustic", "urban_sprawl_areas", - "urban_cool_areas"] + "urban_cool_areas", + "grid_target"] } @@ -870,13 +904,17 @@ abstract class AbstractBDTopoWorkflow extends BDTopoUtils { results.put("grid_indicators", rasterizedIndicators) Map sprawl_indic = Geoindicators.WorkflowGeoIndicators.sprawlIndicators(h2gis_datasource, rasterizedIndicators, "id_grid", grid_indicators_params.indicators, Math.max(x_size, y_size).floatValue()) - if (sprawl_indic) { + if (sprawl_indic && sprawl_indic.urban_sprawl_areas) { results.put("urban_sprawl_areas", sprawl_indic.urban_sprawl_areas) if (sprawl_indic.urban_cool_areas) { results.put("urban_cool_areas", sprawl_indic.urban_cool_areas) } results.put("grid_indicators", sprawl_indic.grid_indicators) } + //We must transform the grid_indicators to produce the target land input + if(processing_parameters.rsu_indicators.indicatorUse.contains("TARGET")){ + results.put("grid_target", Geoindicators.GridIndicators.formatGrid4Target(h2gis_datasource, rasterizedIndicators)) + } info("End computing grid_indicators") } } else { @@ -1057,15 +1095,15 @@ abstract class AbstractBDTopoWorkflow extends BDTopoUtils { } } -/** - * Save the geoclimate tables into files - * @param id_zone the id of the zone - * @param results a list of tables computed by geoclimate - * @param outputFolder the output folder - * @param outputSRID srid code to reproject the result - * @param deleteOutputData true to delete the file if exists - * @return - */ + /** + * Save the geoclimate tables into files + * @param id_zone the id of the zone + * @param results a list of tables computed by geoclimate + * @param outputFolder the output folder + * @param outputSRID srid code to reproject the result + * @param deleteOutputData true to delete the file if exists + * @return + */ def saveOutputFiles(def h2gis_datasource, def results, def outputFiles, def outputFolder, def outputSRID, def reproject, def deleteOutputData, def outputGrid) throws Exception { outputFiles.each { diff --git a/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/WorkflowAbstractTest.groovy b/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/WorkflowAbstractTest.groovy index e82ccf99ca..f33ce23b18 100644 --- a/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/WorkflowAbstractTest.groovy +++ b/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/WorkflowAbstractTest.groovy @@ -35,6 +35,11 @@ abstract class WorkflowAbstractTest { */ abstract int getVersion() + /** + * The path to store the db + * @return + */ + abstract String getDBFolderPath() /** * The folder that contains the BDTopo test data @@ -87,7 +92,7 @@ abstract class WorkflowAbstractTest { def bdTopoParameters = [ "description" : "Full workflow configuration file", "geoclimatedb": [ - "folder": folder.absolutePath, + "folder": getDBFolderPath(), "name" : "testFullWorflow;AUTO_SERVER=TRUE", "delete": false ], @@ -95,7 +100,7 @@ abstract class WorkflowAbstractTest { "folder" : dataFolder, "locations": [getInseeCode()]], "output" : [ - "folder": ["path": folder.absolutePath]], + "folder": ["path": getDBFolderPath()]], "parameters" : ["distance" : 0, rsu_indicators : [ @@ -117,7 +122,7 @@ abstract class WorkflowAbstractTest { def tableNames = process[getInseeCode()] assertTrue(tableNames.size() > 0) - H2GIS h2gis = H2GIS.open(folder.absolutePath + File.separator + "testFullWorflow;AUTO_SERVER=TRUE") + H2GIS h2gis = H2GIS.open(getDBFolderPath() + File.separator + "testFullWorflow;AUTO_SERVER=TRUE") //Test zone assertTrue h2gis.firstRow("select count(*) as count from ${tableNames.zone} where the_geom is not null").count > 0 @@ -165,7 +170,7 @@ abstract class WorkflowAbstractTest { def filePath = getClass().getResource(getFolderName() + File.separator + "COMMUNE.shp") // If some layers are missing, do not try to load them... if (filePath) { - H2GIS h2GIS = H2GIS.open(folder.absolutePath + File.separator + "tmpdb") + H2GIS h2GIS = H2GIS.open(getDBFolderPath() + File.separator + "tmpdb") h2GIS.link(filePath, "COMMUNE", true) Geometry geom = h2GIS.firstRow("""SELECT ST_BUFFER(ST_POINTONSURFACE(the_geom), 200) AS the_geom from commune""".toString()).the_geom h2GIS.close() @@ -175,7 +180,7 @@ abstract class WorkflowAbstractTest { def bdTopoParameters = [ "description" : "Example of configuration file to set the SRID", "geoclimatedb": [ - "folder": folder.absolutePath, + "folder": getDBFolderPath(), "name" : "testFullWorflowSRID;AUTO_SERVER=TRUE", "delete": false ], @@ -183,7 +188,7 @@ abstract class WorkflowAbstractTest { "folder" : dataFolder, "locations": [location]], "output" : [ - "folder": ["path": folder.absolutePath, "tables": ["grid_indicators"]], + "folder": ["path": getDBFolderPath(), "tables": ["grid_indicators"]], "srid" : 4326], "parameters" : ["distance" : 0, @@ -203,10 +208,10 @@ abstract class WorkflowAbstractTest { def tableNames = process.values() def grid_table = tableNames.grid_indicators[0] assertNotNull(grid_table) - H2GIS h2gis = H2GIS.open("${folder.absolutePath + File.separator}testFullWorflowSRID;AUTO_SERVER=TRUE") + H2GIS h2gis = H2GIS.open("${getDBFolderPath() + File.separator}testFullWorflowSRID;AUTO_SERVER=TRUE") assertTrue h2gis.firstRow("select count(*) as count from $grid_table".toString()).count == 100 assertTrue h2gis.firstRow("select count(*) as count from $grid_table where BUILDING_FRACTION>0".toString()).count > 0 - File grid_file = new File(folder.absolutePath + File.separator + "bdtopo_" + getVersion() + "_" + location.join("_") + File.separator + "grid_indicators.fgb") + File grid_file = new File(getDBFolderPath() + File.separator + "bdtopo_" + getVersion() + "_" + location.join("_") + File.separator + "grid_indicators.fgb") assertTrue(grid_file.exists()) h2gis.load(grid_file.absolutePath, "grid_indicators_file", true) assertEquals(4326, h2gis.getSpatialTable("grid_indicators_file").srid) @@ -215,7 +220,7 @@ abstract class WorkflowAbstractTest { @Test void workflowExternalDB() { - def externaldb_dbProperties = [databaseName: "${folder.absolutePath + File.separator}external_db", + def externaldb_dbProperties = [databaseName: "${getDBFolderPath() + File.separator}external_db", user : 'sa', password : 'sa' ] @@ -225,13 +230,13 @@ abstract class WorkflowAbstractTest { "zone" : "zone", "grid_indicators" : "grid_indicators"] //Drop all output tables if exist - H2GIS externalDB = H2GIS.open(folder.absolutePath + File.separator + externaldb_dbProperties.databaseName, + H2GIS externalDB = H2GIS.open(getDBFolderPath() + File.separator + externaldb_dbProperties.databaseName, externaldb_dbProperties.user, externaldb_dbProperties.password) externalDB.execute("DROP TABLE IF EXISTS ${outputTables.values().join(",")};".toString()) def bdTopoParameters = [ "description" : "Example of configuration file to run the BDTopo workflow and store the results in a folder", "geoclimatedb": [ - "folder": folder.getAbsolutePath(), + "folder": getDBFolderPath(), "name" : "bdtopo_workflow_db;AUTO_SERVER=TRUE", "delete": true ], @@ -242,7 +247,7 @@ abstract class WorkflowAbstractTest { "database": ["user" : externaldb_dbProperties.user, "password" : externaldb_dbProperties.password, - "databaseName": folder.absolutePath + File.separator + externaldb_dbProperties.databaseName, + "databaseName": getDBFolderPath() + File.separator + externaldb_dbProperties.databaseName, "tables" : outputTables]], "parameters" : ["distance" : 0, @@ -275,11 +280,11 @@ abstract class WorkflowAbstractTest { def filePath = getClass().getResource(getFolderName() + File.separator + "COMMUNE.shp") // If some layers are missing, do not try to load them... if (filePath) { - def externaldb_dbProperties = [databaseName: "${folder.absolutePath + File.separator}external_db_bbox", + def externaldb_dbProperties = [databaseName: "${getDBFolderPath() + File.separator}external_db_bbox", user : 'sa', password : 'sa' ] - H2GIS externalDB = H2GIS.open(folder.absolutePath + File.separator + externaldb_dbProperties.databaseName, externaldb_dbProperties.user, externaldb_dbProperties.password) + H2GIS externalDB = H2GIS.open(getDBFolderPath() + File.separator + externaldb_dbProperties.databaseName, externaldb_dbProperties.user, externaldb_dbProperties.password) externalDB.link(filePath, "COMMUNE", true) Geometry geom = externalDB.firstRow("""SELECT ST_BUFFER(ST_POINTONSURFACE(the_geom), 200) AS the_geom from commune""".toString()).the_geom @@ -295,7 +300,7 @@ abstract class WorkflowAbstractTest { def bdTopoParameters = [ "description" : "Example of configuration file to run the BDTopo workflow and store the results in a folder", "geoclimatedb": [ - "folder": folder.absolutePath, + "folder": getDBFolderPath(), "name" : "bdtopo_workflow_db_bbox;AUTO_SERVER=TRUE", "delete": true ], @@ -306,7 +311,7 @@ abstract class WorkflowAbstractTest { "database": ["user" : externaldb_dbProperties.user, "password" : externaldb_dbProperties.password, - "databaseName": folder.absolutePath + File.separator + externaldb_dbProperties.databaseName, + "databaseName": getDBFolderPath() + File.separator + externaldb_dbProperties.databaseName, "tables" : outputTables]], "parameters" : ["distance" : 0, @@ -339,7 +344,7 @@ abstract class WorkflowAbstractTest { def bdTopoParameters = [ "description" : "Example of configuration file to run the grid indicators", "geoclimatedb": [ - "folder": folder.absolutePath, + "folder": getDBFolderPath(), "name" : "geoclimate_chain_db;AUTO_SERVER=TRUE", "delete": false ], @@ -347,7 +352,7 @@ abstract class WorkflowAbstractTest { "folder" : dataFolder, "locations": [2000, 2001, 2002]], "output" : [ - "folder": ["path" : folder.absolutePath, + "folder": ["path" : getDBFolderPath(), "tables": ["grid_indicators"]]], "parameters" : ["distance" : 0, @@ -367,7 +372,7 @@ abstract class WorkflowAbstractTest { def bdTopoParameters = [ "description" : "Full workflow configuration file", "geoclimatedb": [ - "folder": folder.absolutePath, + "folder": getDBFolderPath(), "name" : "testFormatedData;AUTO_SERVER=TRUE", "delete": true ], @@ -375,7 +380,7 @@ abstract class WorkflowAbstractTest { "folder" : dataFolder, "locations": [getInseeCode()]], "output" : [ - "folder": ["path": folder.absolutePath]], + "folder": ["path": getDBFolderPath()]], "parameters" : ["distance": 0] ] @@ -391,7 +396,7 @@ abstract class WorkflowAbstractTest { def bdTopoParameters = [ "description" : "Workflow format data", "geoclimatedb": [ - "folder": folder.absolutePath, + "folder": getDBFolderPath(), "name" : "testFormat;AUTO_SERVER=TRUE", "delete": false ], @@ -399,7 +404,7 @@ abstract class WorkflowAbstractTest { "folder" : dataFolder, "locations": [getInseeCode()]], "output" : [ - "folder": ["path": folder.absolutePath]] + "folder": ["path": getDBFolderPath()]] ] Map process = BDTopo.workflow(bdTopoParameters, getVersion()) @@ -407,7 +412,7 @@ abstract class WorkflowAbstractTest { def tableNames = process[getInseeCode()] assertTrue(tableNames.size() > 0) - H2GIS h2gis = H2GIS.open(folder.absolutePath + File.separator + "testFormat;AUTO_SERVER=TRUE") + H2GIS h2gis = H2GIS.open(getDBFolderPath() + File.separator + "testFormat;AUTO_SERVER=TRUE") //Test zone assertTrue h2gis.firstRow("select count(*) as count from ${tableNames.zone} where the_geom is not null").count > 0 @@ -431,4 +436,75 @@ abstract class WorkflowAbstractTest { assertTrue(h2gis.firstRow("""SELECT count(*) as count from ${tableNames.road} where TYPE is not null;""".toString()).count > 0) assertTrue(h2gis.firstRow("""SELECT count(*) as count from ${tableNames.road} where WIDTH is not null or WIDTH>0 ;""".toString()).count > 0) } + + @Test + void testTarguet() { + String dataFolder = getDataFolderPath() + def bdTopoParameters = [ + "description" : "Full workflow configuration file", + "geoclimatedb": [ + "folder": getDBFolderPath(), + "name" : "testFormatedData", + "delete": false + ], + "input" : [ + "folder" : dataFolder, + "locations": [getInseeCode()]], + "output" : [ + "folder": ["path": getDBFolderPath()]], + "parameters" : + ["distance": 0, + rsu_indicators: [ + "indicatorUse" : ["TARGET"] + ] + ] + ] + + Map process = BDTopo.workflow(bdTopoParameters, getVersion()) + assertNotNull(process) + def tableNames = process.values() + def targetGrid = tableNames.grid_target[0] + H2GIS h2gis = H2GIS.open("${getDBFolderPath() + File.separator}testFormatedData") + assertEquals(h2gis.getRowCount(targetGrid), h2gis.firstRow("""select count(*) as count from $targetGrid + where \"roof\"+ \"road\"+ \"watr\"+\"conc\"+\"Veg\" + \"dry\" + \"irr\" >=1""").count) + } + + @Test + void testTargetGridSize() { + String dataFolder = getDataFolderPath() + def bdTopoParameters = [ + "description" : "Full workflow configuration file", + "geoclimatedb": [ + "folder": getDBFolderPath(), + "name" : "testFormatedData", + "delete": false + ], + "input" : [ + "folder" : dataFolder, + "locations": [getInseeCode()]], + "output" : [ + "folder": ["path": getDBFolderPath()]], + "parameters" : + ["distance": 0, + rsu_indicators: [ + "indicatorUse" : ["TARGET", "LCZ"] + ], + "grid_indicators" : [ + "x_size" : 200, + "y_size" : 200, + "indicators": ["LCZ_PRIMARY"] + ] + ] + ] + + Map process = BDTopo.workflow(bdTopoParameters, getVersion()) + assertNotNull(process) + def tableNames = process.values() + def targetGrid = tableNames.grid_target[0] + H2GIS h2gis = H2GIS.open("${getDBFolderPath() + File.separator}testFormatedData") + assertEquals(h2gis.getRowCount(targetGrid), h2gis.firstRow("""select count(*) as count from $targetGrid + where \"roof\"+ \"road\"+ \"watr\"+\"conc\"+\"Veg\" + \"dry\" + \"irr\" >=1""").count) + def gridIndicators = tableNames.grid_indicators[0] + assertTrue(h2gis.getColumnNames(gridIndicators).contains("LCZ_PRIMARY")) + } } \ No newline at end of file diff --git a/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/v2/WorkflowBDTopoV2Test.groovy b/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/v2/WorkflowBDTopoV2Test.groovy index 7dae05314c..fcdfd76956 100644 --- a/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/v2/WorkflowBDTopoV2Test.groovy +++ b/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/v2/WorkflowBDTopoV2Test.groovy @@ -30,7 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue class WorkflowBDTopoV2Test extends WorkflowAbstractTest { @TempDir(cleanup = CleanupMode.ON_SUCCESS) - static File folder + public static File folder @Override ArrayList getFileNames() { @@ -46,6 +46,12 @@ class WorkflowBDTopoV2Test extends WorkflowAbstractTest { return 2 } + @Override + String getDBFolderPath(){ + return folder.absolutePath + } + + @Override String getFolderName() { return "sample_${getInseeCode()}" diff --git a/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/v3/WorkflowBDTopoV3Test.groovy b/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/v3/WorkflowBDTopoV3Test.groovy index 96c9b47abe..2774474d2a 100644 --- a/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/v3/WorkflowBDTopoV3Test.groovy +++ b/bdtopo/src/test/groovy/org/orbisgis/geoclimate/bdtopo/v3/WorkflowBDTopoV3Test.groovy @@ -39,6 +39,11 @@ class WorkflowBDTopoV3Test extends WorkflowAbstractTest { return 3 } + @Override + String getDBFolderPath() { + return folder.absolutePath + } + @Override String getFolderName() { return "sample_${getInseeCode()}" diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index bacdbf63c4..a8281aae34 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -7,3 +7,4 @@ - Simplify database url in config file. Use only the name of the database. e.g : h2://, postgis:// - Add a test to check if the worldpop service is available - Fix github actions +- Add TARGET landcover production diff --git a/geoindicators/src/main/groovy/org/orbisgis/geoclimate/geoindicators/GridIndicators.groovy b/geoindicators/src/main/groovy/org/orbisgis/geoclimate/geoindicators/GridIndicators.groovy index 2909d749ac..42ed32dedf 100644 --- a/geoindicators/src/main/groovy/org/orbisgis/geoclimate/geoindicators/GridIndicators.groovy +++ b/geoindicators/src/main/groovy/org/orbisgis/geoclimate/geoindicators/GridIndicators.groovy @@ -354,3 +354,59 @@ String gridDistances(JdbcDataSource datasource, String input_polygons, String gr throw new SQLException("Cannot compute the grid distances", e) } } + +/** + * Format the grid_indicators table to the TARGET land schema + * + * List of TARGET columns : + * FID – cell identifier, unique numerical number for each grid point (can start at 0 or 1) + * roof – fractional roof planar area + * road – fractional road planar area + * watr – factional water planar area + * conc – fractional concrete planar area + * veg – fractional tree planar area + * dry – fractional dry grass area + * irr – fractional irrigated grass/low vegetation area + * H – average building height (m) + * W – average street width, distance between buildings (m) + * + * @param datasource input database + * @param gridTable input grid_indicators + * @return a grid formated + * + * @author Erwan Bocher, CNRS + */ +String formatGrid4Target(JdbcDataSource datasource, String gridTable) { + //Format target landcover + def grid_target = postfix("grid_target") + try { + datasource.execute(""" + DROP TABLE IF EXISTS ${grid_target}; + CREATE TABLE ${grid_target} as SELECT + THE_GEOM, + CAST(row_number() over(ORDER BY ID_ROW DESC) as integer) as "FID", + BUILDING_FRACTION AS "roof", + ROAD_FRACTION AS "road", + WATER_FRACTION AS "watr", + IMPERVIOUS_FRACTION AS "conc", + HIGH_VEGETATION_FRACTION AS "Veg", + CASE WHEN ( + BUILDING_FRACTION+ROAD_FRACTION+WATER_FRACTION+IMPERVIOUS_FRACTION+high_vegetation_FRACTION+LOW_vegetation_FRACTION < 1) + THEN + (1- (BUILDING_FRACTION+ROAD_FRACTION+WATER_FRACTION+IMPERVIOUS_FRACTION+high_vegetation_FRACTION)) + ELSE + LOW_VEGETATION_FRACTION END AS "dry", + 0 AS "irr", + AVG_HEIGHT_ROOF AS "H", + CASE WHEN + STREET_WIDTH IS NULL THEN 0.1 ELSE STREET_WIDTH END AS "W" + FROM ${gridTable} + """) + return grid_target + }catch (SQLException e){ + //We create an empty table + datasource.execute("""CREATE TABLE $grid_target (FID INT, THE_GEOM GEOMETRY, + "roof" VARCHAR, "road" VARCHAR, "watr" VARCHAR, "conc" VARCHAR, + "Veg" VARCHAR, "dry" VARCHAR, "irr" VARCHAR , "H" VARCHAR, "W" VARCHAR)""") + } +} diff --git a/geoindicators/src/main/groovy/org/orbisgis/geoclimate/geoindicators/WorkflowGeoIndicators.groovy b/geoindicators/src/main/groovy/org/orbisgis/geoclimate/geoindicators/WorkflowGeoIndicators.groovy index e8c95ed18c..d5483ff3f4 100644 --- a/geoindicators/src/main/groovy/org/orbisgis/geoclimate/geoindicators/WorkflowGeoIndicators.groovy +++ b/geoindicators/src/main/groovy/org/orbisgis/geoclimate/geoindicators/WorkflowGeoIndicators.groovy @@ -1241,8 +1241,9 @@ Map computeAllGeoIndicators(JdbcDataSource datasource, String zone, String build } indicatorUse = inputParameters.indicatorUse - //This is a shortcut to extract building with estimated height - if (indicatorUse.isEmpty()) { + //This is a shortcut to produce only the data + //TARGET indicators can be computed atthe grid scale with the input data + if (indicatorUse.isEmpty() || (indicatorUse.size()==1 && indicatorUse.contains("TARGET"))) { //Clean the System properties that stores intermediate table names datasource.dropTable(getCachedTableNames()) clearTablesCache() diff --git a/osm/src/main/groovy/org/orbisgis/geoclimate/osm/WorkflowOSM.groovy b/osm/src/main/groovy/org/orbisgis/geoclimate/osm/WorkflowOSM.groovy index 615cfa2de8..78b999e93e 100644 --- a/osm/src/main/groovy/org/orbisgis/geoclimate/osm/WorkflowOSM.groovy +++ b/osm/src/main/groovy/org/orbisgis/geoclimate/osm/WorkflowOSM.groovy @@ -88,7 +88,7 @@ import java.sql.SQLException * * {"distance" : 1000, * * "prefixName": "", * * rsu_indicators:{ - * * "indicatorUse": ["LCZ", "UTRF", "TEB"], + * * "indicatorUse": ["LCZ", "UTRF", "TEB", "TARGET"], * * "svfSimplified": false, * * "mapOfWeights": * * {"sky_view_factor": 1, @@ -110,7 +110,7 @@ import java.sql.SQLException * - distance The integer value to expand the envelope of zone when recovering the data * - distance The integer value to expand the envelope of zone when recovering the data * (some objects may be badly truncated if they are not within the envelope) - * - indicatorUse List of geoindicator types to compute (default ["LCZ", "UTRF", "TEB"] + * - indicatorUse List of geoindicator types to compute (default ["LCZ", "UTRF", "TEB""] * --> "LCZ" : compute the indicators needed for the LCZ classification (Stewart et Oke, 2012) * --> "UTRF" : compute the indicators needed for the urban typology classification (Bocher et al., 2017) * --> "TEB" : compute the indicators needed for the Town Energy Balance model @@ -286,7 +286,8 @@ Map workflow(def input) throws Exception { "population", "ground_acoustic", "urban_sprawl_areas", - "urban_cool_areas"] + "urban_cool_areas", + "grid_target"] //Get processing parameters def processing_parameters = extractProcessingParameters(parameters.get("parameters")) @@ -627,13 +628,17 @@ Map osm_processing(JdbcDataSource h2gis_datasource, def processing_parameters, d results.put("grid_indicators", rasterizedIndicators) def sprawl_indic = Geoindicators.WorkflowGeoIndicators.sprawlIndicators(h2gis_datasource, rasterizedIndicators, "id_grid", grid_indicators_params.indicators, Math.max(x_size, y_size).floatValue()) - if (sprawl_indic) { + if (sprawl_indic && sprawl_indic.urban_sprawl_areas) { results.put("urban_sprawl_areas", sprawl_indic.urban_sprawl_areas) if (sprawl_indic.urban_cool_areas) { results.put("urban_cool_areas", sprawl_indic.urban_cool_areas) } results.put("grid_indicators", sprawl_indic.grid_indicators) } + //We must transform the grid_indicators to produce the target land input + if(rsu_indicators_params.indicatorUse.contains("TARGET")){ + results.put("grid_target", Geoindicators.GridIndicators.formatGrid4Target(h2gis_datasource, rasterizedIndicators)) + } info("End computing grid_indicators") } } @@ -804,12 +809,17 @@ def extractProcessingParameters(def processing_parameters) throws Exception { //Check for rsu indicators def rsu_indicators = processing_parameters.rsu_indicators + def target_grid_indicators =false if (rsu_indicators) { - def indicatorUseP = rsu_indicators.indicatorUse + def indicatorUseP = rsu_indicators.indicatorUse*.toUpperCase() if (indicatorUseP && indicatorUseP in List) { - def allowed_rsu_indicators = ["LCZ", "UTRF", "TEB"] - def allowedOutputRSUIndicators = allowed_rsu_indicators.intersect(indicatorUseP*.toUpperCase()) + def allowed_rsu_indicators = ["LCZ", "UTRF", "TEB", "TARGET"] + def allowedOutputRSUIndicators = allowed_rsu_indicators.intersect(indicatorUseP) if (allowedOutputRSUIndicators) { + //We must update the grid indicators for TARGET schema + if(indicatorUseP.contains("TARGET")){ + target_grid_indicators = true + } rsu_indicators_default.indicatorUse = indicatorUseP } else { throw new Exception("Please set a valid list of RSU indicator names in ${allowedOutputRSUIndicators}".toString()) @@ -857,7 +867,24 @@ def extractProcessingParameters(def processing_parameters) throws Exception { //Check for grid indicators def grid_indicators = processing_parameters.grid_indicators - if (grid_indicators) { + if(target_grid_indicators && !grid_indicators){ + def grid_indicators_tmp = [ + "x_size" : 100, + "y_size" : 100, + "output" : "fgb", + "rowCol" : false, + "indicators": ["BUILDING_FRACTION", + "BUILDING_HEIGHT", + "WATER_FRACTION", + "ROAD_FRACTION", + "IMPERVIOUS_FRACTION", + "STREET_WIDTH" , + "IMPERVIOUS_FRACTION", + "VEGETATION_FRACTION"] + ] + defaultParameters.put("grid_indicators", grid_indicators_tmp) + } + else if (grid_indicators) { def x_size = grid_indicators.x_size def y_size = grid_indicators.y_size def list_indicators = grid_indicators.indicators @@ -885,6 +912,17 @@ def extractProcessingParameters(def processing_parameters) throws Exception { rsu_indicators.indicatorUse << "UTRF" } } + //Update the GRID indicators list if TARGET output is specified + if(target_grid_indicators){ + allowedOutputIndicators.addAll(["BUILDING_FRACTION", + "BUILDING_HEIGHT", + "WATER_FRACTION", + "ROAD_FRACTION", + "IMPERVIOUS_FRACTION", + "STREET_WIDTH" , + "IMPERVIOUS_FRACTION", + "VEGETATION_FRACTION"]) + } def grid_indicators_tmp = [ "x_size" : x_size, "y_size" : y_size, diff --git a/osm/src/test/groovy/org/orbisgis/geoclimate/osm/WorflowOSMTest.groovy b/osm/src/test/groovy/org/orbisgis/geoclimate/osm/WorflowOSMTest.groovy index 08ccf6b4c8..242240c23b 100644 --- a/osm/src/test/groovy/org/orbisgis/geoclimate/osm/WorflowOSMTest.groovy +++ b/osm/src/test/groovy/org/orbisgis/geoclimate/osm/WorflowOSMTest.groovy @@ -595,7 +595,6 @@ class WorflowOSMTest extends WorkflowAbstractTest { "parameters" : [ rsu_indicators: [ - "unit" : "GRID", "indicatorUse" : ["TEB"], "svfSimplified": true ] @@ -604,13 +603,83 @@ class WorflowOSMTest extends WorkflowAbstractTest { OSM.workflow(createOSMConfigFile(osm_parmeters, directory)) } + @Test + void testTarget() { + String directory = folder.absolutePath + File.separator + "testOSMTEB" + File dirFile = new File(directory) + dirFile.delete() + dirFile.mkdir() + def osm_parmeters = [ + "description" : "Compute the targuet land input", + "geoclimatedb": [ + "folder": dirFile.absolutePath, + "name" : "geoclimate_chain_db", + "delete": false + ], + "input" : [ + "locations": ["Pont-de-Veyle"]], + "output" : [ + "folder": directory], + "parameters" : + [ + rsu_indicators: [ + "indicatorUse" : ["target"] + ] + ] + ] + Map process = OSM.WorkflowOSM.workflow(osm_parmeters) + def tableNames = process.values() + def targetGrid = tableNames.grid_target[0] + H2GIS h2gis = H2GIS.open("${directory + File.separator}geoclimate_chain_db") + assertEquals(h2gis.getRowCount(targetGrid), h2gis.firstRow("""select count(*) as count from $targetGrid + where \"roof\"+ \"road\"+ \"watr\"+\"conc\"+\"Veg\" + \"dry\" + \"irr\" >=1""").count) + } + + @Test + void testTargetGridSize() { + String directory = folder.absolutePath + File.separator + "testOSMTEB" + File dirFile = new File(directory) + dirFile.delete() + dirFile.mkdir() + def osm_parmeters = [ + "description" : "Compute the targuet land input", + "geoclimatedb": [ + "folder": dirFile.absolutePath, + "name" : "geoclimate_chain_db", + "delete": false + ], + "input" : [ + "locations": ["Pont-de-Veyle"]], + "output" : [ + "folder": directory], + "parameters" : + [ + rsu_indicators: [ + "indicatorUse" : ["TARGET", "LCZ"] + ],"grid_indicators" : [ + "x_size" : 200, + "y_size" : 200, + "indicators": [ + "LCZ_PRIMARY"] + ] + ] + ] + Map process = OSM.WorkflowOSM.workflow(osm_parmeters) + def tableNames = process.values() + def targetGrid = tableNames.grid_target[0] + H2GIS h2gis = H2GIS.open("${directory + File.separator}geoclimate_chain_db") + assertEquals(h2gis.getRowCount(targetGrid), h2gis.firstRow("""select count(*) as count from $targetGrid + where \"roof\"+ \"road\"+ \"watr\"+\"conc\"+\"Veg\" + \"dry\" + \"irr\" >=1""").count) + def gridIndicators = tableNames.grid_indicators[0] + assertTrue(h2gis.getColumnNames(gridIndicators).contains("LCZ_PRIMARY")) + } + @Test void testRoadTrafficAndNoiseIndicators() { String directory = folder.absolutePath + File.separator + "testRoad_traffic" File dirFile = new File(directory) dirFile.delete() dirFile.mkdir() - def osm_parmeters = [ "description" : "Example of configuration file to run only the road traffic estimation", "geoclimatedb": [ @@ -709,9 +778,7 @@ class WorflowOSMTest extends WorkflowAbstractTest { "ASPECT_RATIO", //"SVF", "STREET_WIDTH" , - "IMPERVIOUS_FRACTION", - "high_vegetation", - "LOW_vegetation"] + "IMPERVIOUS_FRACTION"] //"lcz_lod":1 ], "worldpop_indicators": true /*