/** * G4blGui.java -- run G4beamline with a Graphical User Interface. * * NOTE: this program expects to be run: * java -cp $G4BL_DIR/share/g4beamline G4blGui [input.file] * It uses the user classpath to find the G4beamline install directory, * expecting the classpath to be the share/g4beamline directory under * $G4BL_DIR. * * Copyright 2007-2012 by Tom Roberts, all rights reserved. * This program is released under the Gnu Public License. */ import java.io.*; import java.util.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.event.*; import java.net.URL; public class G4blGui extends WindowAdapter implements ActionListener, HyperlinkListener { // CopyThread will copy a sub-process' stderr/stdout to stderr/stdout. static class CopyThread extends Thread { BufferedReader in; PrintStream out; CopyThread(InputStream _in, PrintStream _out) { super(); in = new BufferedReader(new InputStreamReader(_in)); out = _out; start(); } public void run() { try { String line; while( (line=in.readLine()) != null) out.println(line); in.close(); } catch(Exception e) { } } }; JFrame frame; JButton runButton; JTextField inputFileField; JTextField outputFileField; JTextField paramField; JTextField otherViewerField; JCheckBox historootEventsField; JSpinner nViewerEventsField; JSpinner nViewerRunsField; String viewer; JTextArea outputArea; boolean doScroll; BufferedWriter outputFile; JScrollPane helpScroll; JScrollPane outputScroll; JEditorPane helpPane; Process g4beamlineProcess; Process wiredProcess; JScrollBar scroll; int lastScroll; boolean aborted; String osName; String system="."; Map env; File currentDirectory; File inputFile; String filesep; String pathsep; String g4bl_dir; boolean needToRunWired; String g4blProcessID; public G4blGui(String[] args) { aborted = false; filesep = System.getProperty("file.separator"); pathsep = System.getProperty("path.separator"); osName = System.getProperty("os.name"); currentDirectory = new File(System.getProperty("user.dir")); String ext = ""; if(osName.startsWith("Windows")){ currentDirectory = new File(System.getProperty("user.home")); ext = ".exe"; } if(!currentDirectory.exists() || !currentDirectory.isDirectory()) currentDirectory = new File(System.getProperty("user.home")); inputFile = null; viewer = "none"; outputArea = null; doScroll = true; outputFile = null; g4beamlineProcess = null; wiredProcess = null; lastScroll = 0; needToRunWired = false; // handle args[] -- change directory to directory containing input.file if(args.length == 1) { inputFile = new File(args[0]); File d = inputFile.getParentFile(); if(inputFile == null || d == null || !inputFile.exists() || !d.exists() || !d.isDirectory()) inputFile = null; // fail silently else currentDirectory = d; } // find the installation directory G4BL_DIR g4bl_dir = Util.findG4blDir(); if(g4bl_dir == null) { JOptionPane.showMessageDialog(frame, "Cannot determine install directory.\n"); System.exit(1); } File dir = new File(g4bl_dir); // find SYSTEM if(osName.startsWith("Windows")) system = "WIN32"; else if(osName.startsWith("Mac")) system = "Darwin"; else if(osName.startsWith("Linux")) system = "Linux"; System.out.printf("SYSTEM='%s'\n",system); // Get the current environmennt into a writable Map<> env = new HashMap(); Map oldenv = System.getenv(); Iterator iter = oldenv.keySet().iterator(); while(iter.hasNext()) { String key = iter.next(); String val = oldenv.get(key); env.put(key,val); } env.put("G4BL_DIR",g4bl_dir); // check for G4BEAMLINE set if(!env.containsKey("G4BEAMLINE")) { env.put("G4BEAMLINE",g4bl_dir + "/bin/g4beamline"); } else { System.out.printf("G4BEAMLINE='%s'\n",env.get("G4BEAMLINE")); } // set ROOTSYS if(!env.containsKey("ROOTSYS")) env.put("ROOTSYS",""); // Put physics datasets into the environment (not overwriting) String geant4_data = Util.findGeant4Data(); while(geant4_data == null) try { int ok = JOptionPane.showConfirmDialog(null, "The Geant4Data are not found; they are required to run G4beamline.\n"+ "If you already have them, you can manually copy or link them to\n"+ " "+g4bl_dir+"/Geant4Data\n"+ "Otherwise, select Yes to run G4blData to download them,\n"+ "or No to exit G4beamline.","Error",JOptionPane.YES_NO_OPTION); if(ok == JOptionPane.NO_OPTION) System.exit(1); // Geant4Data does not exist -- run G4blData runG4blData(); geant4_data = Util.findGeant4Data(); } catch(Exception e) { System.out.println(e.toString()); } File data = new File(geant4_data); String[] list = data.list(); if(list != null) { for(int j=0; j 0) { try { if(Runtime.getRuntime(). exec("kill -2 "+g4blProcessID).waitFor()==0) Thread.sleep(1000); } catch(Exception e) { /* ignore */} } if(g4beamlineProcess != null) { g4beamlineProcess.destroy(); g4beamlineProcess = null; try { Thread.sleep(1000); } catch(Exception e) { } } scroll.setValue(scroll.getMaximum()); } } /** doabort() will abort G4beamline. * Doesn't use Process.destroy() as that might refer to a shell. **/ void doAbortOLD() { try { if(osName.startsWith("Windows")) { // Some systems don't have taskkill, so try // them both, ignoring errors. try { Runtime.getRuntime().exec("tskill g4beamline"); } catch(Exception e1) { /* ignore error */ } Runtime.getRuntime().exec("taskkill /f /im g4beamline.exe"); } else { Runtime.getRuntime().exec("killall g4beamline"); } } catch(Exception e) { /* ignore error */ } } /** user close of the main window comes here **/ public void windowClosing(WindowEvent event) { doAbort(); if(wiredProcess != null) wiredProcess.destroy(); System.exit(0); } /** * runG4beamline() -- run the program with its environment set up * for portability, do everything of the g4bl script, here in Java. **/ Process runG4beamline() throws java.io.IOException { // verify input.file has been selected, and its directory if(currentDirectory == null || !currentDirectory.isDirectory() || inputFile == null || !inputFile.exists()) { JOptionPane.showMessageDialog(frame, "No input file selected.\n" + "Use the Browse button to select one."); return null; } // display data sets to the user, and verify their presence int nData=0; if(env.containsKey("G4ABLADATA")) { ++nData; System.out.printf("G4ABLADATA='%s'\n",env.get("G4ABLADATA")); } if(env.containsKey("G4LEDATA")) { ++nData; System.out.printf("G4LEDATA='%s'\n",env.get("G4LEDATA")); } if(env.containsKey("G4NEUTRONHPDATA")) { ++nData; System.out.printf("G4NEUTRONHPDATA='%s'\n",env.get("G4NEUTRONHPDATA")); } if(env.containsKey("G4NEUTRONXSDATA")) { ++nData; System.out.printf("G4NEUTRONXSDATA='%s'\n",env.get("G4NEUTRONXSDATA")); } if(env.containsKey("G4PIIDATA")) { ++nData; System.out.printf("G4PIIDATA='%s'\n",env.get("G4PIIDATA")); } if(env.containsKey("G4LEVELGAMMADATA")) { ++nData; System.out.printf("G4LEVELGAMMADATA='%s'\n",env.get("G4LEVELGAMMADATA")); } if(env.containsKey("G4RADIOACTIVEDATA")) { ++nData; System.out.printf("G4RADIOACTIVEDATA='%s'\n",env.get("G4RADIOACTIVEDATA")); } if(env.containsKey("G4REALSURFACEDATA")) { ++nData; System.out.printf("G4REALSURFACEDATA='%s'\n",env.get("G4REALSURFACEDATA")); } if(nData == 0) { JOptionPane.showMessageDialog(frame, "Geant4 data files not found"); return null; } // get library search paths (different for each OS) if(system.equals("Linux")) { String ld_library_path = env.get("LD_LIBRARY_PATH"); if(ld_library_path == null) ld_library_path = ""; ld_library_path = g4bl_dir + "/lib" + pathsep + ld_library_path; env.put("LD_LIBRARY_PATH",ld_library_path); System.out.printf("LD_LIBRARY_PATH=%s\n",ld_library_path); } else if(system.equals("Darwin")) { String dyld_library_path = env.get("DYLD_LIBRARY_PATH"); if(dyld_library_path == null) dyld_library_path = ""; dyld_library_path = g4bl_dir + "/lib" + pathsep + dyld_library_path; env.put("DYLD_LIBRARY_PATH",dyld_library_path); System.out.printf("DYLD_LIBRARY_PATH=%s\n",dyld_library_path); } else if(system.equals("WIN32")) { String path = env.get("PATH"); if(path == null) path = env.get("Path"); if(path == null) path = ""; path += pathsep + g4bl_dir + "/bin"; env.put("PATH",path); System.out.printf("PATH=%s\n",path); } // get the updated environment into an array for Runtime.exec() String[] envarray = new String[env.size()]; Iterator iter = env.keySet().iterator(); int i = 0; while(iter.hasNext()) { String key = iter.next(); String val = env.get(key); envarray[i++] = key + "=" + val; } // get viewer, determine actual viewer String v = viewer; if(v.equals("Other")) v = otherViewerField.getText(); if(v.startsWith("Wired")) v = "Wired"; if(v.startsWith("wired")) v = "Wired"; if(v.equals("best")) { if(osName.startsWith("Windows")) v = "OIWin32"; else v = "OIX"; } needToRunWired = v.equals("Wired"); //System.out.printf("v=%s viewer=%s\n",v,viewer); // execute command, permitting spaces in g4bl_dir and inputFile String cmd = "/path/to/g4beamline /path/to/input.file viewer=" + v + " " + paramField.getText() + " "; // (ends with ' ') Vector cmdv = new Vector(); StringBuilder sb = new StringBuilder(); for(int pos=0; pos 0) { cmdv.add(sb.toString()); sb.setLength(0); } continue; } if(c == '"' || c == '\'') { // quotes themselves are omitted ++pos; while(pos < cmd.length() && cmd.charAt(pos) != c) sb.append(cmd.charAt(pos++)); continue; } sb.append(c); } if(historootEventsField.isSelected()) { String d = inputFile.getParent(); if(d == null) d = "."; cmdv.add("eventcuts file='" + d + "/histo_event.txt'"); } cmdv.set(0,env.get("G4BEAMLINE")); cmdv.set(1,inputFile.getAbsolutePath()); String[] cmdarray = (String [])cmdv.toArray(new String[0]); System.out.printf("exec prog:%s\n",cmdarray[0]); for(i=1; i= scroll.getMaximum()-scroll.getVisibleAmount()-64 || scroll.getValue() >= lastScroll || line.startsWith("g4beamline: simulation aborted")); try { outputFile.write(line + "\n"); } catch(Exception e) { } int nLines = outputArea.getLineCount(); if(nLines > 20000) try { // when huge, just keep last lines outputArea.replaceRange( "-- DELETED (full output kept in output file) --\n", outputArea.getLineStartOffset(0), outputArea.getLineStartOffset(nLines-15000)); } catch(Exception e) { } outputArea.append(line + '\n'); if(doScroll) { scroll.setValue(scroll.getMaximum()); lastScroll = scroll.getValue(); } } /** internal class RunMonitorThread copies G4beamline stdout to * outputLine() and handles the finalization of output stuff when * G4beamline exits. This is the place where we know that gbeamline * has exited, so some rather surprising stuff is here (e.g. * runButton, other threads, ....). * (readline() will return null when G4beamline exits.) **/ class RunMonitorThread extends Thread { public RunMonitorThread() { } public void run() { if(g4beamlineProcess == null) return; // outputSetup() already called. runButton.setText("Abort"); try { StderrThread stderrThread = new StderrThread(); stderrThread.start(); StdinThread stdinThread = new StdinThread(); stdinThread.start(); g4blProcessID = ""; try { BufferedReader in = new BufferedReader( new InputStreamReader( g4beamlineProcess.getInputStream())); String line; while((line=in.readLine()) != null) { if(g4blProcessID.length() == 0 && line.startsWith("G4beamline Process ID")) g4blProcessID = line.split(" ")[3]; outputLine(line); } in.close(); } catch(Exception e) { System.err.println(e); outputArea.append(e.toString() + "\nProgram output is probably lost.\n\n"); } sleep(100); // 100 ms to give them a chance to finish stdinThread.interrupt(); stderrThread.interrupt(); } catch(Exception e) { System.err.println(e); outputArea.append(e.toString() + "\nProgram output is probably lost.\n\n"); } finally { try { if(g4beamlineProcess.waitFor() != 0 || aborted) { needToRunWired = false; if(!aborted) JOptionPane.showMessageDialog(frame, "Program Failed"); } if(aborted) outputArea.append("\n*** User Abort ***\n\n"); } catch(Exception e) { /* ignore exception */ } } if(g4beamlineProcess != null) g4beamlineProcess.destroy(); g4beamlineProcess = null; scroll.setValue(scroll.getMaximum()); outputClose(); if(needToRunWired) { outputArea.append("\n... Running the Wired3 event viewer ...\n"); // jump to bottom of outputArea for this message scroll.setValue(scroll.getMaximum()); try { wiredProcess=runWired(); } catch(Exception e) { } } outputArea.append("\n\n\n"); if(doScroll) { try { sleep(100); } catch(Exception e) { } scroll.setValue(scroll.getMaximum()); } runButton.setText(" Run "); } } /** internal class StderrThread copies G4beamline stderr to outputLine() * (readline() will return null when G4beamline exits.) **/ class StderrThread extends Thread { public StderrThread() { } public void run() { if(g4beamlineProcess == null) return; BufferedReader in=null; try { in = new BufferedReader( new InputStreamReader(g4beamlineProcess.getErrorStream())); String line; while((line=in.readLine()) != null) { outputLine(line); } } catch(Exception e) { System.err.println(e); outputArea.append(e.toString() + "\nProgram output is probably lost.\n\n"); } try { if(in != null) in.close(); } catch(Exception e) { } } }; /** internal class StdinThread writes "/run/beamOn N" to stdin. **/ class StdinThread extends Thread { public StdinThread() { } public void run() { if(g4beamlineProcess == null) return; BufferedWriter stdin=null; try { int nViewerEvents = (Integer)nViewerEventsField.getValue(); int nRuns = (Integer)nViewerRunsField.getValue(); stdin = new BufferedWriter( new OutputStreamWriter( g4beamlineProcess.getOutputStream())); for(int i=0; i