File size: 13,906 Bytes
e7427b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
// MargYantra – Road Design Tool
// IRC standards-based calculations for superelevation, camber, and transition curves

interface RoadDesignInput {
  road_type: 'highway' | 'arterial' | 'collector' | 'local' | 'expressway';
  design_speed: number; // km/h
  curve_radius: number; // meters
  cross_slope: number; // percentage
  terrain: 'plain' | 'rolling' | 'mountainous';
  pavement_type: 'flexible' | 'rigid' | 'composite';
}

interface RoadDesignOutput {
  superelevation: number; // percentage
  camber: number; // percentage
  transition_length: number; // meters
  sight_distance: number; // meters
  widening_required: number; // meters
  banking_angle: number; // degrees
  design_considerations: string[];
  irc_references: string[];
  safety_warnings: string[];
  confidence: number;
}

class RoadDesignCalculator {
  private readonly MAX_SUPERELEVATION = 7.0; // IRC standard maximum
  private readonly MIN_CURVE_RADIUS = 30; // minimum for any road
  private readonly MAX_DESIGN_SPEED = 120; // km/h for highways

  // IRC standard values for different road types
  private roadStandards = new Map([
    ['highway', { 
      max_speed: 100, 
      min_radius: 230, 
      camber_flexible: 2.5, 
      camber_rigid: 2.0,
      lane_width: 3.5 
    }],
    ['arterial', { 
      max_speed: 80, 
      min_radius: 120, 
      camber_flexible: 2.5, 
      camber_rigid: 2.0,
      lane_width: 3.5 
    }],
    ['collector', { 
      max_speed: 65, 
      min_radius: 80, 
      camber_flexible: 3.0, 
      camber_rigid: 2.5,
      lane_width: 3.25 
    }],
    ['local', { 
      max_speed: 50, 
      min_radius: 50, 
      camber_flexible: 3.0, 
      camber_rigid: 2.5,
      lane_width: 3.0 
    }],
    ['expressway', { 
      max_speed: 120, 
      min_radius: 360, 
      camber_flexible: 2.0, 
      camber_rigid: 1.7,
      lane_width: 3.75 
    }]
  ]);

  calculateRoadDesign(input: RoadDesignInput): RoadDesignOutput {
    try {
      // Validate inputs
      this.validateInputs(input);

      const roadStd = this.roadStandards.get(input.road_type);
      if (!roadStd) {
        throw new Error(`Unknown road type: ${input.road_type}`);
      }

      // Calculate superelevation
      const superelevation = this.calculateSuperelevation(input.design_speed, input.curve_radius);
      
      // Determine camber
      const camber = this.calculateCamber(input.pavement_type, input.road_type);
      
      // Calculate transition curve length
      const transitionLength = this.calculateTransitionLength(input.design_speed, input.curve_radius, superelevation);
      
      // Calculate sight distance
      const sightDistance = this.calculateSightDistance(input.design_speed, input.curve_radius);
      
      // Calculate mechanical widening
      const widening = this.calculateWidening(input.curve_radius, roadStd.lane_width);
      
      // Convert superelevation to banking angle
      const bankingAngle = Math.atan(superelevation / 100) * (180 / Math.PI);

      // Generate design considerations and warnings
      const designConsiderations = this.getDesignConsiderations(input, superelevation, transitionLength);
      const safetyWarnings = this.getSafetyWarnings(input, superelevation, sightDistance);
      const ircReferences = this.getIRCReferences(input.road_type);

      // Calculate confidence based on design adequacy
      const confidence = this.calculateConfidence(input, superelevation, sightDistance);

      return {
        superelevation: Math.round(superelevation * 100) / 100,
        camber: camber,
        transition_length: Math.round(transitionLength),
        sight_distance: Math.round(sightDistance),
        widening_required: Math.round(widening * 100) / 100,
        banking_angle: Math.round(bankingAngle * 100) / 100,
        design_considerations: designConsiderations,
        irc_references: ircReferences,
        safety_warnings: safetyWarnings,
        confidence: confidence
      };

    } catch (error) {
      throw new Error(`Road design calculation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }

  private validateInputs(input: RoadDesignInput): void {
    if (!input.road_type || !this.roadStandards.has(input.road_type)) {
      throw new Error('Invalid road type. Must be one of: highway, arterial, collector, local, expressway');
    }

    if (!input.design_speed || input.design_speed <= 0 || input.design_speed > this.MAX_DESIGN_SPEED) {
      throw new Error(`Design speed must be between 1 and ${this.MAX_DESIGN_SPEED} km/h`);
    }

    if (!input.curve_radius || input.curve_radius < this.MIN_CURVE_RADIUS) {
      throw new Error(`Curve radius must be at least ${this.MIN_CURVE_RADIUS} meters`);
    }

    if (input.cross_slope !== undefined && (input.cross_slope < -10 || input.cross_slope > 10)) {
      throw new Error('Cross slope must be between -10% and +10%');
    }

    if (!input.terrain || !['plain', 'rolling', 'mountainous'].includes(input.terrain)) {
      throw new Error('Invalid terrain type. Must be one of: plain, rolling, mountainous');
    }

    if (!input.pavement_type || !['flexible', 'rigid', 'composite'].includes(input.pavement_type)) {
      throw new Error('Invalid pavement type. Must be one of: flexible, rigid, composite');
    }
  }

  private calculateSuperelevation(speed: number, radius: number): number {
    // IRC 73-1980 formula for superelevation
    // e = V²/(127R) - f, where f = lateral friction coefficient
    
    const lateralFriction = this.getLateralFrictionCoefficient(speed);
    const superelevation = (speed * speed) / (127 * radius) - lateralFriction;
    
    // Apply IRC limits
    if (superelevation < 0) return 0;
    if (superelevation > this.MAX_SUPERELEVATION) return this.MAX_SUPERELEVATION;
    
    return superelevation;
  }

  private getLateralFrictionCoefficient(speed: number): number {
    // IRC 73-1980 values for lateral friction
    if (speed <= 50) return 0.15;
    if (speed <= 65) return 0.14;
    if (speed <= 80) return 0.13;
    if (speed <= 100) return 0.12;
    return 0.10;
  }

  private calculateCamber(pavementType: string, roadType: string): number {
    const roadStd = this.roadStandards.get(roadType);
    if (!roadStd) return 2.5;

    switch (pavementType) {
      case 'flexible':
        return roadStd.camber_flexible;
      case 'rigid':
        return roadStd.camber_rigid;
      case 'composite':
        return (roadStd.camber_flexible + roadStd.camber_rigid) / 2;
      default:
        return 2.5;
    }
  }

  private calculateTransitionLength(speed: number, radius: number, superelevation: number): number {
    // IRC 73-1980 formula for transition curve length
    // L = 0.0215 * V³ / R (minimum formula)
    // Also consider superelevation development length
    
    const minLength = (0.0215 * speed * speed * speed) / radius;
    const superelevationLength = speed * superelevation / 0.5; // 0.5% per meter development rate
    
    return Math.max(minLength, superelevationLength, 30); // minimum 30m
  }

  private calculateSightDistance(speed: number, radius: number): number {
    // IRC SP 73-2018 stopping sight distance
    const reactionTime = 2.5; // seconds
    const brakingEfficiency = 0.35; // for wet roads
    const grade = 0; // assuming level road
    
    const reactionDistance = (speed * 1000 / 3600) * reactionTime;
    const brakingDistance = (speed * speed) / (254 * (brakingEfficiency + grade / 100));
    
    const stoppingSightDistance = reactionDistance + brakingDistance;
    
    // Check if horizontal curve affects sight distance
    const availableSightDistance = this.calculateHorizontalSightDistance(radius);
    
    return Math.min(stoppingSightDistance, availableSightDistance);
  }

  private calculateHorizontalSightDistance(radius: number): number {
    // For horizontal curves, sight distance is limited by curve geometry
    const middleOrdinate = 1.5; // typical clearance from centerline
    return 2 * Math.sqrt(2 * radius * middleOrdinate - middleOrdinate * middleOrdinate);
  }

  private calculateWidening(radius: number, laneWidth: number): number {
    // IRC SP 73-2018 mechanical widening formula
    const vehicleLength = 6; // meters (design vehicle)
    const wheelBase = 3.5; // meters
    
    const widening = (vehicleLength * vehicleLength) / (2 * radius) + (wheelBase * wheelBase) / (2 * radius);
    
    return Math.max(0, widening);
  }

  private getDesignConsiderations(input: RoadDesignInput, superelevation: number, transitionLength: number): string[] {
    const considerations: string[] = [];
    
    if (superelevation > 5.0) {
      considerations.push('High superelevation - ensure proper drainage design');
    }
    
    if (transitionLength > 200) {
      considerations.push('Long transition curve - check for adequate sight distance');
    }
    
    if (input.terrain === 'mountainous') {
      considerations.push('Mountainous terrain - consider additional safety measures and escape ramps');
    }
    
    if (input.design_speed > 80) {
      considerations.push('High speed design - implement enhanced safety features');
    }
    
    considerations.push('Ensure proper signage and pavement markings as per IRC 35');
    considerations.push('Consider weather conditions and seasonal variations');
    
    return considerations;
  }

  private getSafetyWarnings(input: RoadDesignInput, superelevation: number, sightDistance: number): string[] {
    const warnings: string[] = [];
    const roadStd = this.roadStandards.get(input.road_type);
    
    if (input.curve_radius < (roadStd?.min_radius || 100)) {
      warnings.push(`Curve radius below recommended minimum for ${input.road_type} roads`);
    }
    
    if (superelevation === this.MAX_SUPERELEVATION) {
      warnings.push('Maximum superelevation reached - consider increasing curve radius');
    }
    
    if (sightDistance < this.getMinimumSightDistance(input.design_speed)) {
      warnings.push('Inadequate sight distance - reduce design speed or increase radius');
    }
    
    if (input.design_speed > (roadStd?.max_speed || 50)) {
      warnings.push('Design speed exceeds recommended maximum for this road type');
    }
    
    return warnings;
  }

  private getMinimumSightDistance(speed: number): number {
    // IRC minimum sight distance requirements
    return speed * 2; // simplified minimum requirement
  }

  private getIRCReferences(roadType: string): string[] {
    const references = [
      'IRC 73-1980: Geometric Design Standards for Rural Highways',
      'IRC SP 73-2018: Manual of Specifications & Standards for Four Laning of Highways',
      'IRC 35-2015: Code of Practice for Road Markings',
      'IRC 103-2012: Guidelines for Pedestrian Facilities'
    ];
    
    if (roadType === 'expressway') {
      references.push('IRC 5-2015: Standard Specifications and Code of Practice for Road Bridges');
    }
    
    return references;
  }

  private calculateConfidence(input: RoadDesignInput, superelevation: number, sightDistance: number): number {
    let confidence = 90;
    
    const roadStd = this.roadStandards.get(input.road_type);
    
    // Reduce confidence for edge cases
    if (input.curve_radius < (roadStd?.min_radius || 100) * 1.2) {
      confidence -= 15;
    }
    
    if (superelevation > 6.0) {
      confidence -= 10;
    }
    
    if (sightDistance < this.getMinimumSightDistance(input.design_speed) * 1.1) {
      confidence -= 20;
    }
    
    return Math.max(50, confidence);
  }

  // Helper method to get design speed recommendations
  getDesignSpeedRecommendations(): Record<string, { recommended: number; maximum: number }> {
    return {
      'expressway': { recommended: 100, maximum: 120 },
      'highway': { recommended: 80, maximum: 100 },
      'arterial': { recommended: 65, maximum: 80 },
      'collector': { recommended: 50, maximum: 65 },
      'local': { recommended: 40, maximum: 50 }
    };
  }

  // Method to check design adequacy
  checkDesignAdequacy(input: RoadDesignInput): { adequate: boolean; issues: string[] } {
    const issues: string[] = [];
    const roadStd = this.roadStandards.get(input.road_type);
    
    if (!roadStd) {
      return { adequate: false, issues: ['Invalid road type'] };
    }
    
    if (input.design_speed > roadStd.max_speed) {
      issues.push(`Design speed exceeds maximum for ${input.road_type} (${roadStd.max_speed} km/h)`);
    }
    
    if (input.curve_radius < roadStd.min_radius) {
      issues.push(`Curve radius below minimum for ${input.road_type} (${roadStd.min_radius}m)`);
    }
    
    return {
      adequate: issues.length === 0,
      issues
    };
  }

  // Generate detailed design report
  generateDesignReport(input: RoadDesignInput, output: RoadDesignOutput): string {
    return `
ROAD GEOMETRIC DESIGN REPORT
===========================

INPUT PARAMETERS:
- Road Type: ${input.road_type}
- Design Speed: ${input.design_speed} km/h
- Curve Radius: ${input.curve_radius} m
- Cross Slope: ${input.cross_slope}%
- Terrain: ${input.terrain}
- Pavement Type: ${input.pavement_type}

DESIGN RESULTS:
- Superelevation: ${output.superelevation}%
- Camber: ${output.camber}%
- Transition Length: ${output.transition_length} m
- Sight Distance: ${output.sight_distance} m
- Widening Required: ${output.widening_required} m
- Banking Angle: ${output.banking_angle}°

DESIGN CONSIDERATIONS:
${output.design_considerations.map(c => `- ${c}`).join('\n')}

SAFETY WARNINGS:
${output.safety_warnings.map(w => `- ${w}`).join('\n')}

IRC REFERENCES:
${output.irc_references.map(ref => `- ${ref}`).join('\n')}

Design Confidence: ${output.confidence}%

Generated by Prithvi Guardian AI - MargYantra Module
Date: ${new Date().toLocaleDateString('en-IN')}
`;
  }
}

export const roadDesignCalculator = new RoadDesignCalculator();
export { RoadDesignInput, RoadDesignOutput };