Skip to content

Commit 1edfd81

Browse files
committed
added fixed and intersection metric
1 parent 919e3e6 commit 1edfd81

File tree

9 files changed

+176
-114
lines changed

9 files changed

+176
-114
lines changed

src/assets/messages/incoming.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
"messageId": "message-id-from-msg",
44
"data": {
55
"jobId": "0b41ebc5-350c-42d3-90af-3af4ad3628fb",
6-
"data_file": "https://tdeisamplestorage.blob.core.windows.net/osw/test_upload/Archive.zip",
7-
"algorithms": "fixed"
6+
"data_file": "https://tdeisamplestorage.blob.core.windows.net/osw/test/wenatchee.zip",
7+
"algorithm": "fixed",
8+
"sub_regions_file":""
89
}
910
}

src/calculators/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
from .qm_calculator import QMCalculator
2-
from .qm_fixed_calculator import QMFixedCalculator, QMRandomCalculator
3-
from .xn_qm_lib import QMIXNCalculator
2+
from .qm_fixed_calculator import QMFixedCalculator
3+
from .qm_xn_lib_calculator import QMXNLibCalculator

src/calculators/qm_fixed_calculator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from qm_calculator import QMCalculator, QualityMetricResult
1+
from src.calculators.qm_calculator import QMCalculator, QualityMetricResult
22
import random
33
import geopandas as gpd
44
import sys

src/calculators/qm_xn_lib_calculator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
from qm_calculator import QMCalculator, QualityMetricResult
1+
from src.calculators.qm_calculator import QMCalculator, QualityMetricResult
22
import geopandas as gpd
33
import sys
44
import warnings
55
import networkx as nx
66
import traceback
77
import geonetworkx as gnx
88
import osmnx as ox
9-
import dask_geopandas
9+
import dask_geopandas
1010
from shapely import Point, LineString, MultiLineString, Polygon, MultiPolygon
1111
from shapely.ops import voronoi_diagram
1212
import itertools

src/config.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22
from dotenv import load_dotenv
33
from pydantic_settings import BaseSettings
4-
from src.calculators import QMFixedCalculator, QMRandomCalculator, QMIXNCalculator
4+
from src.calculators import QMFixedCalculator, QMXNLibCalculator
55

66
load_dotenv()
77

@@ -12,7 +12,7 @@ class Config(BaseSettings):
1212
incoming_topic_subscription: str = os.environ.get('QUALITY_REQ_SUB', '')
1313
outgoing_topic_name: str = os.environ.get('QUALITY_RES_TOPIC', '')
1414
storage_container_name: str = os.environ.get('CONTAINER_NAME', 'osw')
15-
algorithm_dictionary: dict = {"fixed":QMFixedCalculator,"ixn":QMIXNCalculator}
15+
algorithm_dictionary: dict = {"fixed":QMFixedCalculator,"ixn":QMXNLibCalculator}
1616
max_concurrent_messages: int = os.environ.get('MAX_CONCURRENT_MESSAGES', 1)
1717

1818
def get_download_folder(self) -> str:

src/models/quality_request.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
class RequestData:
77
jobId: str
88
data_file: str
9-
algorithms: str
10-
intersectionFile: Optional[str] = None
9+
algorithm: str
10+
sub_regions_file: Optional[str] = None
1111

1212

1313
@dataclass

src/services/osw_qm_calculator_service.py

Lines changed: 62 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import zipfile
22
from src.config import Config
3-
from src.calculators import QMIXNCalculator
3+
from src.calculators import QMXNLibCalculator, QMFixedCalculator, QMCalculator
44
import json
55
import os
66
import tempfile
@@ -40,24 +40,58 @@ def calculate_quality_metric(self, input_file, algorithm_names, output_path, ixn
4040
None
4141
4242
"""
43-
with zipfile.ZipFile(input_file, 'r') as input_zip:
44-
input_unzip_folder = tempfile.TemporaryDirectory()
45-
file_list = self.extract_zip(input_zip, input_unzip_folder.name)
46-
logger.info(f"Extracted input files: {file_list}")
47-
input_files_path = [os.path.join(input_unzip_folder.name, file) for file in file_list]
48-
output_unzip_folder = tempfile.TemporaryDirectory()
49-
logger.info(f"Started calculating quality metrics for input files: {input_files_path}")
50-
for input_file in input_files_path:
51-
qm_calculated_json = self.parse_and_calculate_quality_metric(input_file, algorithm_names,ixn_file)
52-
qm_calculated_file_path = os.path.join(output_unzip_folder.name, os.path.basename(input_file))
53-
with open(qm_calculated_file_path, 'w') as qm_file:
54-
json.dump(qm_calculated_json, qm_file)
55-
logger.info(f"Finished calculating quality metrics for input files: {input_files_path}")
56-
logger.info(f'Zipping output files to {output_path}')
57-
self.zip_folder(output_unzip_folder.name, output_path)
58-
logger.info(f'Cleaning up temporary folders.')
59-
input_unzip_folder.cleanup()
60-
output_unzip_folder.cleanup()
43+
try:
44+
with zipfile.ZipFile(input_file, 'r') as input_zip:
45+
input_unzip_folder = tempfile.TemporaryDirectory()
46+
input_files_path = self.extract_zip(input_zip, input_unzip_folder.name)
47+
# logging.info(f"Extracted input files: {file_list}")
48+
# input_files_path = [os.path.join(input_unzip_folder.name, file) for file in file_list]
49+
output_unzip_folder = tempfile.TemporaryDirectory()
50+
logging.info(f"Started calculating quality metrics for input files: {input_files_path}")
51+
# Get only the edges file out of the input files
52+
edges_file_path = [file_path for file_path in input_files_path if 'edges' in file_path]
53+
if len(edges_file_path) == 0:
54+
raise Exception('Edges file not found in input files.')
55+
edges_file_path = edges_file_path[0]
56+
edges_file_basename = os.path.basename(edges_file_path)
57+
edges_file_without_extension = os.path.splitext(edges_file_basename)[0]
58+
for algorithm_name in algorithm_names:
59+
qm_edges_output_path = os.path.join(output_unzip_folder.name, f'{algorithm_name}_{edges_file_without_extension}.geojson')
60+
qm_calculator = self.get_osw_qm_calculator(algorithm_name, ixn_file, edges_file_path, qm_edges_output_path)
61+
qm_calculator.calculate_quality_metric()
62+
# Copy the rest of the files from input to output
63+
for file_path in input_files_path:
64+
if 'edges' in file_path:
65+
continue
66+
file_basename = os.path.basename(file_path)
67+
output_file_path = os.path.join(output_unzip_folder.name, file_basename)
68+
os.rename(file_path, output_file_path)
69+
70+
logging.info(f"Finished calculating quality metrics for input files: {input_files_path}")
71+
logging.info(f'Zipping output files to {output_path}')
72+
self.zip_folder(output_unzip_folder.name, output_path)
73+
logging.info(f'Cleaning up temporary folders.')
74+
input_unzip_folder.cleanup()
75+
output_unzip_folder.cleanup()
76+
except Exception as e:
77+
logging.error(f'Error calculating quality metrics: {e}')
78+
raise e
79+
80+
def get_osw_qm_calculator(self, algorithm_name:str, ixn_file:str=None, edges_file:str=None, output_file:str=None) -> QMCalculator:
81+
"""
82+
Returns an instance of the specified quality metric calculator.
83+
84+
Args:
85+
algorithm_name (str): The name of the quality metric calculator.
86+
87+
Returns:
88+
QMCalculator: An instance of the specified quality metric calculator.
89+
90+
"""
91+
if algorithm_name == 'ixn':
92+
return QMXNLibCalculator(edges_file, output_file, ixn_file)
93+
else:
94+
return QMFixedCalculator(edges_file, output_file)
6195

6296
def zip_folder(self, input_folder, output_zip):
6397
"""
@@ -71,7 +105,6 @@ def zip_folder(self, input_folder, output_zip):
71105
None
72106
73107
"""
74-
print(output_zip)
75108
with zipfile.ZipFile(output_zip, 'w') as output_zip:
76109
for root, dirs, files in os.walk(input_folder):
77110
for file in files:
@@ -90,12 +123,12 @@ def extract_zip(self, input_zip, unzip_folder) -> [str]:
90123
91124
"""
92125
input_zip.extractall(unzip_folder)
93-
# walk through and collect all files
94-
input_files = []
126+
input_file_paths = []
127+
# Get the file paths for all the files using os.walk
95128
for root, dirs, files in os.walk(unzip_folder):
96129
for file in files:
97-
input_files.append(os.path.join(root, file))
98-
return input_files
130+
input_file_paths.append(os.path.join(root, file))
131+
return input_file_paths
99132

100133
def parse_and_calculate_quality_metric(self, input_file, algorithm_names, ixn_file=None):
101134
"""
@@ -117,15 +150,18 @@ def parse_and_calculate_quality_metric(self, input_file, algorithm_names, ixn_fi
117150
if not algo_name in config.algorithm_dictionary:
118151
logger.warning('Algorithm not found : ' + algo_name)
119152
else:
120-
algo_instances.append(config.algorithm_dictionary[algo_name]())
153+
if algo_name != 'ixn':
154+
algo_instances.append(config.algorithm_dictionary[algo_name]())
121155
with open(input_file, 'r') as input_file:
122156
input_json = json.load(input_file)
123157
for feature in input_json['features']:
124158
for calculator in algo_instances:
125159
feature[calculator.qm_metric_tag()] = calculator.calculate_quality_metric(feature)
126160

127161
if 'ixn' in algorithm_names:
128-
ixn_calculator = QMIXNCalculator()
162+
# get the edges file from the input
163+
164+
ixn_calculator = QMXNLibCalculator()
129165
input_json = ixn_calculator.calculate_quality_metric(input_file, ixn_file)
130166

131167
end_time = time.time()

src/services/servicebus_service.py

Lines changed: 74 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -28,68 +28,89 @@ def __new__(cls):
2828

2929
def __init__(self) -> None:
3030
self.config = Config()
31-
self.core = Core()
32-
self.incoming_topic = self.core.get_topic(self.config.incoming_topic_name,
33-
max_concurrent_messages=self.config.max_concurrent_messages)
34-
self.storage_service = StorageService(core=self.core)
31+
core = Core()
32+
self.incoming_topic = core.get_topic(self.config.incoming_topic_name)
33+
self.outgoing_topic = core.get_topic(self.config.outgoing_topic_name)
34+
self.storage_service = StorageService(core)
35+
self.listening_thread = threading.Thread(target=self.incoming_topic.subscribe, args=[self.config.incoming_topic_subscription, self.process_message])
3536
# Start listening to the things
36-
self.listening_thread = threading.Thread(target=self.listen)
37+
# self.incoming_topic.subscribe(self.config.incoming_topic_subscription, self.handle_message)
3738
self.listening_thread.start()
3839
pass
39-
40-
def listen(self):
41-
self.incoming_topic.subscribe(self.config.incoming_topic_subscription, self.handle_message)
42-
pass
4340

44-
def handle_message(self, msg: QueueMessage):
45-
# Logs and creates a thread for processing
46-
self.process_message(msg=msg)
41+
# def handle_message(self, msg: QueueMessage):
42+
# # Logs and creates a thread for processing
43+
# process_thread = threading.Thread(target=self.process_message, args=[msg])
44+
# process_thread.start()
4745

4846
def process_message(self, msg: QueueMessage):
49-
logger.info(f"Processing message {msg.messageId}")
50-
# Parse the message
51-
quality_request = QualityRequest(messageType=msg.messageType, messageId=msg.messageId, data=msg.data)
52-
# Download the file
53-
input_file_url = quality_request.data.data_file
54-
parsed_url = urlparse(input_file_url)
55-
file_name = os.path.basename(parsed_url.path)
56-
input_dir_path = parsed_url.path
57-
download_folder = os.path.join(self.config.get_download_folder(),msg.messageId)
58-
os.makedirs(download_folder,exist_ok=True)
59-
download_path = os.path.join(download_folder,file_name)
60-
self.storage_service.download_remote_file(input_file_url, download_path)
47+
try:
48+
logging.info(f"Processing message {msg.messageId}")
49+
# Parse the message
50+
quality_request = QualityRequest(messageType=msg.messageType,messageId=msg.messageId,data=msg.data)
51+
# Download the file
52+
input_file_url = quality_request.data.data_file
53+
parsed_url = urlparse(input_file_url)
54+
file_name = os.path.basename(parsed_url.path)
55+
input_dir_path = parsed_url.path
56+
download_folder = os.path.join(self.config.get_download_folder(),msg.messageId)
57+
os.makedirs(download_folder,exist_ok=True)
58+
download_path = os.path.join(download_folder,file_name)
59+
self.storage_service.download_remote_file(input_file_url, download_path)
6160

62-
# intersection file
63-
ixn_file_url = quality_request.data.intersectionFile
64-
ixn_file_path = None
65-
if ixn_file_url:
66-
ixn_file_name = os.path.basename(ixn_file_url)
67-
ixn_file_path = os.path.join(download_folder,ixn_file_name)
68-
self.storage_service.download_remote_file(ixn_file_url, ixn_file_path)
69-
# quality_request.data.intersectionFile = ixn_file_path
61+
# intersection file
62+
ixn_file_url = quality_request.data.sub_regions_file
63+
ixn_file_path = None
64+
if ixn_file_url or ixn_file_url != '':
65+
ixn_file_name = os.path.basename(ixn_file_url)
66+
ixn_file_path = os.path.join(download_folder,ixn_file_name)
67+
self.storage_service.download_remote_file(ixn_file_url, ixn_file_path)
68+
# quality_request.data.intersectionFile = ixn_file_path
7069

71-
# Process the file
72-
output_folder = os.path.join(download_folder,'qm')
73-
os.makedirs(output_folder,exist_ok=True)
74-
output_file_local_path = os.path.join(output_folder,'qm-output.zip')
75-
qm_calculator = OswQmCalculator()
76-
algorithm_names = quality_request.data.algorithms.split(',')
77-
qm_calculator.calculate_quality_metric(download_path, algorithm_names,output_file_local_path,ixn_file_path)
78-
# Upload the file
79-
output_file_remote_path = f'{self.get_directory_path(input_file_url)}/qm-{quality_request.data.jobId}-output.zip'
80-
output_file_url = self.storage_service.upload_local_file(output_file_local_path,output_file_remote_path)
81-
logging.info(f'Uploaded file to {output_file_url}')
70+
# Process the file
71+
output_folder = os.path.join(download_folder,'qm')
72+
os.makedirs(output_folder,exist_ok=True)
73+
output_file_local_path = os.path.join(output_folder,'qm-output.zip')
74+
qm_calculator = OswQmCalculator()
75+
algorithm_names = quality_request.data.algorithm.split(',')
76+
qm_calculator.calculate_quality_metric(download_path, algorithm_names,output_file_local_path,ixn_file_path)
77+
# Upload the file
78+
output_file_remote_path = f'{self.get_directory_path(input_file_url)}/qm-{quality_request.data.jobId}-output.zip'
79+
output_file_url = self.storage_service.upload_local_file(output_file_local_path,output_file_remote_path)
80+
logging.info(f'Uploaded file to {output_file_url}')
8281

83-
response = QualityMetricResponse(
84-
messageType=msg.messageType,
85-
messageId=msg.messageId,
86-
data=response_data
87-
)
88-
self.send_response(msg=response)
89-
# Process the message
90-
# Clean up the download_folder
91-
logger.info('Cleaning up download folder')
92-
shutil.rmtree(download_folder)
82+
response_data = {
83+
'status':'success',
84+
'message':'Quality metrics calculated successfully',
85+
'success':True,
86+
'dataset_url':input_file_url,
87+
'qm_dataset_url':output_file_url
88+
}
89+
response = QualityMetricResponse(
90+
messageType=msg.messageType,
91+
messageId=msg.messageId,
92+
data= response_data
93+
)
94+
self.send_response(response)
95+
# Process the message
96+
# Clean up the download_folder
97+
logging.info('Cleaning up download folder')
98+
shutil.rmtree(download_folder)
99+
except Exception as e:
100+
logging.error(f'Error processing message {msg.messageId} : {e}')
101+
response_data = {
102+
'status':'failed',
103+
'message':str(e),
104+
'success':False,
105+
'dataset_url':input_file_url,
106+
'qm_dataset_url':None
107+
}
108+
response = QualityMetricResponse(
109+
messageType=msg.messageType,
110+
messageId=msg.messageId,
111+
data= response_data
112+
)
113+
self.send_response(response)
93114
pass
94115

95116
def send_response(self, msg: QueueMessage):

0 commit comments

Comments
 (0)