From 8140f15c049db49eea008fc5e18720750c467376 Mon Sep 17 00:00:00 2001 From: Pierre Aumond Date: Wed, 24 Apr 2024 14:06:29 +0200 Subject: [PATCH] Add new dynamic tools --- .../Acoustic_Tools/DynamicIndicators.groovy | 121 +++ ...ise_From_Attenuation_Matrix_MatSim.groovy} | 6 +- .../Dynamic_Road_Emission_from_Traffic.groovy | 607 +++++++++++++-- .../Noise_From_Attenuation_Matrix.groovy | 204 +++++ .../Noise_level_from_dynamic_source.groovy | 706 ------------------ .../wps/TestNoiseModelling.groovy | 96 ++- 6 files changed, 987 insertions(+), 753 deletions(-) create mode 100644 wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/Acoustic_Tools/DynamicIndicators.groovy rename wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/Experimental_Matsim/{Noise_From_Attenuation_Matrix.groovy => Noise_From_Attenuation_Matrix_MatSim.groovy} (98%) create mode 100644 wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Noise_From_Attenuation_Matrix.groovy delete mode 100644 wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Noise_level_from_dynamic_source.groovy diff --git a/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/Acoustic_Tools/DynamicIndicators.groovy b/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/Acoustic_Tools/DynamicIndicators.groovy new file mode 100644 index 000000000..85609ccd0 --- /dev/null +++ b/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/Acoustic_Tools/DynamicIndicators.groovy @@ -0,0 +1,121 @@ +/** + * NoiseModelling is an open-source tool designed to produce environmental noise maps on very large urban areas. It can be used as a Java library or be controlled through a user friendly web interface. + * + * This version is developed by the DECIDE team from the Lab-STICC (CNRS) and by the Mixt Research Unit in Environmental Acoustics (Université Gustave Eiffel). + * + * + * NoiseModelling is distributed under GPL 3 license. You can read a copy of this License in the file LICENCE provided with this software. + * + * Contact: contact@noise-planet.org + * + */ + +/** + * @Author Pierre Aumond, Université Gustave Eiffel + */ + +package org.noise_planet.noisemodelling.wps.Acoustic_Tools + +import geoserver.GeoServer +import geoserver.catalog.Store +import groovy.sql.Sql +import org.geotools.jdbc.JDBCDataStore +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +import java.sql.Connection + +title = 'Compute dynamic indicators' +description = 'Compute dynamic indicators as L10, L90
The columns of the table should be named HZ63, HZ125,..., HZ8000 with an HZ prefix that can be changed.' + +inputs = [ + columnName : [ + name : 'Column name', + title : 'Column name', + description: 'Column name on which to perform the calculation. (STRING)
For example : LEQA', + type : String.class + ], + tableName: [ + title : 'Name of the table', + name : 'Name of the table', + description: 'Name of the table on which to perform the calculation. The table must contain multiple sound level values for a single receiver. (STRING)
For example : LDAY_GEOM', + type : String.class + ] +] + +outputs = [ + result: [ + name : 'Result output string', + title : 'Result output string', + description: 'This type of result does not allow the blocks to be linked together.', + type : String.class + ] +] + + +static Connection openGeoserverDataStoreConnection(String dbName) { + if (dbName == null || dbName.isEmpty()) { + dbName = new GeoServer().catalog.getStoreNames().get(0) + } + Store store = new GeoServer().catalog.getStore(dbName) + JDBCDataStore jdbcDataStore = (JDBCDataStore) store.getDataStoreInfo().getDataStore(null) + return jdbcDataStore.getDataSource().getConnection() +} + +def exec(Connection connection, input) { + + // output string, the information given back to the user + String resultString = null + + Logger logger = LoggerFactory.getLogger("org.noise_planet.noisemodelling") + + // print to command window + logger.info('Start : Add Leq and LAeq column') + logger.info("inputs {}", input) // log inputs of the run + + // Open connection + Sql sql = new Sql(connection) + + // ------------------- + // Get inputs + // ------------------- + + // Get name of the prefix + String columnName = input['columnName'] as String + // do it case-insensitive + columnName = columnName.toUpperCase() + + // Get name of the table + String table = input["tableName"] as String + // do it case-insensitive + table = table.toUpperCase() + + sql.execute("DROP TABLE " + table + "_DYN_IND IF EXISTS;") + sql.execute("CREATE TABLE " + table + "_DYN_IND AS SELECT THE_GEOM, " + + "ROUND(MEDIAN(" + columnName + "), 1) L50, " + + "ROUND(percentile_cont(0.9) WITHIN GROUP (ORDER BY " + columnName + "), 1) L10," + + "ROUND(percentile_cont(0.1) WITHIN GROUP (ORDER BY " + columnName + "), 1) L90 FROM " + table + " GROUP BY THE_GEOM;") + + resultString = "The columns LEQA and LEQ have been added to the table: " + table + "." + + // print to command window + logger.info('End : Add Dynamic Indicator') + + // print to WPS Builder + return resultString + +} + +def run(input) { + + // Get name of the database + // by default an embedded h2gis database is created + // Advanced user can replace this database for a postGis or h2Gis server database. + String dbName = "h2gisdb" + + // Open connection + openGeoserverDataStoreConnection(dbName).withCloseable { + Connection connection -> + return [result: exec(connection, input)] + } +} \ No newline at end of file diff --git a/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/Experimental_Matsim/Noise_From_Attenuation_Matrix.groovy b/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/Experimental_Matsim/Noise_From_Attenuation_Matrix_MatSim.groovy similarity index 98% rename from wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/Experimental_Matsim/Noise_From_Attenuation_Matrix.groovy rename to wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/Experimental_Matsim/Noise_From_Attenuation_Matrix_MatSim.groovy index 553ce4658..c1cfa6f5b 100644 --- a/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/Experimental_Matsim/Noise_From_Attenuation_Matrix.groovy +++ b/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/Experimental_Matsim/Noise_From_Attenuation_Matrix_MatSim.groovy @@ -113,7 +113,7 @@ def exec(Connection connection, input) { String resultString Logger logger = LoggerFactory.getLogger("org.noise_planet.noisemodelling") - logger.info('Start : Noise_From_Attenuation_Matrix') + logger.info('Start : Noise_From_Attenuation_Matrix_MatSim') logger.info("inputs {}", input) String matsimRoads = input['matsimRoads'] @@ -193,11 +193,11 @@ def exec(Connection connection, input) { sql.execute(query) - prefix = "HZ" + String prefix = "HZ" sql.execute("ALTER TABLE " + outTableName + " ADD COLUMN LEQA float as 10*log10((power(10,(" + prefix + "63-26.2)/10)+power(10,(" + prefix + "125-16.1)/10)+power(10,(" + prefix + "250-8.6)/10)+power(10,(" + prefix + "500-3.2)/10)+power(10,(" + prefix + "1000)/10)+power(10,(" + prefix + "2000+1.2)/10)+power(10,(" + prefix + "4000+1)/10)+power(10,(" + prefix + "8000-1.1)/10)))") sql.execute("ALTER TABLE " + outTableName + " ADD COLUMN LEQ float as 10*log10((power(10,(" + prefix + "63)/10)+power(10,(" + prefix + "125)/10)+power(10,(" + prefix + "250)/10)+power(10,(" + prefix + "500)/10)+power(10,(" + prefix + "1000)/10)+power(10,(" + prefix + "2000)/10)+power(10,(" + prefix + "4000)/10)+power(10,(" + prefix + "8000)/10)))") - logger.info('End : Noise_From_Attenuation_Matrix') + logger.info('End : Noise_From_Attenuation_Matrix_MatSim') resultString = "Process done. Table of receivers " + outTableName + " created !" logger.info('Result : ' + resultString) return resultString diff --git a/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Dynamic_Road_Emission_from_Traffic.groovy b/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Dynamic_Road_Emission_from_Traffic.groovy index fbdb4a11e..e3839712a 100644 --- a/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Dynamic_Road_Emission_from_Traffic.groovy +++ b/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Dynamic_Road_Emission_from_Traffic.groovy @@ -12,6 +12,7 @@ /** * @Author Pierre Aumond, Université Gustave Eiffel + * @Author Valetin Le Bescond, Université Gustave Eiffel, Ghent University */ package org.noise_planet.noisemodelling.wps.NoiseModelling @@ -22,26 +23,30 @@ import groovy.sql.Sql import groovy.time.TimeCategory import org.geotools.jdbc.JDBCDataStore import org.h2gis.utilities.GeometryTableUtilities +import org.h2gis.utilities.SpatialResultSet import org.h2gis.utilities.TableLocation import org.h2gis.utilities.wrapper.ConnectionWrapper +import org.locationtech.jts.geom.* import org.noise_planet.noisemodelling.emission.EvaluateRoadSourceDynamic import org.noise_planet.noisemodelling.emission.RoadSourceParametersDynamic +import java.security.InvalidParameterException import java.sql.Connection +import java.sql.ResultSet import java.sql.SQLException +import java.util.stream.Collectors title = 'Dynamic Road Emission from traffic' -description = 'Compute dynamic road emission from average traffic data as describe in Aumond, P., Jacquesson, L., & Can, A. (2018). Probabilistic modeling framework for multisource sound mapping. Applied Acoustics, 139, 34-43. .' + - '
The user can indicate the number of iterations he wants the model to calculate.' + +description = 'Calculating dynamic road emissions based on average traffic flows.' + '

The output table is called : LW_DYNAMIC ' + 'and contain :
' + '- TIMESTAMP : The TIMESTAMP iteration (STRING).
' + '- IDRECEIVER : an identifier (INTEGER, PRIMARY KEY).
' + '- THE_GEOM : the 3D geometry of the receivers (POINT).
' + - '- LWD63, LWD125, LWD250, LWD500, LWD1000,LWD2000, LWD4000, LWD8000 : 8 columns giving the day emission sound level for each octave band (FLOAT).' + '- HZ63, HZ125, HZ250, HZ500, HZ1000,HZ2000, HZ4000, HZ8000 : 8 columns giving the day emission sound level for each octave band (FLOAT).' inputs = [ - tableRoads : [name : 'Roads table name', title: 'Roads table name', description: "Name of the Roads table.
" + + tableRoads : [name : 'Roads table name', title: 'Roads table name', description: "Name of the Roads table.
" + "
The table shall contain :
" + "- PK : an identifier. It shall be a primary key (INTEGER, PRIMARY KEY)
" + "- TV_D : Hourly average light and heavy vehicle count (DOUBLE)
" + @@ -51,23 +56,25 @@ inputs = [ "- PVMT : CNOSSOS road pavement identifier (ex: NL05) (VARCHAR)" + "

This table can be generated from the WPS Block 'Import_OSM'. .", type: String.class], - method : [name : 'Method', - title : "method", - description : "method", + method : [name : 'Selected Method', + title : "Selected Method", + description : "
Two methods are available : " + + "
- PROBA : Probabilistic representation of vehicle appearances for each time step (quicker, but sacrifices temporal coherence) Aumond, P., Jacquesson, L., & Can, A. (2018). Probabilistic modeling framework for multisource sound mapping. Applied Acoustics, 139, 34-43. ." + + "
- TNP : Simplified vehicle movements (slower, but maintaining temporal coherence) De Coensel, B.; Brown, A.L.; Tomerini, D. A road traffic noise pattern simulation model that includes distributions of vehicle sound power levels. Appl. Acoust. 2016, 111, 170–178. .", type: String.class], timestep : [name : 'timestep', title : "timestep", - description : "timestep in sec.", + description : "Number of iterations. Timestep in sec.
Default value : 1 ", type: Integer.class], gridStep : [name : 'gridStep', title : "gridStep", - description : "gridStep in meters.", + description : "Distance between location of vehicle along the network in meters.
Default value : 10 ", type: Integer.class], - duration : [name : 'duration', title: 'duration in sec.', - description: 'Number of the iterations to compute (INTEGER).

Default value : 100 ', + duration : [name : 'duration', title: 'duration in sec.', + description: 'Number of the iterations to compute (INTEGER).

Default value : 60 ', type: Integer.class], ] @@ -126,12 +133,12 @@ def exec(Connection connection, input) { // Get every inputs // ------------------- - int duration = 300 + double duration = 60 if (input['duration']) { - duration = Integer.valueOf(input['duration'] as String) + duration = Double.valueOf(input['duration'] as String) } - int timestep = 10 + int timestep = 1 if (input['timestep']) { timestep = Integer.valueOf(input['timestep'] as String) } @@ -158,30 +165,32 @@ def exec(Connection connection, input) { System.out.println('Start time : ' + TimeCategory.minus(new Date(), start)) + sql.execute("DROP TABLE IF EXISTS ROAD_POINTS" ) + sql.execute("CREATE TABLE ROAD_POINTS(ROAD_ID serial, THE_GEOM geometry, LV int, LV_SPD real, HV int, HV_SPD real) AS SELECT r.PK, ST_Tomultipoint(ST_Densify(the_geom, "+gridStep+")), r.LV_D, r.LV_SPD_D, r.HGV_D, r.HGV_SPD_D FROM "+sources_table_name+" r WHERE NOT ST_IsEmpty(r.THE_GEOM) ;") + + sql.execute("drop table VEHICLES if exists;" + + " create table VEHICLES as SELECT ST_AddZ(ST_FORCE3D(the_geom),0.05) geom_3D,* from ST_Explode('ROAD_POINTS');" + + "ALTER TABLE VEHICLES DROP COLUMN the_geom;" + + " ALTER TABLE VEHICLES RENAME COLUMN geom_3D TO the_geom;" + + "alter table VEHICLES add PK INT AUTO_INCREMENT PRIMARY KEY;" + + "ALTER TABLE VEHICLES DROP COLUMN EXPLOD_ID;") + + + sql.execute("DROP TABLE IF EXISTS ALL_VEH_POS_0DB") + sql.execute("CREATE TABLE ALL_VEH_POS_0DB(PK int NOT NULL PRIMARY KEY, ROAD_ID long, THE_GEOM geometry, LWD63 real, LWD125 real, LWD250 real, LWD500 real, LWD1000 real, LWD2000 real, LWD4000 real, LWD8000 real) AS SELECT r.PK, r.ROAD_ID, r.THE_GEOM, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 FROM VEHICLES AS r;") + + if (method == "PROBA"){ System.println("Create the random road traffic table over the number of iterations... ") - sql.execute("drop table TRAFIC_DENSITY IF EXISTS;" + - "create table TRAFIC_DENSITY AS SELECT *,case when LV_SPD_D < 20 then 0.001*LV_D/20 else 0.001*LV_D/LV_SPD_D end LV_DENS_D, case when HGV_SPD_D < 20 then 0.001*HGV_D/20 else 0.001*HGV_D/HGV_SPD_D end HGV_DENS_D FROM "+sources_table_name+" ;" + - "alter table TRAFIC_DENSITY add LENGTH double as select ST_LENGTH(the_geom) ;" + - "ALTER TABLE TRAFIC_DENSITY ALTER COLUMN LV_DENS_D double;" + - "ALTER TABLE TRAFIC_DENSITY ALTER COLUMN HGV_DENS_D double;" + - - "drop table ROAD_POINTS if exists;" + - "create table ROAD_POINTS as SELECT ST_Tomultipoint(ST_Densify(the_geom, "+gridStep+")) points_geom , * from ST_Explode('TRAFIC_DENSITY');" + - "ALTER TABLE ROAD_POINTS DROP COLUMN the_geom;" + - "ALTER TABLE ROAD_POINTS RENAME COLUMN points_geom TO the_geom;" + - "ALTER TABLE ROAD_POINTS DROP COLUMN EXPLOD_ID, PK;" + - - "drop table VEHICLES if exists;" + - " create table VEHICLES as SELECT ST_AddZ(ST_FORCE3D(the_geom),0.05) geom_3D,* from ST_Explode('ROAD_POINTS');" + - "ALTER TABLE VEHICLES DROP COLUMN the_geom;" + - " ALTER TABLE VEHICLES RENAME COLUMN geom_3D TO the_geom;" + - "alter table VEHICLES add column PK serial ;" + - "ALTER TABLE VEHICLES DROP COLUMN EXPLOD_ID;") + sql.execute("drop table VEHICLES_PROBA IF EXISTS;" + + "create table VEHICLES_PROBA AS SELECT *,case when LV_SPD < 20 then 0.001*LV/20 else 0.001*LV/LV_SPD end LV_DENS_D, case when HV_SPD < 20 then 0.001*HV/20 else 0.001*HV/HV_SPD end HGV_DENS_D FROM VEHICLES ;" + + "alter table VEHICLES_PROBA add LENGTH double as select ST_LENGTH(the_geom) ;" + + "ALTER TABLE VEHICLES_PROBA ALTER COLUMN LV_DENS_D double;" + + "ALTER TABLE VEHICLES_PROBA ALTER COLUMN HGV_DENS_D double;" ) IndividualVehicleEmissionProcessData probabilisticProcessData = new IndividualVehicleEmissionProcessData(); - probabilisticProcessData.setDynamicEmissionTable("VEHICLES", sql) + probabilisticProcessData.setDynamicEmissionTable("VEHICLES_PROBA", sql) // random number > Vehicle or not / Light of Heavy @@ -214,12 +223,6 @@ def exec(Connection connection, input) { } } } - - - - - - // Drop table LDEN_GEOM if exists sql.execute("drop table if exists LW_DYNAMIC_GEOM;") // Associate Geometry column to the table LDEN @@ -227,10 +230,96 @@ def exec(Connection connection, input) { sql.execute("CREATE INDEX ON VEHICLES(PK);") sql.execute("create table LW_DYNAMIC_GEOM as select a.IT T,a.PK, b.THE_GEOM, a.Hz63, a.Hz125, a.Hz250, a.Hz500, a.Hz1000, a.Hz2000, a.Hz4000, a.Hz8000 FROM LW_DYNAMIC a LEFT JOIN VEHICLES b ON a.PK = b.PK;") - } + } else { + + sql.execute("DROP TABLE IF EXISTS LW_DYNAMIC_GEOM") + sql.execute("CREATE TABLE LW_DYNAMIC_GEOM(PK long, T real, ROAD_ID long, THE_GEOM geometry, HZ63 real, HZ125 real, HZ250 real, HZ500 real, HZ1000 real, HZ2000 real, HZ4000 real, HZ8000 real)") + + int coundRoad + + String insert = "INSERT INTO LW_DYNAMIC_GEOM VALUES(?, ?, ?, ST_GeomFromText(?), ?, ?, ?, ?, ?, ?, ?, ?)" + + sql.query("SELECT COUNT(*) FROM "+sources_table_name+" ; ", { ResultSet countRes -> + ResultSet rs = countRes.unwrap(ResultSet.class) + while (rs.next()) { + coundRoad = rs.getLong(1) + } + } + ) + + + sql.query("SELECT * FROM "+sources_table_name+" ; ", { ResultSet result -> + + SpatialResultSet rs = result.unwrap(SpatialResultSet.class) + int k=1 + +// ... + while (rs.next()) { + Road road = new Road() + System.out.println(k + "/" + coundRoad + " % " + 100*k/coundRoad) + k++ + road.setRoad( + rs.getLong('PK'), + "", + rs.getGeometry('THE_GEOM'), + rs.getInt('LV_D'), + rs.getDouble('LV_SPD_D'), + rs.getInt('HGV_D'), + rs.getDouble('HGV_SPD_D') + ) + + + sql.query("SELECT * FROM ALL_VEH_POS_0DB WHERE ROAD_ID = " + road.id, { ResultSet result2 -> + SpatialResultSet rs2 = result2.unwrap(SpatialResultSet.class) + while (rs2.next()) { + road.source_points.add(new SourcePoint( + rs2.getLong('PK'), + rs2.getGeometry('THE_GEOM') + )) + } + }) + + + + for (double time = 0; time < duration; time += timestep) { + + road.move(time, duration) + + + + for (SourcePoint source in road.source_points) { + if (source.levels[0]> 0.0){ + sql.execute(insert, [ + source.id, + time, + road.id, + source.geom.toString(), + source.levels[0], + source.levels[1], + source.levels[2], + source.levels[3], + source.levels[4], + source.levels[5], + source.levels[6], + source.levels[7] + ]) + } + } + + } + + // roads.add(road) + } + }) + sql.execute("CREATE INDEX IF NOT EXISTS ST_TID ON LW_DYNAMIC_GEOM(T, PK)") + } + sql.execute("DROP TABLE IF EXISTS ROAD_POINTS") + sql.execute("DROP TABLE IF EXISTS VEHICLES") sql.execute("drop table LW_DYNAMIC if exists;") + sql.execute("drop table VEHICLES_PROBA if exists;") + System.out.println('Intermediate time : ' + TimeCategory.minus(new Date(), start)) System.out.println("Export data to table") @@ -248,6 +337,441 @@ def exec(Connection connection, input) { } + +/** + * + */ +class Road { + + long id + String type + LineString geom + int lv + double lv_spd + int hv + double hv_spd + double length + + public List source_points = new ArrayList() + + List line_segments = new ArrayList() + + List vehicles = new ArrayList() + + Map lw_corr_generators = new LinkedHashMap<>() + + int seed = 2528432 + + Road(){ + line_segments.clear() + vehicles.clear() + lw_corr_generators.clear() + source_points.clear() + } + + void setRoad(long id, String type, Geometry geom, int lv, double lv_spd, int hv, double hv_spd) { + if (geom.getGeometryType() == "MultiLineString") { + geom = geom.getGeometryN(0) + } + if (geom.getGeometryType() != "LineString") { + throw new InvalidParameterException("Only LineString Geometry is supported") + } + this.id = id + this.type = type + this.geom = (LineString) geom + this.lv = lv + this.lv_spd = lv_spd + this.hv = hv + this.hv_spd = hv_spd + this.length = geom.getLength() + + Coordinate[] coordinates = geom.getCoordinates() + for(int i = 1; i < coordinates.length; i++){ + line_segments.add(new LineSegment(coordinates[i-1], coordinates[i])); + } + + /*for (String vehicle_type: [ + Vehicle.LIGHT_VEHICLE_TYPE, Vehicle.MEDIUM_VEHICLE_TYPE, Vehicle.HEAVY_VEHICLE_TYPE, + Vehicle.MOPEDS_VEHICLE_TYPE, Vehicle.MOTORCYCLE_VEHICLE_TYPE + ]) { + lw_corr_generators.put(vehicle_type, new LwCorrectionGenerator(vehicle_type, 1.0, "meanEn")) + }*/ + + double start + DisplacedNegativeExponentialDistribution distribution = new DisplacedNegativeExponentialDistribution(lv, 1, seed) + start = 0 + def samples = distribution.getSamples(lv) + for (int i = 0; i < lv; i++) { + start += samples[i] + vehicles.add(new Vehicle(lv_spd / 3.6, length, start, Vehicle.LIGHT_VEHICLE_TYPE, (i % 2 == 1), 0)) + } + distribution = new DisplacedNegativeExponentialDistribution(hv, 1, seed) + start = 0 + samples = distribution.getSamples(hv) + for (int i = 0; i < hv; i++) { + start += samples[i] + vehicles.add(new Vehicle(hv_spd / 3.6, length, start, Vehicle.HEAVY_VEHICLE_TYPE, (i % 2 == 1), 0)) + } + for (Vehicle vehicle: vehicles) { + vehicle.lw_correction = 2 //lw_corr_generators.get(vehicle.vehicle_type).generate() + } + } + + void move(double time, double max_time) { + resetSourceLevels() + for (Vehicle vehicle in vehicles) { + vehicle.move(time, max_time) + if (vehicle.exists) { + updateSourceLevels(vehicle) + } + } + } + + void updateSourceLevels(Vehicle vehicle) { + SourcePoint closest = null + SourcePoint secondary_closest = null + Coordinate vehicle_point = getPoint(vehicle.getPosition()) + double distance = -1 + double secondary_distance = -1 + for (SourcePoint source in source_points) { + double dist = vehicle_point.distance(source.geom.getCoordinate()) + if (distance == -1) { + closest = source + distance = dist + continue + } + if (dist < distance) { + secondary_closest = closest + secondary_distance = distance + closest = source + distance = dist + continue + } + if (dist < secondary_distance) { + secondary_closest = source + secondary_distance = dist + } + } + double[] vehicle_levels = vehicle.getLw() + double primary_weight = 1.0 + double secondary_weight = 0.0 + if (secondary_closest != null) { + primary_weight = 1 - distance / (distance + secondary_distance) + secondary_weight = 1 - secondary_distance / (distance + secondary_distance) + } + for (int freq = 0; freq < closest.levels.length; freq++) { + closest.levels[freq] = 10 * Math.log10(Math.pow(10, closest.levels[freq] / 10) + primary_weight * Math.pow(10, vehicle_levels[freq] / 10)) + if (secondary_closest != null) { + secondary_closest.levels[freq] = 10 * Math.log10(Math.pow(10, secondary_closest.levels[freq] / 10) + secondary_weight * Math.pow(10, vehicle_levels[freq] / 10)) + } + } + } + + void resetSourceLevels() { + for (SourcePoint source in source_points) { + for (int freq = 0; freq < source.levels.length; freq++) { + source.levels[freq] = -99.0 + } + } + } + + Coordinate getPoint(double position) { + double vh_pos = position % length + vh_pos = (vh_pos + length) % length // handle negative positions (backward vehicles) + double accum_length = 0.0 + Coordinate result = null + for (LineSegment line in line_segments) { + if ((line.getLength() + accum_length) < vh_pos) { + accum_length += line.getLength() + continue + } + double vh_pos_fraction = (vh_pos - accum_length) / line.getLength() + result = line.pointAlong(vh_pos_fraction) + break + } + return result + } + + int getCode() { + if (!type_codes.containsKey(type)) { + return 0 + } + return type_codes.get(type).toInteger() + } + + +} + + +class SourcePoint { + long id + Point geom + int[] freqs = [63, 125, 250, 500, 1000, 2000, 4000, 8000]; + double[] levels = new double[freqs.length]; + + SourcePoint(long id, Geometry geom) { + if (geom.getGeometryType() != "Point") { + throw new InvalidParameterException("Only Point Geometry is supported") + } + this.id = id + this.geom = (Point) geom + } +} + +class Vehicle { + + final static String LIGHT_VEHICLE_TYPE = "1" + final static String MEDIUM_VEHICLE_TYPE = "2" + final static String HEAVY_VEHICLE_TYPE = "3" + final static String MOPEDS_VEHICLE_TYPE = "4" + final static String MOTORCYCLE_VEHICLE_TYPE = "4" + + static int last_id = 0 + + static do_loop = false + static Random rand = new Random(681254665) + + String vehicle_type = LIGHT_VEHICLE_TYPE + int id = 0 + double position = 0.0 + double max_position = 0.0 + double speed = 0.0 // m/s + double time_offset = 10.0 // shift everything by X seconds to ensure enough traffic exists + double time = 0.0 + double start_time = 0 + boolean exists = false + boolean backward = false + + double lw_correction = 0.0 + + static int getNextId() { + last_id++ + return last_id + } + + Vehicle(double speed, double length, double start, String type, boolean is_back, int road_type) { + max_position = length + vehicle_type = type + start_time = start + backward = is_back + id = getNextId() + + if (road_type == 0 ) { + this.speed = (3 * speed / 4) + (rand.nextGaussian() + 1) * (speed / 4) + } + if (this.vehicle_type == HEAVY_VEHICLE_TYPE || this.vehicle_type == MEDIUM_VEHICLE_TYPE) { + this.speed = Math.min(this.speed, 90 / 3.6) // max 90km/h for heavy vehicles + } + } + + Vehicle(double speed, double length, double start) { + this(speed, length, start, LIGHT_VEHICLE_TYPE, false, 5113) + } + + Vehicle(double speed, double length) { + this(speed, length, 0.0, LIGHT_VEHICLE_TYPE, false, 5113) + } + + void move(double input_time, double max_time) { + time = (input_time + time_offset) % max_time + double real_speed = (backward ? (-1 * speed) : speed) + if (do_loop) { + exists = true + position = ((time + max_time + start_time) % max_time) * real_speed + } + else { + if (time >= start_time) { + exists = true + position = ((time - start_time) % max_time) * real_speed + } else { + exists = false + } + if (position > max_position || position < -max_position) { + exists = false + } + } + } + + double getPosition() { + return position % max_position; + } + + double[] getLw() { + int[] freqs = [63, 125, 250, 500, 1000, 2000, 4000, 8000]; + double[] result = new double[freqs.length]; + if (!exists) { + for (int i = 0; i < freqs.length; i++) { + result[i] = -99.0; + } + return result; + } + for (int i = 0; i < freqs.length; i++) { + RoadSourceParametersDynamic rsParametersDynamic = new RoadSourceParametersDynamic( + speed * 3.6, 0, vehicle_type, 1, freqs[i], 20,"NL08", true, 100, 1, + 0, id + ) + // remove lw_correction + result[i] = EvaluateRoadSourceDynamic.evaluate(rsParametersDynamic) + lw_correction; + } + return result; + } +} + + +class LwCorrectionGenerator { + + static Random rand = new Random(546656812) + + + final private static LinkedHashMap > distributions = [ + (Vehicle.LIGHT_VEHICLE_TYPE) : [0], + (Vehicle.MEDIUM_VEHICLE_TYPE) : [0], + (Vehicle.HEAVY_VEHICLE_TYPE) : [0], + (Vehicle.MOPEDS_VEHICLE_TYPE) : [0], + (Vehicle.MOTORCYCLE_VEHICLE_TYPE) : [0] + ]; + + List xy_values; + List partition; + double dx = 1.0 + + + LwCorrectionGenerator(String type, double dx, String zero_point) { + List values = new ArrayList(distributions.get(type)) + int n = values.size() + this.dx = dx + List cum_dist = cumDist(values) + partition = new ArrayList(cum_dist) + partition.remove(n-1) + xy_values = new ArrayList() + double median = 0 + double meandB = 0 + double meanEn = 0 + for (double i = 0; i < n; i +=dx) { + xy_values.add(i) + if (median <= 0 && cum_dist[(int) i] >= 50) { + median = i + } + } + List xy_values_en = new ArrayList() + for (int i = 0; i < xy_values.size(); i++) { + xy_values_en.add(Math.pow(10, xy_values[i] / 10)) + } + meandB = multiplyAndSum(values, xy_values) / sum(values) + meanEn = 10 * Math.log10(multiplyAndSum(values, xy_values_en) / sum(values)) + if (zero_point == "median") { + xy_values = xy_values.stream().map({ e -> e - median}).collect(Collectors.toList()) + } + else if (zero_point == "meandB") { + xy_values = xy_values.stream().map({ e -> e - meandB}).collect(Collectors.toList()) + } + else { + xy_values = xy_values.stream().map({ e -> e - meanEn}).collect(Collectors.toList()) + } + } + + double generate() { + def result = xy_values[rouletteRand(partition)] + result += uniRand(-dx/2.0,dx/2.0) + return result + } + + static List cumDist(List array) { + List input = new ArrayList(array) + double divide = sum(input) + input = input.stream().map({ e -> e / divide }).collect(Collectors.toList()) + List out = new ArrayList() + out.add(input[0]) + for (int i = 1; i < input.size(); i++) + out.add(out.last() + input[i]) + out = out.stream().map({ e -> e * 100.0}).collect(Collectors.toList()) + return out + } + static double sum(List list) { + double sum = 0; + for (double i : list) + sum = sum + i; + return sum; + } + static double multiplyAndSum(List list1, List list2) { + int max = Math.min(list1.size(), list2.size()); + double sum = 0; + for (int i = 0; i < max; i++) { + sum += list1[i] * list2[i]; + } + return sum; + } + + static double uniRand(double left, double right) { + return left + rand.nextDouble() * (right - left) + } + static double rouletteRand(List partition) { + double r = rand.nextDouble() * 100.0 + double v = 0 + for (i in 0.. partition[i]) { + v = i + 1 + } + } + return v + } + +} + + +abstract class HeadwayDistribution { + + protected static int seed; + Random random; + + HeadwayDistribution(int seed) { + this.seed = seed; + random = new Random(seed); + } + + HeadwayDistribution() { + this(1234) + } + + abstract double inverseCumulativeProbability(double p); + + double getNext() { + return inverseCumulativeProbability(random.nextDouble()) + } + + double[] getSamples(int n) { + double[] result = new double[n]; + for (i in 0.. + sql.eachRow('SELECT PK, LV_SPD, LV_DENS_D, HV_SPD, HGV_DENS_D FROM ' + tablename + ';') { row -> int pk = (int) row[0] SPEED_LV.put(pk, (double) row[1]) LV.put(pk, (double) row[2]) diff --git a/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Noise_From_Attenuation_Matrix.groovy b/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Noise_From_Attenuation_Matrix.groovy new file mode 100644 index 000000000..38315cc3e --- /dev/null +++ b/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Noise_From_Attenuation_Matrix.groovy @@ -0,0 +1,204 @@ +/** + * NoiseModelling is an open-source tool designed to produce environmental noise maps on very large urban areas. It can be used as a Java library or be controlled through a user friendly web interface. + * + * This version is developed by Université Gustave Eiffel and CNRS + * + * + * NoiseModelling is distributed under GPL 3 license. You can read a copy of this License in the file LICENCE provided with this software. + * + * Contact: contact@noise-planet.org + * + */ +/** + * @Author Valentin Le Bescond, Université Gustave Eiffel + * @Author Pierre Aumond, Université Gustave Eiffel + */ + +package org.noise_planet.noisemodelling.wps.NoiseModelling + +import geoserver.GeoServer +import geoserver.catalog.Store +import org.geotools.jdbc.JDBCDataStore +import org.h2gis.utilities.wrapper.ConnectionWrapper +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +import java.sql.* +import groovy.sql.Sql + +title = 'Noise Map From Attenuation Matrix' +description = 'Noise Map From Attenuation Matrix.' + + '
' + +inputs = [ + lwTable : [ + name: 'LW(t)', + title: 'LW(t)', + description: 'LW(t)' + + '
The table must contain the following fields :' + + '
PK, THE_GEOM, HZ63, HZ125, HZ250, HZ500, HZ1000, HZ2000, HZ4000, HZ8000, T' + + '
with PK, the IDSOURCE and T a timestring', + type: String.class + ], + attenuationTable : [ + name: 'Attenuation Matrix Table name', + title: 'Attenuation Matrix Table name', + description: 'Attenuation Matrix Table name, Obtained from the Noise_level_from_source script with "confExportSourceId" enabled' + + '
The table must contain the following fields :' + + '
IDRECEIVER, IDSOURCE, THE_GEOM, HZ63, HZ125, HZ250, HZ500, HZ1000, HZ2000, HZ4000, HZ8000', + type: String.class + ], + outputTable : [ + name: 'outputTable Matrix Table name', + title: 'outputTable Matrix Table name', + description: 'outputTable', + type: String.class + ] +] + +outputs = [ + result: [ + name: 'Result output string', + title: 'Result output string', + description: 'This type of result does not allow the blocks to be linked together.', + type: String.class + ] +] + +static Connection openGeoserverDataStoreConnection(String dbName) { + if (dbName == null || dbName.isEmpty()) { + dbName = new GeoServer().catalog.getStoreNames().get(0) + } + Store store = new GeoServer().catalog.getStore(dbName) + JDBCDataStore jdbcDataStore = (JDBCDataStore) store.getDataStoreInfo().getDataStore(null) + return jdbcDataStore.getDataSource().getConnection() +} + + +def run(input) { + + // Get name of the database + String dbName = "h2gisdb" + + // Open connection + openGeoserverDataStoreConnection(dbName).withCloseable { + Connection connection -> + return [result: exec(connection, input)] + } +} + +// main function of the script +def exec(Connection connection, input) { + + connection = new ConnectionWrapper(connection) + + Sql sql = new Sql(connection) + + String resultString + + Logger logger = LoggerFactory.getLogger("org.noise_planet.noisemodelling") + logger.info('Start : Noise_From_Attenuation_Matrix_MatSim') + logger.info("inputs {}", input) + + + String outputTable = input['outputTable'].toString().toUpperCase() + String attenuationTable = input['attenuationTable'].toString().toUpperCase() + String lwTable = input['lwTable'].toString().toUpperCase() + String timeString = "IT" + + DatabaseMetaData dbMeta = connection.getMetaData(); + ResultSet rs = dbMeta.getIndexInfo(null, null, attenuationTable, false, false); + + logger.info("searching indexes on attenuation matrix ... ") + boolean indexIDSOURCE = false; + boolean indexGEOM = false; + while (rs.next()) { + String column = rs.getString("COLUMN_NAME"); + String pos = rs.getString("ORDINAL_POSITION"); + if (column == "IDSOURCE" && pos == "1") { + indexIDSOURCE = true; + logger.info("index on attenuation matrix IDSOURCE found") + } + if (column == "THE_GEOM" && pos == "1") { + indexGEOM = true; + logger.info("index on attenuation matrix THE_GEOM found") + } + } + + if (!indexIDSOURCE) { + logger.info("index on attenuation matrix IDSOURCE, NOT found, creating one...") + sql.execute("CREATE INDEX ON " + attenuationTable + " (IDSOURCE)"); + } + if (!indexGEOM) { + logger.info("index on attenuation matrix THE_GEOM, NOT found, creating one...") + sql.execute("CREATE SPATIAL INDEX ON " + attenuationTable + " (THE_GEOM)"); + } + + + String query = '''CREATE TABLE ''' + outputTable + '''( + PK integer PRIMARY KEY AUTO_INCREMENT, + IDRECEIVER integer, + THE_GEOM geometry, + HZ63 double precision, + HZ125 double precision, + HZ250 double precision, + HZ500 double precision, + HZ1000 double precision, + HZ2000 double precision, + HZ4000 double precision, + HZ8000 double precision, + TIMESTRING varchar + ); + INSERT INTO ''' + outputTable +'''(IDRECEIVER , THE_GEOM , HZ63 , HZ125 , HZ250 , HZ500 , HZ1000 , HZ2000 , HZ4000 , HZ8000 , TIMESTRING ) + SELECT lg.IDRECEIVER, lg.THE_GEOM, + 10 * LOG10( SUM(POWER(10,(mr.HZ63 + lg.HZ63) / 10))) AS HZ63, + 10 * LOG10( SUM(POWER(10,(mr.HZ125 + lg.HZ125) / 10))) AS HZ125, + 10 * LOG10( SUM(POWER(10,(mr.HZ250 + lg.HZ250) / 10))) AS HZ250, + 10 * LOG10( SUM(POWER(10,(mr.HZ500 + lg.HZ500) / 10))) AS HZ500, + 10 * LOG10( SUM(POWER(10,(mr.HZ1000 + lg.HZ1000) / 10))) AS HZ1000, + 10 * LOG10( SUM(POWER(10,(mr.HZ2000 + lg.HZ2000) / 10))) AS HZ2000, + 10 * LOG10( SUM(POWER(10,(mr.HZ4000 + lg.HZ4000) / 10))) AS HZ4000, + 10 * LOG10( SUM(POWER(10,(mr.HZ8000 + lg.HZ8000) / 10))) AS HZ8000, + mr.T AS TIMESTRING + FROM ''' + attenuationTable + ''' lg + INNER JOIN ''' + lwTable + ''' mr ON lg.IDSOURCE = mr.PK + GROUP BY lg.IDRECEIVER, lg.THE_GEOM, mr.T; + ''' + + String query2 = '''CREATE TABLE '''+outputTable+''' AS SELECT lg.IDRECEIVER, lg.THE_GEOM, + 10 * LOG10( SUM(POWER(10,(mr.HZ63 + lg.HZ63) / 10))) AS HZ63, + 10 * LOG10( SUM(POWER(10,(mr.HZ125 + lg.HZ125) / 10))) AS HZ125, + 10 * LOG10( SUM(POWER(10,(mr.HZ250 + lg.HZ250) / 10))) AS HZ250, + 10 * LOG10( SUM(POWER(10,(mr.HZ500 + lg.HZ500) / 10))) AS HZ500, + 10 * LOG10( SUM(POWER(10,(mr.HZ1000 + lg.HZ1000) / 10))) AS HZ1000, + 10 * LOG10( SUM(POWER(10,(mr.HZ2000 + lg.HZ2000) / 10))) AS HZ2000, + 10 * LOG10( SUM(POWER(10,(mr.HZ4000 + lg.HZ4000) / 10))) AS HZ4000, + 10 * LOG10( SUM(POWER(10,(mr.HZ8000 + lg.HZ8000) / 10))) AS HZ8000, + mr.T AS TIMESTRING + FROM ''' + attenuationTable + ''' lg , ''' + lwTable + ''' mr WHERE lg.IDSOURCE = mr.PK + GROUP BY lg.IDRECEIVER, lg.THE_GEOM, mr.T; + ''' + + long start = System.currentTimeMillis(); + sql.execute(String.format("DROP TABLE IF EXISTS LT_GEOM")) + logger.info(query) + sql.execute(query) + long stop = System.currentTimeMillis(); + println(stop-start) + start = System.currentTimeMillis(); + sql.execute(String.format("DROP TABLE IF EXISTS "+outputTable+";")) + logger.info(query2) + sql.execute(query2) + stop = System.currentTimeMillis(); + println(stop-start) + + String prefix = "HZ" + sql.execute("ALTER TABLE "+outputTable+" ADD COLUMN LEQA float as 10*log10((power(10,(" + prefix + "63-26.2)/10)+power(10,(" + prefix + "125-16.1)/10)+power(10,(" + prefix + "250-8.6)/10)+power(10,(" + prefix + "500-3.2)/10)+power(10,(" + prefix + "1000)/10)+power(10,(" + prefix + "2000+1.2)/10)+power(10,(" + prefix + "4000+1)/10)+power(10,(" + prefix + "8000-1.1)/10)))") + sql.execute("ALTER TABLE "+outputTable+" ADD COLUMN LEQ float as 10*log10((power(10,(" + prefix + "63)/10)+power(10,(" + prefix + "125)/10)+power(10,(" + prefix + "250)/10)+power(10,(" + prefix + "500)/10)+power(10,(" + prefix + "1000)/10)+power(10,(" + prefix + "2000)/10)+power(10,(" + prefix + "4000)/10)+power(10,(" + prefix + "8000)/10)))") + + logger.info('End : Noise_From_Attenuation_Matrix_MatSim') + resultString = "Process done. Table of receivers LT_GEOM created !" + logger.info('Result : ' + resultString) + return resultString +} + diff --git a/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Noise_level_from_dynamic_source.groovy b/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Noise_level_from_dynamic_source.groovy deleted file mode 100644 index 919c527cc..000000000 --- a/wps_scripts/src/main/groovy/org/noise_planet/noisemodelling/wps/NoiseModelling/Noise_level_from_dynamic_source.groovy +++ /dev/null @@ -1,706 +0,0 @@ -/** - * NoiseModelling is an open-source tool designed to produce environmental noise maps on very large urban areas. It can be used as a Java library or be controlled through a user friendly web interface. - * - * This version is developed by the DECIDE team from the Lab-STICC (CNRS) and by the Mixt Research Unit in Environmental Acoustics (Université Gustave Eiffel). - * - * - * NoiseModelling is distributed under GPL 3 license. You can read a copy of this License in the file LICENCE provided with this software. - * - * Contact: contact@noise-planet.org - * - */ - -/** - * @Author Pierre Aumond, Université Gustave Eiffel - * @Author Hesry Quentin, Université Gustave Eiffel - * @Author Nicolas Fortin, Université Gustave Eiffel - */ - -package org.noise_planet.noisemodelling.wps.NoiseModelling - -import geoserver.GeoServer -import geoserver.catalog.Store -import groovy.sql.Sql -import org.cts.crs.CRSException -import org.cts.op.CoordinateOperationException -import org.geotools.jdbc.JDBCDataStore -import org.h2gis.api.EmptyProgressVisitor -import org.h2gis.api.ProgressVisitor -import org.h2gis.utilities.GeometryTableUtilities -import org.h2gis.utilities.TableLocation -import org.h2gis.utilities.wrapper.ConnectionWrapper -import org.locationtech.jts.geom.Envelope -import org.locationtech.jts.geom.GeometryFactory - -import org.noise_planet.noisemodelling.emission.* -import org.noise_planet.noisemodelling.pathfinder.* -import org.noise_planet.noisemodelling.pathfinder.utils.JVMMemoryMetric -import org.noise_planet.noisemodelling.pathfinder.utils.KMLDocument -import org.noise_planet.noisemodelling.pathfinder.utils.ReceiverStatsMetric -import org.noise_planet.noisemodelling.pathfinder.utils.ProfilerThread -import org.noise_planet.noisemodelling.pathfinder.utils.ProgressMetric -import org.noise_planet.noisemodelling.propagation.* -import org.noise_planet.noisemodelling.jdbc.* - -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import javax.xml.stream.XMLStreamException -import java.nio.file.Paths -import java.sql.Connection -import java.sql.SQLException -import java.time.LocalDateTime - -title = 'Calculation of the L(t) map from a dynamic noise emission table' -description = 'Calculation of the L(t) map from the road noise emission table.
Tables must be projected in a metric coordinate system (SRID). Use "Change_SRID" WPS Block if needed. ' + - '

The output table is called : LT_GEOM ' + - 'and contain :
' + - '- IDRECEIVER : an identifier (INTEGER, PRIMARY KEY).
' + - '- T : the timestep (INTEGER).
' + - '- THE_GEOM : the 3D geometry of the receivers (POINT).
' + - '- Hz63, Hz125, Hz250, Hz500, Hz1000,Hz2000, Hz4000, Hz8000 : 8 columns giving the day emission sound level for each octave band (FLOAT).' - -inputs = [ - tableBuilding : [ - name : 'Buildings table name', - title : 'Buildings table name', - description: 'Name of the Buildings table.
' + - '
The table shall contain :
' + - '- THE_GEOM : the 2D geometry of the building (POLYGON or MULTIPOLYGON).
' + - '- HEIGHT : the height of the building (FLOAT)', - type : String.class - ], - tableSources : [ - name : 'Sources table name', - title : 'Sources table name', - description: 'Name of the Sources table.
' + - '
The table shall contain :
' + - '- PK : an identifier. It shall be a primary key (INTEGER, PRIMARY KEY).
' + - '- THE_GEOM : the 3D geometry of the sources (POINT, MULTIPOINT, LINESTRING, MULTILINESTRING). According to CNOSSOS-EU, you need to set a height of 0.05 m for a road traffic emission.
' + - '- LW63, LW125, LW250, LW500, LW1000, LW2000, LW4000, LW8000 : 8 columns giving the day emission sound level for each octave band (FLOAT).
' + - '- T : 8 columns giving the evening emission sound level for each octave band (FLOAT).
' + - '- YAW : Source horizontal orientation in degrees. For points 0° North, 90° East. For lines 0° line direction, 90° right of the line direction. (FLOAT).
' + - '- PITCH : Source vertical orientation in degrees. 0° front, 90° top, -90° bottom. (FLOAT).
' + - '- ROLL : Source roll in degrees (FLOAT).
' + - '- DIR_ID : identifier of the directivity sphere from tableSourceDirectivity parameter or train directivity if not provided -> OMNIDIRECTIONAL(0), ROLLING(1), TRACTIONA(2), TRACTIONB(3), AERODYNAMICA(4), AERODYNAMICB(5), BRIDGE(6) (INTEGER).
' + - '

This table can be generated from the WPS Block "Road_Emission_from_Traffic". ', - type : String.class - ], - tableReceivers : [ - name : 'Receivers table name', - title : 'Receivers table name', - description: 'Name of the Receivers table.
' + - '
The table shall contain :
' + - '- PK : an identifier. It shall be a primary key (INTEGER, PRIMARY KEY).
' + - '- THE_GEOM : the 3D geometry of the sources (POINT, MULTIPOINT).
' + - '

This table can be generated from the WPS Blocks in the "Receivers" folder. ', - type : String.class - ], - tableDEM : [ - name : 'DEM table name', - title : 'DEM table name', - description: 'Name of the Digital Elevation Model table.
' + - '
The table shall contain :
' + - '- THE_GEOM : the 3D geometry of the sources (POINT, MULTIPOINT).
' + - '

This table can be generated from the WPS Block "Import_Asc_File". ', - min : 0, max: 1, type: String.class - ], - tableGroundAbs : [ - name : 'Ground absorption table name', - title : 'Ground absorption table name', - description: 'Name of the surface/ground acoustic absorption table.
' + - '
The table shall contain :
' + - '- THE_GEOM : the 2D geometry of the sources (POLYGON or MULTIPOLYGON).
' + - '- G : the acoustic absorption of a ground (FLOAT between 0 : very hard and 1 : very soft).
', - min : 0, max: 1, type: String.class - ], - tableSourceDirectivity : [ - name : 'Source directivity table name', - title : 'Source directivity table name', - description: 'Name of the emission directivity table. If not specified the default is train directivity of cnossos
' + - '
The table shall contain the following fields :
' + - '- DIR_ID : identifier of the directivity sphere (INTEGER)
' + - '- THETA : [-90;90] Vertical angle in degree. 0° front 90° top -90° bottom (FLOAT)
' + - '- PHI : [0;360] Horizontal angle in degree. 0° front 90° right (FLOAT)
' + - '- LW63, LW125, LW250, LW500, LW1000, LW2000, LW4000, LW8000 : attenuation levels in dB for each octave or third octave (FLOAT).
' , - min : 0, max: 1, type: String.class - ], - paramWallAlpha : [ - name : 'wallAlpha', - title : 'Wall absorption coefficient', - description: 'Wall absorption coefficient (FLOAT between 0 : fully absorbent and strictly less than 1 : fully reflective)' + - '

Default value : 0.1 ', - min : 0, max: 1, type: String.class - ], - confReflOrder : [ - name : 'Order of reflexion', - title : 'Order of reflexion', - description: 'Maximum number of reflections to be taken into account (INTEGER).' + - '

Default value : 1 ', - min : 0, max: 1, type: String.class - ], - confMaxSrcDist : [ - name : 'Maximum source-receiver distance', - title : 'Maximum source-receiver distance', - description: 'Maximum distance between source and receiver (FLOAT, in meters).' + - '

Default value : 150 ', - min : 0, max: 1, type: String.class - ], - confMaxReflDist : [ - name : 'Maximum source-reflexion distance', - title : 'Maximum source-reflexion distance', - description: 'Maximum reflection distance from the source (FLOAT, in meters).' + - '

Default value : 50 ', - min : 0, max: 1, type: String.class - ], - confThreadNumber : [ - name : 'Thread number', - title : 'Thread number', - description: 'Number of thread to use on the computer (INTEGER).' + - '
To set this value, look at the number of cores you have.' + - '
If it is set to 0, use the maximum number of cores available.' + - '

Default value : 0 ', - min : 0, max: 1, type: String.class - ], - confDiffVertical : [ - name : 'Diffraction on vertical edges', - title : 'Diffraction on vertical edges', - description: 'Compute or not the diffraction on vertical edges.Following Directive 2015/996, enable this option for rail and industrial sources only.' + - '

Default value : false ', - min : 0, max: 1, type: Boolean.class - ], - confDiffHorizontal : [ - name : 'Diffraction on horizontal edges', - title : 'Diffraction on horizontal edges', - description: 'Compute or not the diffraction on horizontal edges.' + - '

Default value : false ', - min : 0, max: 1, type: Boolean.class - ], - confExportSourceId : [ - name : 'keep source id', - title : 'Separate receiver level by source identifier', - description: 'Keep source identifier in output in order to get noise contribution of each noise source.' + - '

Default value : false ', - min : 0, max: 1, - type : Boolean.class - ], - confHumidity : [ - name : 'Relative humidity', - title : 'Relative humidity', - description: 'Humidity for noise propagation, default value is 70', - min : 0, max: 1, - type : Double.class - ], - confTemperature : [name : 'Temperature', - title : 'Air temperature', - description: 'Air temperature in degree celsius, default value is 15', - min : 0, max: 1, - type : Double.class - ], - confFavorableOccurrencesDay: [ - name : 'Probability of occurrences (Day)', - title : 'Probability of occurrences (Day)', - description: 'comma-delimited string containing the probability of occurrences of favourable propagation conditions.' + - 'The north slice is the last array index not the first one
' + - 'Slice width are 22.5°: (16 slices)
    ' + - '
  • The first column 22.5° contain occurrences between 11.25 to 33.75 °
  • ' + - '
  • The last column 360° contains occurrences between 348.75° to 360° and 0 to 11.25°
Default value 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5', - min : 0, max: 1, - type : String.class - ], - confFavorableOccurrencesEvening: [ - name : 'Probability of occurrences (Evening)', - title : 'Probability of occurrences (Evening)', - description: 'comma-delimited string containing the probability of occurrences of favourable propagation conditions.' + - 'The north slice is the last array index not the first one
' + - 'Slice width are 22.5°: (16 slices)
    ' + - '
  • The first column 22.5° contain occurrences between 11.25 to 33.75 °
  • ' + - '
  • The last column 360° contains occurrences between 348.75° to 360° and 0 to 11.25°
Default value 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5', - min : 0, max: 1, - type : String.class - ], - confFavorableOccurrencesNight: [ - name : 'Probability of occurrences (Night)', - title : 'Probability of occurrences (Night)', - description: 'comma-delimited string containing the probability of occurrences of favourable propagation conditions.' + - 'The north slice is the last array index not the first one
' + - 'Slice width are 22.5°: (16 slices)
    ' + - '
  • The first column 22.5° contain occurrences between 11.25 to 33.75 °
  • ' + - '
  • The last column 360° contains occurrences between 348.75° to 360° and 0 to 11.25°
Default value 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5', - min : 0, max: 1, - type : String.class - ], - confRaysName : [ - name : '', - title : 'Export scene', - description: 'Save each mnt, buildings and propagation rays into the specified table (ex:RAYS) ' + - 'or file URL (ex: file:///Z:/dir/map.kml)' + - 'You can set a table name here in order to save all the rays computed by NoiseModelling' + - '. The number of rays has been limited in this script in order to avoid memory exception' + - '
Default value : empty (do not keep rays) ', - min : 0, max: 1, type: String.class - ] -] - -outputs = [ - result: [ - name : 'Result output string', - title : 'Result output string', - description: 'This type of result does not allow the blocks to be linked together.', - type : String.class - ] -] -// Open Connection to Geoserver -static Connection openGeoserverDataStoreConnection(String dbName) { - if (dbName == null || dbName.isEmpty()) { - dbName = new GeoServer().catalog.getStoreNames().get(0) - } - Store store = new GeoServer().catalog.getStore(dbName) - JDBCDataStore jdbcDataStore = (JDBCDataStore) store.getDataStoreInfo().getDataStore(null) - return jdbcDataStore.getDataSource().getConnection() -} - -def forgeCreateTable(Sql sql, String tableName, LTConfig ltConfig, String geomField, String tableReceiver, String tableResult) { - // Create a logger to display messages in the geoserver logs and in the command prompt. - Logger logger = LoggerFactory.getLogger("org.noise_planet.noisemodelling") - - StringBuilder sb = new StringBuilder("create table "); - sb.append(tableName); - if (!ltConfig.mergeSources) { - sb.append(" (IDRECEIVER bigint NOT NULL"); - sb.append(", IDSOURCE bigint NOT NULL"); - } else { - sb.append(" (IDRECEIVER bigint NOT NULL"); - } - sb.append(", THE_GEOM geometry") - List freqLvl = ltConfig.getPropagationProcessPathData(LTConfig.TIME_PERIOD).freq_lvl; - for (int idfreq = 0; idfreq < freqLvl.size(); idfreq++) { - sb.append(", HZ"); - sb.append(freqLvl.get(idfreq)); - sb.append(" numeric(5, 2)"); - } - sb.append(", LAEQ numeric(5, 2), LEQ numeric(5, 2) ) AS SELECT PK"); - if (!ltConfig.mergeSources) { - sb.append(", IDSOURCE"); - } - sb.append(", ") - sb.append(geomField) - for (int idfreq = 0; idfreq < freqLvl.size(); idfreq++) { - sb.append(", HZ"); - sb.append(freqLvl.get(idfreq)); - } - sb.append(", LAEQ, LEQ FROM ") - sb.append(tableReceiver) - if (!ltConfig.mergeSources) { - // idsource can't be null so we can't left join - sb.append(" a, ") - sb.append(tableResult) - sb.append(" b WHERE a.PK = b.IDRECEIVER") - } else { - sb.append(" a LEFT JOIN ") - sb.append(tableResult) - sb.append(" b ON a.PK = b.IDRECEIVER") - } - sql.execute(sb.toString()) - // apply pk - logger.info("Add primary key on " + tableName) - if (!ltConfig.mergeSources) { - sql.execute("ALTER TABLE " + tableName + " ADD PRIMARY KEY(IDRECEIVER, IDSOURCE)") - } else { - sql.execute("ALTER TABLE " + tableName + " ADD PRIMARY KEY(IDRECEIVER)") - } -} -// run the script -def run(input) { - - // Get name of the database - // by default an embedded h2gis database is created - // Advanced user can replace this database for a postGis or h2Gis server database. - String dbName = "h2gisdb" - - // Open connection - openGeoserverDataStoreConnection(dbName).withCloseable { - Connection connection -> - return [result: exec(connection, input)] - } -} - -static void exportScene(String name, ProfileBuilder builder, ComputeRaysOutAttenuation result, int crs) throws IOException { - try { - FileOutputStream outData = new FileOutputStream(name); - KMLDocument kmlDocument = new KMLDocument(outData); - kmlDocument.setInputCRS("EPSG:" + crs); - kmlDocument.writeHeader(); - if(builder != null) { - kmlDocument.writeTopographic(builder.getTriangles(), builder.getVertices()); - } - if(result != null) { - kmlDocument.writeRays(result.getPropagationPaths()); - } - if(builder != null) { - kmlDocument.writeBuildings(builder); - } - kmlDocument.writeFooter(); - } catch (XMLStreamException | CoordinateOperationException | CRSException ex) { - throw new IOException(ex); - } -} - -// main function of the script -def exec(Connection connection, input) { - - //Need to change the ConnectionWrapper to WpsConnectionWrapper to work under postGIS database - connection = new ConnectionWrapper(connection) - - // output string, the information given back to the user - String resultString = null - - // Create a logger to display messages in the geoserver logs and in the command prompt. - Logger logger = LoggerFactory.getLogger("org.noise_planet.noisemodelling") - - // print to command window - logger.info('Start : LT from Emission') - logger.info("inputs {}", input) // log inputs of the run - - - // ------------------- - // Get every inputs - // ------------------- - - String sources_table_name = input['tableSources'] - // do it case-insensitive - sources_table_name = sources_table_name.toUpperCase() - // Check if srid are in metric projection. - int sridSources = GeometryTableUtilities.getSRID(connection, TableLocation.parse(sources_table_name)) - if (sridSources == 3785 || sridSources == 4326) { - throw new IllegalArgumentException("Error : Please use a metric projection for " + sources_table_name + ".") - } - if (sridSources == 0) { - throw new IllegalArgumentException("Error : The table " + sources_table_name + " does not have an associated SRID.") - } - - - String receivers_table_name = input['tableReceivers'] - // do it case-insensitive - receivers_table_name = receivers_table_name.toUpperCase() - //Get the geometry field of the receiver table - TableLocation receiverTableIdentifier = TableLocation.parse(receivers_table_name) - List geomFieldsRcv = GeometryTableUtilities.getGeometryColumnNames(connection, receiverTableIdentifier) - if (geomFieldsRcv.isEmpty()) { - throw new SQLException(String.format("The table %s does not exists or does not contain a geometry field", receiverTableIdentifier)) - } - // Check if srid are in metric projection and are all the same. - int sridReceivers = GeometryTableUtilities.getSRID(connection, TableLocation.parse(receivers_table_name)) - if (sridReceivers == 3785 || sridReceivers == 4326) { - throw new IllegalArgumentException("Error : Please use a metric projection for " + receivers_table_name + ".") - } - if (sridReceivers == 0) { - throw new IllegalArgumentException("Error : The table " + receivers_table_name + " does not have an associated SRID.") - } - if (sridReceivers != sridSources) { - throw new IllegalArgumentException("Error : The SRID of table " + sources_table_name + " and " + receivers_table_name + " are not the same.") - } - - - String building_table_name = input['tableBuilding'] - // do it case-insensitive - building_table_name = building_table_name.toUpperCase() - // Check if srid are in metric projection and are all the same. - int sridBuildings = GeometryTableUtilities.getSRID(connection, TableLocation.parse(building_table_name)) - if (sridBuildings == 3785 || sridReceivers == 4326) { - throw new IllegalArgumentException("Error : Please use a metric projection for " + building_table_name + ".") - } - if (sridBuildings == 0) { - throw new IllegalArgumentException("Error : The table " + building_table_name + " does not have an associated SRID.") - } - if (sridReceivers != sridBuildings) { - throw new IllegalArgumentException("Error : The SRID of table " + building_table_name + " and " + receivers_table_name + " are not the same.") - } - - String dem_table_name = "" - if (input['tableDEM']) { - dem_table_name = input['tableDEM'] - // do it case-insensitive - dem_table_name = dem_table_name.toUpperCase() - // Check if srid are in metric projection and are all the same. - int sridDEM = GeometryTableUtilities.getSRID(connection, TableLocation.parse(dem_table_name)) - if (sridDEM == 3785 || sridReceivers == 4326) { - throw new IllegalArgumentException("Error : Please use a metric projection for " + dem_table_name + ".") - } - if (sridDEM == 0) { - throw new IllegalArgumentException("Error : The table " + dem_table_name + " does not have an associated SRID.") - } - if (sridDEM != sridSources) { - throw new IllegalArgumentException("Error : The SRID of table " + sources_table_name + " and " + dem_table_name + " are not the same.") - } - } - - - String ground_table_name = "" - if (input['tableGroundAbs']) { - ground_table_name = input['tableGroundAbs'] - // do it case-insensitive - ground_table_name = ground_table_name.toUpperCase() - // Check if srid are in metric projection and are all the same. - int sridGROUND = GeometryTableUtilities.getSRID(connection, TableLocation.parse(ground_table_name)) - if (sridGROUND == 3785 || sridReceivers == 4326) { - throw new IllegalArgumentException("Error : Please use a metric projection for " + ground_table_name + ".") - } - if (sridGROUND == 0) { - throw new IllegalArgumentException("Error : The table " + ground_table_name + " does not have an associated SRID.") - } - if (sridGROUND != sridSources) { - throw new IllegalArgumentException("Error : The SRID of table " + ground_table_name + " and " + sources_table_name + " are not the same.") - } - } - - String tableSourceDirectivity = "" - if (input['tableSourceDirectivity']) { - tableSourceDirectivity = input['tableSourceDirectivity'] - // do it case-insensitive - tableSourceDirectivity = tableSourceDirectivity.toUpperCase() - } - - - int reflexion_order = 0 - if (input['confReflOrder']) { - reflexion_order = Integer.valueOf(input['confReflOrder']) - } - - double max_src_dist = 150 - if (input['confMaxSrcDist']) { - max_src_dist = Double.valueOf(input['confMaxSrcDist']) - } - - double max_ref_dist = 50 - if (input['confMaxReflDist']) { - max_ref_dist = Double.valueOf(input['confMaxReflDist']) - } - - double wall_alpha = 0.1 - if (input['paramWallAlpha']) { - wall_alpha = Double.valueOf(input['paramWallAlpha']) - } - - int n_thread = 0 - if (input['confThreadNumber']) { - n_thread = Integer.valueOf(input['confThreadNumber']) - } - - boolean compute_vertical_diffraction = false - if (input['confDiffVertical']) { - compute_vertical_diffraction = input['confDiffVertical'] - } - - boolean compute_horizontal_diffraction = false - if (input['confDiffHorizontal']) { - compute_horizontal_diffraction = input['confDiffHorizontal'] - } - - - boolean confExportSourceId = false; - if (input['confExportSourceId']) { - confExportSourceId = input['confExportSourceId'] - } - - // ------------------------- - // Initialize some variables - // ------------------------- - - // Set of already processed receivers - Set receivers = new HashSet<>() - - // -------------------------------------------- - // Initialize NoiseModelling propagation part - // -------------------------------------------- - - PointNoiseMap pointNoiseMap = new PointNoiseMap(building_table_name, sources_table_name, receivers_table_name) - LConfig ltConfig = new LConfig(LTConfig.INPUT_MODE.INPUT_MODE_LWT) - ltConfig.setComputeLT(true) - ltConfig.setMergeSources(!confExportSourceId) - - int maximumRaysToExport = 5000 - - File folderExportKML = null - String kmlFileNamePrepend = "" - if (input['confRaysName'] && !((input['confRaysName'] as String).isEmpty())) { - String confRaysName = input['confRaysName'] as String - if(confRaysName.startsWith("file:")) { - ltConfig.setExportRaysMethod(LTConfig.ExportRaysMethods.TO_MEMORY) - URL url = new URL(confRaysName) - File urlFile = new File(url.toURI()) - if(urlFile.isDirectory()) { - folderExportKML = urlFile - } else { - folderExportKML = urlFile.getParentFile() - kmlFileNamePrepend = confRaysName.substring( - Math.max(0, confRaysName.lastIndexOf(File.separator) + 1), - Math.max(0, confRaysName.lastIndexOf("."))) - } - } else { - ltConfig.setExportRaysMethod(LTConfig.ExportRaysMethods.TO_RAYS_TABLE) - ltConfig.setRaysTable(input['confRaysName'] as String) - } - ltConfig.setKeepAbsorption(true); - ltConfig.setMaximumRaysOutputCount(maximumRaysToExport); - } - - LTPointNoiseMapFactory ltProcessing = new LTPointNoiseMapFactory(connection, ltConfig) - - // add optional discrete directivity table name - if(tableSourceDirectivity.isEmpty()) { - // Add train directivity - ltProcessing.insertTrainDirectivity() - } else { - // Load table into specialized class - ltProcessing.directionAttributes = DirectivityTableLoader.loadTable(connection, tableSourceDirectivity, 1) - logger.info(String.format(Locale.ROOT, "Loaded %d directivity from %s table", ltProcessing.directionAttributes.size(), tableSourceDirectivity)) - } - pointNoiseMap.setComputeHorizontalDiffraction(compute_vertical_diffraction) - pointNoiseMap.setComputeVerticalDiffraction(compute_horizontal_diffraction) - pointNoiseMap.setSoundReflectionOrder(reflexion_order) - - // Set environmental parameters - PropagationProcessPathData environmentalDataDay = new PropagationProcessPathData() - - if (input.containsKey('confHumidity')) { - environmentalDataDay.setHumidity(input['confHumidity'] as Double) - } - if (input.containsKey('confTemperature')) { - environmentalDataDay.setTemperature(input['confTemperature'] as Double) - } - - PropagationProcessPathData environmentalDataEvening = new PropagationProcessPathData(environmentalDataDay) - PropagationProcessPathData environmentalDataNight = new PropagationProcessPathData(environmentalDataDay) - if (input.containsKey('confFavorableOccurrencesDay')) { - StringTokenizer tk = new StringTokenizer(input['confFavorableOccurrencesDay'] as String, ',') - double[] favOccurrences = new double[PropagationProcessPathData.DEFAULT_WIND_ROSE.length] - for (int i = 0; i < favOccurrences.length; i++) { - favOccurrences[i] = Math.max(0, Math.min(1, Double.valueOf(tk.nextToken().trim()))) - } - environmentalDataDay.setWindRose(favOccurrences) - } - if (input.containsKey('confFavorableOccurrencesEvening')) { - StringTokenizer tk = new StringTokenizer(input['confFavorableOccurrencesEvening'] as String, ',') - double[] favOccurrences = new double[PropagationProcessPathData.DEFAULT_WIND_ROSE.length] - for (int i = 0; i < favOccurrences.length; i++) { - favOccurrences[i] = Math.max(0, Math.min(1, Double.valueOf(tk.nextToken().trim()))) - } - environmentalDataEvening.setWindRose(favOccurrences) - } - if (input.containsKey('confFavorableOccurrencesNight')) { - StringTokenizer tk = new StringTokenizer(input['confFavorableOccurrencesNight'] as String, ',') - double[] favOccurrences = new double[PropagationProcessPathData.DEFAULT_WIND_ROSE.length] - for (int i = 0; i < favOccurrences.length; i++) { - favOccurrences[i] = Math.max(0, Math.min(1, Double.valueOf(tk.nextToken().trim()))) - } - environmentalDataNight.setWindRose(favOccurrences) - } - - pointNoiseMap.setPropagationProcessPathData(LTConfig.TIME_PERIOD.DAY, environmentalDataDay) - pointNoiseMap.setPropagationProcessPathData(LTConfig.TIME_PERIOD.EVENING, environmentalDataEvening) - pointNoiseMap.setPropagationProcessPathData(LTConfig.TIME_PERIOD.NIGHT, environmentalDataNight) - - // Building height field name - pointNoiseMap.setHeightField("HEIGHT") - // Import table with Snow, Forest, Grass, Pasture field polygons. Attribute G is associated with each polygon - if (ground_table_name != "") { - pointNoiseMap.setSoilTableName(ground_table_name) - } - // Point cloud height above sea level POINT(X Y Z) - if (dem_table_name != "") { - pointNoiseMap.setDemTable(dem_table_name) - } - - pointNoiseMap.setMaximumPropagationDistance(max_src_dist) - pointNoiseMap.setMaximumReflectionDistance(max_ref_dist) - pointNoiseMap.setWallAbsorption(wall_alpha) - pointNoiseMap.setThreadCount(n_thread) - - // -------------------------------------------- - // Initialize NoiseModelling emission part - // -------------------------------------------- - - pointNoiseMap.setComputeRaysOutFactory(ltProcessing) - pointNoiseMap.setPropagationProcessDataFactory(ltProcessing) - - - // Do not propagate for low emission or far away sources - // Maximum error in dB - pointNoiseMap.setMaximumError(0.1d) - // Init Map - pointNoiseMap.initialize(connection, new EmptyProgressVisitor()) - - // -------------------------------------------- - // Run Calculations - // -------------------------------------------- - - // Init ProgressLogger (loading bar) - RootProgressVisitor progressLogger = new RootProgressVisitor(1, true, 1) - - logger.info("Start calculation... ") - LocalDateTime now = LocalDateTime.now(); - ProfilerThread profilerThread = new ProfilerThread(new File(String.format("profile_%d_%d_%d_%dh%d.csv", - now.getYear(), now.getMonthValue(), now.getDayOfMonth(), now.getHour(), now.getMinute()))); - profilerThread.addMetric(ltProcessing); - profilerThread.addMetric(new ProgressMetric(progressLogger)); - profilerThread.addMetric(new JVMMemoryMetric()); - profilerThread.addMetric(new ReceiverStatsMetric()); - profilerThread.setWriteInterval(300); - profilerThread.setFlushInterval(300); - pointNoiseMap.setProfilerThread(profilerThread); - try { - ltProcessing.start() - new Thread(profilerThread).start(); - // Iterate over computation areas - int k = 0 - Map cells = pointNoiseMap.searchPopulatedCells(connection); - ProgressVisitor progressVisitor = progressLogger.subProcess(cells.size()); - new TreeSet<>(cells.keySet()).each { cellIndex -> - Envelope cellEnvelope = pointNoiseMap.getCellEnv(pointNoiseMap.getMainEnvelope(), - cellIndex.getLatitudeIndex(), cellIndex.getLongitudeIndex(), pointNoiseMap.getCellWidth(), - pointNoiseMap.getCellHeight()); - logger.info("Compute domain is " + new GeometryFactory().toGeometry(cellEnvelope)) - logger.info(String.format("Compute... %.3f %% (%d receivers in this cell)", 100 * k++ / cells.size(), cells.get(cellIndex))) - // Run ray propagation - IComputeRaysOut out = pointNoiseMap.evaluateCell(connection, cellIndex.getLatitudeIndex(), cellIndex.getLongitudeIndex(), progressVisitor, receivers) - // Export as a Google Earth 3d scene - if (out instanceof ComputeRaysOutAttenuation && folderExportKML != null) { - ComputeRaysOutAttenuation cellStorage = (ComputeRaysOutAttenuation) out; - exportScene(new File(folderExportKML.getPath(), - String.format(Locale.ROOT, kmlFileNamePrepend + "_%d_%d.kml", cellIndex.getLatitudeIndex(), - cellIndex.getLongitudeIndex())).getPath(), - cellStorage.inputData.profileBuilder, cellStorage, sridSources) - } - - } - } finally { - profilerThread.stop(); - ltProcessing.stop() - } - - // Create a sql connection to interact with the database in SQL - Sql sql = new Sql(connection) - - // Associate Geometry column to the table LT - StringBuilder createdTables = new StringBuilder() - - sql.execute("drop table if exists LT_GEOM;") - logger.info('create table LT_GEOM') - forgeCreateTable(sql, "LT_GEOM", ltConfig, geomFieldsRcv.get(0), receivers_table_name, - ltConfig.lTTable) - createdTables.append(" LT_GEOM") - sql.execute("drop table if exists " + TableLocation.parse(ltConfig.getlTTable())) - - - resultString = "Calculation Done ! " + createdTables.toString() + " table(s) have been created." - - - // print to command window - logger.info('Result : ' + resultString) - logger.info('End : LT from Emission') - - // print to WPS Builder - return resultString - -} diff --git a/wps_scripts/src/test/groovy/org/noise_planet/noisemodelling/wps/TestNoiseModelling.groovy b/wps_scripts/src/test/groovy/org/noise_planet/noisemodelling/wps/TestNoiseModelling.groovy index 43f89e31a..3bdfc1dbb 100644 --- a/wps_scripts/src/test/groovy/org/noise_planet/noisemodelling/wps/TestNoiseModelling.groovy +++ b/wps_scripts/src/test/groovy/org/noise_planet/noisemodelling/wps/TestNoiseModelling.groovy @@ -14,14 +14,17 @@ package org.noise_planet.noisemodelling.wps import groovy.sql.Sql import org.h2.value.ValueBoolean -import org.h2gis.functions.io.dbf.DBFRead import org.h2gis.functions.io.shp.SHPRead import org.h2gis.utilities.JDBCUtilities import org.junit.Test +import org.noise_planet.noisemodelling.wps.Acoustic_Tools.DynamicIndicators +import org.noise_planet.noisemodelling.wps.Experimental.Noise_Map_Difference +import org.noise_planet.noisemodelling.wps.Experimental_Matsim.Noise_From_Attenuation_Matrix_MatSim import org.noise_planet.noisemodelling.wps.Geometric_Tools.Set_Height import org.noise_planet.noisemodelling.wps.Import_and_Export.Import_File import org.noise_planet.noisemodelling.wps.Import_and_Export.Export_Table import org.noise_planet.noisemodelling.wps.NoiseModelling.Dynamic_Road_Emission_from_Traffic +import org.noise_planet.noisemodelling.wps.NoiseModelling.Noise_From_Attenuation_Matrix import org.noise_planet.noisemodelling.wps.NoiseModelling.Noise_level_from_source import org.noise_planet.noisemodelling.wps.NoiseModelling.Noise_level_from_traffic import org.noise_planet.noisemodelling.wps.NoiseModelling.Railway_Emission_from_Traffic @@ -53,12 +56,101 @@ class TestNoiseModelling extends JdbcTestCase { String res = new Dynamic_Road_Emission_from_Traffic().exec(connection, ["tableRoads": "ROADS2", - "method" : "PROBA", + "method" : "oj", "timestep" : 1, "gridStep":10, "duration":100]) + assertEquals("Calculation Done ! The table LW_ROADS has been created.", res) + } + + @Test + void testDynamicRoadEmissionPropagation() { + + SHPRead.importTable(connection, TestDatabaseManager.getResource("ROADS2.shp").getPath()) + + new Import_File().exec(connection, + ["pathFile" : TestNoiseModelling.getResource("buildings.shp").getPath(), + "inputSRID": "2154", + "tableName": "buildings"]) + + new Import_File().exec(connection, + ["pathFile" : TestNoiseModelling.getResource("receivers.shp").getPath(), + "inputSRID": "2154", + "tableName": "receivers"]) + new Set_Height().exec(connection, + [ "tableName":"RECEIVERS", + "height": 1 + ] + ) + + String res = new Dynamic_Road_Emission_from_Traffic().exec(connection, + ["tableRoads": "ROADS2", + "method" : "PROBA", + "timestep" : 1, + "gridStep":10, + "duration":100]) + + res = new Noise_level_from_source().exec(connection, + ["tableBuilding" : "BUILDINGS", + "tableSources" : "ALL_VEH_POS_0DB", + "tableReceivers": "RECEIVERS", + "confMaxSrcDist" : 250, + "confDiffHorizontal" : true, + "confExportSourceId": true, + "confSkipLevening":true, + "confSkipLnight":true, + "confSkipLden":true + ]) + + res = new Noise_From_Attenuation_Matrix().exec(connection, + ["lwTable" : "LW_DYNAMIC_GEOM", + "attenuationTable" : "LDAY_GEOM", + "outputTable" : "LT_GEOM_PROBA" + ]) + + + res = new DynamicIndicators().exec(connection, + ["tableName" : "LT_GEOM_PROBA", + "columnName" : "LEQA" + ]) + + + res = new Dynamic_Road_Emission_from_Traffic().exec(connection, + ["tableRoads": "ROADS2", + "method" : "VALENTIN", + "timestep" : 1, + "gridStep":10, + "duration":300]) + + res = new Noise_level_from_source().exec(connection, + ["tableBuilding" : "BUILDINGS", + "tableSources" : "ALL_VEH_POS_0DB", + "tableReceivers": "RECEIVERS", + "confMaxSrcDist" : 250, + "confDiffHorizontal" : true, + "confExportSourceId": true, + "confSkipLevening":true, + "confSkipLnight":true, + "confSkipLden":true + ]) + + + res = new Noise_From_Attenuation_Matrix().exec(connection, + ["lwTable" : "LW_DYNAMIC_GEOM", + "attenuationTable" : "LDAY_GEOM", + "outputTable" : "LT_GEOM_VAL" + ]) + + res = new DynamicIndicators().exec(connection, + ["tableName" : "LT_GEOM_VAL", + "columnName" : "LEQA" + ]) + + + + assertEquals("Calculation Done ! The table LW_ROADS has been created.", res) }