alterzick's picture
undefined - Initial Deployment
430c0fe verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Well Injection Pair Analysis Simulator - Duri Field</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<style>
#map { height: 500px; }
.chart-container {
width: 100%;
height: 400px;
position: relative;
}
.well-icon {
background-size: contain;
background-repeat: no-repeat;
border-radius: 50%;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 10px;
}
.production-well {
background-color: #3b82f6;
}
.injection-well {
background-color: #ef4444;
}
.connection-line {
stroke-dasharray: 5, 5;
}
.tooltip {
position: absolute;
padding: 8px;
background: rgba(0, 0, 0, 0.8);
color: white;
border-radius: 4px;
pointer-events: none;
font-size: 12px;
z-index: 1000;
}
</style>
</head>
<body class="bg-gray-100">
<div class="container mx-auto px-4 py-8">
<header class="mb-8">
<h1 class="text-3xl font-bold text-blue-800">Well Injection Pair Analysis Simulator</h1>
<h2 class="text-xl text-gray-600">Duri Field, Riau - Sumatra</h2>
<p class="mt-2 text-gray-700">Simulate injection well impacts on production wells in the same zone</p>
</header>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Control Panel -->
<div class="bg-white p-6 rounded-lg shadow-md col-span-1">
<h3 class="text-xl font-semibold mb-4 text-blue-700">Simulation Parameters</h3>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Number of Production Wells</label>
<input type="number" id="prodWellCount" min="1" max="20" value="5"
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Number of Injection Wells</label>
<input type="number" id="injWellCount" min="1" max="10" value="3"
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Maximum Distance (meters)</label>
<input type="number" id="maxDistance" min="100" max="5000" value="2000" step="100"
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Injection Rate (bbl/day)</label>
<input type="number" id="injectionRate" min="100" max="10000" value="2000" step="100"
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-1">Simulation Duration (days)</label>
<input type="number" id="simDuration" min="30" max="365" value="90" step="10"
class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500">
</div>
<button id="runSimulation" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Run Simulation
</button>
<button id="resetSimulation" class="w-full mt-2 bg-gray-500 hover:bg-gray-600 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Reset
</button>
</div>
<!-- Map and Results -->
<div class="bg-white p-6 rounded-lg shadow-md col-span-2">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-semibold text-blue-700">Field Map & Simulation Results</h3>
<div class="flex space-x-2">
<button id="showConnections" class="bg-green-500 hover:bg-green-600 text-white text-sm py-1 px-2 rounded">
Show Connections
</button>
<button id="exportData" class="bg-purple-500 hover:bg-purple-600 text-white text-sm py-1 px-2 rounded">
Export Data
</button>
</div>
</div>
<div id="map" class="mb-6 rounded-lg overflow-hidden"></div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="bg-gray-50 p-4 rounded-lg">
<h4 class="font-medium text-gray-800 mb-2">Production Well Impact Summary</h4>
<div id="prodWellSummary" class="text-sm">
<p class="text-gray-600">Run simulation to see results</p>
</div>
</div>
<div class="bg-gray-50 p-4 rounded-lg">
<h4 class="font-medium text-gray-800 mb-2">Injection Well Contribution</h4>
<div id="injWellSummary" class="text-sm">
<p class="text-gray-600">Run simulation to see results</p>
</div>
</div>
</div>
<div class="mt-4">
<h4 class="font-medium text-gray-800 mb-2">Pressure & Production Impact Chart</h4>
<div id="chartContainer" class="chart-container">
<canvas id="impactChart"></canvas>
</div>
</div>
</div>
</div>
<div class="mt-8 bg-white p-6 rounded-lg shadow-md">
<h3 class="text-xl font-semibold mb-4 text-blue-700">Pair Analysis Details</h3>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Production Well</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Injection Well</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Distance (m)</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Pressure Impact (psi)</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Prod. Rate Change (%)</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Water Cut Change (%)</th>
</tr>
</thead>
<tbody id="pairAnalysisTable" class="bg-white divide-y divide-gray-200">
<tr>
<td colspan="6" class="px-6 py-4 text-center text-sm text-gray-500">No simulation data available</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="mt-8 bg-white p-6 rounded-lg shadow-md">
<h3 class="text-xl font-semibold mb-4 text-blue-700">Mitigation Recommendations</h3>
<div id="mitigationRecommendations" class="space-y-3 text-gray-700">
<p>Based on the simulation results, recommendations will appear here for optimizing injection patterns and mitigating negative impacts on production wells.</p>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
// Initialize map centered on Duri, Riau
const map = L.map('map').setView([1.421, 101.252], 12);
// Add base map layer
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
// Add satellite imagery option
const satelliteLayer = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles &copy; Esri &mdash; Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
});
// Add base map layer control
const baseLayers = {
"Street Map": L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'),
"Satellite": satelliteLayer
};
L.control.layers(baseLayers, null, {position: 'topright'}).addTo(map);
// Initialize variables
let productionWells = [];
let injectionWells = [];
let connections = [];
let impactChart = null;
let tooltip = null;
// DOM elements
const runSimulationBtn = document.getElementById('runSimulation');
const resetSimulationBtn = document.getElementById('resetSimulation');
const showConnectionsBtn = document.getElementById('showConnections');
const exportDataBtn = document.getElementById('exportData');
// Event listeners
runSimulationBtn.addEventListener('click', runSimulation);
resetSimulationBtn.addEventListener('click', resetSimulation);
showConnectionsBtn.addEventListener('click', toggleConnections);
exportDataBtn.addEventListener('click', exportData);
// Initialize tooltip
tooltip = document.createElement('div');
tooltip.className = 'tooltip hidden';
document.body.appendChild(tooltip);
// Create initial wells (for demo purposes)
createInitialWells();
// Functions
function createInitialWells() {
// Clear existing wells
productionWells = [];
injectionWells = [];
// Get counts from inputs
const prodCount = parseInt(document.getElementById('prodWellCount').value);
const injCount = parseInt(document.getElementById('injWellCount').value);
// Create production wells
for (let i = 0; i < prodCount; i++) {
const lat = 1.421 + (Math.random() * 0.04 - 0.02);
const lng = 101.252 + (Math.random() * 0.04 - 0.02);
const well = {
id: `P-${i+1}`,
name: `PROD-${i+1}`,
type: 'production',
lat: lat,
lng: lng,
initialRate: 500 + Math.random() * 1500,
waterCut: 10 + Math.random() * 40,
pressure: 800 + Math.random() * 400
};
productionWells.push(well);
// Add to map
const marker = L.marker([lat, lng], {
icon: L.divIcon({
className: 'well-icon production-well',
html: well.id
})
}).addTo(map);
marker.bindPopup(`<b>${well.name}</b><br>Type: Production<br>Initial Rate: ${well.initialRate.toFixed(0)} bbl/day<br>Water Cut: ${well.waterCut.toFixed(1)}%<br>Pressure: ${well.pressure.toFixed(0)} psi`);
marker.on('mouseover', function(e) {
tooltip.className = 'tooltip';
tooltip.innerHTML = `<b>${well.name}</b><br>Production Well`;
tooltip.style.left = e.containerPoint.x + 'px';
tooltip.style.top = (e.containerPoint.y - 30) + 'px';
});
marker.on('mouseout', function() {
tooltip.className = 'tooltip hidden';
});
}
// Create injection wells
for (let i = 0; i < injCount; i++) {
const lat = 1.421 + (Math.random() * 0.04 - 0.02);
const lng = 101.252 + (Math.random() * 0.04 - 0.02);
const well = {
id: `I-${i+1}`,
name: `INJ-${i+1}`,
type: 'injection',
lat: lat,
lng: lng,
rate: parseInt(document.getElementById('injectionRate').value),
fluid: 'Water'
};
injectionWells.push(well);
// Add to map
const marker = L.marker([lat, lng], {
icon: L.divIcon({
className: 'well-icon injection-well',
html: well.id
})
}).addTo(map);
marker.bindPopup(`<b>${well.name}</b><br>Type: Injection<br>Rate: ${well.rate} bbl/day<br>Fluid: ${well.fluid}`);
marker.on('mouseover', function(e) {
tooltip.className = 'tooltip';
tooltip.innerHTML = `<b>${well.name}</b><br>Injection Well`;
tooltip.style.left = e.containerPoint.x + 'px';
tooltip.style.top = (e.containerPoint.y - 30) + 'px';
});
marker.on('mouseout', function() {
tooltip.className = 'tooltip hidden';
});
}
}
function runSimulation() {
// Clear previous connections
connections.forEach(conn => {
if (conn.line) map.removeLayer(conn.line);
});
connections = [];
// Get simulation parameters
const maxDistance = parseInt(document.getElementById('maxDistance').value);
const injectionRate = parseInt(document.getElementById('injectionRate').value);
const duration = parseInt(document.getElementById('simDuration').value);
// Update injection rates
injectionWells.forEach(well => {
well.rate = injectionRate;
});
// Calculate distances and impacts
const pairAnalysis = [];
productionWells.forEach(prodWell => {
const impacts = [];
injectionWells.forEach(injWell => {
// Calculate distance between wells
const distance = calculateDistance(prodWell, injWell);
if (distance <= maxDistance) {
// Calculate impact based on distance and injection rate
const impactFactor = 1 - (distance / maxDistance);
const pressureImpact = (injectionRate * impactFactor * 0.05) * (duration / 30);
const prodRateChange = (injectionRate * impactFactor * 0.02) * (duration / 30);
const waterCutChange = (injectionRate * impactFactor * 0.03) * (duration / 30);
impacts.push({
injWell: injWell,
distance: distance,
pressureImpact: pressureImpact,
prodRateChange: prodRateChange,
waterCutChange: waterCutChange
});
// Add to pair analysis table
pairAnalysis.push({
prodWell: prodWell,
injWell: injWell,
distance: distance,
pressureImpact: pressureImpact,
prodRateChange: prodRateChange,
waterCutChange: waterCutChange
});
// Create connection line
const line = L.polyline(
[[prodWell.lat, prodWell.lng], [injWell.lat, injWell.lng]],
{
color: '#6b7280',
weight: 2,
dashArray: '5, 5',
className: 'connection-line'
}
).addTo(map);
connections.push({
prodWell: prodWell,
injWell: injWell,
line: line
});
}
});
// Calculate total impacts on production well
if (impacts.length > 0) {
prodWell.totalPressureImpact = impacts.reduce((sum, impact) => sum + impact.pressureImpact, 0);
prodWell.totalProdRateChange = impacts.reduce((sum, impact) => sum + impact.prodRateChange, 0);
prodWell.totalWaterCutChange = impacts.reduce((sum, impact) => sum + impact.waterCutChange, 0);
// Update production well properties
prodWell.finalPressure = prodWell.pressure + prodWell.totalPressureImpact;
prodWell.finalRate = prodWell.initialRate + prodWell.totalProdRateChange;
prodWell.finalWaterCut = Math.min(95, prodWell.waterCut + prodWell.totalWaterCutChange);
} else {
prodWell.totalPressureImpact = 0;
prodWell.totalProdRateChange = 0;
prodWell.totalWaterCutChange = 0;
prodWell.finalPressure = prodWell.pressure;
prodWell.finalRate = prodWell.initialRate;
prodWell.finalWaterCut = prodWell.waterCut;
}
});
// Update UI with results
updateResultsUI(pairAnalysis);
// Generate chart
generateImpactChart();
// Generate mitigation recommendations
generateMitigationRecommendations(pairAnalysis);
}
function calculateDistance(well1, well2) {
// Simple distance calculation (for demo purposes)
const latDiff = well1.lat - well2.lat;
const lngDiff = well1.lng - well2.lng;
return Math.sqrt(latDiff * latDiff + lngDiff * lngDiff) * 111320; // Convert to meters
}
function updateResultsUI(pairAnalysis) {
// Update production well summary
let prodSummaryHTML = '';
productionWells.forEach(well => {
prodSummaryHTML += `
<div class="mb-2 pb-2 border-b border-gray-200">
<div class="flex justify-between">
<span class="font-medium">${well.name}</span>
<span class="text-blue-600">${well.id}</span>
</div>
<div class="grid grid-cols-2 gap-1 text-xs mt-1">
<div>Initial Rate: <span class="font-medium">${well.initialRate.toFixed(0)} bbl/day</span></div>
<div>Final Rate: <span class="font-medium">${well.finalRate.toFixed(0)} bbl/day</span></div>
<div>Pressure: <span class="font-medium">${well.pressure.toFixed(0)}${well.finalPressure.toFixed(0)} psi</span></div>
<div>Water Cut: <span class="font-medium">${well.waterCut.toFixed(1)}% → ${well.finalWaterCut.toFixed(1)}%</span></div>
</div>
</div>
`;
});
document.getElementById('prodWellSummary').innerHTML = prodSummaryHTML;
// Update injection well summary
let injSummaryHTML = '';
injectionWells.forEach(well => {
// Calculate how many production wells this injector affects
const affectedWells = pairAnalysis.filter(pair => pair.injWell.id === well.id).length;
injSummaryHTML += `
<div class="mb-2 pb-2 border-b border-gray-200">
<div class="flex justify-between">
<span class="font-medium">${well.name}</span>
<span class="text-red-600">${well.id}</span>
</div>
<div class="grid grid-cols-2 gap-1 text-xs mt-1">
<div>Rate: <span class="font-medium">${well.rate} bbl/day</span></div>
<div>Affects: <span class="font-medium">${affectedWells} prod. wells</span></div>
</div>
</div>
`;
});
document.getElementById('injWellSummary').innerHTML = injSummaryHTML;
// Update pair analysis table
let tableHTML = '';
pairAnalysis.forEach(pair => {
tableHTML += `
<tr>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-blue-600">${pair.prodWell.name}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-red-600">${pair.injWell.name}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${pair.distance.toFixed(0)}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${pair.pressureImpact.toFixed(1)}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${pair.prodRateChange.toFixed(1)}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${pair.waterCutChange.toFixed(1)}</td>
</tr>
`;
});
if (tableHTML === '') {
tableHTML = `
<tr>
<td colspan="6" class="px-6 py-4 text-center text-sm text-gray-500">No connections within specified distance</td>
</tr>
`;
}
document.getElementById('pairAnalysisTable').innerHTML = tableHTML;
}
function generateImpactChart() {
const ctx = document.getElementById('impactChart').getContext('2d');
// Destroy previous chart if exists
if (impactChart) {
impactChart.destroy();
}
// Prepare data
const labels = productionWells.map(well => well.name);
const initialRates = productionWells.map(well => well.initialRate);
const finalRates = productionWells.map(well => well.finalRate);
const initialWaterCuts = productionWells.map(well => well.waterCut);
const finalWaterCuts = productionWells.map(well => well.finalWaterCut);
impactChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [
{
label: 'Initial Production Rate (bbl/day)',
data: initialRates,
backgroundColor: 'rgba(59, 130, 246, 0.5)',
borderColor: 'rgba(59, 130, 246, 1)',
borderWidth: 1
},
{
label: 'Final Production Rate (bbl/day)',
data: finalRates,
backgroundColor: 'rgba(16, 185, 129, 0.5)',
borderColor: 'rgba(16, 185, 129, 1)',
borderWidth: 1
},
{
label: 'Initial Water Cut (%)',
data: initialWaterCuts,
backgroundColor: 'rgba(249, 168, 37, 0.5)',
borderColor: 'rgba(249, 168, 37, 1)',
borderWidth: 1,
type: 'line',
yAxisID: 'y1'
},
{
label: 'Final Water Cut (%)',
data: finalWaterCuts,
backgroundColor: 'rgba(220, 38, 38, 0.5)',
borderColor: 'rgba(220, 38, 38, 1)',
borderWidth: 1,
type: 'line',
yAxisID: 'y1'
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
title: {
display: true,
text: 'Production Rate (bbl/day)'
}
},
y1: {
position: 'right',
beginAtZero: true,
max: 100,
title: {
display: true,
text: 'Water Cut (%)'
},
grid: {
drawOnChartArea: false
}
}
},
plugins: {
title: {
display: true,
text: 'Production Well Performance Before and After Injection'
},
tooltip: {
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
label += context.parsed.y.toFixed(1);
return label;
}
}
}
}
}
});
}
function generateMitigationRecommendations(pairAnalysis) {
let recommendationsHTML = '';
if (pairAnalysis.length === 0) {
recommendationsHTML = `
<div class="p-4 bg-green-50 rounded-lg">
<h4 class="font-medium text-green-800">No Significant Impacts Detected</h4>
<p class="text-sm text-green-700 mt-1">Based on current injection patterns and distances, no production wells are significantly affected.</p>
</div>
`;
} else {
// Find wells with highest water cut increase
const highWaterCutWells = [...productionWells]
.sort((a, b) => (b.finalWaterCut - b.waterCut) - (a.finalWaterCut - a.waterCut))
.slice(0, 3);
if (highWaterCutWells.length > 0 && highWaterCutWells[0].finalWaterCut - highWaterCutWells[0].waterCut > 10) {
recommendationsHTML += `
<div class="p-4 bg-yellow-50 rounded-lg mb-3">
<h4 class="font-medium text-yellow-800">Water Breakthrough Risk</h4>
<p class="text-sm text-yellow-700 mt-1">The following production wells show significant water cut increase (>10%):</p>
<ul class="list-disc list-inside text-sm text-yellow-700 mt-2 ml-2">
${highWaterCutWells.map(well =>
`<li>${well.name}: Water cut increased from ${well.waterCut.toFixed(1)}% to ${well.finalWaterCut.toFixed(1)}%</li>`
).join('')}
</ul>
<p class="text-sm text-yellow-700 mt-2">Consider adjusting injection rates or patterns for injectors affecting these wells.</p>
</div>
`;
}
// Find injectors affecting most production wells
const injectorImpactCount = {};
pairAnalysis.forEach(pair => {
if (!injectorImpactCount[pair.injWell.id]) {
injectorImpactCount[pair.injWell.id] = 0;
}
injectorImpactCount[pair.injWell.id]++;
});
const mostImpactfulInjectors = Object.entries(injectorImpactCount)
.sort((a, b) => b[1] - a[1])
.slice(0, 2);
if (mostImpactfulInjectors.length > 0 && mostImpactfulInjectors[0][1] > 3) {
recommendationsHTML += `
<div class="p-4 bg-blue-50 rounded-lg mb-3">
<h4 class="font-medium text-blue-800">High-Impact Injectors</h4>
<p class="text-sm text-blue-700 mt-1">The following injectors affect multiple production wells:</p>
<ul class="list-disc list-inside text-sm text-blue-700 mt-2 ml-2">
${mostImpactfulInjectors.map(([id, count]) =>
`<li>${id}: Affects ${count} production wells</li>`
).join('')}
</ul>
<p class="text-sm text-blue-700 mt-2">Consider monitoring these injectors closely as they have broad impact across the field.</p>
</div>
`;
}
// Find isolated production wells (not affected by any injector)
const affectedProdWellIds = new Set(pairAnalysis.map(pair => pair.prodWell.id));
const isolatedProdWells = productionWells.filter(well => !affectedProdWellIds.has(well.id));
if (isolatedProdWells.length > 0) {
recommendationsHTML += `
<div class="p-4 bg-purple-50 rounded-lg">
<h4 class="font-medium text-purple-800">Isolated Production Wells</h4>
<p class="text-sm text-purple-700 mt-1">The following production wells are not receiving pressure support from any injector:</p>
<ul class="list-disc list-inside text-sm text-purple-700 mt-2 ml-2">
${isolatedProdWells.map(well =>
`<li>${well.name}</li>`
).join('')}
</ul>
<p class="text-sm text-purple-700 mt-2">Consider adding new injectors or adjusting existing ones to provide pressure support to these wells.</p>
</div>
`;
}
}
document.getElementById('mitigationRecommendations').innerHTML = recommendationsHTML || `
<p class="text-gray-700">No specific mitigation recommendations based on current simulation parameters.</p>
`;
}
function toggleConnections() {
const isVisible = connections.length > 0 && map.hasLayer(connections[0].line);
if (isVisible) {
connections.forEach(conn => {
map.removeLayer(conn.line);
});
showConnectionsBtn.textContent = 'Show Connections';
showConnectionsBtn.className = 'bg-green-500 hover:bg-green-600 text-white text-sm py-1 px-2 rounded';
} else {
connections.forEach(conn => {
conn.line.addTo(map);
});
showConnectionsBtn.textContent = 'Hide Connections';
showConnectionsBtn.className = 'bg-gray-500 hover:bg-gray-600 text-white text-sm py-1 px-2 rounded';
}
}
function exportData() {
// Prepare data for export
const data = {
simulationParameters: {
productionWellCount: parseInt(document.getElementById('prodWellCount').value),
injectionWellCount: parseInt(document.getElementById('injWellCount').value),
maxDistance: parseInt(document.getElementById('maxDistance').value),
injectionRate: parseInt(document.getElementById('injectionRate').value),
duration: parseInt(document.getElementById('simDuration').value)
},
productionWells: productionWells,
injectionWells: injectionWells,
pairAnalysis: connections.map(conn => {
const pair = productionWells.find(p => p.id === conn.prodWell.id);
const inj = injectionWells.find(i => i.id === conn.injWell.id);
const distance = calculateDistance(pair, inj);
return {
productionWell: pair.name,
injectionWell: inj.name,
distance: distance,
pressureImpact: pair.totalPressureImpact,
productionRateChange: pair.totalProdRateChange,
waterCutChange: pair.totalWaterCutChange
};
})
};
// Create download link
const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(data, null, 2));
const downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute("href", dataStr);
downloadAnchorNode.setAttribute("download", "well_injection_simulation.json");
document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click();
downloadAnchorNode.remove();
// Show notification
alert('Simulation data exported successfully!');
}
function resetSimulation() {
// Clear connections
connections.forEach(conn => {
if (conn.line) map.removeLayer(conn.line);
});
connections = [];
// Reset UI
document.getElementById('prodWellSummary').innerHTML = '<p class="text-gray-600">Run simulation to see results</p>';
document.getElementById('injWellSummary').innerHTML = '<p class="text-gray-600">Run simulation to see results</p>';
document.getElementById('pairAnalysisTable').innerHTML = '<tr><td colspan="6" class="px-6 py-4 text-center text-sm text-gray-500">No simulation data available</td></tr>';
document.getElementById('mitigationRecommendations').innerHTML = '<p class="text-gray-700">Based on the simulation results, recommendations will appear here for optimizing injection patterns and mitigating negative impacts on production wells.</p>';
// Destroy chart if exists
if (impactChart) {
impactChart.destroy();
impactChart = null;
}
// Recreate wells with current parameters
createInitialWells();
// Reset connection button
showConnectionsBtn.textContent = 'Show Connections';
showConnectionsBtn.className = 'bg-green-500 hover:bg-green-600 text-white text-sm py-1 px-2 rounded';
}
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=alterzick/simulation-pair-analysis" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>