Skip to content

Commit

Permalink
Tue oct 17
Browse files Browse the repository at this point in the history
  • Loading branch information
lbutler committed Oct 17, 2023
1 parent 7e15975 commit f3e6d84
Show file tree
Hide file tree
Showing 17 changed files with 430 additions and 24 deletions.
6 changes: 4 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@
"optional": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"initializer_list": "cpp"
"initializer_list": "cpp",
"__locale": "cpp",
"variant": "c"
}
}
}
2 changes: 1 addition & 1 deletion packages/epanet-engine/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM trzeci/emscripten:1.39.4
FROM emscripten/emsdk:3.1.15

RUN apt-get update && \
apt-get install -qqy git && \
Expand Down
20 changes: 14 additions & 6 deletions packages/epanet-engine/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,30 @@ echo "============================================="
emcc -O3 -o ./build/epanetEngine.js /opt/epanet/build/lib/libepanet2.a \
-I /opt/epanet/src/include \
test.c \
src/epanet_wrapper.cpp \
--bind \
-s EXPORTED_FUNCTIONS="['_EN_geterror','_EN_getversion']" \
-s NO_EXIT_RUNTIME="1" \
-s DEAD_FUNCTIONS="[]" \
-s FORCE_FILESYSTEM="1" \
-s INLINING_LIMIT="1" \
-s ALLOW_MEMORY_GROWTH="1" \
-s ERROR_ON_UNDEFINED_SYMBOLS=0 \
-s EXPORTED_RUNTIME_METHODS='["ccall", "getValue", "UTF8ToString", "intArrayToString","FS"]' \
-s WASM=0 \
--llvm-lto 3 \
-s 'EXPORTED_FUNCTIONS=["_free"]' \
-s EXPORTED_RUNTIME_METHODS='["ccall", "getValue", "UTF8ToString", "stringToUTF8", "_free", "intArrayToString","FS"]' \
-s WASM=1 \
-s SINGLE_FILE=1 \
-msimd128 \
-s WASM_ASYNC_COMPILATION=0 \
--memory-init-file 0 \
--closure 0
#-s MODULARIZE=1 \

#src/epanet_wrapper.cpp \
#--bind \

# -msimd128 Enable SIMD https://jott.live/markdown/wasm_vector_addition

#-s BINARYEN_ASYNC_COMPILATION=0 \
#-s MODULARIZE=1 \

cat src/wrapper/cjs-prefix.js build/epanetEngine.js src/wrapper/cjs-postfix.js >> index.js
cat build/epanetEngine.js src/wrapper/es6-postfix.js >> index.es6.js

Expand Down
10 changes: 10 additions & 0 deletions packages/epanet-engine/epanet_version.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#include "emscripten.h"
#include "epanet2_2.h"

EMSCRIPTEN_KEEPALIVE
int getversion()
{
int i;
EN_getversion(&i);
return i;
}
1 change: 1 addition & 0 deletions packages/epanet-engine/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"scripts": {
"build:dockerimage": "docker build -t mydockerimage .",
"build:emscripten": "docker run --rm -v \"$(pwd):/src\" mydockerimage ./build.sh",
"build:emscripten_WASM": "docker run --rm -v \"$(pwd):/src\" mydockerimage ./wasm_build.sh",
"build:app": "cp index.html dist/index.html",
"build:typings": "cp src/index.d.ts dist/index.d.ts",
"build": "yarn run build:emscripten && yarn run build:app && yarn run build:typings",
Expand Down
39 changes: 27 additions & 12 deletions packages/epanet-engine/src/epanet_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,32 @@ class Epanet
EN_deleteproject(ph);
}

// temp speed tests

int getnodeindex2(const std::string& id, intptr_t index)
{
int *ptr1 = reinterpret_cast<int *>(index);
//return EN_getnodeindex(ph, const_cast<char*>(id.c_str()), 0);
EN_Project ph2;
EN_createproject(&ph2);

return EN_getnodeindex(ph2, "J1", ptr1);
}

int getnodeindex(std::string id, intptr_t index)
{
int errcode;
int *ptr1 = reinterpret_cast<int *>(index);
char *idChar = new char[id.length() + 1];

strcpy(idChar, id.c_str());

errcode = EN_getnodeindex(ph, idChar, ptr1);

delete[] idChar;
return errcode;
}

// Project Functions

int open(std::string inputFile, std::string reportFile, std::string outputFile)
Expand Down Expand Up @@ -408,19 +434,7 @@ class Epanet
{
return EN_deletenode(ph, index, actionCode);
}
int getnodeindex(std::string id, intptr_t index)
{
int errcode;
int *ptr1 = reinterpret_cast<int *>(index);
char *idChar = new char[id.length() + 1];

strcpy(idChar, id.c_str());

errcode = EN_getnodeindex(ph, idChar, ptr1);

delete[] idChar;
return errcode;
}
int getnodeid(int index, intptr_t out_id)
{
char *ptr1 = reinterpret_cast<char *>(out_id);
Expand Down Expand Up @@ -995,6 +1009,7 @@ EMSCRIPTEN_BINDINGS(my_module)

class_<Epanet>("Epanet")
.constructor<>()
.function("getnodeindex2", &Epanet::getnodeindex2, allow_raw_pointers())
.function("open", &Epanet::open)
.function("close", &Epanet::close)
.function("runproject", &Epanet::runproject)
Expand Down
2 changes: 2 additions & 0 deletions packages/epanet-engine/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ interface EpanetProjectConstructable {
interface EpanetProject {
// Generated methods

getnodeindex2(id: string, index: number): number;

//Project Functions
open(inputFile: string, reportFile: string, outputFile: string): number;
close(): number;
Expand Down
57 changes: 57 additions & 0 deletions packages/epanet-engine/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,63 @@
#include "epanet2_2.h"

#include "stdio.h"
#include <stdlib.h>




EMSCRIPTEN_KEEPALIVE
EN_Project create_project() {
EN_Project ph = NULL; // EN_Project is already a pointer type.
int errcode = EN_createproject(&ph);
if (errcode != 0) {
// If there was an error, the memory (if allocated) should ideally be freed by the library.
// However, if you suspect a leak, you may need to handle it or check library docs.
return NULL;
}
return ph;
}

EMSCRIPTEN_KEEPALIVE
int loadinp(EN_Project ph) {
int errcode = EN_open(ph, "test.inp", "test.rpt", "test.out");
return errcode;
}

EMSCRIPTEN_KEEPALIVE
int getNodeIndex(EN_Project ph, char *id) {
int index;
EN_getnodeindex(ph, id, &index);
return index;
}

EMSCRIPTEN_KEEPALIVE
void free_project(EN_Project ph) {
free(ph);
}




//EMSCRIPTEN_KEEPALIVE
//int loadinp()
//{
// int errcode;
// EN_createproject(&ph);
// errcode = EN_open(ph, "test.inp", "test.rpt", "test.out");
//
//
// return errcode;
//}
//
//EMSCRIPTEN_KEEPALIVE
//int getNodeIndex()
//{
// int index;
// EN_getnodeindex(ph, "J1", &index);
// return index;
//}


EMSCRIPTEN_KEEPALIVE
int test()
Expand Down
26 changes: 26 additions & 0 deletions packages/epanet-engine/wasm_build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

set -e



echo "============================================="
echo "Compiling wasm "
echo "============================================="
(

mkdir -p build

emcc epanet_version.c -o epanet_version.js \
-I /opt/epanet/src/include \
/opt/epanet/build/lib/libepanet2.a \
-s WASM=1 -s "EXPORTED_FUNCTIONS=['_getversion']"

mkdir -p dist
mv epanet_version.js dist
mv epanet_version.wasm dist

)
echo "============================================="
echo "Compiling wasm bindings done"
echo "============================================="
88 changes: 88 additions & 0 deletions packages/epanet-js/benchmark/engine.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
const Benchmark = require('benchmark');
const { epanetEngine } = require('../../epanet-engine/dist/index.js');

const _instance = epanetEngine;
const _FS = _instance.FS;

_FS.writeFile(
'test.inp',
`[TITLE]
Minimal EPANET Example
[JUNCTIONS]
;ID Elev Demand Pattern
J1 100 10 ;
[RESERVOIRS]
;ID Head Pattern
R1 150 ;
[PIPES]
;ID Node1 Node2 Length Diameter Roughness MinorLoss Status
P1 R1 J1 1000 12 100 0 OPEN
[COORDINATES]
;Node X-Coord Y-Coord
R1 1 1
J1 2 1
[TAGS]
[END]`
);

//console.log(_instance);

let projectPtr = _instance._create_project();
let errorCode = _instance._loadinp(projectPtr);

let nodeId = 'J1';
let nodeIdPtr = _instance._malloc(nodeId.length + 1); // +1 for the null-terminator.
_instance.stringToUTF8(nodeId, nodeIdPtr, nodeId.length + 1);

let index = _instance._getNodeIndex(projectPtr, nodeIdPtr);
console.log('Node index for', nodeId, 'is', index);

const intPointer = _instance._malloc(4);
_instance._free(intPointer);
//
//_instance._getversion2(intPointer);
//const returnValue = _instance.getValue(intPointer, 'i32');
//
//console.log(_instance._loadinp());
//console.log(_instance._getNodeIndex());

let index2 = _instance.ccall(
'getNodeIndex', // C function name
'number', // Return type
['number', 'string'], // Argument types
[projectPtr, nodeId] // Arguments
);

console.log('Node index for', nodeId, 'is', index2);

_instance.stringToUTF8(nodeId, nodeIdPtr, nodeId.length + 1);

const suite = new Benchmark.Suite();

suite
.add('_getversion2', function() {
let index = _instance._getNodeIndex(projectPtr, nodeIdPtr);
})

.add('ccall', function() {
let index2 = _instance.ccall(
'getNodeIndex', // C function name
'number', // Return type
['number', 'string'], // Argument types
[projectPtr, nodeId] // Arguments
);
})

.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
.run({ async: false });
41 changes: 41 additions & 0 deletions packages/epanet-js/benchmark/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const Benchmark = require('benchmark');
const { Project, Workspace } = require('../dist/index.js');
const fs = require('fs');

const tankTestInp = fs.readFileSync(
__dirname + '/../test/data/tankTest.inp',
'utf8'
);
const ws = new Workspace();
ws.writeFile('tankTestInp.inp', tankTestInp);
const epanet = ws._instance.getversion(1);
console.log(epanet);
const model = new Project(ws);
model.open('tankTestInp.inp', 'tankTestInp.rpt', 'tankTestInp.bin');

//const suite = new Benchmark.Suite();
//
//const intPointer = ws._instance._malloc(4);
//
//suite
// .add('getNodeIndex', function() {
// const junctionIndexLookup = model.getNodeIndex('J1');
// //const version = ws.version;
// //ws._instance.getversion(intPointer);
// //const returnValue = ws._instance.getValue(intPointer, 'i32');
// //ws.version;
// })
// .add('getNodeIndex2', function() {
// //const junctionIndexLookup = model.getNodeIndex2('J1');
// //const version = ws.version;
// //ws._instance.getversion(intPointer);
// //const returnValue = ws._instance.getValue(intPointer, 'i32');
// //ws.version;
// })
// .on('cycle', function(event) {
// console.log(String(event.target));
// })
// .on('complete', function() {
// console.log('Fastest is ' + this.filter('fastest').map('name'));
// })
// .run({ async: false });
Loading

0 comments on commit f3e6d84

Please sign in to comment.