Biofuel-Optimiser / templates /generative.html
carrotcake3's picture
Update templates/generative.html
8af7af6 verified
Raw
History Blame Contribute Delete
7.49 kB
{% extends "base.html" %}
{% block content %}
<div class="container py-4">
<!-- Header -->
<div class="mb-4">
<h2 class="fw-bold mb-2">Pure Fuel Generator</h2>
<p class="page-intro-text mb-0">
Generate candidate pure fuel molecules using molecular evolution and rank them based on
cetane number, fuel property constraints, and optional YSI minimisation.
</p>
</div>
<!-- Alerts -->
{% if error %}
<div class="alert alert-danger">
<i class="bi bi-exclamation-triangle me-2"></i>{{ error }}
</div>
{% endif %}
{% if info %}
<div class="alert alert-info">
<i class="bi bi-info-circle me-2"></i>{{ info }}
</div>
{% endif %}
<!-- Configuration form -->
<div class="card card-metric p-4 mb-4">
<h5 class="fw-bold mb-3">Generator Configuration</h5>
<form method="POST" id="gen-form">
<div class="row g-3 align-items-end">
<div class="col-md-4">
<label class="form-label fw-semibold">Optimisation Mode</label>
<select name="mode" id="generatorMode" class="form-select" onchange="toggleTargetCN()">
<option value="target">Target a specific CN</option>
<option value="maximize">Maximise CN</option>
</select>
<div class="form-text">
Choose whether to target a desired CN value or search for the highest CN candidates.
</div>
</div>
<div class="col-md-3" id="targetCnBox">
<label class="form-label fw-semibold">Target CN</label>
<input type="number" step="0.01" name="target_cn" class="form-control" value="50">
<div class="form-text">
CN above 40 is recommended for easier optimisation.
</div>
</div>
<div class="col-md-3">
<label class="form-label fw-semibold">YSI Objective</label>
<div class="form-check mt-2">
<input class="form-check-input" type="checkbox" name="minimize_ysi" id="minimizeYsi">
<label class="form-check-label" for="minimizeYsi">
Minimise YSI
</label>
</div>
<div class="form-text">
Enables multi-objective optimisation for CN and smoke tendency.
</div>
</div>
<div class="col-md-2 text-md-end">
<button id="generate-btn" type="submit" class="btn btn-primary w-100">
Run Generator
</button>
</div>
</div>
<div id="loading" class="mt-3" style="display:none;">
<div class="spinner-border text-primary" role="status"></div>
<span class="ms-2">Generating molecules… this may take a few minutes.</span>
</div>
</form>
</div>
<!-- Run summary -->
{% if run_info %}
<div class="card card-metric p-4 mb-4">
<h5 class="fw-bold mb-3">Generation Summary</h5>
<div class="row g-3">
<div class="col-md-3">
<div class="border rounded-3 p-3 bg-white">
<p class="text-muted small mb-1">Mode</p>
<h6 class="fw-bold mb-0">{{ run_info.mode }}</h6>
</div>
</div>
<div class="col-md-2">
<div class="border rounded-3 p-3 bg-white">
<p class="text-muted small mb-1">Target CN</p>
<h6 class="fw-bold mb-0">
{% if run_info.target_cn is not none %}
{{ run_info.target_cn }}
{% else %}
{% endif %}
</h6>
</div>
</div>
<div class="col-md-3">
<div class="border rounded-3 p-3 bg-white">
<p class="text-muted small mb-1">Objective</p>
<h6 class="fw-bold mb-0">{{ run_info.objective }}</h6>
</div>
</div>
<div class="col-md-2">
<div class="border rounded-3 p-3 bg-white">
<p class="text-muted small mb-1">Filtered</p>
<h6 class="fw-bold mb-0">{{ run_info.n_final }}</h6>
</div>
</div>
<div class="col-md-2">
<div class="border rounded-3 p-3 bg-white">
<p class="text-muted small mb-1">Pareto</p>
<h6 class="fw-bold mb-0">{{ run_info.n_pareto }}</h6>
</div>
</div>
</div>
</div>
{% endif %}
<!-- Final filtered candidates -->
{% if final_table %}
<div class="card card-metric p-4 mb-4">
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
<div>
<h5 class="fw-bold mb-1">Best Candidates with Property Constraints</h5>
<p class="text-muted small mb-0">
Candidates ranked after applying fuel property filters.
</p>
</div>
<form method="POST" action="{{ url_for('download_generator_result', result_type='final') }}">
<input type="hidden" name="results_data" value='{{ final_records | tojson }}'>
<button type="submit" class="btn btn-outline-success btn-sm">
Download Filtered CSV
</button>
</form>
</div>
<div class="table-responsive app-table-wrap molecule-table">
{{ final_table | safe }}
</div>
</div>
{% endif %}
<!-- Unfiltered candidates -->
{% if unfiltered_table %}
<div class="card card-metric p-4 mb-4">
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
<div>
<h5 class="fw-bold mb-1">Best Candidates without Property Constraints</h5>
<p class="text-muted small mb-0">
Raw generated candidates before final property filtering.
</p>
</div>
<form method="POST" action="{{ url_for('download_generator_result', result_type='unfiltered') }}">
<input type="hidden" name="results_data" value='{{ unfiltered_records | tojson }}'>
<button type="submit" class="btn btn-outline-secondary btn-sm">
Download Unfiltered CSV
</button>
</form>
</div>
<div class="table-responsive app-table-wrap molecule-table">
{{ unfiltered_table | safe }}
</div>
</div>
{% endif %}
<!-- Pareto front -->
{% if pareto_table %}
<div class="card card-metric p-4 mb-4">
<div class="d-flex justify-content-between align-items-center flex-wrap gap-2 mb-3">
<div>
<h5 class="fw-bold mb-1">Pareto Front</h5>
<p class="text-muted small mb-0">
Non-dominated candidates balancing CN accuracy and low YSI.
</p>
</div>
<form method="POST" action="{{ url_for('download_generator_result', result_type='pareto') }}">
<input type="hidden" name="results_data" value='{{ pareto_records | tojson }}'>
<button type="submit" class="btn btn-outline-primary btn-sm">
Download Pareto CSV
</button>
</form>
</div>
<div class="table-responsive app-table-wrap molecule-table">
{{ pareto_table | safe }}
</div>
</div>
{% endif %}
</div>
<script>
const form = document.getElementById("gen-form");
const btn = document.getElementById("generate-btn");
const loading = document.getElementById("loading");
function toggleTargetCN() {
const mode = document.getElementById("generatorMode").value;
const targetBox = document.getElementById("targetCnBox");
if (mode === "maximize") {
targetBox.style.display = "none";
} else {
targetBox.style.display = "block";
}
}
document.addEventListener("DOMContentLoaded", toggleTargetCN);
if (form) {
form.addEventListener("submit", () => {
btn.disabled = true;
loading.style.display = "block";
});
}
</script>
{% endblock %}