def grs_near(fromShp, toShp, nearCatCol='tocat', nearDistCol="todistance", maxDist=-1, as_cmd=None): """ v.distance - Finds the nearest element in vector map 'to' for elements in vector map 'from'. """ from gasp.mng.grstbl import add_field add_field(fromShp, nearCatCol, 'INTEGER', ascmd=as_cmd) add_field(fromShp, nearDistCol, 'DOUBLE PRECISION', ascmd=as_cmd) if not as_cmd: import grass.script as grass grass.run_command("v.distance", _from=fromShp, to=toShp, upload='cat,dist', column='{},{}'.format(nearCatCol, nearDistCol), dmax=maxDist) else: from gasp import exec_cmd rcmd = exec_cmd( ("v.distance from={} to={} upload=cat,dist " "column={},{} dmax={}").format(fromShp, toShp, nearCatCol, nearDistCol, maxDist))
def edit_lulc(shp, fld_cls, new_cls): FT_TF_GRASS(shp, 'lulc', 'None') add_field('lulc', 'leg', 'INT') for key in new_cls.keys(): l = new_cls[key]['cls'] sql = " OR ".join([ "{campo}='{value}'".format(campo=fld_cls, value=i) for i in l ]) update_table('lulc', 'leg', int(key), sql) return {'shp': 'lulc', 'fld': 'leg'}
def prod_matrix(origins, destinations, networkGrs, speedLimitCol, onewayCol, thrdId="1", asCmd=None): """ Get Matrix Distance: """ from gasp.to.shp.grs import shp_to_grs from gasp.cpu.grs.mng import category from gasp.anls.exct import sel_by_attr from gasp.mng.grstbl import add_field, add_table, update_table from gasp.mob.grstbx import network_from_arcs from gasp.mob.grstbx import add_pnts_to_network from gasp.mob.grstbx import run_allpairs from gasp.cpu.grs.mng.feat import geomattr_to_db from gasp.cpu.grs.mng.feat import copy_insame_vector from gasp.mng.gen import merge_feat from gasp.prop.feat import feat_count # Merge Origins and Destinations into the same Feature Class ORIGINS_NFEAT = feat_count(origins, gisApi='pandas') DESTINATIONS_NFEAT = feat_count(destinations, gisApi='pandas') ORIGINS_DESTINATIONS = merge_feat([origins, destinations], os.path.join( os.path.dirname(origins), "points_od_{}.shp".format(thrdId)), api='pandas') pointsGrs = shp_to_grs(ORIGINS_DESTINATIONS, "points_od_{}".format(thrdId), asCMD=asCmd) # Connect Points to Network newNetwork = add_pnts_to_network(networkGrs, pointsGrs, "rdv_points_{}".format(thrdId), asCMD=asCmd) # Sanitize Network Table and Cost Columns newNetwork = category(newNetwork, "rdv_points_time_{}".format(thrdId), "add", LyrN="3", geomType="line", asCMD=asCmd) add_table(newNetwork, ("cat integer,kph double precision,length double precision," "ft_minutes double precision," "tf_minutes double precision,oneway text"), lyrN=3, asCMD=asCmd) copy_insame_vector(newNetwork, "kph", speedLimitCol, 3, geomType="line", asCMD=asCmd) copy_insame_vector(newNetwork, "oneway", onewayCol, 3, geomType="line", asCMD=asCmd) geomattr_to_db(newNetwork, "length", "length", "line", createCol=False, unit="meters", lyrN=3, ascmd=asCmd) update_table(newNetwork, "kph", "3.6", "kph IS NULL", lyrN=3, ascmd=asCmd) update_table(newNetwork, "kph", "3.6", "oneway = 'N'", lyrN=3, ascmd=asCmd) update_table(newNetwork, "ft_minutes", "(length * 60) / (kph * 1000.0)", "ft_minutes IS NULL", lyrN=3, ascmd=asCmd) update_table(newNetwork, "tf_minutes", "(length * 60) / (kph * 1000.0)", "tf_minutes IS NULL", lyrN=3, ascmd=asCmd) # Exagerate Oneway's update_table(newNetwork, "ft_minutes", "1000", "oneway = 'TF'", lyrN=3, ascmd=asCmd) update_table(newNetwork, "tf_minutes", "1000", "oneway = 'FT'", lyrN=3, ascmd=asCmd) # Produce matrix matrix = run_allpairs(newNetwork, "ft_minutes", "tf_minutes", 'result_{}'.format(thrdId), arcLyr=3, nodeLyr=2, asCMD=asCmd) # Exclude unwanted OD Pairs q = "({}) AND ({})".format( " OR ".join( ["from_cat={}".format(str(i + 1)) for i in range(ORIGINS_NFEAT)]), " OR ".join([ "to_cat={}".format(str(ORIGINS_NFEAT + i + 1)) for i in range(DESTINATIONS_NFEAT) ])) matrix_sel = sel_by_attr(matrix, q, "sel_{}".format(matrix), geomType="line", lyrN=3, asCMD=asCmd) add_field(matrix_sel, "from_fid", "INTEGER", lyrN=3, asCMD=asCmd) add_field(matrix_sel, "to_fid", "INTEGER", lyrN=3, asCMD=asCmd) update_table(matrix_sel, "from_fid", "from_cat - 1", "from_fid IS NULL", lyrN=3, ascmd=asCmd) update_table(matrix_sel, "to_fid", "to_cat - {} - 1".format(str(ORIGINS_NFEAT)), "to_fid IS NULL", lyrN=3, ascmd=asCmd) return matrix_sel
def geomattr_to_db(shp, attrCol, attr, geomType, createCol=True, unit=None, lyrN=1, ascmd=None): """ v.to.db - Populates attribute values from vector features. v.to.db loads vector map features or metrics into a database table, or prints them (or the SQL queries used to obtain them) in a form of a human-readable report. For uploaded/printed category values '-1' is used for 'no category' and 'null'/'-' if category cannot be found or multiple categories were found. For line azimuths '-1' is used for closed lines (start equals end). attrs options area: * cat: insert new row for each category if doesn't exist yet * area: area size * compact: compactness of an area, calculated as compactness = perimeter / (2 * sqrt(PI * area)) * fd: fractal dimension of boundary defining a polygon, calculated as fd = 2 * (log(perimeter) / log(area)) * perimeter: perimeter length of an area * length: line length * count: number of features for each category * coor: point coordinates, X,Y or X,Y,Z * start: line/boundary starting point coordinates, X,Y or X,Y,Z * end: line/boundary end point coordinates, X,Y or X,Y,Z * sides: categories of areas on the left and right side of the boundary, 'query_layer' is used for area category * query: result of a database query for all records of the geometry(or geometries) from table specified by 'query_layer' option * slope: slope steepness of vector line or boundary * sinuous: line sinuousity, calculated as line length / distance between end points * azimuth: line azimuth, calculated as angle between North direction and endnode direction at startnode * bbox: bounding box of area, N,S,E,W """ from gasp import goToList attrCol = goToList(attrCol) if createCol: from gasp.mng.grstbl import add_field for c in attrCol: add_field(shp, c, "DOUBLE PRECISION", asCMD=ascmd) if not ascmd: vtodb = Module( "v.to.db", map=shp, type=geomType, layer=lyrN, option=attr, columns=",".join(attrCol) if attr != 'length' else attrCol[0], units=unit, run_=False, quiet=True) vtodb() else: from gasp import exec_cmd rcmd = exec_cmd( ("v.to.db map={} type={} layer={} option={} " "columns={} units={} --quiet").format( shp, geomType, lyrN, attr, ",".join(attrCol) if attr != 'length' else attrCol[0], unit))
def cost_surface(dem, lulc, cls_lulc, prod_lulc, roads, kph, barr, grass_location, output, grass_path=None): """ Tool for make a cost surface based on the roads, slope, land use and physical barriers. ach cell has a value that represents the resistance to the movement. """ import os from gasp.oss.ops import create_folder from gasp.os import os_name from gasp.session import run_grass from gasp.prop.rst import get_cellsize from gasp.prop.rst import rst_distinct from .constants import lulc_weight from .constants import get_slope_categories """ Auxiliar Methods """ def edit_lulc(shp, fld_cls, new_cls): FT_TF_GRASS(shp, 'lulc', 'None') add_field('lulc', 'leg', 'INT') for key in new_cls.keys(): l = new_cls[key]['cls'] sql = " OR ".join([ "{campo}='{value}'".format(campo=fld_cls, value=i) for i in l ]) update_table('lulc', 'leg', int(key), sql) return {'shp': 'lulc', 'fld': 'leg'} def combine_to_cost(rst_combined, lst_rst, work, slope_weight, rdv_cos_weight, cellsize, mode_movement): # The tool r.report doesn't work properly, for that we need some aditional information l = [] for i in lst_rst: FT_TF_GRASS(i, os.path.join(work, i + '.tif'), 'None') values = rst_distinct(os.path.join(work, i + '.tif'), gisApi='gdal') l.append(min(values)) # ****** # Now, we can procede normaly txt_file = os.path.join(work, 'text_combine.txt') raster_report(rst_combined, txt_file) open_txt = open(txt_file, 'r') c = 0 dic_combine = {} for line in open_txt.readlines(): try: if c == 4: dic_combine[0] = [str(l[0]), str(l[1])] elif c >= 5: pl = line.split('|') cat = pl[2].split('; ') cat1 = cat[0].split(' ') cat2 = cat[1].split(' ') dic_combine[int(pl[1])] = [cat1[1], cat2[1]] c += 1 except: break cst_dic = {} for key in dic_combine.keys(): cls_slope = int(dic_combine[key][0]) cos_vias = int(dic_combine[key][1]) if cos_vias >= 6: weight4slope = slope_weight[cls_slope]['rdv'] if mode_movement == 'pedestrian': weight4other = (3600.0 * cellsize) / (5.0 * 1000.0) else: weight4other = (3600.0 * cellsize) / (cos_vias * 1000.0) else: weight4slope = slope_weight[cls_slope]['cos'] weight4other = rdv_cos_weight[cos_vias]['weight'] cst_dic[key] = (weight4slope * weight4other) * 10000000.0 return cst_dic def Rules4CstSurface(dic, work): txt = open(os.path.join(work, 'cst_surface.txt'), 'w') for key in dic.keys(): txt.write('{cat} = {cst}\n'.format(cat=str(key), cst=str(dic[key]))) txt.close() return os.path.join(work, 'cst_surface.txt') """ Prepare GRASS GIS Environment """ workspace = os.path.dirname(grass_location) location = os.path.basename(grass_location) # Start GRASS GIS Engine grass_base = run_grass(workspace, location, dem, win_path=grass_path) import grass.script as grass import grass.script.setup as gsetup gsetup.init(grass_base, workspace, location, 'PERMANENT') # Import GRASS GIS Modules from gasp.cpu.grs import grass_converter from gasp.spanlst.surf import slope from gasp.spanlst.rcls import reclassify from gasp.spanlst.rcls import interval_rules from gasp.spanlst.rcls import category_rules from gasp.spanlst.rcls import grass_set_null from gasp.mng.grstbl import add_field, update_table from gasp.anls.ovlay import union from gasp.to.rst import rst_to_grs, grs_to_rst from gasp.to.rst import shp_to_raster from gasp.to.shp.grs import shp_to_grs from gasp.cpu.grs.spanlst import mosaic_raster from gasp.spanlst.local import combine from gasp.spanlst.algebra import rstcalc from gasp.cpu.grs.spanlst import raster_report """Global variables""" # Workspace for temporary files wTmp = create_folder(os.path.join(workspace, 'tmp')) # Cellsize cellsize = float(get_cellsize(dem), gisApi='gdal') # Land Use Land Cover weights lulcWeight = lulc_weight(prod_lulc, cellsize) # Slope classes and weights slope_cls = get_slope_categories() """Make Cost Surface""" # Generate slope raster rst_to_grs(dem, 'dem') slope('dem', 'rst_slope', api="pygrass") # Reclassify Slope rulesSlope = interval_rules(slope_cls, os.path.join(wTmp, 'slope.txt')) reclassify('rst_slope', 'recls_slope', rulesSlope) # LULC - Dissolve, union with barriers and conversion to raster lulc_shp = edit_lulc(lulc, cls_lulc, lulc_weight) shp_to_grs(barr, 'barriers') union(lulc_shp['shp'], 'barriers', 'barrcos', api_gis="grass") update_table('barrcos', 'a_' + lulc_shp['fld'], 99, 'b_cat=1') shp_to_raster('barrcos', 'a_' + lulc_shp['fld'], None, None, 'rst_barrcos', api='pygrass') # Reclassify this raster - convert the values 99 to NULL or NODATA grass_set_null('rst_barrcos', 99) # Add the roads layer to the GRASS GIS shp_to_grs(roads, 'rdv') if kph == 'pedestrian': add_field('rdv', 'foot', 'INT') update_table('rdv', 'foot', 50, 'foot IS NULL') shp_to_raster('rdv', 'foot', None, None, 'rst_rdv', api='pygrass') else: shp_to_raster('rdv', kph, None, None, 'rst_rdv', api='pygrass') # Merge LULC/BARR and Roads mosaic_raster('rst_rdv', 'rst_barrcos', 'rdv_barrcos') # Combine LULC/BARR/ROADS with Slope combine('recls_slope', 'rdv_barrcos', 'rst_combine', api="pygrass") """ Estimating cost for every combination at rst_combine The order of the rasters on the following list has to be the same of GRASS Combine""" cst = combine_to_cost('rst_combine', ['recls_slope', 'rdv_barrcos'], wTmp, slope_cls, lulc_weight, cell_size, kph) # Reclassify combined rst rulesSurface = category_rules(cst, os.path.join('r_surface.txt')) reclassify('rst_combine', 'cst_tmp', rulesSurface) rstcalc('cst_tmp / 10000000.0', 'cst_surface', api='pygrass') grs_to_rst('cst_surface', output)
def vector_based(osmdata, nomenclature, refRaster, lulcShp, overwrite=None, dataStore=None, RoadsAPI='POSTGIS'): """ Convert OSM Data into Land Use/Land Cover Information An vector based approach. TODO: Add a detailed description. RoadsAPI Options: * GRASS * SQLITE * POSTGIS """ # ************************************************************************ # # Python Modules from Reference Packages # # ************************************************************************ # import datetime import os import json # ************************************************************************ # # GASP dependencies # # ************************************************************************ # from gasp.oss import get_filename, get_fileformat from gasp.oss.ops import create_folder from gasp.session import run_grass if RoadsAPI == 'POSTGIS': from gasp.sql.mng.db import create_db from gasp.osm2lulc.utils import osm_to_pgsql else: from gasp.osm2lulc.utils import osm_to_sqdb from gasp.osm2lulc.utils import osm_project, add_lulc_to_osmfeat from gasp.osm2lulc.utils import get_ref_raster from gasp.mng.gen import merge_feat from gasp.osm2lulc.mod1 import grs_vector if RoadsAPI == 'SQLITE' or RoadsAPI == 'POSTGIS': from gasp.osm2lulc.mod2 import roads_sqdb else: from gasp.osm2lulc.mod2 import grs_vec_roads from gasp.osm2lulc.m3_4 import grs_vect_selbyarea from gasp.osm2lulc.mod5 import grs_vect_bbuffer from gasp.osm2lulc.mod6 import vector_assign_pntags_to_build # ************************************************************************ # # Global Settings # # ************************************************************************ # # Check if input parameters exists! if not os.path.exists(os.path.dirname(lulcShp)): raise ValueError('{} does not exist!'.format(os.path.dirname(lulcShp))) if not os.path.exists(osmdata): raise ValueError( 'File with OSM DATA ({}) does not exist!'.format(osmdata)) if not os.path.exists(refRaster): raise ValueError( 'File with reference area ({}) does not exist!'.format(refRaster)) # Check if Nomenclature is valid nomenclature = "URBAN_ATLAS" if nomenclature != "URBAN_ATLAS" and \ nomenclature != "CORINE_LAND_COVER" and \ nomenclature == "GLOBE_LAND_30" else nomenclature time_a = datetime.datetime.now().replace(microsecond=0) # Get Parameters to connect to PostgreSQL conPGSQL = json.load( open( os.path.join(os.path.dirname(os.path.abspath(__file__)), 'con-postgresql.json'), 'r')) if RoadsAPI == 'POSTGIS' else None # Create workspace for temporary files workspace = os.path.join(os.path.dirname(lulcShp), 'osmtolulc') if not dataStore else dataStore # Check if workspace exists if os.path.exists(workspace): if overwrite: create_folder(workspace) else: raise ValueError('Path {} already exists'.format(workspace)) else: create_folder(workspace) # Get Reference Raster refRaster, epsg = get_ref_raster(refRaster, workspace, cellsize=10) from gasp.osm2lulc.var import osmTableData, PRIORITIES, LEGEND __priorities = PRIORITIES[nomenclature] __legend = LEGEND[nomenclature] time_b = datetime.datetime.now().replace(microsecond=0) if RoadsAPI != 'POSTGIS': # ******************************************************************** # # Convert OSM file to SQLITE DB # # ******************************************************************** # osm_db = osm_to_sqdb(osmdata, os.path.join(workspace, 'osm.sqlite')) else: # Convert OSM file to POSTGRESQL DB # conPGSQL["DATABASE"] = create_db(conPGSQL, os.path.splitext( os.path.basename(osmdata))[0], overwrite=True) osm_db = osm_to_pgsql(osmdata, conPGSQL) time_c = datetime.datetime.now().replace(microsecond=0) # ************************************************************************ # # Add Lulc Classes to OSM_FEATURES by rule # # ************************************************************************ # add_lulc_to_osmfeat(osm_db if RoadsAPI != 'POSTGIS' else conPGSQL, osmTableData, nomenclature, api='SQLITE' if RoadsAPI != 'POSTGIS' else RoadsAPI) time_d = datetime.datetime.now().replace(microsecond=0) # ************************************************************************ # # Transform SRS of OSM Data # # ************************************************************************ # osmTableData = osm_project( osm_db if RoadsAPI != 'POSTGIS' else conPGSQL, epsg, api='SQLITE' if RoadsAPI != 'POSTGIS' else RoadsAPI, isGlobeLand=None if nomenclature != 'GLOBE_LAND_30' else True) time_e = datetime.datetime.now().replace(microsecond=0) # ************************************************************************ # # Start a GRASS GIS Session # # ************************************************************************ # grass_base = run_grass(workspace, grassBIN='grass76', location='grloc', srs=epsg) #import grass.script as grass import grass.script.setup as gsetup gsetup.init(grass_base, workspace, 'grloc', 'PERMANENT') # ************************************************************************ # # IMPORT SOME GASP MODULES FOR GRASS GIS # # ************************************************************************ # from gasp.anls.ovlay import erase from gasp.prop.grs import rst_to_region from gasp.mng.genze import dissolve from gasp.mng.grstbl import add_and_update, reset_table, update_table, add_field from gasp.to.shp.grs import shp_to_grs, grs_to_shp from gasp.to.rst import rst_to_grs # ************************************************************************ # # SET GRASS GIS LOCATION EXTENT # # ************************************************************************ # extRst = rst_to_grs(refRaster, 'extent_raster') rst_to_region(extRst) time_f = datetime.datetime.now().replace(microsecond=0) # ************************************************************************ # # MapResults # # ************************************************************************ # osmShps = [] # ************************************************************************ # # 1 - Selection Rule # # ************************************************************************ # ruleOneShp, timeCheck1 = grs_vector( osm_db if RoadsAPI != 'POSTGIS' else conPGSQL, osmTableData['polygons'], apidb=RoadsAPI) osmShps.append(ruleOneShp) time_g = datetime.datetime.now().replace(microsecond=0) # ************************************************************************ # # 2 - Get Information About Roads Location # # ************************************************************************ # ruleRowShp, timeCheck2 = roads_sqdb( osm_db if RoadsAPI == 'SQLITE' else conPGSQL, osmTableData['lines'], osmTableData['polygons'], apidb=RoadsAPI ) if RoadsAPI == 'SQLITE' or RoadsAPI == 'POSTGIS' else grs_vec_roads( osm_db, osmTableData['lines'], osmTableData['polygons']) osmShps.append(ruleRowShp) time_h = datetime.datetime.now().replace(microsecond=0) # ************************************************************************ # # 3 - Area Upper than # # ************************************************************************ # if nomenclature != "GLOBE_LAND_30": ruleThreeShp, timeCheck3 = grs_vect_selbyarea( osm_db if RoadsAPI != 'POSTGIS' else conPGSQL, osmTableData['polygons'], UPPER=True, apidb=RoadsAPI) osmShps.append(ruleThreeShp) time_l = datetime.datetime.now().replace(microsecond=0) else: timeCheck3 = None time_l = None # ************************************************************************ # # 4 - Area Lower than # # ************************************************************************ # if nomenclature != "GLOBE_LAND_30": ruleFourShp, timeCheck4 = grs_vect_selbyarea( osm_db if RoadsAPI != 'POSTGIS' else conPGSQL, osmTableData['polygons'], UPPER=False, apidb=RoadsAPI) osmShps.append(ruleFourShp) time_j = datetime.datetime.now().replace(microsecond=0) else: timeCheck4 = None time_j = None # ************************************************************************ # # 5 - Get data from lines table (railway | waterway) # # ************************************************************************ # ruleFiveShp, timeCheck5 = grs_vect_bbuffer( osm_db if RoadsAPI != 'POSTGIS' else conPGSQL, osmTableData["lines"], api_db=RoadsAPI) osmShps.append(ruleFiveShp) time_m = datetime.datetime.now().replace(microsecond=0) # ************************************************************************ # # 7 - Assign untagged Buildings to tags # # ************************************************************************ # if nomenclature != "GLOBE_LAND_30": ruleSeven11, ruleSeven12, timeCheck7 = vector_assign_pntags_to_build( osm_db if RoadsAPI != 'POSTGIS' else conPGSQL, osmTableData['points'], osmTableData['polygons'], apidb=RoadsAPI) if ruleSeven11: osmShps.append(ruleSeven11) if ruleSeven12: osmShps.append(ruleSeven12) time_n = datetime.datetime.now().replace(microsecond=0) else: timeCheck7 = None time_n = datetime.datetime.now().replace(microsecond=0) # ************************************************************************ # # Produce LULC Map # # ************************************************************************ # """ Get Shps with all geometries related with one class - One Shape for Classe """ from gasp.mng.gen import same_attr_to_shp _osmShps = [] for i in range(len(osmShps)): if not osmShps[i]: continue _osmShps.append( grs_to_shp(osmShps[i], os.path.join(workspace, osmShps[i] + '.shp'), 'auto', lyrN=1, asCMD=True, asMultiPart=None)) _osmShps = same_attr_to_shp(_osmShps, "cat", workspace, "osm_", resultDict=True) del osmShps time_o = datetime.datetime.now().replace(microsecond=0) """ Merge all Classes into one feature class using a priority rule """ osmShps = {} for cls in _osmShps: if cls == '1': osmShps[1221] = shp_to_grs(_osmShps[cls], "osm_1221", asCMD=True) else: osmShps[int(cls)] = shp_to_grs(_osmShps[cls], "osm_" + cls, asCMD=True) # Erase overlapping areas by priority import copy osmNameRef = copy.deepcopy(osmShps) for e in range(len(__priorities)): if e + 1 == len(__priorities): break if __priorities[e] not in osmShps: continue else: for i in range(e + 1, len(__priorities)): if __priorities[i] not in osmShps: continue else: osmShps[__priorities[i]] = erase( osmShps[__priorities[i]], osmShps[__priorities[e]], "{}_{}".format(osmNameRef[__priorities[i]], e), notTbl=True, api='pygrass') time_p = datetime.datetime.now().replace(microsecond=0) # Export all classes lst_merge = [] a = None for i in range(len(__priorities)): if __priorities[i] not in osmShps: continue if not a: reset_table(osmShps[__priorities[i]], { 'cls': 'varchar(5)', 'leg': 'varchar(75)' }, { 'cls': str(__priorities[i]), 'leg': str(__legend[__priorities[i]]) }) a = 1 else: add_and_update(osmShps[__priorities[i]], {'cls': 'varchar(5)'}, {'cls': str(__priorities[i])}) ds = dissolve(osmShps[__priorities[i]], 'dl_{}'.format(str(__priorities[i])), 'cls', api="grass") add_field(ds, 'leg', 'varchar(75)', ascmd=True) update_table(ds, 'leg', str(__legend[__priorities[i]]), 'leg is null') lst_merge.append( grs_to_shp(ds, os.path.join(workspace, "lulc_{}.shp".format( str(__priorities[i]))), 'auto', lyrN=1, asCMD=True, asMultiPart=None)) time_q = datetime.datetime.now().replace(microsecond=0) if get_fileformat(lulcShp) != '.shp': lulcShp = os.path.join(os.path.dirname(lulcShp), get_filename(lulcShp) + '.shp') merge_feat(lst_merge, lulcShp, api='pandas') time_r = datetime.datetime.now().replace(microsecond=0) return lulcShp, { 0: ('set_settings', time_b - time_a), 1: ('osm_to_sqdb', time_c - time_b), 2: ('cls_in_sqdb', time_d - time_c), 3: ('proj_data', time_e - time_d), 4: ('set_grass', time_f - time_e), 5: ('rule_1', time_g - time_f, timeCheck1), 6: ('rule_2', time_h - time_g, timeCheck2), 7: None if not timeCheck3 else ('rule_3', time_l - time_h, timeCheck3), 8: None if not timeCheck4 else ('rule_4', time_j - time_l, timeCheck4), 9: ('rule_5', time_m - time_j if timeCheck4 else time_m - time_h, timeCheck5), 10: None if not timeCheck7 else ('rule_7', time_n - time_m, timeCheck7), 11: ('disj_cls', time_o - time_n), 12: ('priority_rule', time_p - time_o), 13: ('export_cls', time_q - time_p), 14: ('merge_cls', time_r - time_q) }