// // TestSSCluster.java // /* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package visad.cluster; import visad.*; import visad.java3d.*; import visad.java2d.*; import visad.ss.*; import visad.bom.*; import visad.data.vis5d.Vis5DForm; import java.util.Vector; import java.rmi.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.io.IOException; /** TestSSCluster is the class for testing the visad.cluster package.<P> <PRE> If you want to run the demo yourself, download the latest VisAD, and also download the v5d file: ftp://www.ssec.wisc.edu/pub/visad-2.0/QLQ.v5d Then run the four commands: java visad.cluster.TestSSCluster 1 QLQ.v5d java visad.cluster.TestSSCluster 2 QLQ.v5d java visad.cluster.TestSSCluster 3 QLQ.v5d java visad.cluster.TestSSCluster 4 QLQ.v5d These create the four cluster nodes. Wait for all four to print both messages: v5d_type = (Time -> (((row, col, Height) -> QL), ((row, col, Height) -> Q))) data ready as (Time -> ((row, col, Height) -> (QL, Q))) Then run a fifth command for the client: java visad.cluster.TestSSCluster 0 QLQ.v5d As soon as the window pops up, you can click the "Widgets" button and when the widgets have initialized, slide the QL (cloud water) slider over to any value between 0.5 and 1.0. When the "please wait ..." message disappears in the 3-D window, click on the "Go" button to animate. Change animation rate by entering a new number of milliseonds per frame in the text box. Click on any combination of the "Res 1", "Res 2", "Res 3" and "Res 4" buttons to toggle between high and low resolution in each quadrant. Its interesting to click "Res 1", "Res 2" and "Res 4" but not "Res 3", which gives a sense of how this will be used in practice: looking at data from all but one node at low resolution. Of course, with a data set large enough for this to be necessary, the low resolution will not look so blocky, You can also click on the "Maps" button to get the SpreadSheet user interface for setting display mappings. After you click "Done", you'll need to click "Widgets" again to see the widgets that correspond to your new mappings. The display clearly shows the partition between quadrants. We could get rid of these breaks, but at least for the demo its nice to see where the spatial paritions are. Note these five JVMs running on one machine will eat a lot of memory and cycles. </PRE> */ public class TestSSCluster extends FancySSCell implements ActionListener { private RemoteDataReferenceImpl remote_ref = null; public TestSSCluster(String name, Frame parent) throws VisADException, RemoteException { super(name, parent); } /** * override method from BasicSSCell */ protected String addData(int id, Data data, ConstantMap[] cmaps, String source, int type, boolean notify) throws VisADException, RemoteException { // add Data object to cell DataReferenceImpl ref = new DataReferenceImpl(Name); // new if (data instanceof RemoteData) { remote_ref = new RemoteDataReferenceImpl(ref); remote_ref.setData(data); } else { ref.setData(data); } SSCellData cellData; synchronized (CellData) { cellData = addReferenceImpl(id, ref, cmaps, source, type, notify, true); } return cellData.getVariableName(); } /** * override method from BasicSSCell */ protected SSCellData addReferenceImpl(int id, DataReferenceImpl ref, ConstantMap[] cmaps, String source, int type, boolean notify, boolean checkErrors) throws VisADException, RemoteException { // ensure that id is valid if (id == 0) id = getFirstFreeId(); // ensure that ref is valid if (ref == null) ref = new DataReferenceImpl(Name); // notify linked cells of data addition (ADD_DATA message must come first) // if (notify) sendMessage(ADD_DATA, source, ref.getData()); // add data reference to cell SSCellData cellData = new SSCellData(id, this, ref, cmaps, source, type, checkErrors); CellData.add(cellData); if (!IsRemote) { // SERVER: add data reference to display if (HasMappings) VDisplay.addReference(ref, cmaps); // add remote data reference to servers synchronized (Servers) { RemoteDataReferenceImpl remoteRef = (RemoteDataReferenceImpl) cellData.getRemoteReference(); int len = Servers.size(); for (int i=0; i<len; i++) { RemoteServerImpl rs = (RemoteServerImpl) Servers.elementAt(i); rs.addDataReference(remoteRef); } } } return cellData; } /** * override method from BasicSSCell */ public synchronized void setMaps(ScalarMap[] maps) throws VisADException, RemoteException { if (maps == null) return; VisADException vexc = null; RemoteException rexc = null; if (IsRemote) { // CLIENT: send new mappings to server // sendMessage(SET_MAPS, DataUtility.convertMapsToString(maps), null); } else { // SERVER: set up mappings DataReference[] dr; ConstantMap[][] cmaps; synchronized (CellData) { int len = CellData.size(); dr = new DataReference[len]; cmaps = new ConstantMap[len][]; for (int i=0; i<len; i++) { SSCellData cellData = (SSCellData) CellData.elementAt(i); dr[i] = cellData.getReference(); cmaps[i] = cellData.getConstantMaps(); } } String save = getPartialSaveString(); VDisplay.disableAction(); clearMaps(); for (int i=0; i<maps.length; i++) { if (maps[i] != null) { try { VDisplay.addMap(maps[i]); } catch (VisADException exc) { vexc = exc; } catch (RemoteException exc) { rexc = exc; } } } for (int i=0; i<dr.length; i++) { // determine if ImageRendererJ3D can be used boolean ok = false; Data data = dr[i].getData(); if (data == null) { } else if (Possible3D) { MathType type = data.getType(); try { ok = ImageRendererJ3D.isRendererUsable(type, maps); } catch (VisADException exc) { if (DEBUG && DEBUG_LEVEL >= 3) exc.printStackTrace(); } } // add reference if (ok && Dim != JAVA2D_2D) { VDisplay.addReferences(new ImageRendererJ3D(), dr[i], cmaps[i]); } else { if (remote_ref == null) { VDisplay.addReference(dr[i], cmaps[i]); } else { RemoteVDisplay.addReference(remote_ref, cmaps[i]); } } } VDisplay.enableAction(); setPartialSaveString(save, true); } HasMappings = true; if (vexc != null) throw vexc; if (rexc != null) throw rexc; } /** * override method from BasicSSCell */ public synchronized boolean constructDisplay() { boolean success = true; DisplayImpl newDisplay = VDisplay; RemoteDisplay rmtDisplay = RemoteVDisplay; if (IsSlave) { // SLAVE: construct dummy 2-D display try { newDisplay = new DisplayImplJ2D("DUMMY"); } catch (VisADException exc) { if (DEBUG) exc.printStackTrace(); success = false; } catch (RemoteException exc) { if (DEBUG) exc.printStackTrace(); success = false; } } else if (!CanDo3D && Dim != JAVA2D_2D) { // dimension requires Java3D, but Java3D is disabled for this JVM success = false; } else { // construct display of the proper dimension try { if (IsRemote) { // CLIENT: construct new display from server's remote copy if (Dim == JAVA3D_3D) newDisplay = new DisplayImplJ3D(rmtDisplay); else if (Dim == JAVA2D_2D) { newDisplay = new DisplayImplJ2D(rmtDisplay); } else { // Dim == JAVA3D_2D TwoDDisplayRendererJ3D tdr = new TwoDDisplayRendererJ3D(); newDisplay = new DisplayImplJ3D(rmtDisplay, tdr); } } else { // SERVER: construct new display and make a remote copy if (Dim == JAVA3D_3D) { ClientDisplayRendererJ3D cdr = new ClientDisplayRendererJ3D(100000); newDisplay = new DisplayImplJ3D(Name, cdr); } else if (Dim == JAVA2D_2D) newDisplay = new DisplayImplJ2D(Name); else { // Dim == JAVA3D_2D TwoDDisplayRendererJ3D tdr = new TwoDDisplayRendererJ3D(); newDisplay = new DisplayImplJ3D(Name, tdr); } rmtDisplay = new RemoteDisplayImpl(newDisplay); } } catch (NoClassDefFoundError err) { if (DEBUG) err.printStackTrace(); success = false; } catch (UnsatisfiedLinkError err) { if (DEBUG) err.printStackTrace(); success = false; } catch (Exception exc) { if (DEBUG) exc.printStackTrace(); success = false; } } if (success) { if (VDisplay != null) { try { VDisplay.destroy(); } catch (VisADException exc) { if (DEBUG) exc.printStackTrace(); } catch (RemoteException exc) { if (DEBUG) exc.printStackTrace(); } } VDisplay = newDisplay; RemoteVDisplay = rmtDisplay; } return success; } public static void main(String[] args) throws RemoteException, VisADException, IOException { int node_divide = 2; int number_of_nodes = node_divide * node_divide; RemoteNodeField[] node_v5ds = new RemoteNodeField[number_of_nodes]; if (args == null || args.length < 2) { System.out.println("usage: 'java visad.cluster.TestSSCluster " + "n file.v5d'"); System.out.println(" where n = 0 for client, 1 - " + number_of_nodes + " for nodes"); return; } int id = -1; try { id = Integer.parseInt(args[0]); } catch (NumberFormatException e) { System.out.println("usage: 'java visad.cluster.TestSSCluster " + "n file.v5d'"); System.out.println(" where n = 0 for client, 1 - " + number_of_nodes + " for nodes"); return; } if (id < 0 || id > number_of_nodes) { System.out.println("usage: 'java visad.cluster.TestSSCluster " + "n file.v5d'"); System.out.println(" where n = 0 for client, 1 - " + number_of_nodes + " for nodes"); return; } boolean client = (id == 0); Vis5DForm v5d_form = new Vis5DForm(); FieldImpl v5d = (FieldImpl) v5d_form.open(args[1]); if (v5d == null) { System.out.println("cannot open " + args[1]); return; } FunctionType v5d_type = (FunctionType) v5d.getType(); Set time_set = v5d.getDomainSet(); int time_length = time_set.getLength(); MathType v5d_range_type = v5d_type.getRange(); DataImpl v5d_range0 = (DataImpl) v5d.getSample(0); FunctionType grid_type = null; FunctionType grid_type2 = null; FlatField grid0 = null; if (v5d_range_type instanceof FunctionType) { grid_type = (FunctionType) v5d_range_type; grid_type2 = null; grid0 = (FlatField) v5d_range0; } else { grid_type = (FunctionType) ((TupleType) v5d_range_type).getComponent(0); grid_type2 = (FunctionType) ((TupleType) v5d_range_type).getComponent(1); grid0 = (FlatField) ((Tuple) v5d_range0).getComponent(0); } Gridded3DSet domain_set = (Gridded3DSet) grid0.getDomainSet(); Gridded3DSet ps = makePS(domain_set, node_divide); if (!client) { System.out.println("v5d_type = " + v5d_type); RealTupleType domain_type = grid_type.getDomain(); RealTupleType time_tuple = v5d_type.getDomain(); RealType time = (RealType) time_tuple.getComponent(0); RealType x = (RealType) domain_type.getComponent(0); RealType y = (RealType) domain_type.getComponent(1); RealType z = (RealType) domain_type.getComponent(2); RealType val = (RealType) grid_type.getRange(); RealType val2 = (grid_type2 == null) ? null : (RealType) grid_type2.getRange(); float[][] samples = domain_set.getSamples(false); int x_len = domain_set.getLength(0); int y_len = domain_set.getLength(1); int z_len = domain_set.getLength(2); int len = domain_set.getLength(); Gridded3DSet[] subsets = new Gridded3DSet[number_of_nodes]; int k = id - 1; int ik = k % node_divide; int ig = ik * x_len / node_divide; int igp = (ik + 1) * x_len / node_divide; if (ik == (node_divide - 1)) igp = x_len; int jk = k / node_divide; int jg = jk * y_len / node_divide; int jgp = (jk + 1) * y_len / node_divide; if (jk == (node_divide - 1)) jgp = y_len; int sub_x_len = igp - ig; int sub_y_len = jgp - jg; int sub_len = sub_x_len * sub_y_len * z_len; // System.out.println("sub_len = " + sub_len + " out of len = " + len); float[][] sub_samples = new float[3][sub_len]; for (int i=0; i<sub_x_len; i++) { for (int j=0; j<sub_y_len; j++) { for (int m=0; m<z_len; m++) { int a = i + sub_x_len * (j + sub_y_len * m); int b = (i + ig) + x_len * ((j + jg) + y_len * m); sub_samples[0][a] = samples[0][b]; sub_samples[1][a] = samples[1][b]; sub_samples[2][a] = samples[2][b]; } } } subsets[k] = new Gridded3DSet(domain_type, sub_samples, sub_x_len, sub_y_len, z_len, domain_set.getCoordinateSystem(), domain_set.getSetUnits(), null); RemoteNodeDataImpl[] subgrids = new RemoteNodeDataImpl[time_length]; for (int i=0; i<time_length; i++) { DataImpl v5d_sample = (DataImpl) v5d.getSample(i); if (v5d_sample instanceof FlatField) { FlatField grid = (FlatField) v5d_sample; FlatField subgrid = (FlatField) grid.resample(subsets[k]); subgrids[i] = new RemoteNodePartitionedFieldImpl(subgrid); } else { Tuple v5d_tuple = (Tuple) v5d_sample; int ngrids = v5d_tuple.getDimension(); RemoteNodeDataImpl[] subsubgrids = new RemoteNodeDataImpl[ngrids]; FlatField[] combinegrids = new FlatField[ngrids]; for (int j=0; j<ngrids; j++) { FlatField grid = (FlatField) v5d_tuple.getComponent(j); combinegrids[j] = (FlatField) grid.resample(subsets[k]); // subsubgrids[j] = // new RemoteNodePartitionedFieldImpl(combinegrids[j]); } // subgrids[i] = new RemoteNodeTupleImpl(subsubgrids); FlatField subgrid = (FlatField) FieldImpl.combine(combinegrids); subgrids[i] = new RemoteNodePartitionedFieldImpl(subgrid); } } FunctionType new_v5d_type = new FunctionType(time_tuple, subgrids[0].getType()); node_v5ds[k] = new RemoteNodeFieldImpl(new_v5d_type, time_set); node_v5ds[k].setSamples(subgrids, false); int kk = id - 1; String url = "///TestVis5DCluster" + kk; try { Naming.rebind(url, node_v5ds[kk]); } catch (Exception e) { System.out.println("rebind " + kk + " " + e); return; } // just so app doesn't exit DisplayImpl display = new DisplayImplJ2D("dummy"); System.out.println("data ready as " + new_v5d_type); return; } // end if (!client) // this is all client code for (int k=0; k<number_of_nodes; k++) { // to test on a real cluster, change to something like: // String ipname = "node" + k + ".ncar.ucar.edu"; // String url = "//" + ipname + "/TestVis5DCluster" + k; // Then start up the four server commands on machines named // node1.ncar.ucar.edu, node2.ncar.ucar.edu, node3.ncar.ucar.edu // and node1.ncar.ucar.edu (or whatever). String url = "///TestVis5DCluster" + k; try { node_v5ds[k] = (RemoteNodeField) Naming.lookup(url); } catch (Exception e) { System.out.println("lookup " + k + " " + e); return; } } v5d_type = (FunctionType) node_v5ds[0].getType(); System.out.println("data type = " + v5d_type); time_set = node_v5ds[0].getDomainSet(); RemoteClientFieldImpl client_v5d = new RemoteClientFieldImpl(v5d_type, time_set); RemoteClusterData[] table = new RemoteClusterData[number_of_nodes + 1]; for (int i=0; i<number_of_nodes; i++) { table[i] = node_v5ds[i]; } table[number_of_nodes] = client_v5d; for (int i=0; i<table.length; i++) { table[i].setupClusterData(ps, table); } // create JFrame (i.e., a window) for display and slider JFrame frame = new JFrame("test ClientRendererJ3D"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {System.exit(0);} }); TestSSCluster ss = new TestSSCluster("TestSSCluster", frame); ss.addData(client_v5d); // ss.addData(0, client_v5d, null, "", DIRECT_SOURCE, true); // create JPanel in JFrame JPanel panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); frame.getContentPane().add(panel); JPanel bpanel = new JPanel(); bpanel.setLayout(new BoxLayout(bpanel, BoxLayout.X_AXIS)); JButton maps = new JButton("Maps"); maps.addActionListener(ss); maps.setActionCommand("map"); bpanel.add(maps); JButton show = new JButton("Widgets"); show.addActionListener(ss); show.setActionCommand("widgets"); bpanel.add(show); JButton res1 = new JButton("Res 1"); res1.addActionListener(ss); res1.setActionCommand("res1"); bpanel.add(res1); JButton res2 = new JButton("Res 2"); res2.addActionListener(ss); res2.setActionCommand("res2"); bpanel.add(res2); JButton res3 = new JButton("Res 3"); res3.addActionListener(ss); res3.setActionCommand("res3"); bpanel.add(res3); JButton res4 = new JButton("Res 4"); res4.addActionListener(ss); res4.setActionCommand("res4"); bpanel.add(res4); panel.add(ss); panel.add(bpanel); // set size of JFrame and make it visible frame.setSize(600, 600); frame.setVisible(true); } int[] res = {1, 1, 1, 1}; public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); if (cmd.equals("map")) { hideWidgetFrame(); addMapDialog(); } else if (cmd.equals("widgets")) { showWidgetFrame(); } else if (cmd.equals("res1")) { flipRes(0); } else if (cmd.equals("res2")) { flipRes(1); } else if (cmd.equals("res3")) { flipRes(2); } else if (cmd.equals("res4")) { flipRes(3); } } private void flipRes(int k) { res[k] = 5 - res[k]; DisplayImpl display = getDisplay(); Vector renderers = display.getRendererVector(); for (int i=0; i<renderers.size(); i++) { DataRenderer renderer = (DataRenderer) renderers.elementAt(i); if (renderer instanceof ClientRendererJ3D) { ((ClientRendererJ3D) renderer).setResolutions(res); } } display.reDisplayAll(); } private static Gridded3DSet makePS(Gridded3DSet domain_set, int node_divide) throws VisADException { int number_of_nodes = node_divide * node_divide; int x_len = domain_set.getLength(0); int y_len = domain_set.getLength(1); int z_len = domain_set.getLength(2); int len = domain_set.getLength(); float[][] samples = domain_set.getSamples(false); float[][] ps_samples = new float[3][number_of_nodes]; for (int i=0; i<node_divide; i++) { int ie = i * (x_len - 1) / (node_divide - 1); for (int j=0; j<node_divide; j++) { int je = j * (y_len - 1) / (node_divide - 1); int k = i + node_divide * j; int ke = ie + x_len * (je + y_len * (z_len / 2)); ps_samples[0][k] = samples[0][ke]; ps_samples[1][k] = samples[1][ke]; ps_samples[2][k] = samples[2][ke]; } } Gridded3DSet ps = new Gridded3DSet(domain_set.getType(), ps_samples, node_divide, node_divide, 1, domain_set.getCoordinateSystem(), domain_set.getSetUnits(), null); return ps; } }