Skip to main content

05 - Implementation Guide

Technical implementation details for CAD integration


Prerequisites

Dependencies

# 3D rendering
npm install three @react-three/fiber @react-three/drei

# Already installed (verify)
# - React 18+
# - TypeScript
# - Tailwind CSS
# - shadcn/ui components

Existing Code to Reuse

// ML API hooks (already exist)
import { useReusabilityPrediction, useTreatmentRecommendation } from "@/lib/ml-api/hooks";

// Types (already exist)
import { TreatmentInput, WastewaterInput, TreatmentResult, ReusabilityResult } from "@/lib/ml-api/types";

// UI components (already exist)
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";

File Structure

src/
├── app/(core)/cad-integration/
│ ├── page.tsx # Main page component
│ ├── layout.tsx # Optional layout
│ └── components/
│ ├── WTPModel3D.tsx # 3D water treatment plant
│ ├── ComponentInfoPanel.tsx # Selected component info
│ ├── ParameterForm.tsx # Input form
│ ├── ModelSelector.tsx # Model tabs
│ ├── ResultsPanel.tsx # Results display
│ └── ComponentTooltip.tsx # Hover tooltip

├── lib/cad-integration/
│ ├── types.ts # Type definitions
│ ├── components-data.ts # Component metadata store
│ ├── metadata-mapper.ts # Metadata to input mapping
│ └── constants.ts # Constants and configs

└── hooks/
└── useCADIntegration.ts # State management hook

Step 1: Type Definitions

lib/cad-integration/types.ts

import { TreatmentInput, WastewaterInput } from "@/lib/ml-api/types";

// Component types in the WTP
export type WTPComponentType =
| "inlet"
| "screening"
| "grit_chamber"
| "primary_clarifier"
| "aeration_tank"
| "secondary_clarifier"
| "filtration"
| "disinfection"
| "outlet"
| "sludge_thickener"
| "sludge_digester";

// Water quality parameters at a specific stage
export interface WaterQualityMetadata {
pH: number;
TSS: number;
Turbidity: number;
BOD: number;
COD: number;
NH4_N: number;
Total_Nitrogen: number;
Phosphate: number;
Fecal_Coliform: number;
Oil_Grease: number;
TDS: number;
Heavy_Metals: number;
}

// Operational parameters
export interface OperationalMetadata {
flow_rate: number;
aeration_rate?: number;
chemical_dose?: number;
sludge_recycle_rate?: number;
retention_time?: number;
temperature?: number;
}

// Complete component metadata
export interface ComponentMetadata {
id: string;
name: string;
type: WTPComponentType;
position: [number, number, number];
rotation: [number, number, number];
scale: [number, number, number];
color: string;
highlightColor: string;
description: string;
processDescription: string;
waterQuality: WaterQualityMetadata;
operational: OperationalMetadata;
}

// Model selection
export type ModelType = "prediction" | "treatment" | "twin-engine";

// CAD integration state
export interface CADIntegrationState {
selectedComponent: string | null;
hoveredComponent: string | null;
selectedModel: ModelType;
treatmentInput: TreatmentInput;
reusabilityInput: WastewaterInput;
isLoading: boolean;
error: string | null;
}

// Pipe connection
export interface PipeConnection {
from: string;
to: string;
type: "main" | "sludge" | "return";
color: string;
}

Step 2: Component Metadata Store

lib/cad-integration/components-data.ts

import { ComponentMetadata, PipeConnection } from "./types";

export const componentMetadataStore: Record<string, ComponentMetadata> = {
inlet: {
id: "inlet",
name: "Raw Water Inlet",
type: "inlet",
position: [-15, 0, 0],
rotation: [0, 0, Math.PI / 2],
scale: [1, 1, 1],
color: "#8B4513",
highlightColor: "#D2691E",
description: "Raw wastewater entry point",
processDescription: "Untreated wastewater enters the treatment plant here",
waterQuality: {
pH: 6.8,
TSS: 250,
Turbidity: 150,
BOD: 300,
COD: 600,
NH4_N: 35,
Total_Nitrogen: 50,
Phosphate: 12,
Fecal_Coliform: 100000,
Oil_Grease: 50,
TDS: 800,
Heavy_Metals: 1.5,
},
operational: {
flow_rate: 1000,
temperature: 25,
},
},

screening: {
id: "screening",
name: "Screening Unit",
type: "screening",
position: [-11, 0, 0],
rotation: [0, 0, 0],
scale: [1, 1, 1],
color: "#696969",
highlightColor: "#A9A9A9",
description: "Coarse solids removal",
processDescription: "Removes large debris, rags, and floating materials",
waterQuality: {
pH: 6.8,
TSS: 230,
Turbidity: 140,
BOD: 290,
COD: 580,
NH4_N: 35,
Total_Nitrogen: 50,
Phosphate: 12,
Fecal_Coliform: 95000,
Oil_Grease: 45,
TDS: 790,
Heavy_Metals: 1.4,
},
operational: {
flow_rate: 1000,
temperature: 25,
},
},

grit_chamber: {
id: "grit_chamber",
name: "Grit Chamber",
type: "grit_chamber",
position: [-6, 0, 0],
rotation: [0, 0, 0],
scale: [1.5, 1, 1],
color: "#808080",
highlightColor: "#C0C0C0",
description: "Sand and grit removal",
processDescription: "Removes sand, gravel, and heavy inorganic particles",
waterQuality: {
pH: 6.9,
TSS: 200,
Turbidity: 120,
BOD: 280,
COD: 560,
NH4_N: 34,
Total_Nitrogen: 48,
Phosphate: 11,
Fecal_Coliform: 90000,
Oil_Grease: 40,
TDS: 780,
Heavy_Metals: 1.2,
},
operational: {
flow_rate: 1000,
retention_time: 0.5,
temperature: 25,
},
},

primary_clarifier: {
id: "primary_clarifier",
name: "Primary Clarifier",
type: "primary_clarifier",
position: [0, 0, 0],
rotation: [0, 0, 0],
scale: [2, 1.5, 2],
color: "#4682B4",
highlightColor: "#87CEEB",
description: "Primary sedimentation tank",
processDescription: "Settles suspended solids through gravity separation",
waterQuality: {
pH: 7.0,
TSS: 120,
Turbidity: 80,
BOD: 200,
COD: 400,
NH4_N: 32,
Total_Nitrogen: 45,
Phosphate: 10,
Fecal_Coliform: 70000,
Oil_Grease: 25,
TDS: 750,
Heavy_Metals: 1.0,
},
operational: {
flow_rate: 1000,
retention_time: 2,
sludge_recycle_rate: 0,
temperature: 24,
},
},

aeration_tank: {
id: "aeration_tank",
name: "Aeration Tank",
type: "aeration_tank",
position: [7, 0, 0],
rotation: [0, 0, 0],
scale: [3, 1.5, 2],
color: "#20B2AA",
highlightColor: "#48D1CC",
description: "Biological treatment zone",
processDescription: "Aerobic bacteria break down organic matter",
waterQuality: {
pH: 7.2,
TSS: 150,
Turbidity: 60,
BOD: 80,
COD: 180,
NH4_N: 15,
Total_Nitrogen: 30,
Phosphate: 6,
Fecal_Coliform: 40000,
Oil_Grease: 10,
TDS: 700,
Heavy_Metals: 0.8,
},
operational: {
flow_rate: 1000,
aeration_rate: 50,
retention_time: 6,
sludge_recycle_rate: 25,
temperature: 22,
},
},

secondary_clarifier: {
id: "secondary_clarifier",
name: "Secondary Clarifier",
type: "secondary_clarifier",
position: [14, 0, 0],
rotation: [0, 0, 0],
scale: [2, 1.5, 2],
color: "#5F9EA0",
highlightColor: "#7FFFD4",
description: "Secondary sedimentation",
processDescription: "Settles biological floc from aeration tank",
waterQuality: {
pH: 7.3,
TSS: 40,
Turbidity: 25,
BOD: 30,
COD: 80,
NH4_N: 10,
Total_Nitrogen: 20,
Phosphate: 4,
Fecal_Coliform: 20000,
Oil_Grease: 5,
TDS: 650,
Heavy_Metals: 0.5,
},
operational: {
flow_rate: 1000,
retention_time: 3,
sludge_recycle_rate: 30,
temperature: 22,
},
},

filtration: {
id: "filtration",
name: "Filtration Unit",
type: "filtration",
position: [14, 0, -6],
rotation: [0, 0, 0],
scale: [1.5, 1, 1.5],
color: "#DEB887",
highlightColor: "#F5DEB3",
description: "Tertiary filtration",
processDescription: "Sand/media filtration removes remaining particles",
waterQuality: {
pH: 7.4,
TSS: 10,
Turbidity: 5,
BOD: 15,
COD: 40,
NH4_N: 5,
Total_Nitrogen: 12,
Phosphate: 2,
Fecal_Coliform: 5000,
Oil_Grease: 2,
TDS: 600,
Heavy_Metals: 0.3,
},
operational: {
flow_rate: 1000,
retention_time: 0.5,
temperature: 21,
},
},

disinfection: {
id: "disinfection",
name: "Disinfection Unit",
type: "disinfection",
position: [7, 0, -6],
rotation: [0, 0, 0],
scale: [1, 1, 1],
color: "#FFD700",
highlightColor: "#FFFF00",
description: "Chlorination/UV treatment",
processDescription: "Kills pathogens using chlorine or UV light",
waterQuality: {
pH: 7.5,
TSS: 8,
Turbidity: 3,
BOD: 10,
COD: 30,
NH4_N: 3,
Total_Nitrogen: 10,
Phosphate: 1.5,
Fecal_Coliform: 100,
Oil_Grease: 1,
TDS: 580,
Heavy_Metals: 0.2,
},
operational: {
flow_rate: 1000,
chemical_dose: 5,
retention_time: 0.5,
temperature: 21,
},
},

outlet: {
id: "outlet",
name: "Treated Water Outlet",
type: "outlet",
position: [0, 0, -6],
rotation: [0, 0, Math.PI / 2],
scale: [1, 1, 1],
color: "#00CED1",
highlightColor: "#00FFFF",
description: "Final effluent discharge",
processDescription: "Treated water ready for discharge or reuse",
waterQuality: {
pH: 7.5,
TSS: 5,
Turbidity: 2,
BOD: 8,
COD: 25,
NH4_N: 2,
Total_Nitrogen: 8,
Phosphate: 1,
Fecal_Coliform: 50,
Oil_Grease: 0.5,
TDS: 550,
Heavy_Metals: 0.1,
},
operational: {
flow_rate: 950,
temperature: 20,
},
},
};

export const pipeConnections: PipeConnection[] = [
{ from: "inlet", to: "screening", type: "main", color: "#8B4513" },
{ from: "screening", to: "grit_chamber", type: "main", color: "#8B4513" },
{ from: "grit_chamber", to: "primary_clarifier", type: "main", color: "#4682B4" },
{ from: "primary_clarifier", to: "aeration_tank", type: "main", color: "#4682B4" },
{ from: "aeration_tank", to: "secondary_clarifier", type: "main", color: "#20B2AA" },
{ from: "secondary_clarifier", to: "filtration", type: "main", color: "#5F9EA0" },
{ from: "filtration", to: "disinfection", type: "main", color: "#DEB887" },
{ from: "disinfection", to: "outlet", type: "main", color: "#00CED1" },
];

export const componentList = Object.values(componentMetadataStore);

Step 3: Metadata Mapper

lib/cad-integration/metadata-mapper.ts

import { TreatmentInput, WastewaterInput } from "@/lib/ml-api/types";
import { ComponentMetadata } from "./types";

/**
* Maps component metadata to TreatmentInput
*/
export function mapToTreatmentInput(metadata: ComponentMetadata): TreatmentInput {
const { waterQuality, operational } = metadata;

return {
pH: waterQuality.pH,
TSS: waterQuality.TSS,
Turbidity: waterQuality.Turbidity,
BOD: waterQuality.BOD,
COD: waterQuality.COD,
NH4_N: waterQuality.NH4_N,
Total_Nitrogen: waterQuality.Total_Nitrogen,
Phosphate: waterQuality.Phosphate,
Fecal_Coliform: waterQuality.Fecal_Coliform,
Oil_Grease: waterQuality.Oil_Grease,
TDS: waterQuality.TDS,
Heavy_Metals: waterQuality.Heavy_Metals,
flow_rate: operational.flow_rate,
};
}

/**
* Maps component metadata to WastewaterInput
*/
export function mapToWastewaterInput(metadata: ComponentMetadata): WastewaterInput {
const { waterQuality, operational } = metadata;

return {
flow_rate: operational.flow_rate,
influent_BOD: waterQuality.BOD,
influent_COD: waterQuality.COD,
influent_TSS: waterQuality.TSS,
influent_pH: waterQuality.pH,
influent_TDS: waterQuality.TDS,
aeration_rate: operational.aeration_rate,
chemical_dose: operational.chemical_dose,
sludge_recycle_rate: operational.sludge_recycle_rate,
retention_time: operational.retention_time,
temperature: operational.temperature,
};
}

/**
* Default empty TreatmentInput
*/
export const defaultTreatmentInput: TreatmentInput = {
pH: 7,
TSS: 0,
Turbidity: 0,
BOD: 0,
COD: 0,
NH4_N: 0,
Total_Nitrogen: 0,
Phosphate: 0,
Fecal_Coliform: 0,
Oil_Grease: 0,
TDS: 0,
Heavy_Metals: 0,
};

/**
* Default empty WastewaterInput
*/
export const defaultWastewaterInput: WastewaterInput = {
flow_rate: 0,
influent_BOD: 0,
influent_COD: 0,
influent_TSS: 0,
influent_pH: 7,
influent_TDS: 0,
};

Step 4: State Management Hook

hooks/useCADIntegration.ts

"use client";

import { useState, useCallback } from "react";
import { TreatmentInput, WastewaterInput, TreatmentResult, ReusabilityResult } from "@/lib/ml-api/types";
import { useReusabilityPrediction, useTreatmentRecommendation } from "@/lib/ml-api/hooks";
import { componentMetadataStore } from "@/lib/cad-integration/components-data";
import { mapToTreatmentInput, mapToWastewaterInput, defaultTreatmentInput, defaultWastewaterInput } from "@/lib/cad-integration/metadata-mapper";
import { ModelType } from "@/lib/cad-integration/types";

export function useCADIntegration() {
// Selection state
const [selectedComponent, setSelectedComponent] = useState<string | null>(null);
const [hoveredComponent, setHoveredComponent] = useState<string | null>(null);

// Model selection
const [selectedModel, setSelectedModel] = useState<ModelType>("treatment");

// Input parameters
const [treatmentInput, setTreatmentInput] = useState<TreatmentInput>(defaultTreatmentInput);
const [reusabilityInput, setReusabilityInput] = useState<WastewaterInput>(defaultWastewaterInput);

// Results
const [predictionResult, setPredictionResult] = useState<ReusabilityResult | null>(null);
const [treatmentResult, setTreatmentResult] = useState<TreatmentResult | null>(null);

// ML hooks
const { predict: predictReusability, isLoading: reusabilityLoading, error: reusabilityError, reset: resetReusability } = useReusabilityPrediction();

const { recommend: recommendTreatment, isLoading: treatmentLoading, error: treatmentError, reset: resetTreatment } = useTreatmentRecommendation();

const isLoading = reusabilityLoading || treatmentLoading;
const error = reusabilityError || treatmentError;

// Get selected component metadata
const selectedMetadata = selectedComponent ? componentMetadataStore[selectedComponent] : null;

// Handle component selection
const handleComponentSelect = useCallback((componentId: string) => {
setSelectedComponent(componentId);
}, []);

// Handle component hover
const handleComponentHover = useCallback((componentId: string | null) => {
setHoveredComponent(componentId);
}, []);

// Fetch parameters from selected component
const fetchParameters = useCallback(() => {
if (!selectedMetadata) return;

setTreatmentInput(mapToTreatmentInput(selectedMetadata));
setReusabilityInput(mapToWastewaterInput(selectedMetadata));
}, [selectedMetadata]);

// Run selected model
const runModel = useCallback(async () => {
try {
switch (selectedModel) {
case "prediction":
const reusability = await predictReusability(reusabilityInput);
setPredictionResult(reusability);
break;

case "treatment":
const treatment = await recommendTreatment(treatmentInput);
setTreatmentResult(treatment);
break;

case "twin-engine":
const [reusabilityRes, treatmentRes] = await Promise.all([predictReusability(reusabilityInput), recommendTreatment(treatmentInput)]);
setPredictionResult(reusabilityRes);
setTreatmentResult(treatmentRes);
break;
}
} catch (err) {
console.error("Model run failed:", err);
}
}, [selectedModel, treatmentInput, reusabilityInput, predictReusability, recommendTreatment]);

// Reset all state
const reset = useCallback(() => {
setSelectedComponent(null);
setTreatmentInput(defaultTreatmentInput);
setReusabilityInput(defaultWastewaterInput);
setPredictionResult(null);
setTreatmentResult(null);
resetReusability();
resetTreatment();
}, [resetReusability, resetTreatment]);

return {
// Selection
selectedComponent,
hoveredComponent,
selectedMetadata,
handleComponentSelect,
handleComponentHover,

// Model
selectedModel,
setSelectedModel,

// Input
treatmentInput,
setTreatmentInput,
reusabilityInput,
setReusabilityInput,
fetchParameters,

// Results
predictionResult,
treatmentResult,

// Actions
runModel,
reset,

// State
isLoading,
error,
};
}

Step 5: Main Page Component

app/(core)/cad-integration/page.tsx

"use client";

import { Suspense } from "react";
import dynamic from "next/dynamic";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { Loader2, Download, Play, RotateCcw } from "lucide-react";
import { useCADIntegration } from "@/hooks/useCADIntegration";
import { ComponentInfoPanel } from "./components/ComponentInfoPanel";
import { ParameterForm } from "./components/ParameterForm";
import { ResultsPanel } from "./components/ResultsPanel";
import { ModelType } from "@/lib/cad-integration/types";

// Dynamic import for 3D component (no SSR)
const WTPModel3D = dynamic(() => import("./components/WTPModel3D"), {
ssr: false,
loading: () => (
<div className="flex items-center justify-center h-[400px] bg-muted rounded-lg">
<Loader2 className="w-8 h-8 animate-spin" />
</div>
),
});

export default function CADIntegrationPage() {
const {
selectedComponent,
hoveredComponent,
selectedMetadata,
handleComponentSelect,
handleComponentHover,
selectedModel,
setSelectedModel,
treatmentInput,
setTreatmentInput,
reusabilityInput,
setReusabilityInput,
fetchParameters,
predictionResult,
treatmentResult,
runModel,
reset,
isLoading,
error,
} = useCADIntegration();

const hasResults = predictionResult || treatmentResult;

return (
<div className="container mx-auto py-6 space-y-6">
{/* Header */}
<div>
<h1 className="text-3xl font-bold">CAD Integration</h1>
<p className="text-muted-foreground">Interactive Water Treatment Plant Model with ML Predictions</p>
</div>

{/* Main Content */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* 3D Viewport */}
<div className="lg:col-span-2">
<Card>
<CardHeader>
<CardTitle>Water Treatment Plant</CardTitle>
<CardDescription>Click on a component to select it and view its parameters</CardDescription>
</CardHeader>
<CardContent>
<div className="h-[400px] rounded-lg overflow-hidden">
<Suspense fallback={<div className="h-full bg-muted animate-pulse" />}>
<WTPModel3D
selectedComponent={selectedComponent}
hoveredComponent={hoveredComponent}
onComponentSelect={handleComponentSelect}
onComponentHover={handleComponentHover}
/>
</Suspense>
</div>
</CardContent>
</Card>
</div>

{/* Component Info Panel */}
<div>
<ComponentInfoPanel metadata={selectedMetadata} onFetch={fetchParameters} />
</div>
</div>

{/* Model Selection */}
<Card>
<CardHeader>
<CardTitle>Select Model</CardTitle>
<CardDescription>Choose which ML model to run on the fetched parameters</CardDescription>
</CardHeader>
<CardContent>
<Tabs value={selectedModel} onValueChange={(v) => setSelectedModel(v as ModelType)}>
<TabsList className="grid w-full grid-cols-3">
<TabsTrigger value="prediction">Prediction Model</TabsTrigger>
<TabsTrigger value="treatment">Treatment Model</TabsTrigger>
<TabsTrigger value="twin-engine">Twin Engine</TabsTrigger>
</TabsList>

<TabsContent value="prediction" className="mt-4">
<p className="text-sm text-muted-foreground">
Predicts the reusability class of water based on quality parameters. Output includes confidence score and CPCB compliance status.
</p>
</TabsContent>

<TabsContent value="treatment" className="mt-4">
<p className="text-sm text-muted-foreground">
Recommends treatment stage (Primary, Secondary, Tertiary, Advanced) with detailed steps and chemical suggestions.
</p>
</TabsContent>

<TabsContent value="twin-engine" className="mt-4">
<p className="text-sm text-muted-foreground">
Runs both models for comprehensive analysis. Provides reusability prediction and treatment recommendations together.
</p>
</TabsContent>
</Tabs>
</CardContent>
</Card>

{/* Input Form & Results */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Parameter Form */}
<ParameterForm
selectedModel={selectedModel}
treatmentInput={treatmentInput}
reusabilityInput={reusabilityInput}
onTreatmentChange={setTreatmentInput}
onReusabilityChange={setReusabilityInput}
/>

{/* Results Panel */}
<ResultsPanel
selectedModel={selectedModel}
predictionResult={predictionResult}
treatmentResult={treatmentResult}
isLoading={isLoading}
error={error}
/>
</div>

{/* Action Buttons */}
<div className="flex gap-4">
<Button onClick={runModel} disabled={isLoading || !selectedComponent} className="flex-1">
{isLoading ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
Running...
</>
) : (
<>
<Play className="w-4 h-4 mr-2" />
Run {selectedModel === "twin-engine" ? "Twin Engine" : selectedModel === "prediction" ? "Prediction" : "Treatment"} Model
</>
)}
</Button>

<Button variant="outline" onClick={reset}>
<RotateCcw className="w-4 h-4 mr-2" />
Reset
</Button>
</div>

{/* Error Display */}
{error && (
<Card className="border-destructive">
<CardContent className="pt-6">
<p className="text-destructive">{error}</p>
</CardContent>
</Card>
)}
</div>
);
}

Next Steps After Documentation

  1. Review this documentation with the team
  2. Create the file structure as outlined
  3. Implement components one by one
  4. Test with sample component selections
  5. Integrate with existing ML API

Estimated Implementation Time

TaskTime
Type definitions30 min
Component metadata1 hour
3D WTP model2 hours
State management hook1 hour
UI components2 hours
Integration & testing2 hours
Total8-9 hours

Document Version: 1.0
Last Updated: December 2024