From d10504f3eef6b1c3224b8f5197a50d46e4ef1637 Mon Sep 17 00:00:00 2001 From: Nathan Baltzell Date: Tue, 7 Oct 2025 18:33:47 -0400 Subject: [PATCH] add a little ROOT --- .gitignore | 6 +- build-coatjava.sh | 4 + common-tools/clas-io/pom.xml | 37 +++++ common-tools/clas-io/sconscript | 19 +++ common-tools/clas-io/sconstruct | 5 + .../clas-io/src/main/cpp/hoistJNI.cpp | 132 ++++++++++++++++++ .../src/main/java/org/jlab/io/root/Hoist.java | 62 ++++++++ .../main/java/org/jlab/io/root/HoistJNI.java | 13 ++ 8 files changed, 275 insertions(+), 3 deletions(-) create mode 100644 common-tools/clas-io/sconscript create mode 100644 common-tools/clas-io/sconstruct create mode 100644 common-tools/clas-io/src/main/cpp/hoistJNI.cpp create mode 100644 common-tools/clas-io/src/main/java/org/jlab/io/root/Hoist.java create mode 100644 common-tools/clas-io/src/main/java/org/jlab/io/root/HoistJNI.java diff --git a/.gitignore b/.gitignore index e06912d790..2851564bc8 100644 --- a/.gitignore +++ b/.gitignore @@ -46,9 +46,9 @@ hs_err_pid* .project .settings -# no log files: +# no log/data files: *.log *.evio -bin/evio2hipotest -export.sh +# scons litter: +.sconsign.dblite diff --git a/build-coatjava.sh b/build-coatjava.sh index 9b04f4aec7..c2c8046b94 100755 --- a/build-coatjava.sh +++ b/build-coatjava.sh @@ -208,6 +208,10 @@ for pom in $(find common-tools -name pom.xml); do # install_jars $pom $prefix_dir/lib/services fi done + +# install JNI stuff: +$(cd common-tools/clas-io/target && cp *.so ../../../coatjava/lib >& /dev/null || cp *.dylib ../../../coatjava/lib) + echo "installed coatjava to: $prefix_dir" echo "COATJAVA SUCCESSFULLY BUILT !" diff --git a/common-tools/clas-io/pom.xml b/common-tools/clas-io/pom.xml index f4972146be..d258c9b800 100644 --- a/common-tools/clas-io/pom.xml +++ b/common-tools/clas-io/pom.xml @@ -60,6 +60,43 @@ compile + + org.jlab + groot + 4.0.5 + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.6.1 + + + scons-1 + install + exec + + target/native + + + + scons-2 + install + exec + + + + + + + scons + + + + + diff --git a/common-tools/clas-io/sconscript b/common-tools/clas-io/sconscript new file mode 100644 index 0000000000..8d7196c1ad --- /dev/null +++ b/common-tools/clas-io/sconscript @@ -0,0 +1,19 @@ +Import('env') + +javah = env.Command('native', 'src/main/java/org/jlab/io/root/HoistJNI.java', ['javac -h $TARGET $SOURCE', Delete('src/main/java/org/jlab/io/root/HoistJNI.class')]) +AlwaysBuild(javah) + +if 'JAVA_HOME' in env['ENV']: + env['JAVA_HOME'] = env['ENV']['JAVA_HOME'] + env.Append(CPPPATH = ["$JAVA_HOME/include", "$JAVA_HOME/include/linux"]) + +elif env['PLATFORM'] == 'darwin': + env.ParseConfig("echo -I`/usr/libexec/java_home`/include") + env.ParseConfig("echo -I`/usr/libexec/java_home`/include/darwin") + +if env['PLATFORM'] == 'darwin': + env.ParseConfig("echo -Wl,-rpath,`root-config --libdir`") + +env.Append(CPPPATH = ['native']) +env.ParseConfig("root-config --libs --cflags") +env.SharedLibrary('hoistJNI', Glob('*.cpp')) diff --git a/common-tools/clas-io/sconstruct b/common-tools/clas-io/sconstruct new file mode 100644 index 0000000000..b3c8906270 --- /dev/null +++ b/common-tools/clas-io/sconstruct @@ -0,0 +1,5 @@ +import os + +env = Environment(ENV=os.environ) +Export('env') +env.SConscript('sconscript', variant_dir='target', duplicate=0) diff --git a/common-tools/clas-io/src/main/cpp/hoistJNI.cpp b/common-tools/clas-io/src/main/cpp/hoistJNI.cpp new file mode 100644 index 0000000000..a961db8dac --- /dev/null +++ b/common-tools/clas-io/src/main/cpp/hoistJNI.cpp @@ -0,0 +1,132 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "org_jlab_io_root_HoistJNI.h" + +class concurrentMap +{ + std::mutex m_; + std::unordered_map objs; + +public: + TObject* get(std::string k) { + std::unique_lock lock(m_); + return objs[k]; + } + + void set(std::string k, TObject* v) { + std::unique_lock lock(m_); + objs[k] = v; + } +}; + +concurrentMap objects; + +static __attribute__((constructor)) void init() { + gSystem->ResetSignals(); + ROOT::EnableThreadSafety(); + gROOT->SetBatch(true); +} + +JNIEXPORT void JNICALL Java_org_jlab_io_root_HoistJNI_createFile (JNIEnv *env, jobject thisObj, jstring jfname) { + const char *fname = env->GetStringUTFChars(jfname, NULL); + TFile* ff = new TFile(fname, "RECREATE"); + objects.set(fname, ff); + env->ReleaseStringUTFChars(jfname, fname); +} + +JNIEXPORT void JNICALL Java_org_jlab_io_root_HoistJNI_closeFile (JNIEnv *env, jobject thisObj, jstring jfname) { + const char *fname = env->GetStringUTFChars(jfname, NULL); + ((TFile*) objects.get(fname))->Close(); + env->ReleaseStringUTFChars(jfname, fname); +} + +JNIEXPORT void JNICALL Java_org_jlab_io_root_HoistJNI_mkdir( JNIEnv *env, jobject thisObj, jstring jfname, jstring jpath) { + const char *fname = env->GetStringUTFChars(jfname, NULL); + const char *path = env->GetStringUTFChars(jpath, NULL); + ((TFile*) objects.get(fname))->mkdir(path); + env->ReleaseStringUTFChars(jfname, fname); + env->ReleaseStringUTFChars(jpath, path); +} + +JNIEXPORT void JNICALL Java_org_jlab_io_root_HoistJNI_writeH1F (JNIEnv *env, jobject thisObj, jstring jfname, jstring jpath, + jstring jname, jstring jtitle, jint nbins, jdouble xmin, jdouble xmax, jfloatArray jdata) { + + const char *fname = env->GetStringUTFChars(jfname, NULL); + const char *path = env->GetStringUTFChars(jpath, NULL); + const char *name = env->GetStringUTFChars(jname, NULL); + const char *title = env->GetStringUTFChars(jtitle, NULL); + + float *cdata = env->GetFloatArrayElements(jdata, NULL); + + TFile* ff = (TFile*) objects.get(fname); + if(!ff->Get(path)) + ff->mkdir(path); + ff->cd(path); + + TH1F* h1 = new TH1F(name, title, nbins, xmin, xmax); + jsize length = env->GetArrayLength(jdata); + double nentries = 0; + + for(int ib=0;ibSetBinContent(ib+1, cdata[ib]); + nentries += cdata[ib]; + } + + h1->SetEntries(nentries); + h1->Write("",TObject::kOverwrite); + + env->ReleaseFloatArrayElements(jdata, cdata, 0); + env->ReleaseStringUTFChars(jfname, fname); + env->ReleaseStringUTFChars(jpath, path); + env->ReleaseStringUTFChars(jname, name); + env->ReleaseStringUTFChars(jtitle, title); +} + +JNIEXPORT void JNICALL Java_org_jlab_io_root_HoistJNI_writeH2F (JNIEnv *env, jobject thisObj, jstring jfname, jstring jpath, + jstring jname, jstring jtitle, jint nxbins, jdouble xmin, jdouble xmax, jint nybins, jdouble ymin, jdouble ymax, jfloatArray jdata) { + + const char *fname = env->GetStringUTFChars(jfname, NULL); + const char *path = env->GetStringUTFChars(jpath, NULL); + const char *name = env->GetStringUTFChars(jname, NULL); + const char *title = env->GetStringUTFChars(jtitle, NULL); + + float *cdata = env->GetFloatArrayElements(jdata, NULL); + + TFile* ff = (TFile*) objects.get(fname); + if(!ff->Get(path)) + ff->mkdir(path); + ff->cd(path); + + TH2F* h2 = new TH2F(name, title, nxbins, xmin, xmax, nybins, ymin, ymax); + double nentries = 0; + int ii = 0; + + for(int ix=0;ixSetBinContent(ix+1, iy+1, cdata[ii]); + nentries += cdata[ii++]; + } + + h2->SetEntries(nentries); + h2->Write("",TObject::kOverwrite); + + env->ReleaseFloatArrayElements(jdata, cdata, 0); + env->ReleaseStringUTFChars(jfname, fname); + env->ReleaseStringUTFChars(jpath, path); + env->ReleaseStringUTFChars(jname, name); + env->ReleaseStringUTFChars(jtitle, title); +} + diff --git a/common-tools/clas-io/src/main/java/org/jlab/io/root/Hoist.java b/common-tools/clas-io/src/main/java/org/jlab/io/root/Hoist.java new file mode 100644 index 0000000000..9587bceeaa --- /dev/null +++ b/common-tools/clas-io/src/main/java/org/jlab/io/root/Hoist.java @@ -0,0 +1,62 @@ +package org.jlab.io.root; + +import org.jlab.groot.data.H1F; +import org.jlab.groot.data.H2F; + +/** + * Copied from https://github.com/drewkenjo/j2root + */ +public class Hoist { + + HoistJNI hoist = new HoistJNI(); + + private String fname; + private String path = ""; + + public Hoist(String fname) { + this.fname = fname; + hoist.createFile(fname); + } + + public void close() { + hoist.closeFile(fname); + } + + public void mkdir(String path) { + path = path.replaceFirst("^/*","").replaceAll("/*\\$",""); + hoist.mkdir(fname, path); + this.path = path; + } + + public void cd(String path) { + this.path = path.replaceFirst("^/*","").replaceAll("/*\\$",""); + } + + public void write(H1F h1) { + String fullpath = path + "/" + h1.getName(); + int ind = fullpath.lastIndexOf("/"); + String relpath = fullpath.substring(0,ind); + relpath = relpath.replaceFirst("^/*","").replaceAll("/*\\$",""); + String name = fullpath.substring(ind+1); + hoist.writeH1F(fname, relpath, name, + h1.getXaxis().getNBins(), h1.getXaxis().min(), h1.getXaxis().max(), + h1.getData()); + } + + public void write(H2F h2) { + String fullpath = path + "/" + h2.getName(); + int ind = fullpath.lastIndexOf("/"); + String relpath = fullpath.substring(0,ind); + relpath = relpath.replaceFirst("^/*","").replaceAll("/*\\$",""); + String name = fullpath.substring(ind+1); + int xsize = h2.getDataSize(0), ysize = h2.getDataSize(1), ii = 0; + float[] data = new float[xsize*ysize]; + for(int ix=0;ix