added WebAssembly using IMGUI and IMPLOT

This commit is contained in:
Ryan@fsunuc 2023-07-25 19:11:12 -04:00
parent 63821fc099
commit dc91243633
10 changed files with 621 additions and 9 deletions

21
Makefile Normal file
View File

@ -0,0 +1,21 @@
CXX = em++
OUTPUT = test.js
IMGUI_DIR = imgui
SOURCES = test.cpp
SOURCES += implot/implot.cpp implot/implot_items.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_glfw.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_widgets.cpp $(IMGUI_DIR)/imgui_tables.cpp
LIBS = -lGL
WEBGL_VER = -s USE_WEBGL2=1 -s USE_GLFW=3 -s FULL_ES3=1
USE_WASM = -s WASM=1
all: $(SOURCES) $(OUTPUT)
$(OUTPUT): $(SOURCES)
# $(CXX) $(SOURCES) -std=c++11 -o $(OUTPUT) $(LIBS) $(WEBGL_VER) -O2 --preload-file data $(USE_WASM) -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
$(CXX) $(SOURCES) -std=c++11 -o $(OUTPUT) $(LIBS) $(WEBGL_VER) -O2 $(USE_WASM) -Iimplot -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends -IWoods-Saxon
clean:
rm -f $(OUTPUT)

1
Woods-Saxon Symbolic link
View File

@ -0,0 +1 @@
digios/analysis/Woods-Saxon/

104
WoodsSaxon.html Normal file
View File

@ -0,0 +1,104 @@
<!DOCTYPE html>
<html>
<head>
<title>Woods-Saxon Calculation</title>
<link rel="icon" type="image/x-icon" href="logos/SOLARIS_favicon.png">
<script src="https://cdn.plot.ly/plotly-2.16.1.min.js"></script>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, user-scalable=0"/>
</head>
<style>
body{
font-family: Arial, Helvetica, sans-serif;
background : #6DB33E;
}
.column{
float : left;
width: 650px;
padding: 0px;
}
.row:after {
content: "";
display: table;
clear: both;
}
.plotStyle{
width:650px;
height:600px;
}
hr {
height:4px;
background-color:#F7CF3C;
border-style:none;
border-width:none;
}
</style>
<body>
<h1>Woods-Saxon Calculation</h1>
<h2>Under construction....</h2>
<table>
<tr>
<td style="text-align: right;"> V0 </td>
<td><Input type="text" style="width:60px" value="-50" id="V0" enterkeyhint="done"/></td>
<td> MeV</td>
<td style="text-align: right;"> VSO </td>
<td><Input type="text" style="width:60px" value="28" id="VSO" enterkeyhint="done"/></td>
<td> MeV</td>
</tr>
<tr>
<td style="text-align: right;"> R0 </td>
<td><Input type="text" style="width:60px" value="3.5" id="R0" enterkeyhint="done"/></td>
<td> fm</td>
<td style="text-align: right;"> RSO </td>
<td><Input type="text" style="width:60px" value="3.5" id="RSO" enterkeyhint="done"/></td>
<td> fm</td>
</tr>
<tr>
<td style="text-align: right;"> a0 </td>
<td><Input type="text" style="width:60px" value="0.6" id="a0" enterkeyhint="done"/></td>
<td> fm</td>
<td style="text-align: right;"> aSO </td>
<td><Input type="text" style="width:60px" value="0.6" id="aSO" enterkeyhint="done"/></td>
<td> fm</td>
</tr>
<tr>
<td style="text-align: right;"> Charge number </td>
<td><Input type="text" style="width:60px" value="0" id="Z" enterkeyhint="done"/></td>
<td></td>
<td style="text-align: right;"> Rc </td>
<td><Input type="text" style="width:60px" value="3.5" id="Rc" enterkeyhint="done"/></td>
<td> fm</td>
</tr>
<tr></tr>
<tr>
<td style="text-align: right;"> # Step </td>
<td><Input type="text" style="width:60px" value="300" id="nStep" enterkeyhint="done"/></td>
<td></td>
<td style="text-align: right;"> dr </td>
<td><Input type="text" style="width:60px" value="0.1" id="dr" enterkeyhint="done"/></td>
<td> fm</td>
</tr>
<tr>
<td></td>
<td><button onclick="WSCal()">Calculate</button></td>
</tr>
</table>
<div id="Plot_WS" class="plotStyle"></div>
<hr>
<h1>Range calculation.</h1>
<h2> to be added...</h2>
<p></p>
</body>
<script src="WoodsSaxon.js"></script>
</html>

92
WoodsSaxon.js Normal file
View File

@ -0,0 +1,92 @@
var V0;
var R0;
var a0;
var VSO;
var RSO;
var aSO;
var Z;
var Rc;
var nStep;
var dr;
class State{
constructor(energy, jpi){
this.energy = energy;
this.jpi = jpi;
}
}
var states = [];
function WSCal(){
V0 = parseFloat(document.getElementById('V0').value);
R0 = parseFloat(document.getElementById('R0').value);
a0 = parseFloat(document.getElementById('a0').value);
VSO = parseFloat(document.getElementById('VSO').value);
RSO = parseFloat(document.getElementById('RSO').value);
aSO = parseFloat(document.getElementById('aSO').value);
Z = parseInt(document.getElementById('Z').value);
Rc = parseFloat(document.getElementById('Rc').value);
nStep = parseInt(document.getElementById('nStep').value);
dr = parseFloat(document.getElementById('dr').value);
let str = 'WoodsSaxon.py?V0=' + V0 +
'&R0=' + R0 +
'&a0=' + a0 +
'&VSO=' + VSO +
'&RSO=' + RSO +
'&aSO=' + aSO +
'&Z=' + Z +
'&Rc=' + Rc +
'&nStep=' + nStep +
'&dr=' + dr ;
console.log(str);
states = [];
let client = new XMLHttpRequest();
client.onreadystatechange = function() {
let haha = client.responseText.split('\n').slice(11);
haha.forEach(line =>{
console.log(line);
if( !line.includes("=====") && line.length != 0) {
let jpi = line.substring(4, 12);
let energy = parseFloat(line.substring(13,25));
states.push(new State(energy, jpi));
}
});
}
client.open('GET', str, false);
client.send();
states.forEach(st =>{
console.log( st.jpi + ", " + st.energy);
})
Plotly.purge("Plot_WS");
let nEx = states.length;
let data = [];
for( let i = 0; i < nEx; i++){
let newData = {
x : [0,1],
y : [states[i].energy, states[i].energy],
mode:"lines",
name: states[i].jpi,
type:"scatter"
}
data.push(newData);
}
let layout = {
xaxis: {range: [-1, 2], title: { text : "Ex", standoff : 1}, mirror : "allticks", linewidth : "1"},
yaxis: {range: [V0, 0], title: "Energy [MeV]" , mirror : "allticks", linewidth : "1"},
//dragmode : "pan",
margin: { l: 40, r: 40, b : 60, t : 40},
legend: {yanchor:"top", xanchor:"left", x:"0.01",y:"0.99" }
};
Plotly.newPlot( "Plot_WS", data, layout, {responsive: true});
}

24
WoodsSaxon.py Executable file
View File

@ -0,0 +1,24 @@
#!/usr/bin/python3
import cgi, cgitb
form = cgi.FieldStorage()
V0 = form.getvalue('V0')
R0 = form.getvalue('R0')
a0 = form.getvalue('a0')
VSO = form.getvalue('VSO')
RSO = form.getvalue('RSO')
aSO = form.getvalue('aSO')
Z = form.getvalue('Z')
Rc = form.getvalue('Rc')
nStep = form.getvalue('nStep')
dr = form.getvalue('dr')
import os, subprocess
os.chdir(r"files")
result = subprocess.run(['../Woods-Saxon/WSCal', V0, R0, a0, VSO, RSO, aSO, Z, Rc, nStep, dr], stdout=subprocess.PIPE).stdout.decode('utf-8')
print( "Content-type:text/html\r\n\r\n")
print(result)

View File

@ -59,7 +59,7 @@
}
</style>
<body">
<body>
<h1>HELIOSmatics</h1>
@ -467,4 +467,4 @@ function CopyInputs(){
</script>
<html>
</html>

View File

@ -123,10 +123,10 @@
<td style="text-align:right"><a href="instruction.html" target="uploaded">Intructions & Credits</a></td>
</tr>
<tr>
<td style="text-align:right">Woods-Saxon (to be done)</td>
<td style="text-align:right"><a href="WoodsSaxon.html" target="uploaded">Woods-Saxon (const.)</a></td>
</tr>
<tr>
<td style="text-align:right"><a href="nuclearChart.html" target="uploaded">Nuclides Chart (to be done)</a></td>
<td style="text-align:right"><a href="nuclearChart.html" target="uploaded">Nuclides Chart (const.)</a></td>
</tr>
<table>

View File

@ -35,7 +35,7 @@ for( let i = 0; i <= maxN; i++){
AllIso.push(row);
}
function readLocalFile(){
function readMassTable(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
@ -124,6 +124,15 @@ function checkBounded(num1, num2, num3) {
return true;
}
// var IsoCell = [];
// for( let i = 0; i <= maxN; i++){
// const row = [];
// for( let j = 0; j <= maxZ; j++){
// row.push(makeElement(NaN, NaN, NaN, '', white));
// }
// IsoCell.push(row);
// }
//####################################
window.onload = function(){
@ -132,11 +141,23 @@ window.onload = function(){
project.view.viewSize = new paper.Size( maxN * size + padX*2, maxZ*size + padY*2);
readLocalFile();
readMassTable();
for( let i = 0; i <= maxN; i++){
for( let j = 0; j <= maxZ; j++){
let iso = AllIso[i][j];
if( (i == 28 && j == 20) ||
(i == 6 && j == 4) ||
(i == 8 && j == 6) ||
(i == 13 && j == 13) ||
(i == 19 && j == 17) ||
(i == 21 && j == 20)
){
makeElement(startX + i * size + padX, startY - j*size + padY, AllIso[i][j].A, AllIso[i][j].symbol, 'lightgrey');
continue;
}
if( !isNaN(iso.A) ){
// iso.Print();
@ -159,7 +180,7 @@ window.onload = function(){
if( j > 0 && i < maxN ) Qec = iso.mass - AllIso[i+1][j-1].mass + 0.511;
//if( iso.Z > 55 && iso.N >= 82 )console.log( iso.A + iso.symbol + " | " + iso.mass + " | " + Qbm + "," + Qbp + "," + Qec);
if( Qbm > 0 || Qbp > 0 || Qec > 0 || (iso.Z > 83 && Sa < 0 ) || (iso.Z < 20 && Sa < 0 ) ){
if( Qbm > 0 || Qbp > 0 || Qec > 0 || (iso.Z > 83 && Sa < 0 ) || (iso.Z < 20 && Sa < 0 ) || iso.Z > 84 ){
makeElement(startX + i * size + padX, startY - j*size + padY, AllIso[i][j].A, AllIso[i][j].symbol, 'white');
}else{
makeElement(startX + i * size + padX, startY - j*size + padY, AllIso[i][j].A, AllIso[i][j].symbol, 'grey');
@ -223,7 +244,5 @@ window.onload = function(){
}
paper.view.draw();
}

298
test.cpp Normal file
View File

@ -0,0 +1,298 @@
#include <stdio.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
#define GLFW_INCLUDE_ES3
#include <GLES3/gl3.h>
#include <GLFW/glfw3.h>
#include "imgui.h"
#include "imgui_impl_opengl3.h"
#include "imgui_impl_glfw.h"
#ifndef IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
#define IMPLOT_DISABLE_OBSOLETE_FUNCTIONS
#endif
#include "implot.h"
#include <iostream>
#include <vector>
//======= Woods-Saxon Library
#include "RK4.h"
#include "WS.h"
const int nPt = 300;
static float xValues[nPt];
static float WSCValues[nPt];
static float WSSOValues[nPt];
static int selected = -1;
static float Energy[nPt];
static vector<double> wfr;
static vector<vector<double>> wf;
static vector<double> energies;
static vector<string> orbString;
GLFWwindow* g_window;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
int g_width;
int g_height;
// Function used by c++ to get the size of the html canvas
EM_JS(int, canvas_get_width, (), {
return Module.canvas.width;
});
// Function used by c++ to get the size of the html canvas
EM_JS(int, canvas_get_height, (), {
return Module.canvas.height;
});
// Function called by javascript
EM_JS(void, resizeCanvas, (), {
js_resizeCanvas();
});
void on_size_changed(){
glfwSetWindowSize(g_window, g_width, g_height);
ImGui::SetCurrentContext(ImGui::GetCurrentContext());
}
void loop(){
int width = canvas_get_width();
int height = canvas_get_height();
if (width != g_width || height != g_height){
g_width = width;
g_height = height;
on_size_changed();
}
glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// Debug Window
{
ImGui::SetNextWindowSize(ImVec2(400, 100), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowPos(ImVec2(1000, 100), ImGuiCond_FirstUseEver);
ImGui::Begin("Debug");
ImGui::Text("Hello, world!"); // Display some text (you can use a format string too)
ImGui::ColorEdit3("bg color", (float*)&clear_color); // Edit 3 floats representing a color
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::End();
}
// // // Demo Window
// if (true){
// ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiCond_FirstUseEver); // Normally user code doesn't need/want to call this because positions are saved in .ini file anyway. Here we just want to make the demo initial state a bit more friendly!
// ImGui::ShowDemoWindow();
// }
// Woods-Saxon window
{
ImGui::SetNextWindowSize(ImVec2(1000, 1000), ImGuiCond_FirstUseEver);
static float V0 = -45, R0 = 3.5, a0 = 0.6;
static float VSO = 28, RSO = 3.5, aSO = 0.6;
static int Z = 0, nStep = 300;
static float Rc = 3.5, dr = 0.1;
ImGui::Begin("Woods-Saxon Calculation");
ImGui::SliderFloat("V0 [MeV]", &V0, -100, 0);
ImGui::SliderFloat("R0 [fm]", &R0, 1, 10);
ImGui::SliderFloat("a0 [fm]", &a0, 0.1, 2);
ImGui::SliderFloat("VSO [MeV]", &VSO, 0, 40);
ImGui::SliderFloat("RSO [fm]", &RSO, 1, 10);
ImGui::SliderFloat("aSO [fm]", &aSO, 0.1, 2);
ImGui::SliderInt("Z ", &Z, 0, 100);
ImGui::SliderFloat("Rc [fm] ", &Rc, 1, 10);
ImGui::SliderInt("nStep", &nStep, 100, 400);
ImGui::SliderFloat("dr [fm]", &dr, 0.01, 1);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(30, 10));
if( ImGui::Button("Cal WS Level") ){
WoodsSaxon ws;
if( Z == 0 ) {
ws.SetNucleus(1,1);
ws.IsNeutron();
}else{
ws.SetNucleus(1, Z);
ws.IsProton();
ws.SetRc(Rc);
}
ws.SetV0( V0 );
ws.SetR0( R0 );
ws.Seta0( a0 );
ws.SetVSO( VSO );
ws.SetRSO( RSO );
ws.SetaSO( aSO );
ws.SetRange2(0.0001, dr, nStep);
ws.CalWSEnergies(false, 7, 100, 1e-7, 50, 0.2, false);
float dx = nStep * dr / nPt;
wfr.clear();
for( int i = 0; i < nPt; i ++){
float r = i * dx;
xValues[i] = r;
WSCValues[i] = V0/(1 + exp(( r - R0)/a0));
WSSOValues[i] = VSO * exp((r-RSO)/aSO) / pow(1+exp((r-RSO)/aSO), 2) / aSO/ r ;
wfr.push_back(dr*i);
}
wf.clear();
for( int i = 0; i < ws.orbString.size(); i++){
wf.push_back(ws.CalWaveFunction(i, abs(V0)/2, ws.energy[i]));
}
selected = -1;
energies.clear();
orbString.clear();
energies = ws.energy;
orbString = ws.orbString;
//ws.PrintEnergyLevels();
}
ImGui::PopStyleVar();
if( ImGui::TreeNode("WS Energy Levels:") ){
for( int i = 0; i < energies.size(); i++){
char buf[32];
sprintf(buf, "%24.12f MeV %s", energies[i],orbString[i].c_str());
if( ImGui::Selectable(buf, selected == i) ) selected = i;
//ImGui::Text("%12.5f MeV %s", ws.energy[i], ws.orbString[i].c_str());
}
ImGui::TreePop();
}
if( ImPlot::BeginPlot("Plot") ){
ImPlot::SetupLegend(ImPlotLocation_SouthEast);
ImPlot::SetupAxes("r [fm]"," Energy [MeV]");
ImPlot::SetupAxesLimits(0, 10, floor(V0*1.1), 1);
ImPlot::SetupAxisLimitsConstraints(ImAxis_X1, 0, 30);
ImPlot::PlotLine("Central", xValues, WSCValues, nPt);
ImPlot::PlotLine("S-O", xValues, WSSOValues, nPt);
if( selected >= 0 ){
for( int i = 0; i < nPt; i ++) Energy[i] = energies[selected];
ImPlot::PlotLine(orbString[selected].c_str(), xValues, Energy, nPt);
const double * haha = wf[selected].data();
const double * kaka = wfr.data();
ImPlot::PlotLine("WF", kaka, haha, wfr.size());
}
ImPlot::EndPlot();
}
ImGui::End();
}
ImGui::Render();
int display_w, display_h;
glfwMakeContextCurrent(g_window);
glfwGetFramebufferSize(g_window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
glfwMakeContextCurrent(g_window);
}
//^ #########################################################
int init_gl(){
if( !glfwInit() ){
fprintf( stderr, "Failed to initialize GLFW\n" );
return 1;
}
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // We don't want the old OpenGL
// Open a window and create its OpenGL context
int canvasWidth = g_width;
int canvasHeight = g_height;
g_window = glfwCreateWindow(canvasWidth, canvasHeight, "WebGui Demo", NULL, NULL);
if( g_window == NULL ){
fprintf( stderr, "Failed to open GLFW window.\n" );
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(g_window); // Initialize GLEW
return 0;
}
int init_imgui(){
// Setup Dear ImGui binding
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGui_ImplGlfw_InitForOpenGL(g_window, true);
ImGui_ImplOpenGL3_Init();
ImPlot::CreateContext();
// Setup style
//ImGui::StyleColorsDark();
ImGui::StyleColorsLight();
ImGuiIO& io = ImGui::GetIO();
resizeCanvas();
for( int i = 0; i < nPt; i++){
xValues[i] = 0;
WSCValues[i] = 0;
}
return 0;
}
int init(){
init_gl();
init_imgui();
return 0;
}
void quit(){
glfwTerminate();
}
extern "C" int main(int argc, char** argv){
g_width = canvas_get_width();
g_height = canvas_get_height();
if (init() != 0) return 1;
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(loop, 0, 1);
#endif
quit();
return 0;
}

53
test.html Normal file
View File

@ -0,0 +1,53 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebGui Demo</title>
<style>
body {
font-family: arial;
margin: 0;
padding: none;
}
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
div.emscripten { text-align: center; }
div.emscripten_border { border: none; }
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
canvas.emscripten { border: 0px none; background-color: black; }
</style>
</head>
<body>
<div class="emscripten_border">
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
</div>
<script type='text/javascript'>
var Module = {
preRun: [],
postRun: [],
print: (function() {})(),
printErr: function(text) {},
canvas: (function() {
var canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
return canvas;
})(),
setStatus: function(text) {},
totalDependencies: 0,
monitorRunDependencies: function(left) {}
};
window.addEventListener('resize', js_resizeCanvas, false);
function js_resizeCanvas() {
document.getElementById('canvas').width = window.innerWidth;
document.getElementById('canvas').height = window.innerHeight;
}
</script>
<script async type="text/javascript" src="test.js"></script>
</body>
</html>