Arpit-Bansal commited on
Commit
c7ea7db
·
1 Parent(s): 062c4f5

job cards optional everywhere

Browse files
DataService/enhanced_generator.py CHANGED
@@ -256,7 +256,7 @@ class EnhancedMetroDataGenerator:
256
  estimated_hours = random.randint(2, 24)
257
 
258
  job = {
259
- "job_card_id": f"JC-{random.randint(10000, 99999)}",
260
  "trainset_id": ts_id,
261
  "work_order_number": f"WO-{random.randint(100000, 999999)}",
262
  "job_type": random.choice(job_types),
@@ -391,8 +391,12 @@ class EnhancedMetroDataGenerator:
391
 
392
  return contracts
393
 
394
- def generate_complete_enhanced_dataset(self) -> Dict:
395
- """Generate complete enhanced dataset with all improvements."""
 
 
 
 
396
  print("Generating enhanced synthetic data...")
397
 
398
  dataset = {
@@ -413,7 +417,7 @@ class EnhancedMetroDataGenerator:
413
  "trainset_profiles": self.trainset_profiles,
414
  "trainset_status": self.generate_enhanced_trainset_status(),
415
  "fitness_certificates": self.generate_realistic_fitness_certificates(),
416
- "job_cards": self.generate_correlated_job_cards(),
417
  "component_health": self.generate_realistic_component_health(),
418
  "branding_contracts": self.generate_optimized_branding_contracts(),
419
  # Keep the existing generators for other data
@@ -444,6 +448,11 @@ class EnhancedMetroDataGenerator:
444
  "bogie_2": round(random.uniform(0.5, 3.5) / reliability_factor, 2),
445
  "unit": "mm/s"
446
  },
 
 
 
 
 
447
  "overall_condition": "Good" if reliability_factor > 0.85 else "Fair" if reliability_factor > 0.75 else "Poor"
448
  }
449
  sensor_data.append(sensors)
@@ -555,7 +564,8 @@ class EnhancedMetroDataGenerator:
555
  return {
556
  "date": datetime.now().date().isoformat(),
557
  "weather": {
558
- "condition": random.choice(["Clear", "Cloudy", "Rainy"])
 
559
  },
560
  "ridership_forecast": {
561
  "expected_passengers": random.randint(80000, 150000),
@@ -563,9 +573,14 @@ class EnhancedMetroDataGenerator:
563
  }
564
  }
565
 
566
- def save_to_json(self, filename: str = "metro_enhanced_data.json") -> Dict:
567
- """Save enhanced data to JSON file."""
568
- data = self.generate_complete_enhanced_dataset()
 
 
 
 
 
569
 
570
  with open(filename, 'w') as f:
571
  json.dump(data, f, indent=2)
 
256
  estimated_hours = random.randint(2, 24)
257
 
258
  job = {
259
+ "job_id": f"JC-{random.randint(10000, 99999)}",
260
  "trainset_id": ts_id,
261
  "work_order_number": f"WO-{random.randint(100000, 999999)}",
262
  "job_type": random.choice(job_types),
 
391
 
392
  return contracts
393
 
394
+ def generate_complete_enhanced_dataset(self, include_job_cards: bool = False) -> Dict:
395
+ """Generate complete enhanced dataset with all improvements.
396
+
397
+ Args:
398
+ include_job_cards: Whether to include job cards in the dataset. Default False.
399
+ """
400
  print("Generating enhanced synthetic data...")
401
 
402
  dataset = {
 
417
  "trainset_profiles": self.trainset_profiles,
418
  "trainset_status": self.generate_enhanced_trainset_status(),
419
  "fitness_certificates": self.generate_realistic_fitness_certificates(),
420
+ "job_cards": self.generate_correlated_job_cards() if include_job_cards else [],
421
  "component_health": self.generate_realistic_component_health(),
422
  "branding_contracts": self.generate_optimized_branding_contracts(),
423
  # Keep the existing generators for other data
 
448
  "bogie_2": round(random.uniform(0.5, 3.5) / reliability_factor, 2),
449
  "unit": "mm/s"
450
  },
451
+ "temperature": {
452
+ "motor_1": round(random.uniform(45, 85) + (1 - reliability_factor) * 10, 1),
453
+ "motor_2": round(random.uniform(45, 85) + (1 - reliability_factor) * 10, 1),
454
+ "unit": "°C"
455
+ },
456
  "overall_condition": "Good" if reliability_factor > 0.85 else "Fair" if reliability_factor > 0.75 else "Poor"
457
  }
458
  sensor_data.append(sensors)
 
564
  return {
565
  "date": datetime.now().date().isoformat(),
566
  "weather": {
567
+ "condition": random.choice(["Clear", "Cloudy", "Rainy"]),
568
+ "temperature": round(random.uniform(20, 35), 1)
569
  },
570
  "ridership_forecast": {
571
  "expected_passengers": random.randint(80000, 150000),
 
573
  }
574
  }
575
 
576
+ def save_to_json(self, filename: str = "metro_enhanced_data.json", include_job_cards: bool = False) -> Dict:
577
+ """Save enhanced data to JSON file.
578
+
579
+ Args:
580
+ filename: Output filename.
581
+ include_job_cards: Whether to include job cards in the dataset. Default False.
582
+ """
583
+ data = self.generate_complete_enhanced_dataset(include_job_cards=include_job_cards)
584
 
585
  with open(filename, 'w') as f:
586
  json.dump(data, f, indent=2)
DataService/metro_models.py CHANGED
@@ -103,7 +103,7 @@ class Trainset(BaseModel):
103
 
104
  # Compliance and health
105
  fitness_certificates: FitnessCertificates
106
- job_cards: JobCards
107
 
108
  # Branding
109
  branding: Optional[Branding] = None
 
103
 
104
  # Compliance and health
105
  fitness_certificates: FitnessCertificates
106
+ job_cards: Optional[JobCards] = Field(default_factory=lambda: JobCards(open=0, blocking=[]))
107
 
108
  # Branding
109
  branding: Optional[Branding] = None
DataService/schedule_optimizer.py CHANGED
@@ -29,7 +29,8 @@ class MetroScheduleOptimizer:
29
  num_trains: int,
30
  route: Route,
31
  train_health: List[TrainHealthStatus],
32
- depot_name: str = "Muttom_Depot"
 
33
  ):
34
  self.date = date
35
  self.num_trains = num_trains
@@ -37,6 +38,7 @@ class MetroScheduleOptimizer:
37
  self.train_health = {t.trainset_id: t for t in train_health}
38
  self.depot_name = depot_name
39
  self.generator = MetroDataGenerator(num_trains)
 
40
 
41
  # Operating parameters
42
  self.op_hours = OperationalHours()
@@ -58,7 +60,7 @@ class MetroScheduleOptimizer:
58
  for i, train_id in enumerate(self.generator.trainset_ids):
59
  health = self.train_health[train_id]
60
  fitness_certs = self.generator.generate_fitness_certificates(train_id)
61
- job_cards = self.generator.generate_job_cards(train_id)
62
  branding = self.generator.generate_branding()
63
 
64
  readiness = self.generator.calculate_readiness_score(
 
29
  num_trains: int,
30
  route: Route,
31
  train_health: List[TrainHealthStatus],
32
+ depot_name: str = "Muttom_Depot",
33
+ include_job_cards: bool = False
34
  ):
35
  self.date = date
36
  self.num_trains = num_trains
 
38
  self.train_health = {t.trainset_id: t for t in train_health}
39
  self.depot_name = depot_name
40
  self.generator = MetroDataGenerator(num_trains)
41
+ self.include_job_cards = include_job_cards
42
 
43
  # Operating parameters
44
  self.op_hours = OperationalHours()
 
60
  for i, train_id in enumerate(self.generator.trainset_ids):
61
  health = self.train_health[train_id]
62
  fitness_certs = self.generator.generate_fitness_certificates(train_id)
63
+ job_cards = self.generator.generate_job_cards(train_id) if self.include_job_cards else JobCards(open=0, blocking=[])
64
  branding = self.generator.generate_branding()
65
 
66
  readiness = self.generator.calculate_readiness_score(
DataService/synthetic_base.py CHANGED
@@ -281,8 +281,12 @@ class MetroSyntheticDataGenerator:
281
  }
282
  }
283
 
284
- def generate_complete_dataset(self) -> Dict:
285
- """Generate complete synthetic dataset for metro scheduling"""
 
 
 
 
286
  dataset = {
287
  "metadata": {
288
  "generated_at": datetime.now().isoformat(),
@@ -292,7 +296,7 @@ class MetroSyntheticDataGenerator:
292
  },
293
  "trainset_status": self.generate_trainset_status(),
294
  "fitness_certificates": self.generate_fitness_certificates(),
295
- "job_cards": self.generate_job_cards(),
296
  "component_health": self.generate_component_health(),
297
  "iot_sensors": self.generate_iot_sensors(),
298
  "branding_contracts": self.generate_branding_contracts(),
@@ -304,9 +308,14 @@ class MetroSyntheticDataGenerator:
304
  }
305
  return dataset
306
 
307
- def save_to_json(self, filename: str = "metro_synthetic_data.json"):
308
- """Save generated data to JSON file"""
309
- data = self.generate_complete_dataset()
 
 
 
 
 
310
  with open(filename, 'w') as f:
311
  json.dump(data, f, indent=2)
312
  print(f"Synthetic data generated and saved to {filename}")
 
281
  }
282
  }
283
 
284
+ def generate_complete_dataset(self, include_job_cards: bool = False) -> Dict:
285
+ """Generate complete synthetic dataset for metro scheduling.
286
+
287
+ Args:
288
+ include_job_cards: Whether to include job cards in the dataset. Default False.
289
+ """
290
  dataset = {
291
  "metadata": {
292
  "generated_at": datetime.now().isoformat(),
 
296
  },
297
  "trainset_status": self.generate_trainset_status(),
298
  "fitness_certificates": self.generate_fitness_certificates(),
299
+ "job_cards": self.generate_job_cards() if include_job_cards else [],
300
  "component_health": self.generate_component_health(),
301
  "iot_sensors": self.generate_iot_sensors(),
302
  "branding_contracts": self.generate_branding_contracts(),
 
308
  }
309
  return dataset
310
 
311
+ def save_to_json(self, filename: str = "metro_synthetic_data.json", include_job_cards: bool = False):
312
+ """Save generated data to JSON file.
313
+
314
+ Args:
315
+ filename: Output filename.
316
+ include_job_cards: Whether to include job cards in the dataset. Default False.
317
+ """
318
+ data = self.generate_complete_dataset(include_job_cards=include_job_cards)
319
  with open(filename, 'w') as f:
320
  json.dump(data, f, indent=2)
321
  print(f"Synthetic data generated and saved to {filename}")
api/greedyoptim_api.py CHANGED
@@ -104,7 +104,7 @@ class ScheduleOptimizationRequest(BaseModel):
104
  """Request for schedule optimization"""
105
  trainset_status: List[TrainsetStatusInput]
106
  fitness_certificates: List[FitnessCertificateInput]
107
- job_cards: List[JobCardInput]
108
  component_health: List[ComponentHealthInput]
109
 
110
  # Optional metadata
@@ -125,7 +125,7 @@ class CompareMethodsRequest(BaseModel):
125
  """Request to compare multiple optimization methods"""
126
  trainset_status: List[TrainsetStatusInput]
127
  fitness_certificates: List[FitnessCertificateInput]
128
- job_cards: List[JobCardInput]
129
  component_health: List[ComponentHealthInput]
130
 
131
  metadata: Optional[Dict[str, Any]] = None
@@ -181,7 +181,7 @@ def convert_pydantic_to_dict(request: ScheduleOptimizationRequest) -> Dict[str,
181
  data = {
182
  "trainset_status": [ts.dict() for ts in request.trainset_status],
183
  "fitness_certificates": [fc.dict() for fc in request.fitness_certificates],
184
- "job_cards": [jc.dict() for jc in request.job_cards],
185
  "component_health": [ch.dict() for ch in request.component_health],
186
  "metadata": request.metadata or {
187
  "generated_at": datetime.now().isoformat(),
 
104
  """Request for schedule optimization"""
105
  trainset_status: List[TrainsetStatusInput]
106
  fitness_certificates: List[FitnessCertificateInput]
107
+ job_cards: Optional[List[JobCardInput]] = Field(default_factory=list, description="Job cards are optional, defaults to empty list")
108
  component_health: List[ComponentHealthInput]
109
 
110
  # Optional metadata
 
125
  """Request to compare multiple optimization methods"""
126
  trainset_status: List[TrainsetStatusInput]
127
  fitness_certificates: List[FitnessCertificateInput]
128
+ job_cards: Optional[List[JobCardInput]] = Field(default_factory=list, description="Job cards are optional, defaults to empty list")
129
  component_health: List[ComponentHealthInput]
130
 
131
  metadata: Optional[Dict[str, Any]] = None
 
181
  data = {
182
  "trainset_status": [ts.dict() for ts in request.trainset_status],
183
  "fitness_certificates": [fc.dict() for fc in request.fitness_certificates],
184
+ "job_cards": [jc.dict() for jc in request.job_cards] if request.job_cards else [],
185
  "component_health": [ch.dict() for ch in request.component_health],
186
  "metadata": request.metadata or {
187
  "generated_at": datetime.now().isoformat(),
greedyOptim/error_handling.py CHANGED
@@ -54,8 +54,10 @@ class DataValidator:
54
  errors = []
55
 
56
  try:
57
- # Check required top-level keys
58
- required_keys = ['trainset_status', 'fitness_certificates', 'job_cards', 'component_health']
 
 
59
  for key in required_keys:
60
  if key not in data:
61
  errors.append(f"Missing required data section: {key}")
@@ -69,6 +71,15 @@ class DataValidator:
69
  section_errors = cls._validate_section(data[key], key)
70
  errors.extend(section_errors)
71
 
 
 
 
 
 
 
 
 
 
72
  # Cross-validation
73
  if not errors: # Only if basic structure is valid
74
  cross_errors = cls._cross_validate(data)
 
54
  errors = []
55
 
56
  try:
57
+ # Check required top-level keys (job_cards is now optional)
58
+ required_keys = ['trainset_status', 'fitness_certificates', 'component_health']
59
+ optional_keys = ['job_cards']
60
+
61
  for key in required_keys:
62
  if key not in data:
63
  errors.append(f"Missing required data section: {key}")
 
71
  section_errors = cls._validate_section(data[key], key)
72
  errors.extend(section_errors)
73
 
74
+ # Validate optional keys if present
75
+ for key in optional_keys:
76
+ if key in data and data[key]:
77
+ if not isinstance(data[key], list):
78
+ errors.append(f"Data section {key} must be a list")
79
+ continue
80
+ section_errors = cls._validate_section(data[key], key)
81
+ errors.extend(section_errors)
82
+
83
  # Cross-validation
84
  if not errors: # Only if basic structure is valid
85
  cross_errors = cls._cross_validate(data)
greedyOptim/evaluator.py CHANGED
@@ -33,9 +33,9 @@ class TrainsetSchedulingEvaluator:
33
  self.fitness_map[ts_id] = {}
34
  self.fitness_map[ts_id][cert['department']] = cert
35
 
36
- # Job cards by trainset
37
  self.job_map = {}
38
- for job in self.data['job_cards']:
39
  ts_id = job['trainset_id']
40
  if ts_id not in self.job_map:
41
  self.job_map[ts_id] = []
 
33
  self.fitness_map[ts_id] = {}
34
  self.fitness_map[ts_id][cert['department']] = cert
35
 
36
+ # Job cards by trainset (optional - may be empty)
37
  self.job_map = {}
38
+ for job in self.data.get('job_cards', []):
39
  ts_id = job['trainset_id']
40
  if ts_id not in self.job_map:
41
  self.job_map[ts_id] = []