def test_bclpcc(self): merged_dict = covering.merge_coverages([self.partial_coverage, self.partial_coverage2]) merged_dict = covering.update_serviceable_demand(merged_dict, self.serviceable_demand_polygon) bclpcc = covering.create_bclpcc_model(merged_dict, {"total": 3}, 0.2) bclpcc.solve(pulp.GUROBI()) ids = utilities.get_ids(bclpcc, "facility_service_areas") ids2 = utilities.get_ids(bclpcc, "facility2_service_areas") self.assertEqual(['4'], ids) self.assertEqual(['10'], ids2)
def test_traumah(self): traumah = covering.create_traumah_model(self.traumah_coverage, 5, 10) traumah_i = covering.create_traumah_model(self.traumah_coverage, 100, 100) traumah.solve(pulp.GUROBI()) traumah_i.solve(pulp.GUROBI()) ad_ids = utilities.get_ids(traumah, "AirDepot") tc_ids = utilities.get_ids(traumah, "TraumaCenter") self.assertEqual(['0', '1', '2', '4', '5'], ad_ids) self.assertEqual(['10', '12', '15', '16', '18', '19', '21', '22', '7', '9'], tc_ids) self.assertEqual(traumah_i.status, pulp.constants.LpStatusInfeasible)
def test_backup(self): merged_dict = covering.merge_coverages([self.binary_coverage_point, self.binary_coverage_point2]) merged_dict = covering.update_serviceable_demand(merged_dict, self.serviceable_demand_point) bclp = covering.create_backup_model(merged_dict, {"total": 30}) bclp.solve(pulp.GUROBI()) ids = utilities.get_ids(bclp, "facility_service_areas") ids2 = utilities.get_ids(bclp, "facility2_service_areas") self.assertEqual(['1', '3', '4', '5', '6', '7'], ids) self.assertEqual( ['0', '1', '10', '12', '13', '14', '15', '16', '17', '18', '19', '2', '20', '22', '3', '4', '5', '6', '8', '9'], ids2)
def test_bclpcc(self): merged_dict = covering.merge_coverages( [self.partial_coverage, self.partial_coverage2]) merged_dict = covering.update_serviceable_demand( merged_dict, self.serviceable_demand_polygon) bclpcc = covering.create_bclpcc_model(merged_dict, {"total": 3}, 0.2) bclpcc.solve(pulp.GLPK()) ids = utilities.get_ids(bclpcc, "facility_service_areas") ids2 = utilities.get_ids(bclpcc, "facility2_service_areas") self.assertEqual(['4'], ids) self.assertEqual(['10'], ids2)
def test_traumah(self): traumah = covering.create_traumah_model(self.traumah_coverage, 5, 10) traumah_i = covering.create_traumah_model(self.traumah_coverage, 100, 100) traumah.solve(pulp.GLPK()) traumah_i.solve(pulp.GLPK()) ad_ids = utilities.get_ids(traumah, "AirDepot") tc_ids = utilities.get_ids(traumah, "TraumaCenter") self.assertEqual(['0', '1', '2', '3', '5'], ad_ids) self.assertEqual( ['10', '12', '15', '16', '18', '19', '21', '22', '7', '9'], tc_ids) self.assertEqual(traumah_i.status, pulp.constants.LpStatusInfeasible)
def test_lscp(self): merged_dict = covering.merge_coverages([self.binary_coverage_point, self.binary_coverage_point2]) merged_dict = covering.update_serviceable_demand(merged_dict, self.serviceable_demand_point) lscp = covering.create_lscp_model(merged_dict) lscp_i = covering.create_lscp_model(self.binary_coverage_point) lscp.solve(pulp.GUROBI()) lscp_i.solve(pulp.GUROBI()) ids = utilities.get_ids(lscp, "facility_service_areas") ids2 = utilities.get_ids(lscp, "facility2_service_areas") self.assertEqual(['1', '3', '4', '5', '6', '7'], ids) self.assertEqual( ['0', '1', '11', '12', '13', '14', '15', '16', '17', '19', '2', '20', '22', '4', '5', '6', '7', '9'], ids2) self.assertEqual(lscp_i.status, pulp.constants.LpStatusInfeasible)
def test_backup(self): merged_dict = covering.merge_coverages( [self.binary_coverage_point, self.binary_coverage_point2]) merged_dict = covering.update_serviceable_demand( merged_dict, self.serviceable_demand_point) bclp = covering.create_backup_model(merged_dict, {"total": 30}) bclp.solve(pulp.GUROBI()) ids = utilities.get_ids(bclp, "facility_service_areas") ids2 = utilities.get_ids(bclp, "facility2_service_areas") self.assertEqual(['1', '3', '4', '5', '6', '7'], ids) self.assertEqual([ '0', '1', '10', '12', '13', '14', '15', '16', '17', '18', '19', '2', '20', '22', '3', '4', '5', '6', '8', '9' ], ids2)
def test_lscp(self): merged_dict = covering.merge_coverages( [self.binary_coverage_point, self.binary_coverage_point2]) merged_dict = covering.update_serviceable_demand( merged_dict, self.serviceable_demand_point) lscp = covering.create_lscp_model(merged_dict, "lscp.lp") lscp.solve(pulp.GLPK()) ids = utilities.get_ids(lscp, "facility_service_areas") ids2 = utilities.get_ids(lscp, "facility2_service_areas") self.assertEqual(['3', '4', '5', '6', '7'], ids) self.assertEqual([ '0', '1', '11', '12', '13', '14', '15', '16', '17', '18', '19', '2', '20', '21', '22', '4', '5', '6', '9' ], ids2)
def run_example(): providers = QgsProviderRegistry.instance().providerList() for provider in providers: print(provider) print(QgsApplication.showSettings()) demand_points = QgsVectorLayer("/Users/andrewlaird/Desktop/QGIS Mapping/points_2.shp", "demand_points", "ogr") print(demand_points.isValid()) service_areas = QgsVectorLayer("/Users/andrewlaird/Desktop/QGIS Mapping/zones.shp", "service_areas", "ogr") print(service_areas.isValid()) binary_coverage_polygon = pyqgis_analysis.generate_binary_coverage(demand_points, service_areas, "od_rate", "point_id", "zone_id") print(binary_coverage_polygon) # Create the mclp model # Maximize the total coverage (binary polygon) using at most 5 out of 8 facilities logger.info("Creating MCLP model...") mclp = covering.create_threshold_model(binary_coverage_polygon, 100.0) # Solve the model using GLPK logger.info("Solving MCLP...") mclp.solve(pulp.GLPK()) # Get the unique ids of the 5 facilities chosen logger.info("Extracting results") ids = utilities.get_ids(mclp, "zones") # Generate a query that could be used as a definition query or selection in arcpy select_query = pyqgis_analysis.generate_query(ids, unique_field_name="zone_id") logger.info("Output query to use to generate maps is: {}".format(select_query)) # Determine how much demand is covered by the results service_areas.setSubsetString(select_query) total_coverage = pyqgis_analysis.get_covered_demand(demand_points, "od_rate", "binary", service_areas) logger.info("{0:.2f}% of demand is covered".format((100 * total_coverage) / binary_coverage_polygon["totalDemand"]))
def test_cc_threshold(self): ccthreshold = covering.create_cc_threshold_model(self.partial_coverage2, 80) ccthreshold_i = covering.create_cc_threshold_model(self.partial_coverage2, 100) ccthreshold.solve(pulp.GUROBI()) ccthreshold_i.solve(pulp.GUROBI()) ids = utilities.get_ids(ccthreshold, "facility2_service_areas") self.assertEqual(['1', '10', '11', '13', '15', '17', '19', '20', '21', '22', '3', '4', '7', '9'], ids) self.assertEqual(ccthreshold_i.status, pulp.constants.LpStatusInfeasible)
def test_lscp(self): merged_dict = covering.merge_coverages( [self.binary_coverage_point, self.binary_coverage_point2]) merged_dict = covering.update_serviceable_demand( merged_dict, self.serviceable_demand_point) lscp = covering.create_lscp_model(merged_dict) lscp_i = covering.create_lscp_model(self.binary_coverage_point) lscp.solve(pulp.GUROBI()) lscp_i.solve(pulp.GUROBI()) ids = utilities.get_ids(lscp, "facility_service_areas") ids2 = utilities.get_ids(lscp, "facility2_service_areas") self.assertEqual(['1', '3', '4', '5', '6', '7'], ids) self.assertEqual([ '0', '1', '11', '12', '13', '14', '15', '16', '17', '19', '2', '20', '22', '4', '5', '6', '7', '9' ], ids2) self.assertEqual(lscp_i.status, pulp.constants.LpStatusInfeasible)
def test_threshold(self): threshold = covering.create_threshold_model(self.binary_coverage_point2, 30) threshold_i = covering.create_threshold_model(self.binary_coverage_point2, 100) threshold.solve(pulp.GUROBI()) threshold_i.solve(pulp.GUROBI()) ids = utilities.get_ids(threshold, "facility2_service_areas") self.assertEqual(['10', '20', '4'], ids) self.assertEqual(threshold_i.status, pulp.constants.LpStatusInfeasible)
def test_cc_threshold(self): ccthreshold = covering.create_cc_threshold_model( self.partial_coverage2, 80, "ccthreshold.lp") ccthreshold.solve(pulp.GLPK()) ids = utilities.get_ids(ccthreshold, "facility2_service_areas") self.assertEqual([ '1', '11', '13', '15', '17', '19', '20', '21', '22', '3', '4', '5', '7', '9' ], ids)
def test_threshold(self): threshold = covering.create_threshold_model( self.binary_coverage_point2, 30) threshold_i = covering.create_threshold_model( self.binary_coverage_point2, 100) threshold.solve(pulp.GLPK()) threshold_i.solve(pulp.GLPK()) ids = utilities.get_ids(threshold, "facility2_service_areas") self.assertEqual(['10', '17', '4'], ids) self.assertEqual(threshold_i.status, pulp.constants.LpStatusInfeasible)
def test_cc_threshold(self): ccthreshold = covering.create_cc_threshold_model( self.partial_coverage2, 80) ccthreshold_i = covering.create_cc_threshold_model( self.partial_coverage2, 100) ccthreshold.solve(pulp.GLPK()) ccthreshold_i.solve(pulp.GLPK()) ids = utilities.get_ids(ccthreshold, "facility2_service_areas") self.assertEqual([ '1', '11', '13', '15', '17', '19', '20', '21', '22', '3', '4', '5', '7', '9' ], ids) self.assertEqual(ccthreshold_i.status, pulp.constants.LpStatusInfeasible)
def test_threshold(self): threshold = covering.create_threshold_model( self.binary_coverage_point2, 30, "threshold.lp") threshold.solve(pulp.GLPK()) ids = utilities.get_ids(threshold, "facility2_service_areas") self.assertEqual(['10', '17', '4'], ids)
def test_mclpcc(self): mclpcc = covering.create_mclp_cc_model(self.partial_coverage, {"total": 5}, "mclpcc.lp") mclpcc.solve(pulp.GLPK()) ids = utilities.get_ids(mclpcc, "facility_service_areas") self.assertEqual(['1', '4', '5', '6', '7'], ids)
def test_mclp(self): mclp = covering.create_mclp_model(self.binary_coverage_polygon, {"total": 5}, "mclp.lp") mclp.solve(pulp.GLPK()) ids = utilities.get_ids(mclp, "facility_service_areas") self.assertEqual(['1', '4', '5', '6', '7'], ids)
def model(self): # Run a threshold model on a provided demand and response_area layer self._create_run_dirs() # TODO: Figure out why it is necessary to reload here rather than just using the layer. block_layer = QgsVectorLayer(self.paths['block_shp_output'], "block_layer", "ogr") response_area_layer = QgsVectorLayer(self.paths['responder_shp_output'], "response_area_layer", "ogr") if self.logger: self.logger.info("Reloaded layers from file. Found {} blocks and {} response areas." .format(len(list(block_layer.getFeatures())), len(list(response_area_layer.getFeatures())))) binary_coverage_polygon = pyqgis_analysis.generate_partial_coverage(block_layer, response_area_layer, "demand", "point_id", "area_id") # TODO: Build a handler which selects the proper model based on config # TODO: Move this code into a function (class?) for partial_coverage_threshold # Create the mclp model if self.logger: self.logger.info("Creating MCLP model...") mclp = covering.create_cc_threshold_model(binary_coverage_polygon, self.model_run_config['thresholds']) # Solve the model using GLPK if self.logger: self.logger.info("Solving MCLP...") mclp.solve(solvers.PULP_CBC_CMD()) self.problem = mclp if pulp.LpStatus[mclp.status] == "Infeasible": print(pulp.LpStatus[mclp.status]) print("Model run {} deemed infeasible. Skipping...".format(self.model_run_config['run_name'])) self.status = pulp.LpStatus[mclp.status] self.results.parse_model_output(self) return # TODO: Move result extraction into it's own function (or tie to partial_coverage_model object) if self.logger: self.logger.info("Extracting results") ids = utilities.get_ids(mclp, "responder_layer") self.area_ids = ids point_ids = [str(ft['from_point']) for ft in list(response_area_layer.getFeatures()) if str(ft['area_id']) in ids] self.point_ids = point_ids # Generate a query that could be used as a definition query or selection in arcpy select_query = pyqgis_analysis.generate_query(ids, unique_field_name="area_id") point_select_query = pyqgis_analysis.generate_query(point_ids, unique_field_name="point_id") if self.logger: self.logger.info("Output query to use to generate response area maps is: {}".format(select_query)) self.logger.info("Output query to use to generate response point maps is: {}".format(point_select_query)) # Determine how much demand is covered by the results self.selected_points = SelectedPointsLayer().copy(RoadPointLayer(layer=self.road_points)) self.selected_points.layer.setSubsetString(point_select_query) self.selected_areas = SelectedAreasLayer().copy(ResponderLayer(layer=self.response_areas)) self.selected_areas.layer.setSubsetString(select_query) self.results.parse_model_output(self) # TODO: Fix calculation of covered demand and add to output #total_coverage = pyqgis_analysis.get_covered_demand(block_layer, "demand", "partial", # response_area_layer) if self.logger: # self.logger.info( # "{0:.2f}% of demand is covered".format((100 * total_coverage) / binary_coverage_polygon["totalDemand"])) self.logger.info("{} responders".format(len(ids))) _write_shp_file(self.selected_areas.layer, self.paths['model_result_shp_output']) _write_shp_file(self.selected_points.layer, self.paths['selected_points_shp_output']) self._write_qgs_project() return self
ad_layer = arcpy.MakeFeatureLayer_management( r"../sample_data/facility.shp").getOutput(0) # The Trauma Center points tc_layer = arcpy.MakeFeatureLayer_management( r"../sample_data/facility2.shp").getOutput(0) # Generate the trauma coverage dictionary coverage = arcpy_analysis.generate_traumah_coverage(dl,dl_service_area,tc_layer,ad_layer,"Population", 5000,dl_id_field="GEOID10",tc_layer_id_field="ID", ad_layer_id_field="ID") # Create the trauma Pulp linear programming problem # Use 5 Air Depot (Helicopter launch pads) and 10 Trauma Centers traumah = covering.create_traumah_model(coverage,5,10) # Solve the model using GLPK logger.info("Solving TRAUMAH...") traumah.solve(pulp.GLPK()) # Get the unique ids of the 5 facilities chosen logger.info("Extracting results") ad_ids = utilities.get_ids(traumah, "AirDepot") tc_ids = utilities.get_ids(traumah, "TraumaCenter") # Generate a query that could be used as a definition query or selection in arcpy select_query = arcpy_analysis.generate_query(ad_ids, unique_field_name="ID") select_query2 = arcpy_analysis.generate_query(tc_ids, unique_field_name="ID") # Print the important results logger.info("Output query to use to generate maps (showing selected Air Depots) is: {}".format(select_query)) logger.info("Output query to use to generate maps (showing selected Trauma Centers) is: {}".format(select_query2)) logger.info("Total Population Covered: {}".format(pulp.value(traumah.objective)))
demand_polygon_fl = qgis.core.QgsVectorLayer( r"../sample_data/demand_polygon.shp", "demand_polygon_fl", "ogr") facility2_service_areas_fl = qgis.core.QgsVectorLayer( r"../sample_data/facility2_service_areas.shp", "facility2_service_areas_fl", "ogr") # Test partial coverage generation partial_coverage2 = pyqgis_analysis.generate_partial_coverage( demand_polygon_fl, facility2_service_areas_fl, "Population", "GEOID10", "ORIG_ID") # Create the model, minimize the number of facilities that still results in 80 percent coverage logger.info("Creating complemenatary coverage threshold model...") ccthreshold = covering.create_cc_threshold_model(partial_coverage2, 80) # Solve the model logger.info("Solving CC threshold model...") ccthreshold.solve(pulp.GLPK()) # Extract the ids logger.info("Extracting results") ids = utilities.get_ids(ccthreshold, "facility2_service_areas") select_query = pyqgis_analysis.generate_query(ids, unique_field_name="ORIG_ID") logger.info( "Output query to use to generate maps is: {}".format(select_query)) # Determine how much demand is covered by the results facility2_service_areas_fl.setSubsetString(select_query) total_coverage = pyqgis_analysis.get_covered_demand( demand_polygon_fl, "Population", "partial", facility2_service_areas_fl) logger.info("{0:.2f}% of demand is covered".format( (100 * total_coverage) / partial_coverage2["totalDemand"]))
# Facility service area polygon layer has 8 polygons, where each feature has a unique identifier (ORIG_ID) facility_service_areas_fl = arcpy.MakeFeatureLayer_management( r"../sample_data/facility_service_areas.shp").getOutput(0) # Create binary coverage (polygon) dictionary structure # Use population of each polygon as demand, # Use GEOID as the unique field # Ue ORIG_ID as the unique id for the facilities binary_coverage_polygon = arcpy_analysis.generate_binary_coverage(demand_polygon_fl, facility_service_areas_fl, "Population", "GEOID10", "ORIG_ID") # Create the mclp model # Maximize the total coverage (binary polygon) using at most 5 out of 8 facilities logger.info("Creating MCLP model...") mclp = covering.create_mclp_model(binary_coverage_polygon, {"total": 5}) # Solve the model using GLPK logger.info("Solving MCLP...") mclp.solve(pulp.GLPK()) # Get the unique ids of the 5 facilities chosen logger.info("Extracting results") ids = utilities.get_ids(mclp, "facility_service_areas") # Generate a query that could be used as a definition query or selection in arcpy select_query = arcpy_analysis.generate_query(ids, unique_field_name="ORIG_ID") logger.info("Output query to use to generate maps is: {}".format(select_query)) # Determine how much demand is covered by the results facility_service_areas_fl.definitionQuery = select_query total_coverage = arcpy_analysis.get_covered_demand(demand_polygon_fl, "Population", "binary", facility_service_areas_fl) logger.info("{0:.2f}% of demand is covered".format((100 * total_coverage) / binary_coverage_polygon["totalDemand"]))
#make a service area layer service_area_layer = make_service_area_layer(grid_layer) print(len(list(service_area_layer.getFeatures()))) QgsVectorFileWriter.writeAsVectorFormat(service_area_layer, SERVICE_AREA_SHP, "System", service_area_layer.crs(), "ESRI Shapefile") run_example() grid_layer = QgsVectorLayer(GRID_LAYER_SHP, "grid_layer", "ogr") service_area_layer = QgsVectorLayer(SERVICE_AREA_SHP, "service_area_layer", "ogr") binary_coverage_polygon = pyqgis_analysis.generate_binary_coverage(grid_layer, service_area_layer, "demand", "point_id", "area_id") print(binary_coverage_polygon) # Create the mclp model logger.info("Creating MCLP model...") mclp = covering.create_threshold_model(binary_coverage_polygon, 100.0) # Solve the model using GLPK logger.info("Solving MCLP...") mclp.solve(pulp.GLPK()) logger.info("Extracting results") ids = utilities.get_ids(mclp, "areas") # Generate a query that could be used as a definition query or selection in arcpy select_query = pyqgis_analysis.generate_query(ids, unique_field_name="area_id") logger.info("Output query to use to generate maps is: {}".format(select_query)) # Determine how much demand is covered by the results service_area_layer.setSubsetString(select_query) total_coverage = pyqgis_analysis.get_covered_demand(grid_layer, "demand", "binary", service_area_layer) logger.info("{0:.2f}% of demand is covered".format((100 * total_coverage) / binary_coverage_polygon["totalDemand"])) QgsApplication.exitQgis()
def lscp_solver_coverage_dict(dict_coverage, env_path, demand_point, facility_service_area, attr_demand, id_demand_point, id_facility, id_facility_as_string=True): """ Solve a LSCP using the given inputs and parameters :param dict_coverage: (dictionary) Dictionay of coverage :param env_path: (string) Path of the env :param demand_point: (string) File name of the demand point layer :param facility_service_area: (string) File name of the facility service areas :param attr_demand: (string) Field name of demand weight. Not used now :param id_facility_as_string: (boolean) whether the ID attribute of facilities is string :return: (A dict of objects) [demand_coverage, n_facility, list_id_facility] """ # demand layer demand_polygon_fl = arcpy.MakeFeatureLayer_management( os.path.join(env_path, demand_point)).getOutput(0) # service layer facility_service_areas_fl = arcpy.MakeFeatureLayer_management( os.path.join(env_path, facility_service_area)).getOutput(0) # Create binary coverage (polygon) dictionary structure # Use "demand" of each polygon as demand, # Use "id" as the unique field # Use "object_id" as the unique id for the facilities binary_coverage_polygon = dict_coverage # Create the mclp model # Maximize the total coverage (binary polygon) using at most 5 out of 8 facilities logger.info("Creating LSCP model...") lscp = covering.create_lscp_model(binary_coverage_polygon) # Solve the model using GLPK # logger.info("Solving MCLP...") lscp.solve(pulp.GLPK()) # get rid of the file postfix: .shp # example: york_facility_sample_buffer_100 facility_layer_name = os.path.splitext(facility_service_area)[0] # print(facility_layer_name) ids = utilities.get_ids(lscp, facility_layer_name) # print "List of IDs: ", ids # select_query = arcpy_analysis.generate_query(ids, unique_field_name=id_facility, wrap_values_in_quotes=id_facility_as_string) # # logger.info("Output query to use to generate maps is: {}".format(select_query)) # # Determine how much demand is covered by the results # facility_service_areas_fl.definitionQuery = select_query # total_coverage = arcpy_analysis.get_covered_demand(demand_polygon_fl, attr_demand, "binary", # facility_service_areas_fl) # # logger.info("{0:.2f}% of demand is covered".format((100 * total_coverage) / binary_coverage_polygon["totalDemand"])) result = {} print "Total demand is: ", binary_coverage_polygon["totalDemand"] # result["demand_coverage"] = (total_coverage) / binary_coverage_polygon["totalDemand"] result["demand_coverage"] = 1.0 # number of facilities used result["n_facility"] = len(ids) result["list_id_facility"] = " ".join(str(x) for x in ids) return result
5000, dl_id_field="GEOID10", tc_layer_id_field="ID", ad_layer_id_field="ID") # Create the trauma Pulp linear programming problem # Use 5 Air Depot (Helicopter launch pads) and 10 Trauma Centers traumah = covering.create_traumah_model(coverage, 5, 10) # Solve the model using GLPK logger.info("Solving TRAUMAH...") traumah.solve(pulp.GLPK()) # Get the unique ids of the 5 facilities chosen logger.info("Extracting results") ad_ids = utilities.get_ids(traumah, "AirDepot") tc_ids = utilities.get_ids(traumah, "TraumaCenter") # Generate a query that could be used as a definition query or selection in arcpy select_query = arcpy_analysis.generate_query(ad_ids, unique_field_name="ID") select_query2 = arcpy_analysis.generate_query(tc_ids, unique_field_name="ID") # Print the important results logger.info( "Output query to use to generate maps (showing selected Air Depots) is: {}" .format(select_query)) logger.info( "Output query to use to generate maps (showing selected Trauma Centers) is: {}" .format(select_query2)) logger.info("Total Population Covered: {}".format( pulp.value(traumah.objective)))
demand_point_fl, facility2_service_areas_fl, "Population", "GEOID10", "ORIG_ID") # Merge the binary coverages together, serviceable area is auto-updated for binary coverage total_binary_coverage = covering.merge_coverages( [binary_coverage_point1, binary_coverage_point2]) # Create the mclp model # Maximize the total coverage (binary polygon) using at most 5 out of 8 facilities logger.info("Creating MCLP model...") lscp = covering.create_lscp_model(total_binary_coverage, "lscp.lp") # Solve the model using GLPK logger.info("Solving LSCP...") lscp.solve(pulp.GLPK()) # Get the unique ids of the facilities chosen logger.info("Extracting results") ids = utilities.get_ids(lscp, "facility_service_areas") ids2 = utilities.get_ids(lscp, "facility2_service_areas") # Generate a query that could be used as a definition query or selection in arcpy select_query = arcpy_analysis.generate_query(ids, unique_field_name="ORIG_ID") # Generate a second query for the other layer select_query2 = arcpy_analysis.generate_query(ids2, unique_field_name="ORIG_ID") logger.info( "Output query to use to generate maps is: {}".format(select_query)) logger.info( "Output query to use to generate maps is: {}".format(select_query2)) # Determine how much demand is covered by the results facility_service_areas_fl.definitionQuery = select_query facility2_service_areas_fl.defintionQuery = select_query2 total_coverage = arcpy_analysis.get_covered_demand(
sh = logging.StreamHandler(sys.stdout) sh.setFormatter(formatter) logger.addHandler(sh) # Read the layers demand_polygon_fl = qgis.core.QgsVectorLayer(r"../sample_data/demand_polygon.shp", "demand_polygon_fl", "ogr") facility2_service_areas_fl = qgis.core.QgsVectorLayer(r"../sample_data/facility2_service_areas.shp", "facility2_service_areas_fl", "ogr") # Test partial coverage generation partial_coverage2 = pyqgis_analysis.generate_partial_coverage(demand_polygon_fl, facility2_service_areas_fl, "Population", "GEOID10", "ORIG_ID") # Create the model, minimize the number of facilities that still results in 80 percent coverage logger.info("Creating complemenatary coverage threshold model...") ccthreshold = covering.create_cc_threshold_model(partial_coverage2, 80) # Solve the model logger.info("Solving CC threshold model...") ccthreshold.solve(pulp.GLPK()) # Extract the ids logger.info("Extracting results") ids = utilities.get_ids(ccthreshold, "facility2_service_areas") select_query = pyqgis_analysis.generate_query(ids, unique_field_name="ORIG_ID") logger.info("Output query to use to generate maps is: {}".format(select_query)) # Determine how much demand is covered by the results facility2_service_areas_fl.setSubsetString(select_query) total_coverage = pyqgis_analysis.get_covered_demand(demand_polygon_fl, "Population", "partial", facility2_service_areas_fl) logger.info("{0:.2f}% of demand is covered".format((100 * total_coverage) / partial_coverage2["totalDemand"]))
# Create binary coverage (polygon) dictionary structure # Use population of each polygon as demand, # Use GEOID as the unique field # Ue ORIG_ID as the unique id for the facilities binary_coverage_polygon = arcpy_analysis.generate_binary_coverage( demand_polygon_fl, facility_service_areas_fl, "Population", "GEOID10", "ORIG_ID") # Create the mclp model # Maximize the total coverage (binary polygon) using at most 5 out of 8 facilities logger.info("Creating MCLP model...") mclp = covering.create_mclp_model(binary_coverage_polygon, {"total": 5}, "mclp.lp") # Solve the model using GLPK logger.info("Solving MCLP...") mclp.solve(pulp.GLPK()) # Get the unique ids of the 5 facilities chosen logger.info("Extracting results") ids = utilities.get_ids(mclp, "facility_service_areas") # Generate a query that could be used as a definition query or selection in arcpy select_query = arcpy_analysis.generate_query(ids, unique_field_name="ORIG_ID") logger.info( "Output query to use to generate maps is: {}".format(select_query)) # Determine how much demand is covered by the results facility_service_areas_fl.definitionQuery = select_query total_coverage = arcpy_analysis.get_covered_demand( demand_polygon_fl, "Population", "binary", facility_service_areas_fl) logger.info("{0:.2f}% of demand is covered".format( (100 * total_coverage) / binary_coverage_polygon["totalDemand"]))
def test_mclpcc(self): mclpcc = covering.create_mclp_cc_model(self.partial_coverage, {"total": 5}) mclpcc.solve(pulp.GUROBI()) ids = utilities.get_ids(mclpcc, "facility_service_areas") self.assertEqual(['1', '4', '5', '6', '7'], ids)
def test_mclp(self): mclp = covering.create_mclp_model(self.binary_coverage_polygon, {"total": 5}) mclp.solve(pulp.GUROBI()) ids = utilities.get_ids(mclp, "facility_service_areas") self.assertEqual(['1', '4', '5', '6', '7'], ids)
def mclp_solver(env_path, demand_point, facility_service_area, attr_demand, id_demand_point, id_facility, num_facility, id_facility_as_string=True): """ Solve a MCLP using the given inputs and parameters. This function will overwrite the FeatureClass called mclp_analysis_layer :param env_path: (string) Path of the env :param demand_point: (string) File name of the demand point layer :param facility_service_area: (string) File name of the facility service areas :param attr_demand: (int or float) the attribute of demand :param id_demand_point: (int or string) the ID attribute in demand_point :param id_facility: (int or string) the ID attribute in facility_service_area :param num_facility: (int) Number of facilities to site :param id_facility_as_string: (boolean) whether the ID attribute of facilities is string :return: (A dict of objects) [demand_coverage, n_facility, list_id_facility] """ # demand layer demand_polygon_fl = arcpy.MakeFeatureLayer_management( os.path.join(env_path, demand_point)).getOutput(0) # service layer facility_service_areas_fl = arcpy.MakeFeatureLayer_management( os.path.join(env_path, facility_service_area)).getOutput(0) # Create binary coverage (polygon) dictionary structure # Use "demand" of each polygon as demand, # Use "id" as the unique field # Use "object_id" as the unique id for the facilities print(arcpy.Describe(facility_service_areas_fl).shapeType) binary_coverage_polygon = arcpy_analysis.generate_binary_coverage( demand_polygon_fl, facility_service_areas_fl, attr_demand, id_demand_point, id_facility) # Create the mclp model # Maximize the total coverage (binary polygon) using at most 5 out of 8 facilities # logger.info("Creating MCLP model...") mclp = covering.create_mclp_model(binary_coverage_polygon, {"total": num_facility}) # Solve the model using GLPK print("Solving MCLP...") mclp.solve(pulp.GLPK()) # print(mclp.variables()) # get the ids not covered # print('Demand not covered: ') # for var in mclp.variables(): # if var.name.split("$")[0] == "Y": # if var.varValue < 1.0: # print(var.name) # get the ids covered print('Demand covered: ') list_objectid_dem_covered = [] for var in mclp.variables(): if var.name.split("$")[0] == "Y": if var.varValue >= 1.0: list_objectid_dem_covered.append(var.name.split("$")[1]) print list_objectid_dem_covered # get rid of the file postfix: .shp # example: york_facility_sample_buffer_100 facility_layer_name = os.path.splitext(facility_service_area)[0] # print(facility_layer_name) ids = utilities.get_ids(mclp, facility_layer_name) print 'List of selected facilities: ', ids # As the attribute object_id is a string type, the 'wrap_values_in_quotes' should be set as True select_query = arcpy_analysis.generate_query( ids, unique_field_name=id_facility, wrap_values_in_quotes=id_facility_as_string) logger.info( "Output query to use to generate maps is: {}".format(select_query)) # Determine how much demand is covered by the results facility_service_areas_fl.definitionQuery = select_query total_coverage = arcpy_analysis.get_covered_demand( demand_polygon_fl, attr_demand, "binary", facility_service_areas_fl) logger.info(total_coverage) logger.info(binary_coverage_polygon["totalDemand"]) # logger.info("{0:.2f}% of demand is covered".format((100 * total_coverage) / binary_coverage_polygon["totalDemand"])) result = {} result["demand_coverage"] = ( total_coverage) / binary_coverage_polygon["totalDemand"] result["n_facility"] = num_facility result["list_id_facility"] = " ".join(str(x) for x in ids) print result["list_id_facility"] return result
block_layer = QgsVectorLayer(BLOCK_OUTLINE_SHP, "block_layer", "ogr") response_area_layer = QgsVectorLayer(RESPONSE_AREA_LAYER_SHP, "response_area_layer", "ogr") binary_coverage_polygon = pyqgis_analysis.generate_partial_coverage( block_layer, response_area_layer, "demand", "point_id", "area_id") print(binary_coverage_polygon) # Create the mclp model logger.info("Creating MCLP model...") mclp = covering.create_cc_threshold_model(binary_coverage_polygon, 80) # Solve the model using GLPK logger.info("Solving MCLP...") mclp.solve(pulp.GLPK(options=['--mipgap', '.1'])) logger.info("Extracting results") ids = utilities.get_ids(mclp, "{}_response_area_layer".format(SELECTION_VALUE)) print(ids) # Generate a query that could be used as a definition query or selection in arcpy select_query = pyqgis_analysis.generate_query(ids, unique_field_name="area_id") logger.info( "Output query to use to generate maps is: {}".format(select_query)) # Determine how much demand is covered by the results response_area_layer.setSubsetString(select_query) total_coverage = pyqgis_analysis.get_covered_demand( block_layer, "demand", "partial", response_area_layer) logger.info("{0:.2f}% of demand is covered".format( (100 * total_coverage) / binary_coverage_polygon["totalDemand"])) logger.info("{} responders".format(len(ids))) QgsVectorFileWriter.writeAsVectorFormat(response_area_layer, MODEL_RESULT_PATH, "System",
fl_variable_name=facility_variable_name) # formulate model logger.info("Creating MCLP model...") mclp = covering.create_mclp_model(dict_coverage, {"total": num_facility}) # solve logger.info("Solving MCLP...") mclp.solve(pulp.GLPK()) # Get the unique ids of the facilities chosen logger.info("Extracting results") # Get the id set of facilities chosen set_facility_id_chosen = set( utilities.get_ids(mclp, facility_variable_name)) logger.info("Set of facility ids: {}".format(set_facility_id_chosen)) logger.info("Number of facilities selected: {}".format( len(set_facility_id_chosen))) # Query the demand covered from the dict_coverage total_demand_covered = 0.0 for demand_id, demand_obj in dict_coverage["demand"].items(): # if this demand_id is covered by any facility in ids if not set_facility_id_chosen.isdisjoint( demand_obj["coverage"]["facility"].keys()): total_demand_covered += demand_obj["demand"] logger.info("{0:.2f}% of demand is covered".format(
"Population", "GEOID10", "ORIG_ID") binary_coverage_point2 = arcpy_analysis.generate_binary_coverage(demand_point_fl, facility2_service_areas_fl, "Population", "GEOID10", "ORIG_ID") # Merge the binary coverages together, serviceable area is auto-updated for binary coverage total_binary_coverage = covering.merge_coverages([binary_coverage_point1, binary_coverage_point2]) # Create the mclp model # Maximize the total coverage (binary polygon) using at most 5 out of 8 facilities logger.info("Creating MCLP model...") lscp = covering.create_lscp_model(total_binary_coverage) # Solve the model using GLPK logger.info("Solving LSCP...") lscp.solve(pulp.GLPK()) # Get the unique ids of the facilities chosen logger.info("Extracting results") ids = utilities.get_ids(lscp, "facility_service_areas") ids2 = utilities.get_ids(lscp, "facility2_service_areas") # Generate a query that could be used as a definition query or selection in arcpy select_query = arcpy_analysis.generate_query(ids, unique_field_name="ORIG_ID") # Generate a second query for the other layer select_query2 = arcpy_analysis.generate_query(ids2, unique_field_name="ORIG_ID") logger.info("Output query to use to generate maps is: {}".format(select_query)) logger.info("Output query to use to generate maps is: {}".format(select_query2)) # Determine how much demand is covered by the results facility_service_areas_fl.definitionQuery = select_query facility2_service_areas_fl.defintionQuery = select_query2 total_coverage = arcpy_analysis.get_covered_demand(demand_point_fl, "Population", "binary", facility_service_areas_fl, facility2_service_areas_fl) logger.info("{0:.2f}% of demand is covered".format((100 * total_coverage) / total_binary_coverage["totalDemand"]))