From 90eeb8f46fd737a8da4ee980133e76df572769de Mon Sep 17 00:00:00 2001
From: baseendje
Date: Wed, 10 Jun 2020 19:14:57 +0200
Subject: [PATCH 01/67] Loading post-processing scripts part 1
---
src/dataIO/CumulativeLoad.java | 49 ++
src/dataIO/FolderOperations.java | 94 +++
src/gui/GuiActions.java | 521 +++++++++------
src/gui/GuiMenu.java | 1065 +++++++++++++++---------------
src/idynomics/Idynomics.java | 19 +
src/idynomics/PostProcess.java | 32 +
src/utility/Helper.java | 8 +
7 files changed, 1056 insertions(+), 732 deletions(-)
create mode 100644 src/dataIO/CumulativeLoad.java
create mode 100644 src/dataIO/FolderOperations.java
create mode 100644 src/idynomics/PostProcess.java
diff --git a/src/dataIO/CumulativeLoad.java b/src/dataIO/CumulativeLoad.java
new file mode 100644
index 000000000..3a5b6f550
--- /dev/null
+++ b/src/dataIO/CumulativeLoad.java
@@ -0,0 +1,49 @@
+package dataIO;
+
+import org.w3c.dom.Element;
+
+import compartment.Compartment;
+import idynomics.Idynomics;
+import instantiable.Instance;
+import processManager.ProcessManager;
+import referenceLibrary.XmlRef;
+import utility.Helper;
+
+public class CumulativeLoad {
+
+ Element document;
+
+ public CumulativeLoad()
+ {
+
+ }
+
+ public CumulativeLoad(String xml)
+ {
+ document = XmlHandler.loadDocument(xml);
+ }
+
+ public void postProcess()
+ {
+ Compartment comp = null;
+ for ( Element e : XmlHandler.getElements( document, XmlRef.process) )
+ {
+ comp.addProcessManager(
+ (ProcessManager) Instance.getNew(e, comp, (String[])null));
+ }
+ }
+
+ public Compartment getCompartment(String comp)
+ {
+ if( Idynomics.simulator.getCompartmentNames().contains(comp))
+ return Idynomics.simulator.getCompartment(comp);
+ if( Helper.intParseable(comp) )
+ return Idynomics.simulator.getCompartment(
+ Idynomics.simulator.getCompartmentNames().get(
+ Integer.valueOf(comp) ) );
+ Log.out(this.getClass().getSimpleName() + " could not retrieve "
+ + "compartment: " + comp);
+ return null;
+
+ }
+}
diff --git a/src/dataIO/FolderOperations.java b/src/dataIO/FolderOperations.java
new file mode 100644
index 000000000..26b28603a
--- /dev/null
+++ b/src/dataIO/FolderOperations.java
@@ -0,0 +1,94 @@
+package dataIO;
+
+import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
+
+public class FolderOperations {
+
+ public static final String[] extensions = new String[] { "exi", "xml" };
+
+ /**
+ * \brief Check whether passed files contain at least 1 folder
+ * @param files
+ * @return
+ */
+ public static boolean includesfolders( File ... files )
+ {
+ for( File f : files )
+ if ( f.isDirectory() )
+ return true;
+ return false;
+ }
+
+ /**
+ * \brief return all files from passed file and folder list but do not
+ * include sub-folders
+ *
+ * @param subfolders
+ * @param files
+ * @return
+ */
+ public static List getFiles( File ... files )
+ {
+ LinkedList out = new LinkedList();
+ for( File f : files )
+ {
+ if ( f.isFile() )
+ out.add( f );
+ else
+ for (File fileEntry : f.listFiles())
+ out.addAll( getFiles( false, fileEntry ) );
+ }
+ return out;
+ }
+
+ /**
+ * \brief return all files and optionally all files in all sub-folders
+ * @param subfolders
+ * @param files
+ * @return
+ */
+ public static List getFiles( boolean subfolders, File ... files )
+ {
+ LinkedList out = new LinkedList();
+ for( File f : files )
+ {
+ if ( f.isFile() )
+ out.add( f );
+ else if ( subfolders )
+ for (File fileEntry : f.listFiles())
+ out.addAll( getFiles( subfolders, fileEntry ) );
+ }
+ return out;
+ }
+
+ /**
+ * \brief filter all files with common iDynoMiCS extensions
+ * @param files
+ * @return
+ */
+ public static List filterFiles( File ... files )
+ {
+ return filterFiles( extensions, files);
+ }
+
+ /**
+ * \brief filter all files with given extensions
+ * @param extension
+ * @param files
+ * @return
+ */
+ public static List filterFiles( String[] extension, File ... files )
+ {
+ LinkedList out = new LinkedList();
+ for( File file : files )
+ for( String s : extension )
+ if( file.getName().toLowerCase().contains( s ) )
+ {
+ out.add( file );
+ break;
+ }
+ return out;
+ }
+}
diff --git a/src/gui/GuiActions.java b/src/gui/GuiActions.java
index 9ba9ec510..f3af2bead 100644
--- a/src/gui/GuiActions.java
+++ b/src/gui/GuiActions.java
@@ -1,211 +1,310 @@
-/**
- *
- */
-package gui;
-
-import java.awt.EventQueue;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import javax.swing.JFileChooser;
-import javax.swing.JFrame;
-import javax.swing.JOptionPane;
-
-import dataIO.FileHandler;
-import dataIO.Log;
-import idynomics.Global;
-import idynomics.Idynomics;
-import idynomics.Simulator;
-import render.AgentMediator;
-import render.Render;
-import utility.Helper;
-
-/**
- *
- *
- * @author Robert Clegg (r.j.clegg@bham.ac.uk) University of Birmingham, U.K.
- * @author Bastiaan Cockx @BastiaanCockx (baco@env.dtu.dk), DTU, Denmark
- */
-public final class GuiActions
-{
-
- /*************************************************************************
- * DEALING WITH FILES
- ************************************************************************/
-
- /**
- * \brief Method to select protocol files from a file selection dialog
- *
- * @return XML file selected from the dialog box.
- */
- public static void chooseFile()
- {
- /* Open a FileChooser window in the current directory. */
- JFileChooser chooser = new JFileChooser("" +
- System.getProperty("user.dir")+"/protocol");
- chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
- // TODO Allow the user to select multiple files.
- chooser.setMultiSelectionEnabled(false);
- File f = null;
- if ( chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION )
- f = chooser.getSelectedFile();
-
- openFile(f);
- }
-
- public static void openFile(File f)
- {
- Idynomics.simulator = new Simulator();
- Idynomics.global = new Global();
- /* load content if a protocol file has been selected */
- if ( f == null )
- {
- Idynomics.global.protocolFile = null;
- GuiConsole.writeOut("No protocol file selected.\n");
- }
- else
- {
- Idynomics.global.protocolFile = f.getAbsolutePath();
- GuiConsole.writeOut(Idynomics.global.protocolFile + " \n");
- checkProtocol();
- GuiButtons.resetProgressBar();
- GuiActions.loadCurrentState();
- GuiMain.setStatus( Idynomics.global.protocolFile );
- }
- }
-
- public static String inputUrl()
- {
- JFrame f;
- f=new JFrame();
- return JOptionPane.showInputDialog(f,"Enter URL");
- }
-
- public static void downloadFile(String url)
- {
- String local = "tmp_dl.xml";
- FileHandler handler = new FileHandler();
-
- if (url == null)
- url = inputUrl();
-
- Log.out("Downloading file: " + url + " -> " + local );
- handler.fnew(local);
- InputStream webIS = null;
- FileOutputStream fo = null;
- URL urly = null;
-
- try {
- urly = new URL(url);
- } catch ( MalformedURLException e) {
- e.printStackTrace();
- }
-
-
- try {
- webIS = urly.openStream();
- int c = 0;
- do {
- c = webIS.read();
- if (c !=-1) {
- handler.write((byte) c);
- }
- } while(c != -1);
- webIS.close();
- handler.fclose();
- Log.out("finished Download");
- } catch (IOException e) {
- e.printStackTrace();
- }
- File in = new File(local);
- openFile(in);
- }
-
- public static void checkProtocol()
- {
- if ( Idynomics.global.protocolFile == null )
- {
- GuiConsole.writeErr("No protocol file specified.\n");
- }
- else
- {
- Idynomics.setupSimulator(Idynomics.global.protocolFile);
- if ( Idynomics.simulator.isReadyForLaunch() )
- GuiConsole.writeOut("Protocol is ready to launch...\n");
- else
- GuiConsole.writeErr("Problem in protocol file!\n");
- }
- }
-
- public static void loadCurrentState()
- {
- GuiMain.update();
- }
-
- /*************************************************************************
- * SIMULATION CONTROL
- ************************************************************************/
-
- public static void runSimulation()
- {
- GuiEditor.setAttributes();
- if ( Idynomics.simulator == null )
- Log.printToScreen( "no simulation set.", true);
- else
- {
- Idynomics.simulator.setNode();
- GuiButtons.resetProgressBar();
- Idynomics.launchSimulator();
- }
- }
-
- public static void pauseSimulation()
- {
- if ( Idynomics.simulator == null )
- return;
- try
- {
- // TODO This doesn't work yet...
- Idynomics.simulator.wait();
- }
- catch (InterruptedException e)
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- public static void stopSimulation()
- {
- if ( Idynomics.simulator == null )
- return;
- // TODO this can probably be made a lot cleaner!
- Idynomics.simulator.timer.setEndOfSimulation(
- Idynomics.simulator.timer.getEndOfCurrentIteration());
- }
-
- /*************************************************************************
- * RENDERING 3D SCENE
- ************************************************************************/
-
- public static void render()
- {
- /* is the simulator set? */
- if ( Idynomics.simulator == null )
- Log.printToScreen("No simulator available.", false);
- else if ( Helper.selectSpatialCompartment() == null )
- Log.printToScreen("No spatial compartment available.", false);
- else
- {
- /* create and invoke the renderer */
- Render myRender = new Render(
- new AgentMediator( Helper.selectSpatialCompartment() ) );
- EventQueue.invokeLater(myRender);
- }
- }
-}
+/**
+ *
+ */
+package gui;
+
+import java.awt.EventQueue;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.List;
+
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+
+import dataIO.FileHandler;
+import dataIO.FolderOperations;
+import dataIO.Log;
+import idynomics.Global;
+import idynomics.Idynomics;
+import idynomics.PostProcess;
+import idynomics.Simulator;
+import render.AgentMediator;
+import render.Render;
+import utility.Helper;
+
+/**
+ *
+ *
+ * @author Robert Clegg (r.j.clegg@bham.ac.uk) University of Birmingham, U.K.
+ * @author Bastiaan Cockx @BastiaanCockx (baco@env.dtu.dk), DTU, Denmark
+ */
+public final class GuiActions
+{
+
+ /*************************************************************************
+ * DEALING WITH FILES
+ ************************************************************************/
+
+ /**
+ * \brief Method to select protocol files from a file selection dialog
+ *
+ * @return XML file selected from the dialog box.
+ */
+ public static void chooseFile()
+ {
+ /* Open a FileChooser window in the current directory. */
+ JFileChooser chooser = new JFileChooser("" +
+ System.getProperty("user.dir")+"/protocol");
+ chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ // TODO Allow the user to select multiple files.
+ chooser.setMultiSelectionEnabled(false);
+ File f = null;
+ if ( chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION )
+ f = chooser.getSelectedFile();
+
+ openFile(f);
+ }
+
+ public static File chooseFile(String relPath, String description)
+ {
+ /* Open a FileChooser window in the current directory. */
+ JFileChooser chooser = new JFileChooser("" +
+ System.getProperty("user.dir")+"/protocol");
+ chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ // TODO Allow the user to select multiple files.
+ chooser.setMultiSelectionEnabled(false);
+ chooser.setToolTipText(description);
+ chooser.setDialogTitle(description);
+ File f = null;
+ if ( chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION )
+ f = chooser.getSelectedFile();
+ return f;
+ }
+
+ public static File chooseFolder(String description)
+ {
+ /* Open a FileChooser window in the current directory. */
+ JFileChooser chooser = new JFileChooser("" +
+ System.getProperty("user.dir"));
+ chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ // TODO Allow the user to select multiple files.
+ chooser.setMultiSelectionEnabled(false);
+ chooser.setToolTipText(description);
+ chooser.setDialogTitle(description);
+ File f = null;
+ if ( chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION )
+ f = chooser.getSelectedFile();
+ return f;
+ }
+
+ public static File[] chooseMulitple(String description)
+ {
+ /* Open a FileChooser window in the current directory. */
+ JFileChooser chooser = new JFileChooser("" +
+ System.getProperty("user.dir"));
+ chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ // TODO Allow the user to select multiple files.
+ chooser.setMultiSelectionEnabled(true);
+ chooser.setToolTipText(description);
+ chooser.setDialogTitle(description);
+ File[] f = null;
+ if ( chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION )
+ f = chooser.getSelectedFiles();
+ return f;
+ }
+
+ public static File[] chooseFilesAndFolders(String description)
+ {
+ /* Open a FileChooser window in the current directory. */
+ JFileChooser chooser = new JFileChooser("" +
+ System.getProperty("user.dir"));
+ chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+ // TODO Allow the user to select multiple files.
+ chooser.setMultiSelectionEnabled(true);
+ chooser.setToolTipText(description);
+ chooser.setDialogTitle(description);
+ File[] f = null;
+ if ( chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION )
+ f = chooser.getSelectedFiles();
+ return f;
+ }
+
+ public static void postProcess()
+ {
+ File script = chooseFile( "postprocessing",
+ "Select post-processing script" );
+ File[] files = chooseFilesAndFolders(
+ "Select simulation state files (.exi or .xml)" );
+ List finalFiles = null;
+ if( FolderOperations.includesfolders(files))
+ {
+ if( Helper.obtainInput(
+ "Would you like to include sub-folders?", false) )
+ /* note do look into the first line of folders */
+ finalFiles = FolderOperations.getFiles(true, files);
+ else
+ finalFiles = FolderOperations.getFiles(files);
+ }
+ else
+ {
+ finalFiles = FolderOperations.getFiles(true, files);
+ }
+ if( Helper.obtainInput( "Would you like to continue processing " +
+ finalFiles.size() + " files?", false) )
+ {
+ Idynomics.postProcess = new PostProcess(script, finalFiles);
+ Idynomics.runPostProcess();
+ }
+ else
+ {
+ Log.out("post-processing cancelled by user");
+ }
+ }
+
+ public static void openFile(File f)
+ {
+ Idynomics.simulator = new Simulator();
+ Idynomics.global = new Global();
+ /* load content if a protocol file has been selected */
+ if ( f == null )
+ {
+ Idynomics.global.protocolFile = null;
+ GuiConsole.writeOut("No protocol file selected.\n");
+ }
+ else
+ {
+ Idynomics.global.protocolFile = f.getAbsolutePath();
+ GuiConsole.writeOut(Idynomics.global.protocolFile + " \n");
+ checkProtocol();
+ GuiButtons.resetProgressBar();
+ GuiActions.loadCurrentState();
+ GuiMain.setStatus( Idynomics.global.protocolFile );
+ }
+ }
+
+ public static String inputUrl()
+ {
+ JFrame f;
+ f=new JFrame();
+ return JOptionPane.showInputDialog(f,"Enter URL");
+ }
+
+ public static void downloadFile(String url)
+ {
+ String local = "tmp_dl.xml";
+ FileHandler handler = new FileHandler();
+
+ if (url == null)
+ url = inputUrl();
+
+ Log.out("Downloading file: " + url + " -> " + local );
+ handler.fnew(local);
+ InputStream webIS = null;
+ FileOutputStream fo = null;
+ URL urly = null;
+
+ try {
+ urly = new URL(url);
+ } catch ( MalformedURLException e) {
+ e.printStackTrace();
+ }
+
+
+ try {
+ webIS = urly.openStream();
+ int c = 0;
+ do {
+ c = webIS.read();
+ if (c !=-1) {
+ handler.write((byte) c);
+ }
+ } while(c != -1);
+ webIS.close();
+ handler.fclose();
+ Log.out("finished Download");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ File in = new File(local);
+ openFile(in);
+ }
+
+ public static void checkProtocol()
+ {
+ if ( Idynomics.global.protocolFile == null )
+ {
+ GuiConsole.writeErr("No protocol file specified.\n");
+ }
+ else
+ {
+ Idynomics.setupSimulator(Idynomics.global.protocolFile);
+ if ( Idynomics.simulator.isReadyForLaunch() )
+ GuiConsole.writeOut("Protocol loaded successfully.\n");
+ else
+ GuiConsole.writeErr("Problem in protocol file!\n");
+ }
+ }
+
+ public static void loadCurrentState()
+ {
+ GuiMain.update();
+ }
+
+ /*************************************************************************
+ * SIMULATION CONTROL
+ ************************************************************************/
+
+ public static void runSimulation()
+ {
+ GuiEditor.setAttributes();
+ if ( Idynomics.simulator == null )
+ Log.printToScreen( "no simulation set.", true);
+ else
+ {
+ Idynomics.simulator.setNode();
+ GuiButtons.resetProgressBar();
+ Idynomics.launchSimulator();
+ }
+ }
+
+ public static void pauseSimulation()
+ {
+ if ( Idynomics.simulator == null )
+ return;
+ try
+ {
+ // TODO This doesn't work yet...
+ Idynomics.simulator.wait();
+ }
+ catch (InterruptedException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ public static void stopSimulation()
+ {
+ if ( Idynomics.simulator == null )
+ return;
+ // TODO this can probably be made a lot cleaner!
+ Idynomics.simulator.timer.setEndOfSimulation(
+ Idynomics.simulator.timer.getEndOfCurrentIteration());
+ }
+
+ /*************************************************************************
+ * RENDERING 3D SCENE
+ ************************************************************************/
+
+ public static void render()
+ {
+ /* is the simulator set? */
+ if ( Idynomics.simulator == null )
+ Log.printToScreen("No simulator available.", false);
+ else if ( Helper.selectSpatialCompartment() == null )
+ Log.printToScreen("No spatial compartment available.", false);
+ else
+ {
+ /* create and invoke the renderer */
+ Render myRender = new Render(
+ new AgentMediator( Helper.selectSpatialCompartment() ) );
+ EventQueue.invokeLater(myRender);
+ }
+ }
+}
diff --git a/src/gui/GuiMenu.java b/src/gui/GuiMenu.java
index f2b87c255..6ba2c1b04 100644
--- a/src/gui/GuiMenu.java
+++ b/src/gui/GuiMenu.java
@@ -1,521 +1,544 @@
-/**
- *
- */
-package gui;
-
-import java.awt.event.ActionEvent;
-import java.awt.event.KeyEvent;
-
-import javax.swing.AbstractAction;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
-import javax.swing.JRadioButtonMenuItem;
-import javax.swing.KeyStroke;
-
-import analysis.FilteredTable;
-import analysis.quantitative.Raster;
-import dataIO.Diagram;
-import dataIO.DrawMediator;
-import dataIO.Log;
-import dataIO.Log.Tier;
-import idynomics.Idynomics;
-import idynomics.Simulator;
-import idynomics.launchable.SamplerLaunch;
-import utility.Helper;
-
-/**
- *
- * @author Bastiaan Cockx @BastiaanCockx (baco@env.dtu.dk), DTU, Denmark
- * @author Robert Clegg (r.j.clegg@bham.ac.uk) University of Birmingham, U.K.
- */
-public final class GuiMenu
-{
- private static JMenuBar _menuBar;
-
- public static JMenuBar getMenuBar()
- {
- _menuBar = new JMenuBar();
- _menuBar.add(fileMenu());
- _menuBar.add(interactionMenu());
- return _menuBar;
- }
-
-
- private static JMenu fileMenu()
- {
- JMenu menu, levelMenu;
- JMenuItem menuItem;
- JRadioButtonMenuItem rbMenuItem;
- /*
- * Set up the File menu.
- */
- menu = new JMenu("File");
- menu.setMnemonic(KeyEvent.VK_F);
- menu.getAccessibleContext().setAccessibleDescription("File options");
- /*
- * Add the option of making a new simulation.
- */
- menuItem = new JMenuItem(new GuiMenu.NewFile());
- menuItem.setAccelerator(KeyStroke.getKeyStroke(
- KeyEvent.VK_N, ActionEvent.CTRL_MASK));
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Make a new simulation");
- menu.add(menuItem);
- /*
- * Add the option of opening a protocol file.
- */
- menuItem = new JMenuItem(new GuiMenu.FileOpen());
- menuItem.setAccelerator(KeyStroke.getKeyStroke(
- KeyEvent.VK_O, ActionEvent.CTRL_MASK));
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Open existing protocol file");
- menu.add(menuItem);
-
-
- menuItem = new JMenuItem(new GuiMenu.FileDownload());
- menuItem.setAccelerator(KeyStroke.getKeyStroke(
- KeyEvent.VK_D, ActionEvent.CTRL_MASK));
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Download protocol file");
- menu.add(menuItem);
-
- /*
- * Add the option of rendering a compartment.
- */
- menuItem = new JMenuItem(new GuiMenu.RenderThis());
- menuItem.setAccelerator(KeyStroke.getKeyStroke(
- KeyEvent.VK_R, ActionEvent.CTRL_MASK));
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Render a spatial compartment");
- menu.add(menuItem);
- /*
- * Output level.
- * NOTE this will not work through the menu bar, instead edit trough
- * simulation state.
- menu.addSeparator();
- levelMenu = new JMenu("OutputLevel");
- levelMenu.setMnemonic(KeyEvent.VK_L);
- ButtonGroup group = new ButtonGroup();
- for ( Log.Tier t : Log.Tier.values() )
- {
- rbMenuItem = new JRadioButtonMenuItem(new GuiMenu.LogTier(t));
- group.add(rbMenuItem);
- levelMenu.add(rbMenuItem);
- }
- menu.add(levelMenu);
- */
-
- /*
- * Master protocol sampling
- */
- menu.addSeparator();
- menuItem = new JMenuItem(new GuiMenu.Sampling());
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Sample master protocol file");
- menu.add(menuItem);
-
- /*
- * Finally, return the File menu.
- */
- return menu;
- }
-
-
- private static JMenu interactionMenu()
- {
- JMenu menu;
- JMenuItem menuItem;
- /*
- * Set up the File menu.
- */
- menu = new JMenu("Interact");
- menu.setMnemonic(KeyEvent.VK_G);
- menu.getAccessibleContext().setAccessibleDescription("Interactive");
- /*
- * Add the option of rendering a compartment.
- */
- menuItem = new JMenuItem(new GuiMenu.Current());
- menuItem.setAccelerator(KeyStroke.getKeyStroke(
- KeyEvent.VK_L, ActionEvent.CTRL_MASK));
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Edit simulation state");
- menu.add(menuItem);
- /*
- * Draw to graphics file
- */
- menuItem = new JMenuItem(new GuiMenu.Draw());
- menuItem.setAccelerator(KeyStroke.getKeyStroke(
- KeyEvent.VK_D, ActionEvent.CTRL_MASK));
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Draw to file");
- menu.add(menuItem);
- /*
- * Draw raster
- */
- menuItem = new JMenuItem(new GuiMenu.StructureAnalysis());
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Draw raster to file");
- menu.add(menuItem);
- /*
- * Draw species diagram
- */
- menuItem = new JMenuItem(new GuiMenu.SpeciesDiagram());
- menuItem.setAccelerator(KeyStroke.getKeyStroke(
- KeyEvent.VK_D, ActionEvent.CTRL_MASK));
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Request agent information");
- menu.add(menuItem);
- /*
- * Draw reaction diagram
- */
- menuItem = new JMenuItem(new ReactionDiagram());
- menuItem.setAccelerator(KeyStroke.getKeyStroke(
- KeyEvent.VK_D, ActionEvent.CTRL_MASK));
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Request agent information");
- menu.add(menuItem);
- /*
- * Query some agents
- */
- menuItem = new JMenuItem(new GuiMenu.Query());
- menuItem.setAccelerator(KeyStroke.getKeyStroke(
- KeyEvent.VK_T, ActionEvent.CTRL_MASK));
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Request agent information");
- menu.add(menuItem);
- /*
- * Query some agents
- */
- menuItem = new JMenuItem(new GuiMenu.QueryToFile());
- menuItem.setAccelerator(KeyStroke.getKeyStroke(
- KeyEvent.VK_Y, ActionEvent.CTRL_MASK));
- menuItem.getAccessibleContext().setAccessibleDescription(
- "Request agent information and store in output folder");
- menu.add(menuItem);
- /*
- * Finally, return the File menu.
- */
- return menu;
- }
-
- /*************************************************************************
- *
- ************************************************************************/
-
- public static class NewFile extends AbstractAction
- {
- private static final long serialVersionUID = 8931286266304166474L;
-
- /**
- * Action for the file open sub-menu.
- */
- public NewFile()
- {
- super("Make new protocol");
- }
-
- public void actionPerformed(ActionEvent e)
- {
- Idynomics.simulator = new Simulator();
- GuiActions.loadCurrentState();
- }
- }
-
- public static class FileOpen extends AbstractAction
- {
- private static final long serialVersionUID = 2247122248926681550L;
-
- /**
- * Action for the file open sub-menu.
- */
- public FileOpen()
- {
- super("Open..");
- }
-
- public void actionPerformed(ActionEvent e)
- {
- GuiActions.chooseFile();
- }
- }
-
- public static class FileDownload extends AbstractAction
- {
- private static final long serialVersionUID = 2247122248926681550L;
-
- /**
- * Action for the file open sub-menu.
- */
- public FileDownload()
- {
- super("Download..");
- }
-
- public void actionPerformed(ActionEvent e)
- {
- GuiActions.downloadFile(null);
- }
- }
-
- public static class RenderThis extends AbstractAction
- {
- private static final long serialVersionUID = 974971035938028563L;
-
- /**
- * Create a new {@code Render} object and invoke it.
- *
- *
The {@code Render} object handles its own {@code JFrame}.
- */
- public RenderThis()
- {
- super("Render");
- }
-
- public void actionPerformed(ActionEvent e)
- {
- GuiActions.render();
- }
- }
-
- public static class SpeciesDiagram extends AbstractAction
- {
-
- /**
- *
- */
- private static final long serialVersionUID = 3011117385035501302L;
-
- public SpeciesDiagram()
- {
- super("Species Diagram");
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (Helper.compartmentAvailable())
- {
- String fileName = "speciesDiagram";
- Diagram diag = new Diagram();
- diag.createCustomFile(fileName);
- diag.speciesDiagram();
- diag.closeFile();
- Log.printToScreen("species diagram created.", false);
- }
- }
-
- }
-
- public static class ReactionDiagram extends AbstractAction
- {
-
- /**
- *
- */
- private static final long serialVersionUID = 3011117385035501302L;
-
- public ReactionDiagram()
- {
- super("Reaction Diagram");
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (Helper.compartmentAvailable())
- {
- String fileName = "reactionDiagram";
- Diagram diag = new Diagram();
- diag.createCustomFile(fileName);
- diag.reactionDiagram( Helper.selectCompartment() );
- diag.closeFile();
- Log.printToScreen("reaction diagram created.", false);
- }
- }
-
- }
-
- public static class Query extends AbstractAction
- {
-
- /**
- *
- */
- private static final long serialVersionUID = 3011117385035501302L;
-
- public Query()
- {
- super("Query");
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (Helper.compartmentAvailable())
- {
- String table = GuiConsole.requestInput("Table logic");
- table = table.replaceAll("\\s+","");
- FilteredTable tab = new FilteredTable(table);
- Log.printToScreen(tab.display(), false);
- }
- }
-
- }
-
- public static class QueryToFile extends AbstractAction
- {
-
- /**
- *
- */
- private static final long serialVersionUID = 3011117385035501302L;
-
- public QueryToFile()
- {
- super("QueryToFile");
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (Helper.compartmentAvailable())
- {
- String table = GuiConsole.requestInput("Table logic");
- table = table.replaceAll("\\s+","");
- FilteredTable tab = new FilteredTable(table);
- tab.toFile();
- }
- }
-
- }
-
- public static class StructureAnalysis extends AbstractAction
- {
-
- /**
- *
- */
- private static final long serialVersionUID = 3011117385035501302L;
-
- public StructureAnalysis()
- {
- super("StructureAnalysis");
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (Helper.compartmentAvailable())
- {
- if ( Helper.selectSpatialCompartment() == null )
- Log.printToScreen("No spatial compartment available.",
- false );
- {
- Raster raster = new Raster(
- Helper.selectSpatialCompartment(), true );
- raster.rasterize( Double.valueOf(
- Helper.obtainInput( null, "Raster scale" ) ) );
- raster.plot( raster.agentMap(), 1.0,
- Helper.obtainInput( null, "filename") );
- }
- }
- }
-
- }
-
- public static class Draw extends AbstractAction
- {
-
- /**
- *
- */
- private static final long serialVersionUID = 3011117385035501302L;
-
- public Draw()
- {
- super("Draw to file");
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- DrawMediator.drawState();
- }
-
- }
-
- public static class Current extends AbstractAction
- {
-
- /**
- *
- */
- private static final long serialVersionUID = 3011117385035501302L;
-
- public Current()
- {
- super("Edit simulation");
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (Helper.compartmentAvailable())
- GuiActions.loadCurrentState();
- }
-
- }
-
- public static class LogTier extends AbstractAction
- {
- private static final long serialVersionUID = 2660256074849177100L;
-
- /**
- * The output level {@code Tier} for the log file that this button
- * represents.
- */
- private Tier _tier;
-
- /**
- * Action for the set Log Tier sub-menu.
- */
- public LogTier(Log.Tier tier)
- {
- super(tier.toString());
- this._tier = tier;
- }
-
- public void actionPerformed(ActionEvent e)
- {
- Log.set(this._tier);
- }
- }
-
- public static class Sampling extends AbstractAction
- {
-
- private SamplerLaunch smp = new SamplerLaunch();
-
- public Sampling()
- {
- super("Sample master");
- }
-
- @Override
- public void actionPerformed(ActionEvent e) {
- smp.initialize(null);
- }
- }
-
-// public static class GuiView extends AbstractAction
-// {
-// private static final long serialVersionUID = 8725075624293930079L;
-//
-// private ViewType _view;
-//
-// public GuiView(ViewType view)
-// {
-// super(view.toString());
-// this._view = view;
-// }
-//
-// public void actionPerformed(ActionEvent e)
-// {
-// GuiLaunch.setView(this._view);
-// }
-// }
-}
+/**
+ *
+ */
+package gui;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.KeyStroke;
+
+import analysis.FilteredTable;
+import analysis.quantitative.Raster;
+import dataIO.Diagram;
+import dataIO.DrawMediator;
+import dataIO.Log;
+import dataIO.Log.Tier;
+import idynomics.Idynomics;
+import idynomics.Simulator;
+import idynomics.launchable.SamplerLaunch;
+import utility.Helper;
+
+/**
+ *
+ * @author Bastiaan Cockx @BastiaanCockx (baco@env.dtu.dk), DTU, Denmark
+ * @author Robert Clegg (r.j.clegg@bham.ac.uk) University of Birmingham, U.K.
+ */
+public final class GuiMenu
+{
+ private static JMenuBar _menuBar;
+
+ public static JMenuBar getMenuBar()
+ {
+ _menuBar = new JMenuBar();
+ _menuBar.add(fileMenu());
+ _menuBar.add(interactionMenu());
+ return _menuBar;
+ }
+
+
+ private static JMenu fileMenu()
+ {
+ JMenu menu, levelMenu;
+ JMenuItem menuItem;
+ JRadioButtonMenuItem rbMenuItem;
+ /*
+ * Set up the File menu.
+ */
+ menu = new JMenu("File");
+ menu.setMnemonic(KeyEvent.VK_F);
+ menu.getAccessibleContext().setAccessibleDescription("File options");
+ /*
+ * Add the option of making a new simulation.
+ */
+ menuItem = new JMenuItem(new GuiMenu.NewFile());
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ KeyEvent.VK_N, ActionEvent.CTRL_MASK));
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Make a new simulation");
+ menu.add(menuItem);
+ /*
+ * Add the option of opening a protocol file.
+ */
+ menuItem = new JMenuItem(new GuiMenu.FileOpen());
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ KeyEvent.VK_O, ActionEvent.CTRL_MASK));
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Open existing protocol file");
+ menu.add(menuItem);
+
+
+ menuItem = new JMenuItem(new GuiMenu.FileDownload());
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ KeyEvent.VK_D, ActionEvent.CTRL_MASK));
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Download protocol file");
+ menu.add(menuItem);
+
+ /*
+ * Add the option of rendering a compartment.
+ */
+ menuItem = new JMenuItem(new GuiMenu.RenderThis());
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ KeyEvent.VK_R, ActionEvent.CTRL_MASK));
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Render a spatial compartment");
+ menu.add(menuItem);
+ /*
+ * Output level.
+ * NOTE this will not work through the menu bar, instead edit trough
+ * simulation state.
+ menu.addSeparator();
+ levelMenu = new JMenu("OutputLevel");
+ levelMenu.setMnemonic(KeyEvent.VK_L);
+ ButtonGroup group = new ButtonGroup();
+ for ( Log.Tier t : Log.Tier.values() )
+ {
+ rbMenuItem = new JRadioButtonMenuItem(new GuiMenu.LogTier(t));
+ group.add(rbMenuItem);
+ levelMenu.add(rbMenuItem);
+ }
+ menu.add(levelMenu);
+ */
+
+ /*
+ * Master protocol sampling
+ */
+ menu.addSeparator();
+ menuItem = new JMenuItem(new GuiMenu.Sampling());
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Sample master protocol file");
+ menu.add(menuItem);
+
+ menuItem = new JMenuItem(new GuiMenu.PostProcess());
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Perform post processing");
+ menu.add(menuItem);
+
+ /*
+ * Finally, return the File menu.
+ */
+ return menu;
+ }
+
+
+ private static JMenu interactionMenu()
+ {
+ JMenu menu;
+ JMenuItem menuItem;
+ /*
+ * Set up the File menu.
+ */
+ menu = new JMenu("Interact");
+ menu.setMnemonic(KeyEvent.VK_G);
+ menu.getAccessibleContext().setAccessibleDescription("Interactive");
+ /*
+ * Add the option of rendering a compartment.
+ */
+ menuItem = new JMenuItem(new GuiMenu.Current());
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ KeyEvent.VK_L, ActionEvent.CTRL_MASK));
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Edit simulation state");
+ menu.add(menuItem);
+ /*
+ * Draw to graphics file
+ */
+ menuItem = new JMenuItem(new GuiMenu.Draw());
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ KeyEvent.VK_D, ActionEvent.CTRL_MASK));
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Draw to file");
+ menu.add(menuItem);
+ /*
+ * Draw raster
+ */
+ menuItem = new JMenuItem(new GuiMenu.StructureAnalysis());
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Draw raster to file");
+ menu.add(menuItem);
+ /*
+ * Draw species diagram
+ */
+ menuItem = new JMenuItem(new GuiMenu.SpeciesDiagram());
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ KeyEvent.VK_D, ActionEvent.CTRL_MASK));
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Request agent information");
+ menu.add(menuItem);
+ /*
+ * Draw reaction diagram
+ */
+ menuItem = new JMenuItem(new ReactionDiagram());
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ KeyEvent.VK_D, ActionEvent.CTRL_MASK));
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Request agent information");
+ menu.add(menuItem);
+ /*
+ * Query some agents
+ */
+ menuItem = new JMenuItem(new GuiMenu.Query());
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ KeyEvent.VK_T, ActionEvent.CTRL_MASK));
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Request agent information");
+ menu.add(menuItem);
+ /*
+ * Query some agents
+ */
+ menuItem = new JMenuItem(new GuiMenu.QueryToFile());
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ KeyEvent.VK_Y, ActionEvent.CTRL_MASK));
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Request agent information and store in output folder");
+ menu.add(menuItem);
+ /*
+ * Finally, return the File menu.
+ */
+ return menu;
+ }
+
+ /*************************************************************************
+ *
+ ************************************************************************/
+
+ public static class NewFile extends AbstractAction
+ {
+ private static final long serialVersionUID = 8931286266304166474L;
+
+ /**
+ * Action for the file open sub-menu.
+ */
+ public NewFile()
+ {
+ super("Make new protocol");
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ Idynomics.simulator = new Simulator();
+ GuiActions.loadCurrentState();
+ }
+ }
+
+ public static class FileOpen extends AbstractAction
+ {
+ private static final long serialVersionUID = 2247122248926681550L;
+
+ /**
+ * Action for the file open sub-menu.
+ */
+ public FileOpen()
+ {
+ super("Open..");
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ GuiActions.chooseFile();
+ }
+ }
+
+ public static class FileDownload extends AbstractAction
+ {
+ private static final long serialVersionUID = 2247122248926681550L;
+
+ /**
+ * Action for the file open sub-menu.
+ */
+ public FileDownload()
+ {
+ super("Download..");
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ GuiActions.downloadFile(null);
+ }
+ }
+
+ public static class RenderThis extends AbstractAction
+ {
+ private static final long serialVersionUID = 974971035938028563L;
+
+ /**
+ * Create a new {@code Render} object and invoke it.
+ *
+ *
The {@code Render} object handles its own {@code JFrame}.
+ */
+ public RenderThis()
+ {
+ super("Render");
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ GuiActions.render();
+ }
+ }
+
+ public static class PostProcess extends AbstractAction
+ {
+ private static final long serialVersionUID = 2247122248926681550L;
+
+ /**
+ * Action for the file open sub-menu.
+ */
+ public PostProcess()
+ {
+ super("Post-process");
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ GuiActions.postProcess();
+ }
+ }
+
+ public static class SpeciesDiagram extends AbstractAction
+ {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3011117385035501302L;
+
+ public SpeciesDiagram()
+ {
+ super("Species Diagram");
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (Helper.compartmentAvailable())
+ {
+ String fileName = "speciesDiagram";
+ Diagram diag = new Diagram();
+ diag.createCustomFile(fileName);
+ diag.speciesDiagram();
+ diag.closeFile();
+ Log.printToScreen("species diagram created.", false);
+ }
+ }
+
+ }
+
+ public static class ReactionDiagram extends AbstractAction
+ {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3011117385035501302L;
+
+ public ReactionDiagram()
+ {
+ super("Reaction Diagram");
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (Helper.compartmentAvailable())
+ {
+ String fileName = "reactionDiagram";
+ Diagram diag = new Diagram();
+ diag.createCustomFile(fileName);
+ diag.reactionDiagram( Helper.selectCompartment() );
+ diag.closeFile();
+ Log.printToScreen("reaction diagram created.", false);
+ }
+ }
+
+ }
+
+ public static class Query extends AbstractAction
+ {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3011117385035501302L;
+
+ public Query()
+ {
+ super("Query");
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (Helper.compartmentAvailable())
+ {
+ String table = GuiConsole.requestInput("Table logic");
+ table = table.replaceAll("\\s+","");
+ FilteredTable tab = new FilteredTable(table);
+ Log.printToScreen(tab.display(), false);
+ }
+ }
+
+ }
+
+ public static class QueryToFile extends AbstractAction
+ {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3011117385035501302L;
+
+ public QueryToFile()
+ {
+ super("QueryToFile");
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (Helper.compartmentAvailable())
+ {
+ String table = GuiConsole.requestInput("Table logic");
+ table = table.replaceAll("\\s+","");
+ FilteredTable tab = new FilteredTable(table);
+ tab.toFile();
+ }
+ }
+
+ }
+
+ public static class StructureAnalysis extends AbstractAction
+ {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3011117385035501302L;
+
+ public StructureAnalysis()
+ {
+ super("StructureAnalysis");
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (Helper.compartmentAvailable())
+ {
+ if ( Helper.selectSpatialCompartment() == null )
+ Log.printToScreen("No spatial compartment available.",
+ false );
+ {
+ Raster raster = new Raster(
+ Helper.selectSpatialCompartment(), true );
+ raster.rasterize( Double.valueOf(
+ Helper.obtainInput( null, "Raster scale" ) ) );
+ raster.plot( raster.agentMap(), 1.0,
+ Helper.obtainInput( null, "filename") );
+ }
+ }
+ }
+
+ }
+
+ public static class Draw extends AbstractAction
+ {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3011117385035501302L;
+
+ public Draw()
+ {
+ super("Draw to file");
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ DrawMediator.drawState();
+ }
+
+ }
+
+ public static class Current extends AbstractAction
+ {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 3011117385035501302L;
+
+ public Current()
+ {
+ super("Edit simulation");
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (Helper.compartmentAvailable())
+ GuiActions.loadCurrentState();
+ }
+
+ }
+
+ public static class LogTier extends AbstractAction
+ {
+ private static final long serialVersionUID = 2660256074849177100L;
+
+ /**
+ * The output level {@code Tier} for the log file that this button
+ * represents.
+ */
+ private Tier _tier;
+
+ /**
+ * Action for the set Log Tier sub-menu.
+ */
+ public LogTier(Log.Tier tier)
+ {
+ super(tier.toString());
+ this._tier = tier;
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ Log.set(this._tier);
+ }
+ }
+
+ public static class Sampling extends AbstractAction
+ {
+
+ private SamplerLaunch smp = new SamplerLaunch();
+
+ public Sampling()
+ {
+ super("Sample master");
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ smp.initialize(null);
+ }
+ }
+
+// public static class GuiView extends AbstractAction
+// {
+// private static final long serialVersionUID = 8725075624293930079L;
+//
+// private ViewType _view;
+//
+// public GuiView(ViewType view)
+// {
+// super(view.toString());
+// this._view = view;
+// }
+//
+// public void actionPerformed(ActionEvent e)
+// {
+// GuiLaunch.setView(this._view);
+// }
+// }
+}
diff --git a/src/idynomics/Idynomics.java b/src/idynomics/Idynomics.java
index 6fb1586b0..89f18d45d 100644
--- a/src/idynomics/Idynomics.java
+++ b/src/idynomics/Idynomics.java
@@ -48,6 +48,11 @@ public strictfp class Idynomics
*/
public static Simulator simulator;
+ /**
+ * {@code PostProcess} object: there can only be one.
+ */
+ public static PostProcess postProcess;
+
/**
* iDynoMiCS internal unit system.
*/
@@ -64,6 +69,11 @@ public strictfp class Idynomics
*/
public static Thread simThread;
+ /**
+ * post-processing thread
+ */
+ public static Thread postProcessingThread;
+
/**
* Contains all predefined className package association for easy class
* initiation from xml file.
@@ -275,6 +285,15 @@ public static void launchSimulator()
simThread.start();
}
+ /**
+ * run
+ */
+ public static void runPostProcess()
+ {
+ postProcessingThread = new Thread(postProcess);
+ postProcessingThread.start();
+ }
+
/**
* \brief TODO
*
diff --git a/src/idynomics/PostProcess.java b/src/idynomics/PostProcess.java
new file mode 100644
index 000000000..ff19a50c2
--- /dev/null
+++ b/src/idynomics/PostProcess.java
@@ -0,0 +1,32 @@
+package idynomics;
+
+import java.io.File;
+import java.util.List;
+
+public class PostProcess implements Runnable {
+
+ /**
+ * Files to be post processed
+ */
+ private List _files;
+
+ /**
+ * Post processing script
+ */
+ private File _script;
+
+ public PostProcess(File script, List files)
+ {
+ this._script = script;
+ this._files = files;
+ }
+
+ @Override
+ public void run()
+ {
+ for( File f : _files)
+ {
+ Idynomics.setupSimulator( f.getAbsolutePath() );
+ }
+ }
+}
diff --git a/src/utility/Helper.java b/src/utility/Helper.java
index e5bc3b614..0512ffd06 100644
--- a/src/utility/Helper.java
+++ b/src/utility/Helper.java
@@ -737,6 +737,14 @@ public static boolean dblParseable(String strParse)
return false;
}
+ public static boolean intParseable(String strParse)
+ {
+ if (strParse.matches("\\d+")){
+ return true;
+ }
+ return false;
+ }
+
public static boolean boolParseable(String strParse)
{
for( String s : Helper.rejections)
From 5cf6655cf283cf27a64cabc5f43a28c2dd944bd9 Mon Sep 17 00:00:00 2001
From: baseendje
Date: Thu, 11 Jun 2020 11:01:28 +0200
Subject: [PATCH 02/67] further work on post-process
---
src/dataIO/CumulativeLoad.java | 15 +++++++++++++++
src/idynomics/PostProcess.java | 5 +++++
2 files changed, 20 insertions(+)
diff --git a/src/dataIO/CumulativeLoad.java b/src/dataIO/CumulativeLoad.java
index 3a5b6f550..157b33158 100644
--- a/src/dataIO/CumulativeLoad.java
+++ b/src/dataIO/CumulativeLoad.java
@@ -1,6 +1,10 @@
package dataIO;
+import java.util.Collection;
+import java.util.List;
+
import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
import compartment.Compartment;
import idynomics.Idynomics;
@@ -23,6 +27,17 @@ public CumulativeLoad(String xml)
document = XmlHandler.loadDocument(xml);
}
+ public Collection getProcessNodes()
+ {
+ return XmlHandler.getElements( document ,XmlRef.process );
+ }
+
+ public String test()
+ {
+
+ return "";
+ }
+
public void postProcess()
{
Compartment comp = null;
diff --git a/src/idynomics/PostProcess.java b/src/idynomics/PostProcess.java
index ff19a50c2..c6936893a 100644
--- a/src/idynomics/PostProcess.java
+++ b/src/idynomics/PostProcess.java
@@ -3,6 +3,8 @@
import java.io.File;
import java.util.List;
+import dataIO.CumulativeLoad;
+
public class PostProcess implements Runnable {
/**
@@ -14,11 +16,14 @@ public class PostProcess implements Runnable {
* Post processing script
*/
private File _script;
+
+ private CumulativeLoad loader;
public PostProcess(File script, List files)
{
this._script = script;
this._files = files;
+ this.loader = new CumulativeLoad( this._script.getAbsolutePath() );
}
@Override
From 760b97b0b9c427833b6474ba47f43f3f4653a577 Mon Sep 17 00:00:00 2001
From: baseendje
Date: Mon, 15 Jun 2020 13:48:13 +0200
Subject: [PATCH 03/67] functional prototype post-processing
---
src/compartment/AgentContainer.java | 2 +
src/compartment/Compartment.java | 1573 +++++++++--------
src/dataIO/CumulativeLoad.java | 14 +-
src/dataIO/GraphicalExporter.java | 2 +
src/dataIO/PovExport.java | 5 +-
src/dataIO/SvgExport.java | 6 +
src/gui/GuiActions.java | 2 +-
src/idynomics/PostProcess.java | 4 +
src/processManager/ProcessManager.java | 864 ++++-----
.../library/GraphicalOutput.java | 3 +-
src/referenceLibrary/AspectRef.java | 2 +
11 files changed, 1257 insertions(+), 1220 deletions(-)
diff --git a/src/compartment/AgentContainer.java b/src/compartment/AgentContainer.java
index 715910a28..70c445490 100644
--- a/src/compartment/AgentContainer.java
+++ b/src/compartment/AgentContainer.java
@@ -18,6 +18,7 @@
import dataIO.Log;
import dataIO.Log.Tier;
import gereralPredicates.IsSame;
+import instantiable.object.InstantiableList;
import linearAlgebra.Vector;
import physicalObject.PhysicalObject;
import referenceLibrary.AspectRef;
@@ -777,6 +778,7 @@ public Module getModule()
/* Add the agent childConstrutor for adding of additional agents. */
modelNode.addChildSpec( ClassRef.agent,
Module.Requirements.ZERO_TO_MANY);
+
/* If there are agents, add them as child nodes. */
for ( Agent a : this.getAllAgents() )
modelNode.add( a.getModule() );
diff --git a/src/compartment/Compartment.java b/src/compartment/Compartment.java
index 195405120..dde72748c 100644
--- a/src/compartment/Compartment.java
+++ b/src/compartment/Compartment.java
@@ -1,782 +1,791 @@
-package compartment;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.w3c.dom.Element;
-
-import agent.Agent;
-import boundary.Boundary;
-import boundary.SpatialBoundary;
-import compartment.agentStaging.Spawner;
-import dataIO.Log;
-import dataIO.Log.Tier;
-import dataIO.XmlHandler;
-import generalInterfaces.CanPrelaunchCheck;
-import grid.SpatialGrid;
-import idynomics.Idynomics;
-import instantiable.Instance;
-import instantiable.Instantiable;
-import linearAlgebra.Orientation;
-import linearAlgebra.Vector;
-import physicalObject.PhysicalObject;
-import processManager.ProcessComparator;
-import processManager.ProcessManager;
-import reaction.RegularReaction;
-import referenceLibrary.ClassRef;
-import referenceLibrary.XmlRef;
-import settable.Attribute;
-import settable.Module;
-import settable.Module.Requirements;
-import settable.Settable;
-import shape.Dimension.DimName;
-import shape.Shape;
-import spatialRegistry.TreeType;
-import utility.Helper;
-
-/**
- * \brief TODO
- *
- *
A compartment owns
- *
one shape
- *
one environment container
- *
one agent container
- *
zero to many process managers
- *
- *
The environment container and the agent container both have a reference
- * to the shape, but do not know about each other. Agent-environment
- * interactions must be mediated by a process manager. Each process manager has
- * a reference to the environment container and the agent container, and
- * therefore can ask either of these about the compartment shape. It is
- * important though, that process managers do not have a reference to the
- * compartment they belong to: otherwise, a naive developer could have a
- * process manager call the {@code step()} method in {@code Compartment},
- * causing such chaos that even the thought of it keeps Rob awake at night.
- *
- *
In summary, the hierarchy of ownership is: shape -> agent/environment
- * containers -> process managers -> compartment. All the arrows point in the
- * same direction, meaning no entanglement of the kind iDynoMiCS 1 suffered.
- *
- * @author Robert Clegg (r.j.clegg@bham.ac.uk) University of Birmingham, U.K.
- * @author Bastiaan Cockx @BastiaanCockx (baco@env.dtu.dk), DTU, Denmark
- * @author Stefan Lang (stefan.lang@uni-jena.de)
- * Friedrich-Schiller University Jena, Germany
- * @author Sankalp Arya (sankalp.arya@nottingham.ac.uk) University of Nottingham, U.K.
- */
-public class Compartment implements CanPrelaunchCheck, Instantiable, Settable, Comparable
-{
- /**
- * This has a name for reporting purposes.
- */
- public String name;
- /**
- * Shape describes the geometry and size.
- *
- * TODO also the resolution calculators?
- */
- protected Shape _shape;
- /**
- * Scaling factor determines the ratio of real to modelled size.
- * All calculations for boundary movement will use this for scaling up from
- * the modelled size to actual biofilm size.
- */
- protected double _scalingFactor = 1.0;
- /**
- * AgentContainer deals with all agents, whether they have spatial location
- * or not.
- */
- public AgentContainer agents;
- /**
- * EnvironmentContainer deals with all solutes.
- */
- public EnvironmentContainer environment;
- /**
- * ProcessManagers handle the interactions between agents and solutes.
- * The order of the list is important.
- */
- protected LinkedList _processes =
- new LinkedList();
- /**
- * ProcessComparator orders Process Managers by their time priority.
- */
- protected ProcessComparator _procComp = new ProcessComparator();
- /**
- * Local time should always be between {@code Timer.getCurrentTime()} and
- * {@code Timer.getEndOfCurrentTime()}.
- */
- // TODO temporary fix, reassess
- //protected double _localTime = Idynomics.simulator.timer.getCurrentTime();
- protected double _localTime;
-
- /**
- * the compartment parent node constructor (simulator)
- */
- private Settable _parentNode;
-
- /**
- *
- */
- private int _priority = Integer.MAX_VALUE;
-
- /* ***********************************************************************
- * CONSTRUCTORS
- * **********************************************************************/
-
- public Compartment()
- {
-
- }
-
- public Compartment(String name)
- {
- this.name = name;
- }
-
- public void remove(Object object)
- {
- if ( object instanceof ProcessManager )
- this._processes.remove(object);
- }
-
- public Settable newBlank()
- {
- Compartment newComp = new Compartment();
- return newComp;
- }
-
- /**
- * \brief
- *
- * @param aShape
- */
- public void setShape(Shape aShape)
- {
- if( Log.shouldWrite(Tier.EXPRESSIVE))
- Log.out(Tier.EXPRESSIVE, "Compartment \""+this.name+
- "\" taking shape \""+aShape.getName()+"\"");
- this._shape = aShape;
- this.environment = new EnvironmentContainer(this._shape);
- this.agents = new AgentContainer(this._shape);
- }
- /**
- * \brief Initialise this {@code Compartment} from an XML node.
- *
- * TODO diffusivity
- * @param xmlElem An XML element from a protocol file.
- */
- public void instantiate(Element xmlElem, Settable parent)
- {
- /*
- * Compartment initiation
- */
- this.name = XmlHandler.obtainAttribute(
- xmlElem, XmlRef.nameAttribute, XmlRef.compartment);
- if( XmlHandler.hasAttribute(xmlElem, XmlRef.priority))
- this._priority = Integer.valueOf( XmlHandler.gatherAttribute(
- xmlElem, XmlRef.priority) );
- Idynomics.simulator.addCompartment(this);
- /*
- * Set up the shape.
- */
- Element elem = XmlHandler.findUniqueChild(xmlElem, XmlRef.compartmentShape);
- String[] str = new String[] { XmlHandler.gatherAttribute(elem, XmlRef.classAttribute) };
- if ( str[0] == null )
- str = Shape.getAllOptions();
- this.setShape( (Shape) Instance.getNew(elem, this, str) );
- /* NOTE density scaling is done on individual basis {@Link
- * DensityScaling} so agents can maintain constant radius for 2D and 3D
- * cases. */
-
- double[] simulatedLengths = this.getShape().getDimensionLengths();
- // Check for scale attribute, specifying explicitly provided scale.
- String scalingFac = XmlHandler.gatherAttribute(xmlElem, XmlRef.compartmentScale);
- if ( !Helper.isNullOrEmpty(scalingFac) )
- {
- double scFac = Double.valueOf(scalingFac);
- this.setScalingFactor(scFac);
- }
- // Check for significant dimensions.
- else if (simulatedLengths.length != 0)
- {
- // Scaling factor not provided explicitly, calculate from realLengths
- Shape compShape = this.getShape();
- DimName dimN = compShape.getRealDimExtremeName();
- if ( Helper.isNullOrEmpty(compShape.getRealDimExtremeName()) )
- {
- double simulatedVolume = compShape.getTotalVolume();
- double realVolume = compShape.getTotalRealVolume();
- this.setScalingFactor(realVolume / simulatedVolume);
- }
- else
- {
- double simulatedArea = compShape.getBoundarySurfaceArea(dimN, 1);
- double realArea = compShape.getRealSurfaceArea(dimN, 1);
- this.setScalingFactor(realArea / simulatedArea);
- }
- }
-
- for( Boundary b : this._shape.getAllBoundaries())
- {
- b.setContainers(environment, agents);
- // FIXME trying to figure out how to get the well mixed region working,
- // quite funky investigate
-// if (b instanceof SpatialBoundary)
-// ((SpatialBoundary) b).setLayerThickness(Double.valueOf(
-// XmlHandler.obtainAttribute(xmlElem,
-// XmlRef.layerThickness, XmlRef.compartment)));
- }
- /*
- * set container parentNodes
- */
- agents.setParent(this);
- environment.setParent(this);
- /*
- * setup tree
- */
- String type = XmlHandler.gatherAttribute(xmlElem, XmlRef.tree);
- type = Helper.setIfNone(type, String.valueOf( agents.getSpatialTreeType() ));
- this.agents.setSpatialTreeType(TreeType.valueOf(type));
- /*
- * Look for spawner elements
- */
- Spawner spawner;
- TreeMap spawners = new TreeMap();
- for ( Element e : XmlHandler.getElements( xmlElem, XmlRef.spawnNode) )
- {
- if ( e.hasAttribute( XmlRef.classAttribute ) )
- {
- spawner = (Spawner) Instance.getNew(e, this);
- /* check for duplicate priority */
- int priority = Helper.nextAvailableKey(
- spawner.getPriority(),spawners.keySet() );
- if (spawners.containsKey( spawner.getPriority() ))
- {
- if( Log.shouldWrite(Tier.EXPRESSIVE))
- Log.out(Tier.EXPRESSIVE, "WARNING: Spawner with "
- + "duplicate priority next priority is picked "
- + "by simulator.");
- }
- spawners.put(priority, spawner);
- }
- }
- /* verify whether this always returns in correct order (it should) */
- for( Spawner s : spawners.values() )
- s.spawn();
-
- if( Log.shouldWrite(Tier.EXPRESSIVE))
- Log.out(Tier.EXPRESSIVE, "Compartment " + this.name +
- " initialised with " + this.agents.getNumAllAgents() +
- " agents.");
-
- /*
- * Read in agents.
- */
- for ( Element e : XmlHandler.getElements( xmlElem, XmlRef.agent) )
- this.addAgent(new Agent( e, this ));
- if( Log.shouldWrite(Tier.EXPRESSIVE))
- Log.out(Tier.EXPRESSIVE, "Compartment "+this.name+" initialised with "+
- this.agents.getNumAllAgents()+" agents");
- /*
- * Load solutes.
- */
- if( Log.shouldWrite(Tier.EXPRESSIVE))
- Log.out(Tier.EXPRESSIVE, "Compartment reading in solutes");
- Element solutes = XmlHandler.findUniqueChild(xmlElem, XmlRef.solutes);
- for ( Element e : XmlHandler.getElements(solutes, XmlRef.solute))
- {
- new SpatialGrid( e, this.environment);
- }
- /*
- * Load extra-cellular reactions.
- */
- if( Log.shouldWrite(Tier.EXPRESSIVE))
- Log.out(Tier.EXPRESSIVE, "Compartment reading in (environmental) reactions");
- for ( Element e : XmlHandler.getElements( xmlElem, XmlRef.reaction) )
- new RegularReaction(e, this.environment);
- /*
- * Read in process managers.
- */
- if( Log.shouldWrite(Tier.EXPRESSIVE))
- Log.out(Tier.EXPRESSIVE,"Compartment "+this.name+ " loading "+XmlHandler.
- getElements(xmlElem, XmlRef.process).size()+" processManagers");
- for ( Element e : XmlHandler.getElements( xmlElem, XmlRef.process) )
- {
- this.addProcessManager(
- (ProcessManager) Instance.getNew(e, this, (String[])null));
- }
-
- for ( Element e : XmlHandler.getElements(xmlElem,XmlRef.physicalObject))
- {
- this.addPhysicalObject( (PhysicalObject) Instance.getNew(e, this,
- PhysicalObject.class.getName()));
- }
-
- /* NOTE: we fetch the class from the xml node */
- elem = XmlHandler.findUniqueChild(xmlElem, XmlRef.orientation);
- str = new String[] { XmlHandler.gatherAttribute(elem, XmlRef.variable) };
- if ( str[0] == null )
- {
- this.getShape().setOrientation( new Orientation( Vector.zerosDbl(
- this._shape.getNumberOfDimensions() ), this ) );
- } else {
- this.getShape().setOrientation( (Orientation) Instance.getNew( elem,
- this, Orientation.class.getName() ) );
- }
- }
-
-
-
- /* ***********************************************************************
- * BASIC SETTERS & GETTERS
- * **********************************************************************/
-
- public String getName()
- {
- return this.name;
- }
-
- public Shape getShape()
- {
- return this._shape;
- }
-
- public boolean isDimensionless()
- {
- return this._shape.getNumberOfDimensions() == 0;
- }
-
- public int getNumDims()
- {
- return this._shape.getNumberOfDimensions();
- }
-
- public void setSideLengths(double[] sideLengths)
- {
- this._shape.setDimensionLengths(sideLengths);
- }
-
- /**
- * \brief Add a boundary to this compartment's shape.
- *
- * @param aBoundary Any boundary, whether spatial or non-spatial.
- */
- // TODO move this spatial/non-spatial splitting to Shape?
- public void addBoundary(Boundary aBoundary)
- {
- aBoundary.setContainers(this.environment, this.agents);
- if ( aBoundary instanceof SpatialBoundary )
- {
- SpatialBoundary sB = (SpatialBoundary) aBoundary;
- DimName dim = sB.getDimName();
- int extreme = sB.getExtreme();
- this._shape.setBoundary(dim, extreme, sB);
- }
- else
- this._shape.addOtherBoundary(aBoundary);
- }
-
- /**
- * \brief Add the given {@code ProcessManager} to the list, making sure
- * that it is in the correct place.
- *
- * @param aProcessManager
- */
- public void addProcessManager(ProcessManager aProcessManager)
- {
- this._processes.add(aProcessManager);
- // TODO Rob [18Apr2016]: Check if the process's next time step is
- // earlier than the current time.
- Collections.sort(this._processes, this._procComp);
- }
-
- /**
- * \brief Add the given agent to this compartment.
- *
- * @param Agent Agent to add.
- */
- public void addAgent(Agent agent)
- {
-
- this.agents.addAgent(agent);
- agent.setCompartment(this);
- }
-
- public void addPhysicalObject(PhysicalObject p)
- {
- this.agents._physicalObjects.add(p);
- }
-
- public void addReaction(RegularReaction reaction)
- {
- this.environment.addReaction(reaction);
- }
-
- public void addSolute(SpatialGrid solute)
- {
- this.environment.addSolute(solute);
- }
-
- /**
- * \brief Remove the given agent from this compartment, registering its
- * removal.
- *
- *
This should be used only removal from the entire simulation, and not
- * for transfer to another compartment. For example, cell lysis.
- *
- * @param agent Agent to remove.
- */
- public void registerRemoveAgent(Agent agent)
- {
- agent.setCompartment(null);
- this.agents.registerRemoveAgent(agent);
- }
-
- /**
- * \brief Get the {@code SpatialGrid} for the given solute name.
- *
- * @param soluteName {@code String} name of the solute required.
- * @return The {@code SpatialGrid} for that solute, or {@code null} if it
- * does not exist.
- */
- public SpatialGrid getSolute(String soluteName)
- {
- return this.environment.getSoluteGrid(soluteName);
- }
-
- /* ***********************************************************************
- * STEPPING
- * **********************************************************************/
-
- /**
- * \brief Connects any disconnected boundaries to a new partner boundary on
- * the appropriate compartment.
- *
- * Note that generation of spatial boundaries by this method is not yet
- * possible. It is therefore necessary to specify spatial boundaries and to
- * omit their partners in the protocol file.
- * @param compartments List of compartments to choose from.
- */
- public void checkBoundaryConnections(Collection compartments)
- {
- List compartmentNames = new LinkedList();
- for ( Compartment c : compartments )
- compartmentNames.add(c.getName());
-
- for ( Boundary b : this._shape.getDisconnectedBoundaries() )
- {
- String name = b.getPartnerCompartmentName();
- Compartment comp = findByName(compartments, name);
- while ( comp == null )
- {
- if( Log.shouldWrite(Tier.CRITICAL) )
- Log.out(Tier.CRITICAL,
- "Cannot connect boundary " + b.getName() +
- " in compartment " + this.getName());
- name = Helper.obtainInput(compartmentNames,
- "Please choose a compartment:", true);
- comp = findByName(compartments, name);
- }
- if( Log.shouldWrite(Tier.EXPRESSIVE) )
- Log.out(Tier.EXPRESSIVE,
- "Connecting boundary " + b.getName() +
- " to a partner boundary of type " +
- b.getPartnerClass().toString() + " in compartment " +
- comp.getName());
- Boundary partner = b.makePartnerBoundary();
- comp.addBoundary(partner);
- }
- }
-
- /**
- * \brief Do all inbound agent & solute transfers.
- */
- public void preStep()
- {
- /*
- * Ask all Agents waiting in boundary arrivals lounges to enter the
- * compartment now.
- */
- this.agents.agentsArrive();
-
- this.agents.sortLocatedAgents();
- /*
- * Ask all boundaries to update their solute concentrations.
- */
- this.environment.updateSoluteBoundaries();
- }
-
- /**
- * \brief Iterate over the process managers until the local time would
- * exceed the global time step.
- */
- public void step()
- {
- this._localTime = Idynomics.simulator.timer.getCurrentTime();
- if( Log.shouldWrite(Tier.DEBUG) )
- {
- Log.out(Tier.DEBUG, "Compartment "+this.name+
- " at local time "+this._localTime);
- }
-
- if ( this._processes.isEmpty() )
- return;
- ProcessManager currentProcess = this._processes.getFirst();
- while ( (this._localTime = currentProcess.getTimeForNextStep() )
- < Idynomics.simulator.timer.getEndOfCurrentIteration() &&
- Idynomics.simulator.active() )
- {
- if( Log.shouldWrite(Tier.DEBUG) )
- Log.out(Tier.DEBUG, "Compartment "+this.name+
- " running process "+currentProcess.getName()+
- " at local time "+this._localTime);
-
- /*
- * First process on the list does its thing. This should then
- * increase its next step time.
- */
- currentProcess.step();
- /*
- * Reinsert this process at the appropriate position in the list.
- */
- Collections.sort(this._processes, this._procComp);
- /*
- * Choose the new first process for the next iteration.
- */
- currentProcess = this._processes.getFirst();
- }
- }
-
- /**
- * \brief Do all outbound agent & solute transfers.
- */
- public void postStep()
- {
- /*
- * Boundaries grab the agents they want, settling any conflicts between
- * boundaries.
- */
- this.agents.boundariesGrabAgents();
- /*
- * Tell all agents queued to leave the compartment to move now.
- */
- this.agents.agentsDepart();
- }
-
- /* ***********************************************************************
- * PRE-LAUNCH CHECK
- * **********************************************************************/
-
- public boolean isReadyForLaunch()
- {
- if ( this._shape == null )
- {
- Log.out(Tier.CRITICAL, "Compartment shape is undefined!");
- return false;
- }
- if ( ! this._shape.isReadyForLaunch() )
- return false;
- return true;
- }
-
- /* ***********************************************************************
- * REPORTING
- * **********************************************************************/
-
- public void printSoluteGrid(String soluteName)
- {
- this.environment.printSolute(soluteName);
- }
-
- public void printAllSoluteGrids()
- {
- this.environment.printAllSolutes();
- }
-
- /**
- * @return TODO
- */
- public Map getRealTimeStats()
- {
- Map out = new HashMap();
- for ( ProcessManager pm : this._processes )
- {
- if (out.containsKey(pm.getName()))
- out.put(pm.getName(), out.get(pm.getName()) + pm.getRealTimeTaken());
- else
- out.put(pm.getName(), pm.getRealTimeTaken());
- }
- return out;
- }
-
- /* ***********************************************************************
- * Model Node factory
- * **********************************************************************/
-
- @Override
- public Module getModule()
- {
- /* The compartment node. */
- Module modelNode = new Module(XmlRef.compartment, this);
- modelNode.setRequirements(Requirements.ZERO_TO_FEW);
- /* Set title for GUI. */
- if ( this.getName() != null )
- modelNode.setTitle(this.getName());
-
- /* Add the name attribute. */
- modelNode.add( new Attribute(XmlRef.nameAttribute,
- this.getName(), null, true ) );
- modelNode.add( new Attribute(XmlRef.priority,
- String.valueOf(this._priority), null, true ) );
-
- modelNode.add( new Attribute(XmlRef.compartmentScale,
- String.valueOf(this.getScalingFactor()), null, true ) );
- /* Add the shape if it exists. */
- if ( this._shape != null )
- modelNode.add( this._shape.getModule() );
- /* Add the Environment node. */
- modelNode.add( this.environment.getModule() );
- /* Add the Agents node. */
- modelNode.add( this.agents.getModule() );
- /* Add the process managers node. */
- modelNode.add( this.getProcessNode() );
-
- modelNode.add( getObjectNode() );
-
- /* spatial registry NOTE we are handling this here since the agent
- * container does not have the proper init infrastructure */
- modelNode.add( new Attribute(XmlRef.tree,
- String.valueOf( this.agents.getSpatialTreeType() ) ,
- Helper.enumToStringArray( TreeType.class ), false ) );
-
- return modelNode;
- }
-
- /**
- * \brief Helper method for {@link #getModule()}.
- *
- * @return Model node for the process managers.
- */
- private Module getProcessNode()
- {
- /* The process managers node. */
- Module modelNode = new Module( XmlRef.processManagers, this );
- modelNode.setRequirements( Requirements.EXACTLY_ONE );
- /*
- * Work around: we need an object in order to call the newBlank method
- * from TODO investigate a cleaner way of doing this
- */
- modelNode.addChildSpec( ClassRef.processManager,
- Helper.collectionToArray( ProcessManager.getAllOptions() ),
- Module.Requirements.ZERO_TO_MANY );
-
- /* Add existing process managers as child nodes. */
- for ( ProcessManager p : this._processes )
- modelNode.add( p.getModule() );
- return modelNode;
- }
-
- /**
- * \brief Helper method for {@link #getModule()}.
- *
- * @return Model node for the process managers.
- */
- private Module getObjectNode()
- {
- /* The process managers node. */
- Module modelNode = new Module( XmlRef.objects, this );
- modelNode.setRequirements( Requirements.EXACTLY_ONE );
- /*
- * TODO add Object child spec
- */
-
- /* Add existing process managers as child nodes. */
- for (PhysicalObject p : this.agents._physicalObjects )
- modelNode.add( p.getModule() );
- return modelNode;
- }
-
- @Override
- public void setModule(Module node)
- {
- /* Set the modelNode for compartment. */
- if ( node.getTag().equals(this.defaultXmlTag()) )
- {
- /* Update the name. */
- this.name = node.getAttribute( XmlRef.nameAttribute ).getValue();
- this._priority = Integer.valueOf(node.getAttribute(
- XmlRef.priority ).getValue() );
-
- /* set the tree type */
- String tree = node.getAttribute( XmlRef.tree ).getValue();
- if ( ! Helper.isNullOrEmpty( tree ) )
- this.agents.setSpatialTreeType( TreeType.valueOf( tree ) );
- }
- /*
- * Set the child nodes.
- * Agents, process managers and solutes are container nodes: only
- * child nodes need to be set here.
- */
- Settable.super.setModule(node);
- }
-
- public void removeModule(String specifier)
- {
- Idynomics.simulator.removeCompartment(this);
- }
-
- @Override
- public String defaultXmlTag()
- {
- return XmlRef.compartment;
- }
-
- @Override
- public void setParent(Settable parent)
- {
- this._parentNode = parent;
- }
-
- @Override
- public Settable getParent()
- {
- return this._parentNode;
- }
-
- /* ***********************************************************************
- * Helper methods
- * **********************************************************************/
-
- public static Compartment findByName(
- Collection compartments, String name)
- {
- for ( Compartment c : compartments )
- if ( c.getName().equals(name) )
- return c;
- return null;
- }
-
- public void setScalingFactor(double scFac)
- {
- this._scalingFactor = scFac;
- }
-
- public double getScalingFactor()
- {
- return this._scalingFactor;
- }
-
- @Override
- public int compareTo(Compartment o)
- {
- int temp = this._priority - o._priority;
- if ( temp != 0 )
- return temp;
- else
- return this.name.compareTo(o.name);
- }
-}
+package compartment;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.w3c.dom.Element;
+
+import agent.Agent;
+import boundary.Boundary;
+import boundary.SpatialBoundary;
+import compartment.agentStaging.Spawner;
+import dataIO.Log;
+import dataIO.Log.Tier;
+import dataIO.XmlHandler;
+import generalInterfaces.CanPrelaunchCheck;
+import grid.SpatialGrid;
+import idynomics.Idynomics;
+import instantiable.Instance;
+import instantiable.Instantiable;
+import instantiable.object.InstantiableList;
+import linearAlgebra.Orientation;
+import linearAlgebra.Vector;
+import physicalObject.PhysicalObject;
+import processManager.ProcessComparator;
+import processManager.ProcessManager;
+import reaction.RegularReaction;
+import referenceLibrary.ClassRef;
+import referenceLibrary.XmlRef;
+import settable.Attribute;
+import settable.Module;
+import settable.Module.Requirements;
+import settable.Settable;
+import shape.Dimension.DimName;
+import shape.Shape;
+import spatialRegistry.TreeType;
+import utility.Helper;
+
+/**
+ * \brief TODO
+ *
+ *
A compartment owns
+ *
one shape
+ *
one environment container
+ *
one agent container
+ *
zero to many process managers
+ *
+ *
The environment container and the agent container both have a reference
+ * to the shape, but do not know about each other. Agent-environment
+ * interactions must be mediated by a process manager. Each process manager has
+ * a reference to the environment container and the agent container, and
+ * therefore can ask either of these about the compartment shape. It is
+ * important though, that process managers do not have a reference to the
+ * compartment they belong to: otherwise, a naive developer could have a
+ * process manager call the {@code step()} method in {@code Compartment},
+ * causing such chaos that even the thought of it keeps Rob awake at night.
+ *
+ *
In summary, the hierarchy of ownership is: shape -> agent/environment
+ * containers -> process managers -> compartment. All the arrows point in the
+ * same direction, meaning no entanglement of the kind iDynoMiCS 1 suffered.
+ *
+ * @author Robert Clegg (r.j.clegg@bham.ac.uk) University of Birmingham, U.K.
+ * @author Bastiaan Cockx @BastiaanCockx (baco@env.dtu.dk), DTU, Denmark
+ * @author Stefan Lang (stefan.lang@uni-jena.de)
+ * Friedrich-Schiller University Jena, Germany
+ * @author Sankalp Arya (sankalp.arya@nottingham.ac.uk) University of Nottingham, U.K.
+ */
+public class Compartment implements CanPrelaunchCheck, Instantiable, Settable, Comparable
+{
+ /**
+ * This has a name for reporting purposes.
+ */
+ public String name;
+ /**
+ * Shape describes the geometry and size.
+ *
+ * TODO also the resolution calculators?
+ */
+ protected Shape _shape;
+ /**
+ * Scaling factor determines the ratio of real to modelled size.
+ * All calculations for boundary movement will use this for scaling up from
+ * the modelled size to actual biofilm size.
+ */
+ protected double _scalingFactor = 1.0;
+ /**
+ * AgentContainer deals with all agents, whether they have spatial location
+ * or not.
+ */
+ public AgentContainer agents;
+ /**
+ * EnvironmentContainer deals with all solutes.
+ */
+ public EnvironmentContainer environment;
+ /**
+ * ProcessManagers handle the interactions between agents and solutes.
+ * The order of the list is important.
+ */
+ protected LinkedList _processes =
+ new LinkedList();
+ /**
+ * ProcessComparator orders Process Managers by their time priority.
+ */
+ protected ProcessComparator _procComp = new ProcessComparator();
+ /**
+ * Local time should always be between {@code Timer.getCurrentTime()} and
+ * {@code Timer.getEndOfCurrentTime()}.
+ */
+ // TODO temporary fix, reassess
+ //protected double _localTime = Idynomics.simulator.timer.getCurrentTime();
+ protected double _localTime;
+
+ /**
+ * the compartment parent node constructor (simulator)
+ */
+ private Settable _parentNode;
+
+ /**
+ *
+ */
+ private int _priority = Integer.MAX_VALUE;
+
+ /* ***********************************************************************
+ * CONSTRUCTORS
+ * **********************************************************************/
+
+ public Compartment()
+ {
+
+ }
+
+ public Compartment(String name)
+ {
+ this.name = name;
+ }
+
+ public void remove(Object object)
+ {
+ if ( object instanceof ProcessManager )
+ this._processes.remove(object);
+ }
+
+ public Settable newBlank()
+ {
+ Compartment newComp = new Compartment();
+ return newComp;
+ }
+
+ /**
+ * \brief
+ *
+ * @param aShape
+ */
+ public void setShape(Shape aShape)
+ {
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ Log.out(Tier.EXPRESSIVE, "Compartment \""+this.name+
+ "\" taking shape \""+aShape.getName()+"\"");
+ this._shape = aShape;
+ this.environment = new EnvironmentContainer(this._shape);
+ this.agents = new AgentContainer(this._shape);
+ }
+ /**
+ * \brief Initialise this {@code Compartment} from an XML node.
+ *
+ * TODO diffusivity
+ * @param xmlElem An XML element from a protocol file.
+ */
+ public void instantiate(Element xmlElem, Settable parent)
+ {
+ /*
+ * Compartment initiation
+ */
+ this.name = XmlHandler.obtainAttribute(
+ xmlElem, XmlRef.nameAttribute, XmlRef.compartment);
+ if( XmlHandler.hasAttribute(xmlElem, XmlRef.priority))
+ this._priority = Integer.valueOf( XmlHandler.gatherAttribute(
+ xmlElem, XmlRef.priority) );
+ Idynomics.simulator.addCompartment(this);
+ /*
+ * Set up the shape.
+ */
+ Element elem = XmlHandler.findUniqueChild(xmlElem, XmlRef.compartmentShape);
+ String[] str = new String[] { XmlHandler.gatherAttribute(elem, XmlRef.classAttribute) };
+ if ( str[0] == null )
+ str = Shape.getAllOptions();
+ this.setShape( (Shape) Instance.getNew(elem, this, str) );
+ /* NOTE density scaling is done on individual basis {@Link
+ * DensityScaling} so agents can maintain constant radius for 2D and 3D
+ * cases. */
+
+ double[] simulatedLengths = this.getShape().getDimensionLengths();
+ // Check for scale attribute, specifying explicitly provided scale.
+ String scalingFac = XmlHandler.gatherAttribute(xmlElem, XmlRef.compartmentScale);
+ if ( !Helper.isNullOrEmpty(scalingFac) )
+ {
+ double scFac = Double.valueOf(scalingFac);
+ this.setScalingFactor(scFac);
+ }
+ // Check for significant dimensions.
+ else if (simulatedLengths.length != 0)
+ {
+ // Scaling factor not provided explicitly, calculate from realLengths
+ Shape compShape = this.getShape();
+ DimName dimN = compShape.getRealDimExtremeName();
+ if ( Helper.isNullOrEmpty(compShape.getRealDimExtremeName()) )
+ {
+ double simulatedVolume = compShape.getTotalVolume();
+ double realVolume = compShape.getTotalRealVolume();
+ this.setScalingFactor(realVolume / simulatedVolume);
+ }
+ else
+ {
+ double simulatedArea = compShape.getBoundarySurfaceArea(dimN, 1);
+ double realArea = compShape.getRealSurfaceArea(dimN, 1);
+ this.setScalingFactor(realArea / simulatedArea);
+ }
+ }
+
+ for( Boundary b : this._shape.getAllBoundaries())
+ {
+ b.setContainers(environment, agents);
+ // FIXME trying to figure out how to get the well mixed region working,
+ // quite funky investigate
+// if (b instanceof SpatialBoundary)
+// ((SpatialBoundary) b).setLayerThickness(Double.valueOf(
+// XmlHandler.obtainAttribute(xmlElem,
+// XmlRef.layerThickness, XmlRef.compartment)));
+ }
+ /*
+ * set container parentNodes
+ */
+ agents.setParent(this);
+ environment.setParent(this);
+ /*
+ * setup tree
+ */
+ String type = XmlHandler.gatherAttribute(xmlElem, XmlRef.tree);
+ type = Helper.setIfNone(type, String.valueOf( agents.getSpatialTreeType() ));
+ this.agents.setSpatialTreeType(TreeType.valueOf(type));
+ /*
+ * Look for spawner elements
+ */
+ Spawner spawner;
+ TreeMap spawners = new TreeMap();
+ for ( Element e : XmlHandler.getElements( xmlElem, XmlRef.spawnNode) )
+ {
+ if ( e.hasAttribute( XmlRef.classAttribute ) )
+ {
+ spawner = (Spawner) Instance.getNew(e, this);
+ /* check for duplicate priority */
+ int priority = Helper.nextAvailableKey(
+ spawner.getPriority(),spawners.keySet() );
+ if (spawners.containsKey( spawner.getPriority() ))
+ {
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ Log.out(Tier.EXPRESSIVE, "WARNING: Spawner with "
+ + "duplicate priority next priority is picked "
+ + "by simulator.");
+ }
+ spawners.put(priority, spawner);
+ }
+ }
+ /* verify whether this always returns in correct order (it should) */
+ for( Spawner s : spawners.values() )
+ s.spawn();
+
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ Log.out(Tier.EXPRESSIVE, "Compartment " + this.name +
+ " initialised with " + this.agents.getNumAllAgents() +
+ " agents.");
+
+ /*
+ * Read in agents.
+ */
+ for ( Element e : XmlHandler.getElements( xmlElem, XmlRef.agent) )
+ this.addAgent(new Agent( e, this ));
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ Log.out(Tier.EXPRESSIVE, "Compartment "+this.name+" initialised with "+
+ this.agents.getNumAllAgents()+" agents");
+ /*
+ * Load solutes.
+ */
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ Log.out(Tier.EXPRESSIVE, "Compartment reading in solutes");
+ Element solutes = XmlHandler.findUniqueChild(xmlElem, XmlRef.solutes);
+ for ( Element e : XmlHandler.getElements(solutes, XmlRef.solute))
+ {
+ new SpatialGrid( e, this.environment);
+ }
+ /*
+ * Load extra-cellular reactions.
+ */
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ Log.out(Tier.EXPRESSIVE, "Compartment reading in (environmental) reactions");
+ for ( Element e : XmlHandler.getElements( xmlElem, XmlRef.reaction) )
+ new RegularReaction(e, this.environment);
+ /*
+ * Read in process managers.
+ */
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ Log.out(Tier.EXPRESSIVE,"Compartment "+this.name+ " loading "+XmlHandler.
+ getElements(xmlElem, XmlRef.process).size()+" processManagers");
+ for ( Element e : XmlHandler.getElements( xmlElem, XmlRef.process) )
+ {
+ this.addProcessManager(
+ (ProcessManager) Instance.getNew(e, this, (String[])null));
+ }
+
+ for ( Element e : XmlHandler.getElements(xmlElem,XmlRef.physicalObject))
+ {
+ this.addPhysicalObject( (PhysicalObject) Instance.getNew(e, this,
+ PhysicalObject.class.getName()));
+ }
+
+ /* NOTE: we fetch the class from the xml node */
+ elem = XmlHandler.findUniqueChild(xmlElem, XmlRef.orientation);
+ str = new String[] { XmlHandler.gatherAttribute(elem, XmlRef.variable) };
+ if ( str[0] == null )
+ {
+ this.getShape().setOrientation( new Orientation( Vector.zerosDbl(
+ this._shape.getNumberOfDimensions() ), this ) );
+ } else {
+ this.getShape().setOrientation( (Orientation) Instance.getNew( elem,
+ this, Orientation.class.getName() ) );
+ }
+ }
+
+
+
+ /* ***********************************************************************
+ * BASIC SETTERS & GETTERS
+ * **********************************************************************/
+
+ public String getName()
+ {
+ return this.name;
+ }
+
+ public Shape getShape()
+ {
+ return this._shape;
+ }
+
+ public boolean isDimensionless()
+ {
+ return this._shape.getNumberOfDimensions() == 0;
+ }
+
+ public int getNumDims()
+ {
+ return this._shape.getNumberOfDimensions();
+ }
+
+ public void setSideLengths(double[] sideLengths)
+ {
+ this._shape.setDimensionLengths(sideLengths);
+ }
+
+ /**
+ * \brief Add a boundary to this compartment's shape.
+ *
+ * @param aBoundary Any boundary, whether spatial or non-spatial.
+ */
+ // TODO move this spatial/non-spatial splitting to Shape?
+ public void addBoundary(Boundary aBoundary)
+ {
+ aBoundary.setContainers(this.environment, this.agents);
+ if ( aBoundary instanceof SpatialBoundary )
+ {
+ SpatialBoundary sB = (SpatialBoundary) aBoundary;
+ DimName dim = sB.getDimName();
+ int extreme = sB.getExtreme();
+ this._shape.setBoundary(dim, extreme, sB);
+ }
+ else
+ this._shape.addOtherBoundary(aBoundary);
+ }
+
+ /**
+ * \brief Add the given {@code ProcessManager} to the list, making sure
+ * that it is in the correct place.
+ *
+ * @param aProcessManager
+ */
+ public void addProcessManager(ProcessManager aProcessManager)
+ {
+ this._processes.add(aProcessManager);
+ // TODO Rob [18Apr2016]: Check if the process's next time step is
+ // earlier than the current time.
+ Collections.sort(this._processes, this._procComp);
+ }
+
+ /**
+ * \brief Add the given agent to this compartment.
+ *
+ * @param Agent Agent to add.
+ */
+ public void addAgent(Agent agent)
+ {
+
+ this.agents.addAgent(agent);
+ agent.setCompartment(this);
+ }
+
+ public void addPhysicalObject(PhysicalObject p)
+ {
+ this.agents._physicalObjects.add(p);
+ }
+
+ public void addReaction(RegularReaction reaction)
+ {
+ this.environment.addReaction(reaction);
+ }
+
+ public void addSolute(SpatialGrid solute)
+ {
+ this.environment.addSolute(solute);
+ }
+
+ /**
+ * \brief Remove the given agent from this compartment, registering its
+ * removal.
+ *
+ *
This should be used only removal from the entire simulation, and not
+ * for transfer to another compartment. For example, cell lysis.
+ *
+ * @param agent Agent to remove.
+ */
+ public void registerRemoveAgent(Agent agent)
+ {
+ agent.setCompartment(null);
+ this.agents.registerRemoveAgent(agent);
+ }
+
+ /**
+ * \brief Get the {@code SpatialGrid} for the given solute name.
+ *
+ * @param soluteName {@code String} name of the solute required.
+ * @return The {@code SpatialGrid} for that solute, or {@code null} if it
+ * does not exist.
+ */
+ public SpatialGrid getSolute(String soluteName)
+ {
+ return this.environment.getSoluteGrid(soluteName);
+ }
+
+ /* ***********************************************************************
+ * STEPPING
+ * **********************************************************************/
+
+ /**
+ * \brief Connects any disconnected boundaries to a new partner boundary on
+ * the appropriate compartment.
+ *
+ * Note that generation of spatial boundaries by this method is not yet
+ * possible. It is therefore necessary to specify spatial boundaries and to
+ * omit their partners in the protocol file.
+ * @param compartments List of compartments to choose from.
+ */
+ public void checkBoundaryConnections(Collection compartments)
+ {
+ List compartmentNames = new LinkedList();
+ for ( Compartment c : compartments )
+ compartmentNames.add(c.getName());
+
+ for ( Boundary b : this._shape.getDisconnectedBoundaries() )
+ {
+ String name = b.getPartnerCompartmentName();
+ Compartment comp = findByName(compartments, name);
+ while ( comp == null )
+ {
+ if( Log.shouldWrite(Tier.CRITICAL) )
+ Log.out(Tier.CRITICAL,
+ "Cannot connect boundary " + b.getName() +
+ " in compartment " + this.getName());
+ name = Helper.obtainInput(compartmentNames,
+ "Please choose a compartment:", true);
+ comp = findByName(compartments, name);
+ }
+ if( Log.shouldWrite(Tier.EXPRESSIVE) )
+ Log.out(Tier.EXPRESSIVE,
+ "Connecting boundary " + b.getName() +
+ " to a partner boundary of type " +
+ b.getPartnerClass().toString() + " in compartment " +
+ comp.getName());
+ Boundary partner = b.makePartnerBoundary();
+ comp.addBoundary(partner);
+ }
+ }
+
+ /**
+ * \brief Do all inbound agent & solute transfers.
+ */
+ public void preStep()
+ {
+ /*
+ * Ask all Agents waiting in boundary arrivals lounges to enter the
+ * compartment now.
+ */
+ this.agents.agentsArrive();
+
+ this.agents.sortLocatedAgents();
+ /*
+ * Ask all boundaries to update their solute concentrations.
+ */
+ this.environment.updateSoluteBoundaries();
+ }
+
+ /**
+ * \brief Iterate over the process managers until the local time would
+ * exceed the global time step.
+ */
+ public void step()
+ {
+ this._localTime = Idynomics.simulator.timer.getCurrentTime();
+ if( Log.shouldWrite(Tier.DEBUG) )
+ {
+ Log.out(Tier.DEBUG, "Compartment "+this.name+
+ " at local time "+this._localTime);
+ }
+
+ if ( this._processes.isEmpty() )
+ return;
+ ProcessManager currentProcess = this._processes.getFirst();
+ while ( (this._localTime = currentProcess.getTimeForNextStep() )
+ < Idynomics.simulator.timer.getEndOfCurrentIteration() &&
+ Idynomics.simulator.active() )
+ {
+ if( Log.shouldWrite(Tier.DEBUG) )
+ Log.out(Tier.DEBUG, "Compartment "+this.name+
+ " running process "+currentProcess.getName()+
+ " at local time "+this._localTime);
+
+ /*
+ * First process on the list does its thing. This should then
+ * increase its next step time.
+ */
+ currentProcess.step();
+ /*
+ * Reinsert this process at the appropriate position in the list.
+ */
+ Collections.sort(this._processes, this._procComp);
+ /*
+ * Choose the new first process for the next iteration.
+ */
+ currentProcess = this._processes.getFirst();
+ }
+ }
+
+ /**
+ * \brief Do all outbound agent & solute transfers.
+ */
+ public void postStep()
+ {
+ /*
+ * Boundaries grab the agents they want, settling any conflicts between
+ * boundaries.
+ */
+ this.agents.boundariesGrabAgents();
+ /*
+ * Tell all agents queued to leave the compartment to move now.
+ */
+ this.agents.agentsDepart();
+ }
+
+ public void process(String process)
+ {
+ for ( ProcessManager p : this._processes )
+ if( p.getName().equals(process) )
+ p.step();
+ }
+
+ /* ***********************************************************************
+ * PRE-LAUNCH CHECK
+ * **********************************************************************/
+
+ public boolean isReadyForLaunch()
+ {
+ if ( this._shape == null )
+ {
+ Log.out(Tier.CRITICAL, "Compartment shape is undefined!");
+ return false;
+ }
+ if ( ! this._shape.isReadyForLaunch() )
+ return false;
+ return true;
+ }
+
+ /* ***********************************************************************
+ * REPORTING
+ * **********************************************************************/
+
+ public void printSoluteGrid(String soluteName)
+ {
+ this.environment.printSolute(soluteName);
+ }
+
+ public void printAllSoluteGrids()
+ {
+ this.environment.printAllSolutes();
+ }
+
+ /**
+ * @return TODO
+ */
+ public Map getRealTimeStats()
+ {
+ Map out = new HashMap();
+ for ( ProcessManager pm : this._processes )
+ {
+ if (out.containsKey(pm.getName()))
+ out.put(pm.getName(), out.get(pm.getName()) + pm.getRealTimeTaken());
+ else
+ out.put(pm.getName(), pm.getRealTimeTaken());
+ }
+ return out;
+ }
+
+ /* ***********************************************************************
+ * Model Node factory
+ * **********************************************************************/
+
+ @Override
+ public Module getModule()
+ {
+ /* The compartment node. */
+ Module modelNode = new Module(XmlRef.compartment, this);
+ modelNode.setRequirements(Requirements.ZERO_TO_FEW);
+ /* Set title for GUI. */
+ if ( this.getName() != null )
+ modelNode.setTitle(this.getName());
+
+ /* Add the name attribute. */
+ modelNode.add( new Attribute(XmlRef.nameAttribute,
+ this.getName(), null, true ) );
+ modelNode.add( new Attribute(XmlRef.priority,
+ String.valueOf(this._priority), null, true ) );
+
+ modelNode.add( new Attribute(XmlRef.compartmentScale,
+ String.valueOf(this.getScalingFactor()), null, true ) );
+ /* Add the shape if it exists. */
+ if ( this._shape != null )
+ modelNode.add( this._shape.getModule() );
+ /* Add the Environment node. */
+ modelNode.add( this.environment.getModule() );
+ /* Add the Agents node. */
+ modelNode.add( this.agents.getModule() );
+
+ /* Add the process managers node. */
+ modelNode.add( this.getProcessNode() );
+
+ modelNode.add( getObjectNode() );
+
+ /* spatial registry NOTE we are handling this here since the agent
+ * container does not have the proper init infrastructure */
+ modelNode.add( new Attribute(XmlRef.tree,
+ String.valueOf( this.agents.getSpatialTreeType() ) ,
+ Helper.enumToStringArray( TreeType.class ), false ) );
+
+ return modelNode;
+ }
+
+ /**
+ * \brief Helper method for {@link #getModule()}.
+ *
+ * @return Model node for the process managers.
+ */
+ private Module getProcessNode()
+ {
+ /* The process managers node. */
+ Module modelNode = new Module( XmlRef.processManagers, this );
+ modelNode.setRequirements( Requirements.EXACTLY_ONE );
+ /*
+ * Work around: we need an object in order to call the newBlank method
+ * from TODO investigate a cleaner way of doing this
+ */
+ modelNode.addChildSpec( ClassRef.processManager,
+ Helper.collectionToArray( ProcessManager.getAllOptions() ),
+ Module.Requirements.ZERO_TO_MANY );
+
+ /* Add existing process managers as child nodes. */
+ for ( ProcessManager p : this._processes )
+ modelNode.add( p.getModule() );
+ return modelNode;
+ }
+
+ /**
+ * \brief Helper method for {@link #getModule()}.
+ *
+ * @return Model node for the process managers.
+ */
+ private Module getObjectNode()
+ {
+ /* The process managers node. */
+ Module modelNode = new Module( XmlRef.objects, this );
+ modelNode.setRequirements( Requirements.EXACTLY_ONE );
+ /*
+ * TODO add Object child spec
+ */
+
+ /* Add existing process managers as child nodes. */
+ for (PhysicalObject p : this.agents._physicalObjects )
+ modelNode.add( p.getModule() );
+ return modelNode;
+ }
+
+ @Override
+ public void setModule(Module node)
+ {
+ /* Set the modelNode for compartment. */
+ if ( node.getTag().equals(this.defaultXmlTag()) )
+ {
+ /* Update the name. */
+ this.name = node.getAttribute( XmlRef.nameAttribute ).getValue();
+ this._priority = Integer.valueOf(node.getAttribute(
+ XmlRef.priority ).getValue() );
+
+ /* set the tree type */
+ String tree = node.getAttribute( XmlRef.tree ).getValue();
+ if ( ! Helper.isNullOrEmpty( tree ) )
+ this.agents.setSpatialTreeType( TreeType.valueOf( tree ) );
+ }
+ /*
+ * Set the child nodes.
+ * Agents, process managers and solutes are container nodes: only
+ * child nodes need to be set here.
+ */
+ Settable.super.setModule(node);
+ }
+
+ public void removeModule(String specifier)
+ {
+ Idynomics.simulator.removeCompartment(this);
+ }
+
+ @Override
+ public String defaultXmlTag()
+ {
+ return XmlRef.compartment;
+ }
+
+ @Override
+ public void setParent(Settable parent)
+ {
+ this._parentNode = parent;
+ }
+
+ @Override
+ public Settable getParent()
+ {
+ return this._parentNode;
+ }
+
+ /* ***********************************************************************
+ * Helper methods
+ * **********************************************************************/
+
+ public static Compartment findByName(
+ Collection compartments, String name)
+ {
+ for ( Compartment c : compartments )
+ if ( c.getName().equals(name) )
+ return c;
+ return null;
+ }
+
+ public void setScalingFactor(double scFac)
+ {
+ this._scalingFactor = scFac;
+ }
+
+ public double getScalingFactor()
+ {
+ return this._scalingFactor;
+ }
+
+ @Override
+ public int compareTo(Compartment o)
+ {
+ int temp = this._priority - o._priority;
+ if ( temp != 0 )
+ return temp;
+ else
+ return this.name.compareTo(o.name);
+ }
+}
diff --git a/src/dataIO/CumulativeLoad.java b/src/dataIO/CumulativeLoad.java
index 157b33158..e2f34714d 100644
--- a/src/dataIO/CumulativeLoad.java
+++ b/src/dataIO/CumulativeLoad.java
@@ -6,10 +6,12 @@
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
+import aspect.AspectReg;
import compartment.Compartment;
import idynomics.Idynomics;
import instantiable.Instance;
import processManager.ProcessManager;
+import referenceLibrary.AspectRef;
import referenceLibrary.XmlRef;
import utility.Helper;
@@ -38,13 +40,19 @@ public String test()
return "";
}
- public void postProcess()
+ public void postProcess(int num)
{
Compartment comp = null;
for ( Element e : XmlHandler.getElements( document, XmlRef.process) )
{
- comp.addProcessManager(
- (ProcessManager) Instance.getNew(e, comp, (String[])null));
+ String name = XmlHandler.gatherAttribute(e, XmlRef.nameAttribute);
+ String compartment = XmlHandler.gatherAttribute(e.getParentNode(), XmlRef.nameAttribute);
+ comp = Idynomics.simulator.getCompartment(compartment);
+ ProcessManager p = (ProcessManager) Instance.getNew(e, comp, (String[])null);
+ p.set(AspectRef.fileNumber, num);
+ comp.addProcessManager( p );
+ comp.process(name);
+
}
}
diff --git a/src/dataIO/GraphicalExporter.java b/src/dataIO/GraphicalExporter.java
index 8873c5c0e..e65d141a0 100644
--- a/src/dataIO/GraphicalExporter.java
+++ b/src/dataIO/GraphicalExporter.java
@@ -177,5 +177,7 @@ public default void init(String _prefix, Shape shape)
}
public void createCustomFile(String fileName);
+
+ public void setFileNumber(Integer number);
}
diff --git a/src/dataIO/PovExport.java b/src/dataIO/PovExport.java
index f356d33a0..49647caaa 100644
--- a/src/dataIO/PovExport.java
+++ b/src/dataIO/PovExport.java
@@ -83,7 +83,10 @@ public void createCustomFile(String fileName)
}
-
+ public void setFileNumber(Integer number)
+ {
+ this._filewriterfilenr = number;
+ }
/**
*
diff --git a/src/dataIO/SvgExport.java b/src/dataIO/SvgExport.java
index b03f593d7..7731ec4f9 100644
--- a/src/dataIO/SvgExport.java
+++ b/src/dataIO/SvgExport.java
@@ -108,6 +108,12 @@ public void closeFile()
*
*/
+
+ public void setFileNumber(Integer number)
+ {
+ this._filewriterfilenr = number;
+ }
+
/**
*
*/
diff --git a/src/gui/GuiActions.java b/src/gui/GuiActions.java
index f3af2bead..f3ee2cc99 100644
--- a/src/gui/GuiActions.java
+++ b/src/gui/GuiActions.java
@@ -65,7 +65,7 @@ public static File chooseFile(String relPath, String description)
{
/* Open a FileChooser window in the current directory. */
JFileChooser chooser = new JFileChooser("" +
- System.getProperty("user.dir")+"/protocol");
+ System.getProperty("user.dir")+"/"+relPath);
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
// TODO Allow the user to select multiple files.
chooser.setMultiSelectionEnabled(false);
diff --git a/src/idynomics/PostProcess.java b/src/idynomics/PostProcess.java
index c6936893a..8881485cc 100644
--- a/src/idynomics/PostProcess.java
+++ b/src/idynomics/PostProcess.java
@@ -29,9 +29,13 @@ public PostProcess(File script, List files)
@Override
public void run()
{
+ int num = 0;
for( File f : _files)
{
Idynomics.setupSimulator( f.getAbsolutePath() );
+ loader.postProcess(num);
+ Idynomics.simulator = new Simulator();
+ num++;
}
}
}
diff --git a/src/processManager/ProcessManager.java b/src/processManager/ProcessManager.java
index 57c60a7fd..357595ae4 100644
--- a/src/processManager/ProcessManager.java
+++ b/src/processManager/ProcessManager.java
@@ -1,433 +1,433 @@
-package processManager;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-import org.w3c.dom.Element;
-
-import aspect.AspectInterface;
-import aspect.AspectReg;
-import compartment.AgentContainer;
-import compartment.Compartment;
-import compartment.EnvironmentContainer;
-import dataIO.Log;
-import dataIO.Log.Tier;
-import dataIO.XmlHandler;
-import generalInterfaces.Redirectable;
-import idynomics.Idynomics;
-import instantiable.Instantiable;
-import referenceLibrary.ClassRef;
-import referenceLibrary.XmlRef;
-import settable.Attribute;
-import settable.Module;
-import settable.Module.Requirements;
-import settable.Settable;
-import utility.Helper;
-
-/**
- * \brief Abstract class for managing a process within a {@code Compartment}.
- *
- * @author Robert Clegg (r.j.clegg@bham.ac.uk) University of Birmingham, U.K.
- * @author Bastiaan Cockx @BastiaanCockx (baco@env.dtu.dk), DTU, Denmark.
- */
-public abstract class ProcessManager implements Instantiable, AspectInterface,
- Settable, Redirectable
-{
- /**
- * The name of this {@code ProcessManager}, for reporting.
- */
- protected String _name;
- /**
- * In the event of a time-clash between {@code ProcessManager}s, the one
- * with greater priority goes first.
- */
- protected int _priority;
- /**
- * The time at which this should next perform its step.
- */
- protected double _timeForNextStep = 0.0;
- /**
- * How often this should perform its step.
- */
- protected double _timeStepSize;
- /**
- * Force one internal step before simulation.
- */
- protected int _skips = 0;
- /**
- * How often this has been skipped since last run.
- */
- private int _skipped = 0;
- /**
- * The aspect registry.
- */
- private AspectReg _aspectRegistry = new AspectReg();
- /**
- * Reference to the environment of the compartment this process belongs to.
- * Contains a reference to the compartment shape.
- */
- protected EnvironmentContainer _environment;
- /**
- * Reference to the agents of the compartment this process belongs to.
- * Contains a reference to the compartment shape.
- */
- protected AgentContainer _agents;
-
- /**
- *
- */
- protected String _compartmentName;
-
- /**
- * Parent (owner) node, used for proper object removal via gui.
- */
- protected Settable _parentNode;
-
- /**
- * Used to track time used per process manager
- */
- private long _realTimeTaken = 0;
-
- /**
- * Used to track time used per process manager
- */
- private long _tick;
-
- /* ***********************************************************************
- * CONSTRUCTORS
- * **********************************************************************/
-
- /**
- * Generic init for Instantiatable implementation
- *
- *
- * NOTE this implementation is a bit 'hacky' to deal with
- * 1) The layered structure of process managers.
- * 2) The fact that process managers are initiated with environment, agents
- * and compartment name, something the instantiatable interface can only
- * Provide by supplying parent.
- *
- *
- * @param xmlElem
- * @param parent (in this case the compartment).
- */
- public void instantiate(Element xmlElem, Settable parent)
- {
- this.init(xmlElem, ((Compartment) parent).environment,
- ((Compartment) parent).agents,((Compartment) parent).getName());
- }
-
- /**
- * \brief Initialise the process from XML protocol file, plus the relevant
- * information about the compartment it belongs to.
- *
- * @param xmlElem Relevant part of the XML protocol file.
- * @param environment The {@code EnvironmentContainer} of the
- * {@code Compartment} this process belongs to.
- * @param agents The {@code AgentContainer} of the
- * {@code Compartment} this process belongs to.
- * @param compartmentName The name of the {@code Compartment} this process
- * belongs to.
- */
- public void init(Element xmlElem, EnvironmentContainer environment,
- AgentContainer agents, String compartmentName)
- {
- this._environment = environment;
- this._agents = agents;
- this._compartmentName = compartmentName;
-
- if (xmlElem != null)
- this.loadAspects(xmlElem);
- /*
- * Read in the process attributes.
- */
- Element p = (Element) xmlElem;
- if (Helper.isNullOrEmpty(this._name))
- this.setName( XmlHandler.obtainAttribute(p, XmlRef.nameAttribute,
- this.defaultXmlTag()));
- /* Process priority - default is zero. */
- int priority = 0;
- if ( XmlHandler.hasAttribute(p, XmlRef.processPriority) )
- priority = Integer.valueOf(p.getAttribute(XmlRef.processPriority) );
- this.setPriority(priority);
- /* Initial time to step. */
- double time = Idynomics.simulator.timer.getCurrentTime();
- if ( XmlHandler.hasAttribute(p, XmlRef.processFirstStep) )
- time = Double.valueOf(p.getAttribute(XmlRef.processFirstStep) );
- this.setTimeForNextStep(time);
- /* Time step size. */
- time = Idynomics.simulator.timer.getTimeStepSize();
- if ( XmlHandler.hasAttribute(p, XmlRef.processTimeStepSize) )
- time = Double.valueOf( p.getAttribute(XmlRef.processTimeStepSize));
- this.setTimeStepSize(time);
- if ( XmlHandler.hasAttribute(p, XmlRef.processSkips ))
- {
- this._skips = Integer.valueOf( p.getAttribute(XmlRef.processSkips));
- }
- this.redirect(xmlElem);
- if( Log.shouldWrite(Tier.EXPRESSIVE))
- Log.out(Tier.EXPRESSIVE, this._name + " loaded");
- }
-
- /* ***********************************************************************
- * BASIC SETTERS & GETTERS
- * ***********************************************************************/
-
- /**
- * \brief Return the aspect registry (implementation of aspect interface).
- */
- public AspectReg reg()
- {
- return _aspectRegistry;
- }
-
- /**
- * \brief Get this {@code ProcessManager}'s name.
- *
- * @return {@code String} name.
- */
- public String getName()
- {
- if (this._name == null)
- return "";
- else
- return this._name;
- }
-
- /**
- * \brief Set this {@code ProcessManager}'s name.
- *
- * @param {@code String} name.
- */
- public void setName(String name)
- {
- this._name = name;
- }
-
- /**
- * \brief Set the priority of this {@code ProcessManager}.
- *
- *
A higher priority {@code ProcessManager} goes first if two have a
- * time clash in the {@code Compartment} they belong to.
- *
- * @param priority Any integer value.
- */
- public void setPriority(int priority)
- {
- this._priority = priority;
- }
-
- /**
- * @return The priority of this {@code ProcessManager}.
- */
- public int getPriority()
- {
- return this._priority;
- }
-
- /**]
- * \brief Set the time point at which this will next step: useful for
- * testing.
- *
- * @param newTime The time point at which this should next step.
- */
- public void setTimeForNextStep(double newTime)
- {
- this._timeForNextStep = newTime;
- }
-
- /**
- * @return The time point at which this will next step.
- */
- public double getTimeForNextStep()
- {
- return this._timeForNextStep;
- }
-
- /**
- * \brief Set the time step directly: useful for testing.
- *
- * @param newStepSize Time step to use.
- */
- public void setTimeStepSize(double newStepSize)
- {
- this._timeStepSize = newStepSize;
- }
-
- /**
- * @return The local time step.
- */
- public double getTimeStepSize()
- {
- return this._timeStepSize;
- }
-
- /* ***********************************************************************
- * STEPPING
- * **********************************************************************/
-
- /**
- * \brief Perform the step of this process manager, also updating its local
- * time manager.
- *
- * @param environment The {@code EnvironmentContainer} of the
- * {@code Compartment} this process belongs to.
- * @param agents The {@code AgentContainer} of the
- * {@code Compartment} this process belongs to.
- */
- public void step()
- {
- double now = this._timeForNextStep;
- /* Move the time for next step forward by the step size. */
- this._timeForNextStep = BigDecimal.valueOf( _timeForNextStep ).add(
- BigDecimal.valueOf( _timeStepSize ) ).doubleValue();
-
- if ( this._skips > ++this._skipped )
- {
- /* skip */
- }
- else
- {
- this._tick = System.currentTimeMillis();
- /*This is where subclasses of ProcessManager do their step. Note
- * that this._timeStepSize may change if an adaptive timestep is
- * used. */
- this.internalStep();
- if ( !Idynomics.simulator.active())
- return;
-
- Tier level = Tier.EXPRESSIVE;
- if ( Log.shouldWrite(level) )
- {
- /* logging time, using BigDecimal prevents weird last decimal
- * round-off errors. */
- Log.out( level, this._name + ": " + now + " -> " +
- this._timeForNextStep + " (" + ( BigDecimal.valueOf(
- System.currentTimeMillis() - _tick ).multiply(
- BigDecimal.valueOf( 0.001 ) ).doubleValue() ) + "s)");
- }
- this._realTimeTaken += (System.currentTimeMillis() - _tick);
- this._skipped = 0;
- }
- }
-
- /**
- * \brief Perform the internal step for this process manager: this will be
- * implemented by each sub-class of {@code ProcessManager}.
- */
- protected abstract void internalStep();
-
- /* ***********************************************************************
- * REPORTING
- * **********************************************************************/
-
- public long getRealTimeTaken()
- {
- return this._realTimeTaken;
- }
-
- /* ***********************************************************************
- * NODE CONSTRUCTION
- * **********************************************************************/
-
- /**
- * \brief returns all known (ClassRef) process managers
- * @return all known (ClassRef) process managers
- */
- public static List getAllOptions()
- {
- return ClassRef.getAllOptions("processManager.library");
- }
-
- /**
- * Obtain module for xml output and gui representation.
- */
- public Module getModule()
- {
- Module modelNode = new Module(defaultXmlTag(), this);
- modelNode.setRequirements(Requirements.ZERO_TO_MANY);
- modelNode.setTitle(this._name);
-
- modelNode.add(new Attribute(XmlRef.nameAttribute,
- this._name, null, true ));
-
- if ( Idynomics.xmlPackageLibrary.has( this.getClass().getSimpleName() ))
- modelNode.add(new Attribute(XmlRef.classAttribute,
- this.getClass().getSimpleName(), null, false ));
- else
- modelNode.add(new Attribute(XmlRef.classAttribute,
- this.getClass().getName(), null, false ));
-
- modelNode.add(new Attribute(XmlRef.processPriority,
- String.valueOf(this._priority), null, true ));
-
- modelNode.add(new Attribute(XmlRef.processTimeStepSize,
- String.valueOf(this._timeStepSize), null, true ));
-
- modelNode.add(new Attribute(XmlRef.processFirstStep,
- String.valueOf(this._timeForNextStep), null, true ));
-
- for ( String key : this.reg().getLocalAspectNames() )
- modelNode.add(reg().getAspectNode(key));
-
- modelNode.addChildSpec( ClassRef.aspect,
- Module.Requirements.ZERO_TO_MANY);
-
- return modelNode;
- }
-
-
- /**
- * Set value's that (may) have been changed trough the gui.
- */
- public void setModule(Module node)
- {
- /* Set the name */
- this._name = node.getAttribute( XmlRef.nameAttribute ).getValue();
-
- /* Set the priority */
- this._priority = Integer.valueOf( node.getAttribute(
- XmlRef.processPriority ).getValue() );
-
- /* Set the timestep */
- this._timeStepSize = Double.valueOf( node.getAttribute(
- XmlRef.processTimeStepSize ).getValue() );
-
- /* Set the time for the first step from now */
- this._timeForNextStep = Double.valueOf( node.getAttribute(
- XmlRef.processFirstStep ).getValue() );
-
- /* Set any potential child modules */
- Settable.super.setModule(node);
- }
-
- /**
- * Remove processManager from the compartment
- * NOTE a bit of a work around but this prevents the pm form having to have
- * access to the compartment directly
- */
- public void removeModule(String specifier)
- {
- Idynomics.simulator.deleteFromCompartment(this._compartmentName, this);
- }
-
- /**
- *
- */
- public String defaultXmlTag()
- {
- return XmlRef.process;
- }
-
-
- public void setParent(Settable parent)
- {
- this._parentNode = parent;
- }
-
- @Override
- public Settable getParent()
- {
- return this._parentNode;
- }
+package processManager;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import org.w3c.dom.Element;
+
+import aspect.AspectInterface;
+import aspect.AspectReg;
+import compartment.AgentContainer;
+import compartment.Compartment;
+import compartment.EnvironmentContainer;
+import dataIO.Log;
+import dataIO.Log.Tier;
+import dataIO.XmlHandler;
+import generalInterfaces.Redirectable;
+import idynomics.Idynomics;
+import instantiable.Instantiable;
+import referenceLibrary.ClassRef;
+import referenceLibrary.XmlRef;
+import settable.Attribute;
+import settable.Module;
+import settable.Module.Requirements;
+import settable.Settable;
+import utility.Helper;
+
+/**
+ * \brief Abstract class for managing a process within a {@code Compartment}.
+ *
+ * @author Robert Clegg (r.j.clegg@bham.ac.uk) University of Birmingham, U.K.
+ * @author Bastiaan Cockx @BastiaanCockx (baco@env.dtu.dk), DTU, Denmark.
+ */
+public abstract class ProcessManager implements Instantiable, AspectInterface,
+ Settable, Redirectable
+{
+ /**
+ * The name of this {@code ProcessManager}, for reporting.
+ */
+ protected String _name;
+ /**
+ * In the event of a time-clash between {@code ProcessManager}s, the one
+ * with greater priority goes first.
+ */
+ protected int _priority;
+ /**
+ * The time at which this should next perform its step.
+ */
+ protected double _timeForNextStep = 0.0;
+ /**
+ * How often this should perform its step.
+ */
+ protected double _timeStepSize;
+ /**
+ * Force one internal step before simulation.
+ */
+ protected int _skips = 0;
+ /**
+ * How often this has been skipped since last run.
+ */
+ private int _skipped = 0;
+ /**
+ * The aspect registry.
+ */
+ private AspectReg _aspectRegistry = new AspectReg();
+ /**
+ * Reference to the environment of the compartment this process belongs to.
+ * Contains a reference to the compartment shape.
+ */
+ protected EnvironmentContainer _environment;
+ /**
+ * Reference to the agents of the compartment this process belongs to.
+ * Contains a reference to the compartment shape.
+ */
+ protected AgentContainer _agents;
+
+ /**
+ *
+ */
+ protected String _compartmentName;
+
+ /**
+ * Parent (owner) node, used for proper object removal via gui.
+ */
+ protected Settable _parentNode;
+
+ /**
+ * Used to track time used per process manager
+ */
+ private long _realTimeTaken = 0;
+
+ /**
+ * Used to track time used per process manager
+ */
+ private long _tick;
+
+ /* ***********************************************************************
+ * CONSTRUCTORS
+ * **********************************************************************/
+
+ /**
+ * Generic init for Instantiatable implementation
+ *
+ *
+ * NOTE this implementation is a bit 'hacky' to deal with
+ * 1) The layered structure of process managers.
+ * 2) The fact that process managers are initiated with environment, agents
+ * and compartment name, something the instantiatable interface can only
+ * Provide by supplying parent.
+ *
+ *
+ * @param xmlElem
+ * @param parent (in this case the compartment).
+ */
+ public void instantiate(Element xmlElem, Settable parent)
+ {
+ this.init(xmlElem, ((Compartment) parent).environment,
+ ((Compartment) parent).agents,((Compartment) parent).getName());
+ }
+
+ /**
+ * \brief Initialise the process from XML protocol file, plus the relevant
+ * information about the compartment it belongs to.
+ *
+ * @param xmlElem Relevant part of the XML protocol file.
+ * @param environment The {@code EnvironmentContainer} of the
+ * {@code Compartment} this process belongs to.
+ * @param agents The {@code AgentContainer} of the
+ * {@code Compartment} this process belongs to.
+ * @param compartmentName The name of the {@code Compartment} this process
+ * belongs to.
+ */
+ public void init(Element xmlElem, EnvironmentContainer environment,
+ AgentContainer agents, String compartmentName)
+ {
+ this._environment = environment;
+ this._agents = agents;
+ this._compartmentName = compartmentName;
+
+ if (xmlElem != null)
+ this.loadAspects(xmlElem);
+ /*
+ * Read in the process attributes.
+ */
+ Element p = (Element) xmlElem;
+ if (Helper.isNullOrEmpty(this._name))
+ this.setName( XmlHandler.obtainAttribute(p, XmlRef.nameAttribute,
+ this.defaultXmlTag()));
+ /* Process priority - default is zero. */
+ int priority = 0;
+ if ( XmlHandler.hasAttribute(p, XmlRef.processPriority) )
+ priority = Integer.valueOf(p.getAttribute(XmlRef.processPriority) );
+ this.setPriority(priority);
+ /* Initial time to step. */
+ double time = Idynomics.simulator.timer.getCurrentTime();
+ if ( XmlHandler.hasAttribute(p, XmlRef.processFirstStep) )
+ time = Double.valueOf(p.getAttribute(XmlRef.processFirstStep) );
+ this.setTimeForNextStep(time);
+ /* Time step size. */
+ time = Idynomics.simulator.timer.getTimeStepSize();
+ if ( XmlHandler.hasAttribute(p, XmlRef.processTimeStepSize) )
+ time = Double.valueOf( p.getAttribute(XmlRef.processTimeStepSize));
+ this.setTimeStepSize(time);
+ if ( XmlHandler.hasAttribute(p, XmlRef.processSkips ))
+ {
+ this._skips = Integer.valueOf( p.getAttribute(XmlRef.processSkips));
+ }
+ this.redirect(xmlElem);
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ Log.out(Tier.EXPRESSIVE, this._name + " loaded");
+ }
+
+ /* ***********************************************************************
+ * BASIC SETTERS & GETTERS
+ * ***********************************************************************/
+
+ /**
+ * \brief Return the aspect registry (implementation of aspect interface).
+ */
+ public AspectReg reg()
+ {
+ return _aspectRegistry;
+ }
+
+ /**
+ * \brief Get this {@code ProcessManager}'s name.
+ *
+ * @return {@code String} name.
+ */
+ public String getName()
+ {
+ if (this._name == null)
+ return "";
+ else
+ return this._name;
+ }
+
+ /**
+ * \brief Set this {@code ProcessManager}'s name.
+ *
+ * @param {@code String} name.
+ */
+ public void setName(String name)
+ {
+ this._name = name;
+ }
+
+ /**
+ * \brief Set the priority of this {@code ProcessManager}.
+ *
+ *
A higher priority {@code ProcessManager} goes first if two have a
+ * time clash in the {@code Compartment} they belong to.
+ *
+ * @param priority Any integer value.
+ */
+ public void setPriority(int priority)
+ {
+ this._priority = priority;
+ }
+
+ /**
+ * @return The priority of this {@code ProcessManager}.
+ */
+ public int getPriority()
+ {
+ return this._priority;
+ }
+
+ /**]
+ * \brief Set the time point at which this will next step: useful for
+ * testing.
+ *
+ * @param newTime The time point at which this should next step.
+ */
+ public void setTimeForNextStep(double newTime)
+ {
+ this._timeForNextStep = newTime;
+ }
+
+ /**
+ * @return The time point at which this will next step.
+ */
+ public double getTimeForNextStep()
+ {
+ return this._timeForNextStep;
+ }
+
+ /**
+ * \brief Set the time step directly: useful for testing.
+ *
+ * @param newStepSize Time step to use.
+ */
+ public void setTimeStepSize(double newStepSize)
+ {
+ this._timeStepSize = newStepSize;
+ }
+
+ /**
+ * @return The local time step.
+ */
+ public double getTimeStepSize()
+ {
+ return this._timeStepSize;
+ }
+
+ /* ***********************************************************************
+ * STEPPING
+ * **********************************************************************/
+
+ /**
+ * \brief Perform the step of this process manager, also updating its local
+ * time manager.
+ *
+ * @param environment The {@code EnvironmentContainer} of the
+ * {@code Compartment} this process belongs to.
+ * @param agents The {@code AgentContainer} of the
+ * {@code Compartment} this process belongs to.
+ */
+ public void step()
+ {
+ double now = this._timeForNextStep;
+ /* Move the time for next step forward by the step size. */
+ this._timeForNextStep = BigDecimal.valueOf( _timeForNextStep ).add(
+ BigDecimal.valueOf( _timeStepSize ) ).doubleValue();
+
+ if ( this._skips > ++this._skipped )
+ {
+ /* skip */
+ }
+ else
+ {
+ this._tick = System.currentTimeMillis();
+ /*This is where subclasses of ProcessManager do their step. Note
+ * that this._timeStepSize may change if an adaptive timestep is
+ * used. */
+ this.internalStep();
+ if ( !Idynomics.simulator.active())
+ return;
+
+ Tier level = Tier.EXPRESSIVE;
+ if ( Log.shouldWrite(level) )
+ {
+ /* logging time, using BigDecimal prevents weird last decimal
+ * round-off errors. */
+ Log.out( level, this._name + ": " + now + " -> " +
+ this._timeForNextStep + " (" + ( BigDecimal.valueOf(
+ System.currentTimeMillis() - _tick ).multiply(
+ BigDecimal.valueOf( 0.001 ) ).doubleValue() ) + "s)");
+ }
+ this._realTimeTaken += (System.currentTimeMillis() - _tick);
+ this._skipped = 0;
+ }
+ }
+
+ /**
+ * \brief Perform the internal step for this process manager: this will be
+ * implemented by each sub-class of {@code ProcessManager}.
+ */
+ protected abstract void internalStep();
+
+ /* ***********************************************************************
+ * REPORTING
+ * **********************************************************************/
+
+ public long getRealTimeTaken()
+ {
+ return this._realTimeTaken;
+ }
+
+ /* ***********************************************************************
+ * NODE CONSTRUCTION
+ * **********************************************************************/
+
+ /**
+ * \brief returns all known (ClassRef) process managers
+ * @return all known (ClassRef) process managers
+ */
+ public static List getAllOptions()
+ {
+ return ClassRef.getAllOptions("processManager.library");
+ }
+
+ /**
+ * Obtain module for xml output and gui representation.
+ */
+ public Module getModule()
+ {
+ Module modelNode = new Module(defaultXmlTag(), this);
+ modelNode.setRequirements(Requirements.ZERO_TO_MANY);
+ modelNode.setTitle(this._name);
+
+ modelNode.add(new Attribute(XmlRef.nameAttribute,
+ this._name, null, true ));
+
+ if ( Idynomics.xmlPackageLibrary.has( this.getClass().getSimpleName() ))
+ modelNode.add(new Attribute(XmlRef.classAttribute,
+ this.getClass().getSimpleName(), null, false ));
+ else
+ modelNode.add(new Attribute(XmlRef.classAttribute,
+ this.getClass().getName(), null, false ));
+
+ modelNode.add(new Attribute(XmlRef.processPriority,
+ String.valueOf(this._priority), null, true ));
+
+ modelNode.add(new Attribute(XmlRef.processTimeStepSize,
+ String.valueOf(this._timeStepSize), null, true ));
+
+ modelNode.add(new Attribute(XmlRef.processFirstStep,
+ String.valueOf(this._timeForNextStep), null, true ));
+
+ for ( String key : this.reg().getLocalAspectNames() )
+ modelNode.add(reg().getAspectNode(key));
+
+ modelNode.addChildSpec( ClassRef.aspect,
+ Module.Requirements.ZERO_TO_MANY);
+
+ return modelNode;
+ }
+
+
+ /**
+ * Set value's that (may) have been changed trough the gui.
+ */
+ public void setModule(Module node)
+ {
+ /* Set the name */
+ this._name = node.getAttribute( XmlRef.nameAttribute ).getValue();
+
+ /* Set the priority */
+ this._priority = Integer.valueOf( node.getAttribute(
+ XmlRef.processPriority ).getValue() );
+
+ /* Set the timestep */
+ this._timeStepSize = Double.valueOf( node.getAttribute(
+ XmlRef.processTimeStepSize ).getValue() );
+
+ /* Set the time for the first step from now */
+ this._timeForNextStep = Double.valueOf( node.getAttribute(
+ XmlRef.processFirstStep ).getValue() );
+
+ /* Set any potential child modules */
+ Settable.super.setModule(node);
+ }
+
+ /**
+ * Remove processManager from the compartment
+ * NOTE a bit of a work around but this prevents the pm form having to have
+ * access to the compartment directly
+ */
+ public void removeModule(String specifier)
+ {
+ Idynomics.simulator.deleteFromCompartment(this._compartmentName, this);
+ }
+
+ /**
+ *
+ */
+ public String defaultXmlTag()
+ {
+ return XmlRef.process;
+ }
+
+
+ public void setParent(Settable parent)
+ {
+ this._parentNode = parent;
+ }
+
+ @Override
+ public Settable getParent()
+ {
+ return this._parentNode;
+ }
}
\ No newline at end of file
diff --git a/src/processManager/library/GraphicalOutput.java b/src/processManager/library/GraphicalOutput.java
index 072977d21..06b0a37e4 100644
--- a/src/processManager/library/GraphicalOutput.java
+++ b/src/processManager/library/GraphicalOutput.java
@@ -128,7 +128,6 @@ public void init(Element xmlElem, EnvironmentContainer environment,
str = Helper.obtainIfNone( this.getString(OUTPUT_WRITER),
"output writer", true, this.options() );
this._graphics = (GraphicalExporter) Instance.getNew(null, null, str);
-
/* write scene files (used by pov ray) */
this._graphics.init( this._prefix, this._shape );
@@ -152,6 +151,8 @@ private Collection options()
@Override
protected void internalStep()
{
+ if ( this.getInt(AspectRef.fileNumber) != null )
+ this._graphics.setFileNumber(this.getInt(AspectRef.fileNumber));
/* Initiate new file. */
this._graphics.createFile(this._prefix);
diff --git a/src/referenceLibrary/AspectRef.java b/src/referenceLibrary/AspectRef.java
index cfedadf5e..14123bd09 100644
--- a/src/referenceLibrary/AspectRef.java
+++ b/src/referenceLibrary/AspectRef.java
@@ -580,4 +580,6 @@ public static String[] getAllOptions()
public static final String decompressionCellLength = "decompressionCellLength";
public static final String decompressionThreshold = "decompressionThreshold";
+
+ public static final String fileNumber = "fileNumber";
}
From 3799597b7e84942ca1d4eeec4b7302a098f5970f Mon Sep 17 00:00:00 2001
From: baseendje
Date: Mon, 15 Jun 2020 13:48:30 +0200
Subject: [PATCH 04/67] test processing script
---
postprocessing/test.xml | 8 ++++++++
1 file changed, 8 insertions(+)
create mode 100644 postprocessing/test.xml
diff --git a/postprocessing/test.xml b/postprocessing/test.xml
new file mode 100644
index 000000000..51577a8e8
--- /dev/null
+++ b/postprocessing/test.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
\ No newline at end of file
From 5ccce7278cb9c4168ba8b2e8fe0f9e66b720bf4b Mon Sep 17 00:00:00 2001
From: baseendje
Date: Mon, 15 Jun 2020 16:38:01 +0200
Subject: [PATCH 05/67] implementing file conversion, looking for bug
---
src/dataIO/XmlExport.java | 21 ++++++++-
src/gui/GuiActions.java | 82 ++++++++++++++++++++++++++++++++++++
src/gui/GuiMenu.java | 54 ++++++++++++++++++++++++
src/idynomics/Simulator.java | 6 +++
4 files changed, 162 insertions(+), 1 deletion(-)
diff --git a/src/dataIO/XmlExport.java b/src/dataIO/XmlExport.java
index d782f8f70..cb527d7c4 100644
--- a/src/dataIO/XmlExport.java
+++ b/src/dataIO/XmlExport.java
@@ -87,7 +87,19 @@ public void newXml(String prefix)
this._xmlFile.write(XML_HEADER);
}
-
+ public void newXml(String filePath, boolean absolutePath)
+ {
+ String fileString;
+ if( this._exiEncoding )
+ this._xmlFile.bufferOutput();
+ if( absolutePath )
+ fileString = filePath + (this._exiEncoding ? ".exi" : ".xml");
+ else
+ fileString = Idynomics.global.outputLocation + filePath +
+ (this._exiEncoding ? ".exi" : ".xml");
+ this._xmlFile.fnew(fileString);
+ this._xmlFile.write(XML_HEADER);
+ }
/**
* Close the XML file and increment the file number counter for the next
@@ -118,4 +130,11 @@ public void writeFile()
this.writeState();
this.closeXml();
}
+
+ public void writeFile(String file)
+ {
+ this.newXml(file, true);
+ this.writeState();
+ this.closeXml();
+ }
}
diff --git a/src/gui/GuiActions.java b/src/gui/GuiActions.java
index f3ee2cc99..301f082a7 100644
--- a/src/gui/GuiActions.java
+++ b/src/gui/GuiActions.java
@@ -61,6 +61,29 @@ public static void chooseFile()
openFile(f);
}
+ public static File saveFile()
+ {
+ boolean confirm = true;
+
+ JFileChooser chooser = new JFileChooser("" +
+ System.getProperty("user.dir"));
+ File file = new File(System.getProperty("user.dir")+ "/filename");
+ chooser.setFileSelectionMode(JFileChooser.SAVE_DIALOG);
+ chooser.setCurrentDirectory(file);
+ // TODO Allow the user to select multiple files.
+ chooser.setMultiSelectionEnabled(false);
+ File f = null;
+ if ( chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION )
+ f = chooser.getSelectedFile();
+ if( f.exists() )
+ confirm = Helper.confirmation("Would you like to overwrite: " +
+ f.getName());
+ if( confirm )
+ return f;
+ else
+ return null;
+ }
+
public static File chooseFile(String relPath, String description)
{
/* Open a FileChooser window in the current directory. */
@@ -225,6 +248,65 @@ public static void downloadFile(String url)
openFile(in);
}
+ public static void saveToFile(File f)
+ {
+ if ( f == null )
+ {
+ GuiConsole.writeOut("Saving canceled.\n");
+ }
+ else
+ {
+ Idynomics.simulator.saveSimulationState(f.getAbsolutePath(),
+ Helper.confirmation("Would you like to compress to exi format?"));
+ }
+ }
+
+ public static void convertFiles()
+ {
+ File[] files = chooseFilesAndFolders(
+ "Select simulation state files (.exi or .xml)" );
+ List finalFiles = null;
+ if( FolderOperations.includesfolders(files))
+ {
+ if( Helper.obtainInput(
+ "Would you like to include sub-folders?", false) )
+ /* note do look into the first line of folders */
+ finalFiles = FolderOperations.getFiles(true, files);
+ else
+ finalFiles = FolderOperations.getFiles(files);
+ }
+ else
+ {
+ finalFiles = FolderOperations.getFiles(true, files);
+ }
+ if( Helper.obtainInput( "Would you like to continue processing " +
+ finalFiles.size() + " files?", false) )
+ {
+ for( File f : files )
+ {
+ boolean exi = false;
+ String out = null;
+ String path = f.getAbsolutePath();
+ if( path.toLowerCase().contains(".xml"))
+ {
+ exi = true;
+ out = path.toLowerCase().replaceAll(".xml", ".exi");
+ } else if( path.toLowerCase().contains(".exi"))
+ {
+ exi = false;
+ out = path.toLowerCase().replaceAll(".exi", ".xml");
+ }
+ Idynomics.setupSimulator( f.getAbsolutePath() );
+ Idynomics.simulator.saveSimulationState(out, exi);
+ Idynomics.simulator = new Simulator();
+ }
+ }
+ else
+ {
+ Log.out("post-processing cancelled by user");
+ }
+ }
+
public static void checkProtocol()
{
if ( Idynomics.global.protocolFile == null )
diff --git a/src/gui/GuiMenu.java b/src/gui/GuiMenu.java
index 6ba2c1b04..1ff4f4de0 100644
--- a/src/gui/GuiMenu.java
+++ b/src/gui/GuiMenu.java
@@ -80,6 +80,19 @@ private static JMenu fileMenu()
"Download protocol file");
menu.add(menuItem);
+
+ menuItem = new JMenuItem(new GuiMenu.FileSave());
+ menuItem.setAccelerator(KeyStroke.getKeyStroke(
+ KeyEvent.VK_S, ActionEvent.CTRL_MASK));
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Save protocol file");
+ menu.add(menuItem);
+
+ menuItem = new JMenuItem(new GuiMenu.ConvertFiles());
+ menuItem.getAccessibleContext().setAccessibleDescription(
+ "Batch convert files");
+ menu.add(menuItem);
+
/*
* Add the option of rendering a compartment.
*/
@@ -227,6 +240,7 @@ public void actionPerformed(ActionEvent e)
}
}
+
public static class FileOpen extends AbstractAction
{
private static final long serialVersionUID = 2247122248926681550L;
@@ -259,10 +273,50 @@ public FileDownload()
public void actionPerformed(ActionEvent e)
{
+ GuiActions.chooseFile();
GuiActions.downloadFile(null);
}
}
+ public static class FileSave extends AbstractAction
+ {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Action for the file open sub-menu.
+ */
+ public FileSave()
+ {
+ super("Save");
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ GuiActions.saveToFile( GuiActions.saveFile() );
+ }
+ }
+
+ public static class ConvertFiles extends AbstractAction
+ {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Action for the file open sub-menu.
+ */
+ public ConvertFiles()
+ {
+ super("Convert Files");
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ GuiActions.convertFiles();
+ }
+ }
+
+
public static class RenderThis extends AbstractAction
{
private static final long serialVersionUID = 974971035938028563L;
diff --git a/src/idynomics/Simulator.java b/src/idynomics/Simulator.java
index 3207dc842..c5f25d6ca 100644
--- a/src/idynomics/Simulator.java
+++ b/src/idynomics/Simulator.java
@@ -626,6 +626,12 @@ public String getXml()
{
return this._modelNode.getXML();
}
+
+ public void saveSimulationState(String path, boolean exi)
+ {
+ XmlExport xmlOut = new XmlExport(exi);
+ xmlOut.writeFile(path);
+ }
@Override
public void setParent(Settable parent)
From b464b70f186d0c5fe88be645e1bf6cbc1af23edc Mon Sep 17 00:00:00 2001
From: baseendje
Date: Mon, 15 Jun 2020 16:48:13 +0200
Subject: [PATCH 06/67] Solve issue that would result in crash after the
removal of whitespace
---
src/linearAlgebra/Array.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/linearAlgebra/Array.java b/src/linearAlgebra/Array.java
index da04b6bca..54c70451c 100644
--- a/src/linearAlgebra/Array.java
+++ b/src/linearAlgebra/Array.java
@@ -33,7 +33,7 @@ public final class Array
*/
// NOTE arrayString.split(DELIMITER) does not work when we use "|" here!
// This can change, but check it works with testJUnit.LinearAlgebraTest
- public final static String DELIMITER = "% \n";
+ public final static String DELIMITER = "%";
/*************************************************************************
* STANDARD NEW ARRAYS
From 5a7fa3171c5aa6971662fe55cdc3d8ac19e0c7ff Mon Sep 17 00:00:00 2001
From: baseendje
Date: Mon, 15 Jun 2020 17:10:03 +0200
Subject: [PATCH 07/67] Implemented basic file conversion xml exi
---
src/gui/GuiActions.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/gui/GuiActions.java b/src/gui/GuiActions.java
index 301f082a7..573723241 100644
--- a/src/gui/GuiActions.java
+++ b/src/gui/GuiActions.java
@@ -282,7 +282,7 @@ public static void convertFiles()
if( Helper.obtainInput( "Would you like to continue processing " +
finalFiles.size() + " files?", false) )
{
- for( File f : files )
+ for( File f : finalFiles )
{
boolean exi = false;
String out = null;
@@ -290,11 +290,11 @@ public static void convertFiles()
if( path.toLowerCase().contains(".xml"))
{
exi = true;
- out = path.toLowerCase().replaceAll(".xml", ".exi");
+ out = path.toLowerCase().replaceAll(".xml", "");
} else if( path.toLowerCase().contains(".exi"))
{
exi = false;
- out = path.toLowerCase().replaceAll(".exi", ".xml");
+ out = path.toLowerCase().replaceAll(".exi", "");
}
Idynomics.setupSimulator( f.getAbsolutePath() );
Idynomics.simulator.saveSimulationState(out, exi);
From 95f23d0240c7003f3effd2edc2c3e7d3d909018e Mon Sep 17 00:00:00 2001
From: Bastiaan
Date: Thu, 26 Nov 2020 13:49:58 +0100
Subject: [PATCH 08/67] check-out fresh branch for todos
---
src/agent/Body.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/agent/Body.java b/src/agent/Body.java
index 198f15907..2c86e4b45 100644
--- a/src/agent/Body.java
+++ b/src/agent/Body.java
@@ -353,7 +353,6 @@ public void instantiate(Element xmlElem, Settable parent)
constructBody();
}
-
}
/*************************************************************************
From 251585ae4ea678ef0933ed91ee412dd4d1e5b649 Mon Sep 17 00:00:00 2001
From: Bastiaan
Date: Thu, 26 Nov 2020 14:46:18 +0100
Subject: [PATCH 09/67] getter for HSB and RGB spec of color
---
protocol/ecoli tests/ecoli2D.xml | 4 +--
protocol/unit-tests/reaction_diffusion.xml | 1 -
src/colour/Colour.java | 42 ++++++++++++++++------
src/colour/ColourSpecification.java | 8 ++---
src/compartment/Compartment.java | 8 ++---
5 files changed, 39 insertions(+), 24 deletions(-)
diff --git a/protocol/ecoli tests/ecoli2D.xml b/protocol/ecoli tests/ecoli2D.xml
index 243629b65..92d1c1dfd 100644
--- a/protocol/ecoli tests/ecoli2D.xml
+++ b/protocol/ecoli tests/ecoli2D.xml
@@ -153,14 +153,14 @@
+ firstStep="0.0" >
+ firstStep="0.0" >
diff --git a/protocol/unit-tests/reaction_diffusion.xml b/protocol/unit-tests/reaction_diffusion.xml
index 7373ea81a..390ff86bd 100644
--- a/protocol/unit-tests/reaction_diffusion.xml
+++ b/protocol/unit-tests/reaction_diffusion.xml
@@ -37,7 +37,6 @@
-
diff --git a/src/colour/Colour.java b/src/colour/Colour.java
index 00a3ef4d3..eb1fb3eaf 100644
--- a/src/colour/Colour.java
+++ b/src/colour/Colour.java
@@ -1,5 +1,6 @@
package colour;
+import java.awt.Color;
import java.util.LinkedList;
import java.util.List;
@@ -13,6 +14,8 @@ public enum Format
RGB;
}
+ private Color jColor;
+
public final float[] zeros = new float[3];
private Format format;
@@ -33,12 +36,20 @@ public enum Format
public Colour(float[] baseColour, String format, String name)
{
- this.initialColour = baseColour;
- this.format = Format.valueOf(format);
+ this.format = Format.valueOf( format );
+ if( Format.HSB.equals( this.format ))
+ this.initialColour = baseColour;
+ else
+ {
+ this.initialColour = Color.RGBtoHSB(
+ Math.round( baseColour[0]*255 ),
+ Math.round( baseColour[1]*255 ),
+ Math.round( baseColour[2]*255 ), null);
+ }
this.name = name;
}
- public void addGradient(float[] gradient)
+ public void addGradient( float[] gradient )
{
if( gradients.size() >= 3)
{
@@ -48,13 +59,13 @@ public void addGradient(float[] gradient)
this.gradients.add( gradient );
}
- public void addGradient(String first, String second, String third)
+ public void addGradient( String first, String second, String third )
{
float[] out = new float[3];
if( first == null )
out[0] = 0.0f;
else
- out[0] = Float.valueOf(first);
+ out[0] = Float.valueOf( first );
if( second == null )
out[1] = 0.0f;
else
@@ -72,7 +83,7 @@ public void addGradient(String first, String second, String third)
* @param opacity - given opacity
* @return
*/
- public float[] returnColour(float[] dial, float opacity)
+ public float[] returnColourHSB(float[] dial, float opacity)
{
this.opacity = opacity;
float[] HSBOOut = {0.0f, 0.0f, 0.0f, this.opacity};
@@ -86,10 +97,9 @@ public float[] returnColour(float[] dial, float opacity)
public float line(int gradient, int field)
{
- float[] grad = (this.gradients.size() > gradient ?
- this.gradients.get( gradient ) :
- zeros );
- return dial[gradient]*(grad[field]-initialColour[field]);
+ float[] grad = ( this.gradients.size() > gradient ?
+ this.gradients.get( gradient ) : zeros );
+ return dial[gradient] * ( grad[field] - initialColour[field] );
}
/**
@@ -101,7 +111,7 @@ public float line(int gradient, int field)
* object, which is 1.0 at setup unless defined in the palette).
* @return
*/
- public float[] returnColour(float[] dial)
+ public float[] returnColourHSB(float[] dial)
{
float[] HSBOOut = {0.0f, 0.0f, 0.0f};
for (int i = 0; i < 3; i++)
@@ -111,6 +121,16 @@ public float[] returnColour(float[] dial)
}
return HSBOOut;
}
+
+ public float[] returnColourRGB(float[] dial)
+ {
+ float[] hsb = returnColourHSB(dial);
+ jColor = new Color(Color.HSBtoRGB( hsb[0], hsb[1], hsb[2] ));
+ return new float[] {
+ jColor.getRed() / 255,
+ jColor.getGreen() / 255,
+ jColor.getBlue() / 255 };
+ }
public void setOpacity(Float opacity)
{
diff --git a/src/colour/ColourSpecification.java b/src/colour/ColourSpecification.java
index f0718f333..d5a8b0b43 100644
--- a/src/colour/ColourSpecification.java
+++ b/src/colour/ColourSpecification.java
@@ -26,9 +26,9 @@ public ColourSpecification(Palette palette, String filter)
public float[] colorize(AspectInterface subject)
{
/* placeholder code before merge */
- String factor = subject.getString(filter);
- if( !factors.containsKey(factor) )
- this.factors.put(factor, palette.getNext());
- return this.factors.get(factor).returnColour(new float[3]);
+ String factor = subject.getString( filter );
+ if( !factors.containsKey( factor ) )
+ this.factors.put( factor, palette.getNext() );
+ return this.factors.get( factor ).returnColourRGB( new float[3] );
}
}
diff --git a/src/compartment/Compartment.java b/src/compartment/Compartment.java
index 0593ab718..ce9d014d4 100644
--- a/src/compartment/Compartment.java
+++ b/src/compartment/Compartment.java
@@ -528,10 +528,6 @@ public void preStep()
this.agents.agentsArrive();
this.agents.sortLocatedAgents();
- /*
- * Ask all boundaries to update their solute concentrations.
- */
- this.environment.updateSoluteBoundaries();
}
/**
@@ -640,7 +636,8 @@ public Map getRealTimeStats()
for ( ProcessManager pm : this._processes )
{
if (out.containsKey(pm.getName()))
- out.put(pm.getName(), out.get(pm.getName()) + pm.getRealTimeTaken());
+ out.put(pm.getName(), out.get(pm.getName()) +
+ pm.getRealTimeTaken());
else
out.put(pm.getName(), pm.getRealTimeTaken());
}
@@ -823,4 +820,3 @@ public int compareTo(Compartment o)
return this.name.compareTo(o.name);
}
}
->>>>>>> Process
From 749f7196e1d8770e1f44aef832628bcd6852a9cd Mon Sep 17 00:00:00 2001
From: Bastiaan
Date: Thu, 26 Nov 2020 14:50:42 +0100
Subject: [PATCH 10/67] fixed issue with loading in un-numbered agents
---
src/agent/Agent.java | 5 ++++-
src/compartment/Compartment.java | 1 -
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/agent/Agent.java b/src/agent/Agent.java
index 50d8338cd..730ab52e4 100644
--- a/src/agent/Agent.java
+++ b/src/agent/Agent.java
@@ -113,7 +113,10 @@ public void init(Node xmlNode, Compartment comp)
{
String in = XmlHandler.gatherAttribute(xmlNode,
XmlRef.identity);
- this.number(Integer.valueOf(in));
+ if( in == null)
+ this.number(null);
+ else
+ this.number(Integer.valueOf(in));
// Place located agents
loadAspects(xmlNode);
}
diff --git a/src/compartment/Compartment.java b/src/compartment/Compartment.java
index ce9d014d4..608788563 100644
--- a/src/compartment/Compartment.java
+++ b/src/compartment/Compartment.java
@@ -26,7 +26,6 @@
import idynomics.Idynomics;
import instantiable.Instance;
import instantiable.Instantiable;
-import instantiable.object.InstantiableList;
import linearAlgebra.Orientation;
import linearAlgebra.Vector;
import physicalObject.PhysicalObject;
From 2d1c06815f9870d5fbb04bb7bd9ed79ffea45359 Mon Sep 17 00:00:00 2001
From: Bastiaan
Date: Thu, 26 Nov 2020 18:12:20 +0100
Subject: [PATCH 11/67] colour palette in Render classes, fixed issue with
rounding HSB hue
---
colourPalettes/Colours.xml | 6 +-
src/agent/Agent.java | 4 +-
src/colour/Colour.java | 6 +-
src/colour/ColourSpecification.java | 5 +
src/colour/Palette.java | 13 +-
src/gui/GuiActions.java | 11 +-
src/gui/GuiMenu.java | 1 -
src/idynomics/Global.java | 6 +
.../library/GraphicalOutput.java | 7 +-
src/referenceLibrary/AspectRef.java | 2 +
src/render/AgentMediator.java | 115 ++++++++++++------
src/render/Render.java | 45 +++++++
12 files changed, 165 insertions(+), 56 deletions(-)
diff --git a/colourPalettes/Colours.xml b/colourPalettes/Colours.xml
index de5a1529b..2881cec29 100644
--- a/colourPalettes/Colours.xml
+++ b/colourPalettes/Colours.xml
@@ -1,14 +1,14 @@
-
-
-
diff --git a/src/agent/Agent.java b/src/agent/Agent.java
index 730ab52e4..7a5cd5783 100644
--- a/src/agent/Agent.java
+++ b/src/agent/Agent.java
@@ -89,7 +89,8 @@ public void init(Node xmlNode, Compartment comp)
// Spawn random agents
for(int i = 0; i < temp.getLength(); i++)
{
- /* TODO this is a cheat, make a standard method for this */
+ /* NOTE this remains here for older protocols, for newer ones we
+ * should use the spawner classes. */
int n = Integer.valueOf(XmlHandler.obtainAttribute(
temp.item(i), XmlRef.numberOfAgents,
this.defaultXmlTag() ) );
@@ -125,7 +126,6 @@ public void init(Node xmlNode, Compartment comp)
private void number(Integer in)
{
-
if(in != null)
{
if ( UNIQUE_ID <= in )
diff --git a/src/colour/Colour.java b/src/colour/Colour.java
index eb1fb3eaf..73d1ea74c 100644
--- a/src/colour/Colour.java
+++ b/src/colour/Colour.java
@@ -127,9 +127,9 @@ public float[] returnColourRGB(float[] dial)
float[] hsb = returnColourHSB(dial);
jColor = new Color(Color.HSBtoRGB( hsb[0], hsb[1], hsb[2] ));
return new float[] {
- jColor.getRed() / 255,
- jColor.getGreen() / 255,
- jColor.getBlue() / 255 };
+ jColor.getRed() / 255.0f,
+ jColor.getGreen() / 255.0f,
+ jColor.getBlue() / 255.0f };
}
public void setOpacity(Float opacity)
diff --git a/src/colour/ColourSpecification.java b/src/colour/ColourSpecification.java
index d5a8b0b43..b215552c1 100644
--- a/src/colour/ColourSpecification.java
+++ b/src/colour/ColourSpecification.java
@@ -31,4 +31,9 @@ public float[] colorize(AspectInterface subject)
this.factors.put( factor, palette.getNext() );
return this.factors.get( factor ).returnColourRGB( new float[3] );
}
+
+ public String toString()
+ {
+ return this.filter;
+ }
}
diff --git a/src/colour/Palette.java b/src/colour/Palette.java
index 7388227ad..718dbd447 100644
--- a/src/colour/Palette.java
+++ b/src/colour/Palette.java
@@ -7,6 +7,7 @@
import org.w3c.dom.Element;
import dataIO.Log;
+import dataIO.Log.Tier;
import dataIO.XmlHandler;
import linearAlgebra.Vector;
@@ -84,13 +85,21 @@ public Palette(String paletteName)
c.getAttribute( Property.OPACITY.tag ) ) );
}
}
- Log.out( "Loaded " + this.unAssigned.size() + " colours from palette.");
+ Log.out(Tier.EXPRESSIVE, "Loaded " + this.unAssigned.size() +
+ " colours from palette.");
+ }
+
+ public void reset()
+ {
+ this.unAssigned.clear();
+ for( String n : colours.keySet() )
+ this.unAssigned.add(n);
}
public Colour getNext()
{
String out = unAssigned.getFirst();
- unAssigned.remove(out);
+ unAssigned.remove( out );
return colours.get( out );
}
}
diff --git a/src/gui/GuiActions.java b/src/gui/GuiActions.java
index d7bfcb2ad..dd0454e5b 100644
--- a/src/gui/GuiActions.java
+++ b/src/gui/GuiActions.java
@@ -20,6 +20,7 @@
import dataIO.FileHandler;
import dataIO.FolderOperations;
import dataIO.Log;
+import dataIO.Log.Tier;
import idynomics.Global;
import idynomics.Idynomics;
import idynomics.PostProcess;
@@ -225,7 +226,7 @@ public static void downloadFile(String url)
try {
urly = new URL(url);
} catch ( MalformedURLException e) {
- e.printStackTrace();
+ Log.out(Tier.NORMAL, "unable to aquire protocol from url: " + url);
}
@@ -241,11 +242,11 @@ public static void downloadFile(String url)
webIS.close();
handler.fclose();
Log.out("finished Download");
- } catch (IOException e) {
- e.printStackTrace();
+ File in = new File(local);
+ openFile(in);
+ } catch (IOException | NullPointerException e) {
+ Log.out(Tier.NORMAL, "File download failed");
}
- File in = new File(local);
- openFile(in);
}
public static void saveToFile(File f)
diff --git a/src/gui/GuiMenu.java b/src/gui/GuiMenu.java
index 1ff4f4de0..aee641248 100644
--- a/src/gui/GuiMenu.java
+++ b/src/gui/GuiMenu.java
@@ -273,7 +273,6 @@ public FileDownload()
public void actionPerformed(ActionEvent e)
{
- GuiActions.chooseFile();
GuiActions.downloadFile(null);
}
}
diff --git a/src/idynomics/Global.java b/src/idynomics/Global.java
index cb01640cb..f6b0c5368 100644
--- a/src/idynomics/Global.java
+++ b/src/idynomics/Global.java
@@ -166,6 +166,12 @@ public void updateSettings()
*/
public static boolean csv_bookkeeping = false;
+ /**
+ * the default color specification for graphical output, NOTE in the future
+ * we probably want to set this to "species"
+ */
+ public static String default_colour_specification = "pigment";
+
/**
* enable xml bookkeeping (also logging complete agent xml)
* Warning: very slow
diff --git a/src/processManager/library/GraphicalOutput.java b/src/processManager/library/GraphicalOutput.java
index 91d9b0c61..45d70afeb 100644
--- a/src/processManager/library/GraphicalOutput.java
+++ b/src/processManager/library/GraphicalOutput.java
@@ -145,8 +145,11 @@ public void init(Element xmlElem, EnvironmentContainer environment,
this.palette = new Palette( String.valueOf(
this.getOr( AspectRef.colourPalette, Global.default_palette) ) );
- /* placeholder spec */
- colSpec = new ColourSpecification(palette, "species");
+
+ /* In the future we may want to change the default to "species" */
+ colSpec = new ColourSpecification(palette, (String)
+ this.getOr( AspectRef.colourSpecification,
+ Global.default_colour_specification));
}
diff --git a/src/referenceLibrary/AspectRef.java b/src/referenceLibrary/AspectRef.java
index 1888ccc96..15c1ace20 100644
--- a/src/referenceLibrary/AspectRef.java
+++ b/src/referenceLibrary/AspectRef.java
@@ -620,4 +620,6 @@ public static String[] getAllOptions()
public static final String linearFunction = "linearFunction";
public static final String fileNumber = "fileNumber";
+
+ public static final String colourSpecification = "colourSpecification";
}
diff --git a/src/render/AgentMediator.java b/src/render/AgentMediator.java
index 11db8dba8..586cc74c2 100644
--- a/src/render/AgentMediator.java
+++ b/src/render/AgentMediator.java
@@ -14,10 +14,13 @@
import com.jogamp.opengl.util.gl2.GLUT;
import agent.Agent;
+import colour.ColourSpecification;
+import colour.Palette;
import compartment.AgentContainer;
import compartment.Compartment;
import grid.ArrayType;
import grid.SpatialGrid;
+import idynomics.Global;
import linearAlgebra.Vector;
import referenceLibrary.AspectRef;
import shape.CartesianShape;
@@ -137,6 +140,10 @@ public class AgentMediator implements CommandMediator {
private int j;
+ private Palette palette;
+
+ private ColourSpecification colSpec;
+
/**
* used to set up the open gl camera
*/
@@ -145,6 +152,29 @@ public float kickback() {
return _kickback;
}
+ public String currentColourSpecification()
+ {
+ return this.colSpec.toString();
+ }
+
+ public void setColourSpecification(String filter)
+ {
+ this.colSpec = new ColourSpecification(palette, filter);
+ }
+
+
+ public void setPalette(String palette)
+ {
+ this.palette = new Palette( palette );
+ this.colSpec = new ColourSpecification( this.palette,
+ currentColourSpecification() );
+ }
+
+ public void resetPalette()
+ {
+ palette.reset();
+ }
+
public double[] orientation()
{
if (this._shape instanceof CartesianShape)
@@ -178,6 +208,13 @@ public AgentMediator(Compartment c)
if( solutes.size() > 2 )
soluteColors.put("Blue", (String)solutes.toArray()[2]);
+ this.palette = new Palette( String.valueOf( Global.default_palette ));
+
+ /* In the future we may want to change the default to "species" */
+ this.colSpec = new ColourSpecification( palette,
+ Global.default_colour_specification );
+
+
this._compartment = c;
/* keep dimensions that are not significant at 0 */
@@ -240,44 +277,45 @@ public void draw(GLAutoDrawable drawable) {
AspectRef.surfaceList) ? a.get(AspectRef.surfaceList) :
new LinkedList()))
{
- _pigment = a.getValue("pigment");
- _pigment = Helper.setIfNone(_pigment, "WHITE");
- if (!(_pigment instanceof String))
- {
- double[] _pigmentDouble = (double[]) _pigment;
- for (int i = 0; i < _pigmentDouble.length; i++)
- {
- _rgba[i] = (float) _pigmentDouble[i];
- }
- }
- else
- {
- switch ((String) _pigment)
- {
- case "GREEN" :
- _rgba = new float[] {0.0f, 1.0f, 0.0f};
- break;
- case "RED" :
- _rgba = new float[] {1.0f, 0.0f, 0.0f};
- break;
- case "BLUE" :
- _rgba = new float[] {0.01f, 0.0f, 1.0f};
- break;
- case "PURPLE" :
- _rgba = new float[] {1.0f, 0.0f, 1.0f};
- break;
- case "ORANGE" :
- _rgba = new float[] {1.0f, 0.6f, 0.1f};
- break;
- case "BLACK" :
- _rgba = new float[] {0.0f, 0.0f, 0.0f};
- break;
- case "WHITE" :
- default :
- _rgba = new float[] {1.0f, 1.0f, 1.0f};
- break;
- }
- }
+ _rgba = colSpec.colorize(a);
+// _pigment = a.getValue("pigment");
+// _pigment = Helper.setIfNone(_pigment, "WHITE");
+// if (!(_pigment instanceof String))
+// {
+// double[] _pigmentDouble = (double[]) _pigment;
+// for (int i = 0; i < _pigmentDouble.length; i++)
+// {
+// _rgba[i] = (float) _pigmentDouble[i];
+// }
+// }
+// else
+// {
+// switch ((String) _pigment)
+// {
+// case "GREEN" :
+// _rgba = new float[] {0.0f, 1.0f, 0.0f};
+// break;
+// case "RED" :
+// _rgba = new float[] {1.0f, 0.0f, 0.0f};
+// break;
+// case "BLUE" :
+// _rgba = new float[] {0.01f, 0.0f, 1.0f};
+// break;
+// case "PURPLE" :
+// _rgba = new float[] {1.0f, 0.0f, 1.0f};
+// break;
+// case "ORANGE" :
+// _rgba = new float[] {1.0f, 0.6f, 0.1f};
+// break;
+// case "BLACK" :
+// _rgba = new float[] {0.0f, 0.0f, 0.0f};
+// break;
+// case "WHITE" :
+// default :
+// _rgba = new float[] {1.0f, 1.0f, 1.0f};
+// break;
+// }
+// }
/*
* Render the appropriate surface
@@ -661,4 +699,5 @@ public void solutTranparancy() {
_soluteTranparancy += 0.05f;
}
+
}
diff --git a/src/render/Render.java b/src/render/Render.java
index 6decd367c..afe4df91a 100644
--- a/src/render/Render.java
+++ b/src/render/Render.java
@@ -27,6 +27,7 @@
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
+import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
@@ -42,6 +43,7 @@
import dataIO.Log;
import dataIO.Log.Tier;
+import gui.GuiActions;
import idynomics.Global;
import idynomics.Idynomics;
@@ -789,5 +791,48 @@ public void actionPerformed(ActionEvent g) {
}
});
+ /* Palette */
+ inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "Palette") ;
+ actionMap.put("Palette", new AbstractAction(){
+ private static final long serialVersionUID = 346448974654345823L;
+
+ @Override
+ public void actionPerformed(ActionEvent g) {
+ System.out.println("Palette");
+ File f = GuiActions.chooseFile("colourPalettes",
+ "Choose palette file.");
+ if( f.canRead() )
+ ((AgentMediator) r._commandMediator).setPalette(
+ f.getName() );
+ else
+ Log.out("Could not read palette file.");
+ }
+ });
+
+ /* Palette */
+ inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0), "Colour specification") ;
+ actionMap.put("Colour specification", new AbstractAction(){
+ private static final long serialVersionUID = 346448974654345823L;
+
+ @Override
+ public void actionPerformed(ActionEvent g) {
+ System.out.println("Colour specification");
+ /* We could do this a bit cleaner */
+ String in = inputDialog("Colour specification", ((AgentMediator)
+ r._commandMediator).currentColourSpecification());
+ ((AgentMediator) r._commandMediator).setColourSpecification(in);
+ ((AgentMediator) r._commandMediator).resetPalette();
+ }
+ });
+ }
+
+ public static String inputDialog(String message, String initial)
+ {
+ JFrame f;
+ f=new JFrame();
+ if( initial == null )
+ return JOptionPane.showInputDialog( f,message );
+ else
+ return JOptionPane.showInputDialog( f, message, initial );
}
}
From 3bf38349d9b34d3724ef3677aaadfe35edc0ac65 Mon Sep 17 00:00:00 2001
From: Bastiaan
Date: Thu, 26 Nov 2020 18:12:35 +0100
Subject: [PATCH 12/67] alternative colour palette
---
colourPalettes/rainbow.xml | 51 ++++++++++++++++++++++++++++++++++++++
1 file changed, 51 insertions(+)
create mode 100644 colourPalettes/rainbow.xml
diff --git a/colourPalettes/rainbow.xml b/colourPalettes/rainbow.xml
new file mode 100644
index 000000000..48ad9b51e
--- /dev/null
+++ b/colourPalettes/rainbow.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From ffbd9c5a080885e3176207e31648e554b71ed0b2 Mon Sep 17 00:00:00 2001
From: baseendje
Date: Tue, 1 Dec 2020 20:23:25 +0100
Subject: [PATCH 13/67] Eco Ego and multigrid investigations
---
protocol/Strep/Eco Ego.xml | 153 ++++++++
protocol/benchmark_3.xml | 14 +-
protocol/ecoli tests/ecoli.xml | 341 +++++++++---------
protocol/ecoli tests/ecoli2D.xml | 4 +-
.../library/SolveDiffusionSteadyState.java | 4 +-
src/solver/PDEmultigrid.java | 61 ++--
6 files changed, 369 insertions(+), 208 deletions(-)
create mode 100644 protocol/Strep/Eco Ego.xml
diff --git a/protocol/Strep/Eco Ego.xml b/protocol/Strep/Eco Ego.xml
new file mode 100644
index 000000000..c67175f7a
--- /dev/null
+++ b/protocol/Strep/Eco Ego.xml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/benchmark_3.xml b/protocol/benchmark_3.xml
index bb7b9d50e..ea5bd5e2e 100644
--- a/protocol/benchmark_3.xml
+++ b/protocol/benchmark_3.xml
@@ -6,10 +6,6 @@
-
-
-
-
-
-
+ firstStep="0.0">
@@ -186,7 +178,7 @@
+ firstStep="0.0">
@@ -204,7 +196,7 @@
+ firstStep="0.0">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/ecoli tests/ecoli2D.xml b/protocol/ecoli tests/ecoli2D.xml
index 92d1c1dfd..ad2dc8308 100644
--- a/protocol/ecoli tests/ecoli2D.xml
+++ b/protocol/ecoli tests/ecoli2D.xml
@@ -132,8 +132,8 @@
-
-
+
+
diff --git a/src/processManager/library/SolveDiffusionSteadyState.java b/src/processManager/library/SolveDiffusionSteadyState.java
index 9e52f31bd..9f754e841 100644
--- a/src/processManager/library/SolveDiffusionSteadyState.java
+++ b/src/processManager/library/SolveDiffusionSteadyState.java
@@ -56,9 +56,9 @@ public void init(Element xmlElem, EnvironmentContainer environment,
{
super.init(xmlElem, environment, agents, compartmentName);
- double absTol = (double) this.getOr(ABS_TOLERANCE, 1.0e-18);
+ double absTol = (double) this.getOr(ABS_TOLERANCE, 1.0e-9);
- double relTol = (double) this.getOr(REL_TOLERANCE, 1.0e-18);
+ double relTol = (double) this.getOr(REL_TOLERANCE, 1.0e-3);
// TODO Let the user choose which ODEsolver to use.
this._solver = new PDEmultigrid(
diff --git a/src/solver/PDEmultigrid.java b/src/solver/PDEmultigrid.java
index 195cde8e5..11b9488eb 100644
--- a/src/solver/PDEmultigrid.java
+++ b/src/solver/PDEmultigrid.java
@@ -73,7 +73,7 @@ public class PDEmultigrid extends PDEsolver
/**
* maximum number of pre-steps
*/
- private int _numPreSteps = 150;
+ private int _numPreSteps = 1500;
/**
* maximum number of coarse steps
*/
@@ -81,7 +81,7 @@ public class PDEmultigrid extends PDEsolver
/**
* maximum number of post steps
*/
- private int _numPostSteps = 150; // 1 -> 1000, 0.5 -> 2500 seems to work
+ private int _numPostSteps = 1500; // 1 -> 1000, 0.5 -> 2500 seems to work
/**
* Absolute threshold of the residual value at which relaxation is
@@ -100,7 +100,7 @@ public class PDEmultigrid extends PDEsolver
/**
* Enable stopping relaxation when stop conditions are met
*/
- private boolean _enableEarlyStop = false;
+ private boolean _enableEarlyStop = true;
/**
* Warn for large differences between Vcycle residuals (Debugging tool)
*/
@@ -113,6 +113,8 @@ public class PDEmultigrid extends PDEsolver
* Stored old residual (Debugging tool internal use)
*/
private double tempRes[];
+
+ private double tempRel[];
/**
* Stored layer number (Debugging tool internal use)
*/
@@ -499,6 +501,8 @@ private boolean doVCycle(Collection variables, int numLayers)
currentCommon = this._commonMultigrid.getGrid();
if( tempRes == null)
tempRes = new double[variables.size()];
+ if( tempRel == null)
+ tempRel = new double[variables.size()];
int i = 0;
for ( SpatialGrid variable : variables )
@@ -529,9 +533,6 @@ private boolean doVCycle(Collection variables, int numLayers)
this.num = 0;
}
- this.tempRes[i] = residual;
- i++;
-
continueVCycle = (continueVCycle || residual > truncationError);
if ( continueVCycle && Log.shouldWrite(Tier.DEBUG) )
Log.out(Tier.DEBUG, "residual " + residual+ " > truncation"
@@ -552,6 +553,9 @@ private void relaxAll(int numRepetitions)
currentGrids.add(layer.getGrid());
SpatialGrid currentCommon = this._commonMultigrid.getGrid();
+ tempRes = new double[this._variableNames.length];
+ tempRel = new double[this._variableNames.length];
+
int nGrid = currentGrids.size();
double[][] validate = new double[nGrid][3];
@@ -571,21 +575,30 @@ private void relaxAll(int numRepetitions)
boolean stop = true;
for ( SpatialGrid grid : currentGrids )
{
- tempRes = new double[this._variableNames.length];
this.relax(grid, currentCommon);
if ( !this._reachedStopCondition )
stop = false;
}
if ( stop ) {
// if( Log.shouldWrite(Tier.DEBUG) )
- Log.out("Breaking early: "+ i +" of "
+ Log.out("Met stop conditions at: "+ i+1 +" of "
+ numRepetitions );
break relaxLoops;
}
- if( i+1 >= numRepetitions && Log.shouldWrite(Tier.DEBUG) )
+ if( i+1 >= numRepetitions && Log.shouldWrite(Tier.NORMAL) )
{
- Log.out(Tier.DEBUG, i + " " + Vector.max(this.tempRes) + " > " +
- this._absToleranceLevel );
+ if( Vector.max(this.tempRes) > this._absToleranceLevel )
+ {
+ Log.out(Tier.NORMAL, i+1 + " " + Vector.max(this.tempRes) +
+ " > " + this._absToleranceLevel );
+ Log.out(Vector.toString(tempRes));
+ }
+ else
+ {
+ Log.out(Tier.NORMAL, i+1 + " " + Vector.max(this.tempRel) +
+ " > " + this._relToleranceLevel );
+ Log.out(Vector.toString(tempRel));
+ }
}
}
/* update reaction rate matrix at current concn */
@@ -727,6 +740,13 @@ private void relax(SpatialGrid variable, SpatialGrid commonGrid)
residual = (lop - rhs) / totalNhbWeight;
this.tempRes[pos] = Math.max(this.tempRes[pos], Math.abs(residual));
double relChange = residual / concn;
+ if( concn <= 0.0 )
+ {
+ relChange = 0.0;
+ if( residual < 0.0 ) /* seriously? */
+ residual = 0.0;
+ }
+ this.tempRel[pos] = Math.max(this.tempRel[pos], Math.abs(relChange));
/* Prepare to update the local concentration. */
concn += residual;
if (Math.abs(residual) > this._absToleranceLevel &&
@@ -871,6 +891,13 @@ private void calculateResidual(SpatialGrid variable,
if ( this._enableEarlyStop )
this._reachedStopCondition = true;
+ int pos = 0;
+ for (int i = 0; i < this._variableNames.length; i++)
+ {
+ if( variable.getName().equals(this._variableNames[i]))
+ pos = i;
+ }
+
/* FIXME: inverting the order we iterate the grid changes the result
* I don't think the method should be sensitive to the direction of
* evaluation! Bas [09.12.2019]
@@ -959,18 +986,8 @@ private void calculateResidual(SpatialGrid variable,
* TODO
*/
residual = (lop - rhs) / totalNhbWeight;
- double relChange = residual / concn;
- /* Prepare to update the local concentration. */
concn += residual;
- if (Math.abs(residual) > this._absToleranceLevel &&
- Math.abs(relChange) > this._relToleranceLevel)
- {
- this._reachedStopCondition = false;
- } else {
- if( Log.shouldWrite(Tier.DEBUG) )
- Log.out(Tier.DEBUG, "residual = "+residual+" relChange = "+
- relChange );
- }
+
/* Check if we need to remain non-negative. */
if ( (!this._allowNegatives) && (concn < 0.0) )
concn = 0.0;
From 9b0b312a83b7f87e91481cfa914cebacc2128e60 Mon Sep 17 00:00:00 2001
From: baseendje
Date: Wed, 2 Dec 2020 16:51:19 +0100
Subject: [PATCH 14/67] multigrid investigations
---
protocol/Strep/Eco Ego.xml | 16 +-
protocol/case_study2/eight_a_edit.xml | 248 +++++++++++++++
src/idynomics/Global.java | 2 +-
src/processManager/ProcessDiffusion.java | 15 +-
src/solver/PDEmultigrid.java | 369 +++++++++++------------
5 files changed, 446 insertions(+), 204 deletions(-)
create mode 100644 protocol/case_study2/eight_a_edit.xml
diff --git a/protocol/Strep/Eco Ego.xml b/protocol/Strep/Eco Ego.xml
index c67175f7a..2e492a990 100644
--- a/protocol/Strep/Eco Ego.xml
+++ b/protocol/Strep/Eco Ego.xml
@@ -3,7 +3,7 @@
-
+
@@ -47,13 +47,13 @@
-
+
-
+
-
+
@@ -82,7 +82,7 @@
-
+
@@ -134,11 +134,13 @@
-
+
-
+
+
diff --git a/protocol/case_study2/eight_a_edit.xml b/protocol/case_study2/eight_a_edit.xml
new file mode 100644
index 000000000..d49a8e3b6
--- /dev/null
+++ b/protocol/case_study2/eight_a_edit.xml
@@ -0,0 +1,248 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/idynomics/Global.java b/src/idynomics/Global.java
index f6b0c5368..e2141d47b 100644
--- a/src/idynomics/Global.java
+++ b/src/idynomics/Global.java
@@ -170,7 +170,7 @@ public void updateSettings()
* the default color specification for graphical output, NOTE in the future
* we probably want to set this to "species"
*/
- public static String default_colour_specification = "pigment";
+ public static String default_colour_specification = "species";
/**
* enable xml bookkeeping (also logging complete agent xml)
diff --git a/src/processManager/ProcessDiffusion.java b/src/processManager/ProcessDiffusion.java
index f8043ba0d..76aa39323 100644
--- a/src/processManager/ProcessDiffusion.java
+++ b/src/processManager/ProcessDiffusion.java
@@ -275,13 +275,14 @@ protected void applyEnvReactions(Collection solutes)
}
}
- if( Global.bookkeeping )
- for (String t : totals.keySet())
- /* NOTE we should rewrite how to access the compartment because
- * this is pretty inefficient. */
- Idynomics.simulator.getCompartment(this._compartmentName).
- registerBook(EventType.REACTION, t, "ENIVIRONMENT",
- String.valueOf( totals.get(t) ), null );
+ // this class should only calculate, but values may not be final
+// if( Global.bookkeeping )
+// for (String t : totals.keySet())
+// /* NOTE we should rewrite how to access the compartment because
+// * this is pretty inefficient. */
+// Idynomics.simulator.getCompartment(this._compartmentName).
+// registerBook(EventType.REACTION, t, "ENIVIRONMENT",
+// String.valueOf( totals.get(t) ), null );
}
diff --git a/src/solver/PDEmultigrid.java b/src/solver/PDEmultigrid.java
index 11b9488eb..c865c4346 100644
--- a/src/solver/PDEmultigrid.java
+++ b/src/solver/PDEmultigrid.java
@@ -36,6 +36,9 @@
* reaction kinetics, this solver implements the Full Approximation Storage
* (FAS) Algorithm discussed towards the end of the chapter.
*
+ *
+ * Read: Numerical Recipes in C page 885 +/- 5
+ *
*
Here are the meanings of the various symbols used in that chapter,
* within the context of iDynoMiCS 2:
*
u, the variable, is concentration
@@ -73,7 +76,7 @@ public class PDEmultigrid extends PDEsolver
/**
* maximum number of pre-steps
*/
- private int _numPreSteps = 1500;
+ private int _numPreSteps = 150;
/**
* maximum number of coarse steps
*/
@@ -81,7 +84,7 @@ public class PDEmultigrid extends PDEsolver
/**
* maximum number of post steps
*/
- private int _numPostSteps = 1500; // 1 -> 1000, 0.5 -> 2500 seems to work
+ private int _numPostSteps = 150; // 1 -> 1000, 0.5 -> 2500 seems to work
/**
* Absolute threshold of the residual value at which relaxation is
@@ -101,6 +104,8 @@ public class PDEmultigrid extends PDEsolver
* Enable stopping relaxation when stop conditions are met
*/
private boolean _enableEarlyStop = true;
+
+ private double ALPHA = 0.33;
/**
* Warn for large differences between Vcycle residuals (Debugging tool)
*/
@@ -187,7 +192,9 @@ public void solve(Collection variables,
this.refreshCommonGrid(commonGrid);
for ( SpatialGrid var : variables )
this.refreshVariable(var);
-
+
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ Log.out(Tier.EXPRESSIVE, "coarse grid");
this.solveCoarsest(variables);
/* See Figure 19.6.2 */
@@ -336,8 +343,16 @@ private void solveCoarsest(Collection variables)
this.relaxAll(this._numCoarseStep);
}
+ /**
+ *
+ *
+ *
+ */
+
private boolean doVCycle(Collection variables, int numLayers)
{
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ Log.out(Tier.EXPRESSIVE, "v "+ numLayers);
MultigridLayer variableMultigrid;
SpatialGrid currentLayer, currentCommon;
double truncationError, residual;
@@ -349,36 +364,8 @@ private boolean doVCycle(Collection variables, int numLayers)
/*
* Smooth the current layer for a set number of iterations.
*/
- /* Disabled Debug message
- if ( Log.shouldWrite(Tier.DEBUG) )
- {
- Log.out(Tier.DEBUG, "Before pre-relaxing layer, concns in range:");
- double min, max;
- for ( SpatialGrid variable : variables )
- {
- currentLayer = this.getMultigrid(variable).getGrid();
- min = currentLayer.getMin(CONCN);
- max = currentLayer.getMax(CONCN);
- Log.out(Tier.DEBUG, "\t"+variable.getName()+": ["+min+", "+max+"]");
- }
- }
- */
-
this.relaxAll(this._numPreSteps);
- /* Disabled Debug message
- if ( Log.shouldWrite(Tier.DEBUG) )
- {
- Log.out(Tier.DEBUG, "After pre-relaxing layer, concns in range:");
- double min, max;
- for ( SpatialGrid variable : variables )
- {
- currentLayer = this.getMultigrid(variable).getGrid();
- min = currentLayer.getMin(CONCN);
- max = currentLayer.getMax(CONCN);
- Log.out(Tier.DEBUG, "\t"+variable.getName()+": ["+min+", "+max+"]");
- }
- }
- */
+
/*
* Update the local truncation error using current CONCN values.
* In Numerical Recipes in C, this is is τ (tau) as defined in
@@ -418,7 +405,7 @@ private boolean doVCycle(Collection variables, int numLayers)
}
/* Update the PRODUCTIONRATE arrays using updated CONCN values. */
- this._updater.prestep(currentGrids, 0.0);
+// this._updater.prestep(currentGrids, 0.0);
/*
* TODO
* The relative truncation error is the difference between the
@@ -482,10 +469,6 @@ private boolean doVCycle(Collection variables, int numLayers)
currentLayer.addArrayToArray(CONCN, RELATIVEERROR);
if ( ! this._allowNegatives )
currentLayer.makeNonnegative(CONCN);
-
-// DEBUGGIMG
-// System.out.println(layerCounter + "\t" + currentLayer.getName() + " \t" + currentLayer.getMin(PRODUCTIONRATE) + " " );
-// System.out.println(layerCounter + "\t" + currentLayer.getName() + " \t" + currentLayer.getMin(CONCN) + " " );
}
/* Relaxation */
this.relaxAll(this._numPostSteps);
@@ -580,27 +563,28 @@ private void relaxAll(int numRepetitions)
stop = false;
}
if ( stop ) {
-// if( Log.shouldWrite(Tier.DEBUG) )
- Log.out("Met stop conditions at: "+ i+1 +" of "
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ Log.out(Tier.EXPRESSIVE,
+ "Met stop conditions at: "+ (i+1) +" of "
+ numRepetitions );
break relaxLoops;
}
if( i+1 >= numRepetitions && Log.shouldWrite(Tier.NORMAL) )
{
- if( Vector.max(this.tempRes) > this._absToleranceLevel )
- {
- Log.out(Tier.NORMAL, i+1 + " " + Vector.max(this.tempRes) +
- " > " + this._absToleranceLevel );
- Log.out(Vector.toString(tempRes));
- }
- else
- {
- Log.out(Tier.NORMAL, i+1 + " " + Vector.max(this.tempRel) +
- " > " + this._relToleranceLevel );
- Log.out(Vector.toString(tempRel));
- }
+ if( Log.shouldWrite(Tier.EXPRESSIVE))
+ if( Vector.max(this.tempRes) > this._absToleranceLevel )
+ {
+ Log.out(Tier.EXPRESSIVE, (i+1) + " " + Vector.max(this.tempRes) +
+ " > " + this._absToleranceLevel );
+ }
+ else
+ {
+ Log.out(Tier.EXPRESSIVE, (i+1) + " " + Vector.max(this.tempRel) +
+ " > " + this._relToleranceLevel );
+ }
}
}
+
/* update reaction rate matrix at current concn */
this._updater.prestep(currentGrids, 0.0);
@@ -740,11 +724,17 @@ private void relax(SpatialGrid variable, SpatialGrid commonGrid)
residual = (lop - rhs) / totalNhbWeight;
this.tempRes[pos] = Math.max(this.tempRes[pos], Math.abs(residual));
double relChange = residual / concn;
+
+ /* NOTE Hard prevention of negative concentrations here investigate
+ *
+ */
if( concn <= 0.0 )
{
relChange = 0.0;
- if( residual < 0.0 ) /* seriously? */
+ if( residual < 0.0 ) /* concn 0.0 but still negative res?? */
+ {
residual = 0.0;
+ }
}
this.tempRel[pos] = Math.max(this.tempRel[pos], Math.abs(relChange));
/* Prepare to update the local concentration. */
@@ -763,6 +753,7 @@ private void relax(SpatialGrid variable, SpatialGrid commonGrid)
concn = 0.0;
/* Update the value and continue to the next voxel. */
variable.setValueAtCurrent(CONCN, concn);
+// variable.setValueAt(destinationType, current, residual);
}
}
@@ -782,133 +773,27 @@ private void calculateResidual(SpatialGrid variable,
{
/* Commented out is the older method of calculating the residual, verify
the new method and remove commented code when completely satisfied. */
-// Shape shape = variable.getShape();
-// double diffusiveFlow, rateFromReactions, residual;
-//
-// @SuppressWarnings("unused")
-// double prod, concn, diffusivity, vol, rhs;
-// double nhbDist, nhbSArea, nhbDiffusivity, nhbWeight, nhbConcn, bndryFlow;
-// double lop;
-// @SuppressWarnings("unused")
-// int[] current, nhb;
-//
-// for ( current = shape.resetIterator(); shape.isIteratorValid();
-// current = shape.iteratorNext() )
-// {
-// if ( WellMixedConstants.isWellMixed(commonGrid, current) )
-// {
-// /* Reset the value here in case it used to be inside the
-// * boundary layer and move on to the next voxel. */
-// variable.setValueAt(destinationType, current, 0.0);
-// continue;
-// }
-//
-// concn = variable.getValueAtCurrent(CONCN);
-// prod = variable.getValueAtCurrent(PRODUCTIONRATE);
-// diffusivity = variable.getValueAtCurrent(DIFFUSIVITY);
-// vol = shape.getCurrVoxelVolume();
-// /* The right-hand side of Equation 19.6.23. */
-// rhs = variable.getValueAtCurrent(NONLINEARITY);
-// /* Reset both lop and dlop. */
-// lop = 0.0;
-// bndryFlow = 0.0;
-// /* Sum up over all neighbours. */
-// nhbLoop: for ( nhb = shape.resetNbhIterator();
-// shape.isNbhIteratorValid(); nhb = shape.nbhIteratorNext() )
-// {
-// boolean isInside = shape.isNbhIteratorInside();
-// /* First find the appropriate diffusivity. */
-// if ( isInside )
-// {
-// /*
-// * If the neighbor voxel is inside the compartment, use the
-// * harmonic mean average diffusivity of the two voxels.
-// */
-// nhbDiffusivity = variable.getValueAtNhb(DIFFUSIVITY);
-// nhbDiffusivity =
-// ExtraMath.harmonicMean(diffusivity, nhbDiffusivity);
-// }
-// else
-// {
-// /*
-// * If this is a boundary that does not contribute (e.g. a
-// * solid boundary) then do not include it in the weighting.
-// */
-// bndryFlow = shape.nbhIteratorOutside()
-// .getDiffusiveFlow(variable);
-// if ( bndryFlow == 0.0 )
-// continue nhbLoop;
-// /*
-// * Otherwise, just use the current voxel's diffusivity.
-// */
-// nhbDiffusivity = diffusivity;
-// }
-// nhbDist = shape.nhbCurrDistance();
-// nhbSArea = shape.nhbCurrSharedArea();
-// /*
-// * The weighting of each voxel is in terms of per time.
-// */
-// nhbWeight = (nhbSArea * nhbDiffusivity) / (nhbDist * vol);
-// /*
-// * The actual contribution of the neighbor voxel to the
-// * concentration of the current voxel depends on whether it is
-// * inside the compartment or on a boundary.
-// */
-// if ( isInside )
-// {
-// nhbConcn = variable.getValueAtNhb(CONCN);
-// lop += nhbWeight * (nhbConcn - concn);
-// }
-// else
-// {
-// /* Here we convert the flow (mass per time) into a change
-// * rate in concentration. */
-// lop += bndryFlow / vol;
-// }
-// }
-// diffusiveFlow = lop;
-// /*diffusiveFlow = 0.0;
-// for ( shape.resetNbhIterator(); shape.isNbhIteratorValid();
-// shape.nbhIteratorNext() )
-// {
-// diffusiveFlow += variable.getDiffusionFromNeighbor();
-// }*/
-// rateFromReactions = variable.getValueAt(PRODUCTIONRATE, current);
-// residual = (diffusiveFlow + rateFromReactions) /
-// shape.getCurrVoxelVolume();
-// variable.setValueAt(destinationType, current, residual);
-// }
-
- if ( ! this._allowNegatives )
- variable.makeNonnegative(CONCN);
Shape shape = variable.getShape();
- /* Temporary storage. */
+ double diffusiveFlow, rateFromReactions, residual;
+
+ @SuppressWarnings("unused")
double prod, concn, diffusivity, vol, rhs;
double nhbDist, nhbSArea, nhbDiffusivity, nhbWeight, nhbConcn, bndryFlow;
- double lop, totalNhbWeight, residual;
+ double lop;
@SuppressWarnings("unused")
int[] current, nhb;
- if ( this._enableEarlyStop )
- this._reachedStopCondition = true;
- int pos = 0;
- for (int i = 0; i < this._variableNames.length; i++)
- {
- if( variable.getName().equals(this._variableNames[i]))
- pos = i;
- }
-
- /* FIXME: inverting the order we iterate the grid changes the result
- * I don't think the method should be sensitive to the direction of
- * evaluation! Bas [09.12.2019]
- */
for ( current = shape.resetIterator(); shape.isIteratorValid();
current = shape.iteratorNext() )
{
-
- /* Skip this voxel if it is considered well-mixed. */
- if ( WellMixedConstants.isWellMixed(commonGrid, current))
+ if ( WellMixedConstants.isWellMixed(commonGrid, current) )
+ {
+ /* Reset the value here in case it used to be inside the
+ * boundary layer and move on to the next voxel. */
+ variable.setValueAt(destinationType, current, 0.0);
continue;
+ }
+
concn = variable.getValueAtCurrent(CONCN);
prod = variable.getValueAtCurrent(PRODUCTIONRATE);
diffusivity = variable.getValueAtCurrent(DIFFUSIVITY);
@@ -917,7 +802,6 @@ private void calculateResidual(SpatialGrid variable,
rhs = variable.getValueAtCurrent(NONLINEARITY);
/* Reset both lop and dlop. */
lop = 0.0;
- totalNhbWeight = 0.0;
bndryFlow = 0.0;
/* Sum up over all neighbours. */
nhbLoop: for ( nhb = shape.resetNbhIterator();
@@ -956,7 +840,6 @@ private void calculateResidual(SpatialGrid variable,
* The weighting of each voxel is in terms of per time.
*/
nhbWeight = (nhbSArea * nhbDiffusivity) / (nhbDist * vol);
- totalNhbWeight += nhbWeight;
/*
* The actual contribution of the neighbor voxel to the
* concentration of the current voxel depends on whether it is
@@ -974,26 +857,134 @@ private void calculateResidual(SpatialGrid variable,
lop += bndryFlow / vol;
}
}
- /*
- * For the FAS, the source term is implicit in the L-operator
- * (see Equations 19.6.21-22).
- *
- * NOTE: lop has units of concentration per time whereas prod would
- * have units of mass per time
- */
- lop += prod / vol;
- /*
- * TODO
- */
- residual = (lop - rhs) / totalNhbWeight;
- concn += residual;
-
- /* Check if we need to remain non-negative. */
- if ( (!this._allowNegatives) && (concn < 0.0) )
- concn = 0.0;
- /* Update the value and continue to the next voxel. */
+ diffusiveFlow = lop;
+ /*diffusiveFlow = 0.0;
+ for ( shape.resetNbhIterator(); shape.isNbhIteratorValid();
+ shape.nbhIteratorNext() )
+ {
+ diffusiveFlow += variable.getDiffusionFromNeighbor();
+ }*/
+ rateFromReactions = variable.getValueAt(PRODUCTIONRATE, current);
+ residual = (diffusiveFlow + rateFromReactions) /
+ shape.getCurrVoxelVolume();
variable.setValueAt(destinationType, current, residual);
}
+//
+// if ( ! this._allowNegatives )
+// variable.makeNonnegative(CONCN);
+// Shape shape = variable.getShape();
+// /* Temporary storage. */
+// double prod, concn, diffusivity, vol, rhs;
+// double nhbDist, nhbSArea, nhbDiffusivity, nhbWeight, nhbConcn, bndryFlow;
+// double lop, totalNhbWeight, residual;
+// @SuppressWarnings("unused")
+// int[] current, nhb;
+// if ( this._enableEarlyStop )
+// this._reachedStopCondition = true;
+//
+// int pos = 0;
+// for (int i = 0; i < this._variableNames.length; i++)
+// {
+// if( variable.getName().equals(this._variableNames[i]))
+// pos = i;
+// }
+//
+// /* FIXME: inverting the order we iterate the grid changes the result
+// * I don't think the method should be sensitive to the direction of
+// * evaluation! Bas [09.12.2019]
+// */
+// for ( current = shape.resetIterator(); shape.isIteratorValid();
+// current = shape.iteratorNext() )
+// {
+//
+// /* Skip this voxel if it is considered well-mixed. */
+// if ( WellMixedConstants.isWellMixed(commonGrid, current))
+// continue;
+// concn = variable.getValueAtCurrent(CONCN);
+// prod = variable.getValueAtCurrent(PRODUCTIONRATE);
+// diffusivity = variable.getValueAtCurrent(DIFFUSIVITY);
+// vol = shape.getCurrVoxelVolume();
+// /* The right-hand side of Equation 19.6.23. */
+// rhs = variable.getValueAtCurrent(NONLINEARITY);
+// /* Reset both lop and dlop. */
+// lop = 0.0;
+// totalNhbWeight = 0.0;
+// bndryFlow = 0.0;
+// /* Sum up over all neighbours. */
+// nhbLoop: for ( nhb = shape.resetNbhIterator();
+// shape.isNbhIteratorValid(); nhb = shape.nbhIteratorNext() )
+// {
+// boolean isInside = shape.isNbhIteratorInside();
+// /* First find the appropriate diffusivity. */
+// if ( isInside )
+// {
+// /*
+// * If the neighbor voxel is inside the compartment, use the
+// * harmonic mean average diffusivity of the two voxels.
+// */
+// nhbDiffusivity = variable.getValueAtNhb(DIFFUSIVITY);
+// nhbDiffusivity =
+// ExtraMath.harmonicMean(diffusivity, nhbDiffusivity);
+// }
+// else
+// {
+// /*
+// * If this is a boundary that does not contribute (e.g. a
+// * solid boundary) then do not include it in the weighting.
+// */
+// bndryFlow = shape.nbhIteratorOutside()
+// .getDiffusiveFlow(variable);
+// if ( bndryFlow == 0.0 )
+// continue nhbLoop;
+// /*
+// * Otherwise, just use the current voxel's diffusivity.
+// */
+// nhbDiffusivity = diffusivity;
+// }
+// nhbDist = shape.nhbCurrDistance();
+// nhbSArea = shape.nhbCurrSharedArea();
+// /*
+// * The weighting of each voxel is in terms of per time.
+// */
+// nhbWeight = (nhbSArea * nhbDiffusivity) / (nhbDist * vol);
+// totalNhbWeight += nhbWeight;
+// /*
+// * The actual contribution of the neighbor voxel to the
+// * concentration of the current voxel depends on whether it is
+// * inside the compartment or on a boundary.
+// */
+// if ( isInside )
+// {
+// nhbConcn = variable.getValueAtNhb(CONCN);
+// lop += nhbWeight * (nhbConcn - concn);
+// }
+// else
+// {
+// /* Here we convert the flow (mass per time) into a change
+// * rate in concentration. */
+// lop += bndryFlow / vol;
+// }
+// }
+// /*
+// * For the FAS, the source term is implicit in the L-operator
+// * (see Equations 19.6.21-22).
+// *
+// * NOTE: lop has units of concentration per time whereas prod would
+// * have units of mass per time
+// */
+// lop += prod / vol;
+// /*
+// * TODO
+// */
+// residual = (lop - rhs) / totalNhbWeight;
+// concn += residual;
+//
+// /* Check if we need to remain non-negative. */
+// if ( (!this._allowNegatives) && (concn < 0.0) )
+// concn = 0.0;
+// /* Update the value and continue to the next voxel. */
+// variable.setValueAt(destinationType, current, residual);
+// }
}
@Override
From 5193137f1599f16c67bff93e905297665f6a849d Mon Sep 17 00:00:00 2001
From: baseendje
Date: Thu, 3 Dec 2020 17:13:36 +0100
Subject: [PATCH 15/67] Working on full miltigrid port for testing puroposes
---
protocol/Strep/Eco Ego.xml | 4 +
src/linearAlgebra/Array.java | 11 +
src/linearAlgebra/Matrix.java | 6 +
src/linearAlgebra/Vector.java | 6 +
src/shape/Domain.java | 5 +
src/shape/Shape.java | 2 +-
src/solver/PDEmultigrid.java | 3 +
src/solver/mgFas/DiffusionSolver.java | 220 ++++++
src/solver/mgFas/Domain.java | 832 +++++++++++++++++++++++
src/solver/mgFas/MultiGridFAS.java | 218 ++++++
src/solver/mgFas/MultigridSolute.java | 746 ++++++++++++++++++++
src/solver/mgFas/MultigridUtils.java | 579 ++++++++++++++++
src/solver/mgFas/SoluteGrid.java | 293 ++++++++
src/solver/mgFas/SolverGrid.java | 900 +++++++++++++++++++++++++
src/solver/mgFas/Solver_multigrid.java | 363 ++++++++++
src/utility/ExtraMath.java | 2 +-
16 files changed, 4188 insertions(+), 2 deletions(-)
create mode 100644 src/shape/Domain.java
create mode 100644 src/solver/mgFas/DiffusionSolver.java
create mode 100644 src/solver/mgFas/Domain.java
create mode 100644 src/solver/mgFas/MultiGridFAS.java
create mode 100644 src/solver/mgFas/MultigridSolute.java
create mode 100644 src/solver/mgFas/MultigridUtils.java
create mode 100644 src/solver/mgFas/SoluteGrid.java
create mode 100644 src/solver/mgFas/SolverGrid.java
create mode 100644 src/solver/mgFas/Solver_multigrid.java
diff --git a/protocol/Strep/Eco Ego.xml b/protocol/Strep/Eco Ego.xml
index 2e492a990..63c5657c8 100644
--- a/protocol/Strep/Eco Ego.xml
+++ b/protocol/Strep/Eco Ego.xml
@@ -87,6 +87,10 @@
+
diff --git a/src/linearAlgebra/Array.java b/src/linearAlgebra/Array.java
index 9f801ae95..22189d147 100644
--- a/src/linearAlgebra/Array.java
+++ b/src/linearAlgebra/Array.java
@@ -114,6 +114,11 @@ public static double[][][] array(int ni, int nj, int nk, double value)
double[][][] out = new double[ni][nj][nk];
return setAll(out, value);
}
+
+ public static Double[][][] arrayDouble(int ni, int nj, int nk)
+ {
+ return new Double[ni][nj][nk];
+ }
/**
* \brief A new cubic array of {@code double}s.
@@ -288,6 +293,12 @@ public static void copyTo(double[][][] destination, double[][][] array)
Matrix.copyTo(destination[i], array[i]);
}
+ public static void copyTo(Double[][][] destination, Double[][][] array)
+ {
+ for ( int i = 0 ; i < array.length; i++ )
+ Matrix.copyTo(destination[i], array[i]);
+ }
+
/**
* \brief Make a deep copy of the given array.
*
diff --git a/src/linearAlgebra/Matrix.java b/src/linearAlgebra/Matrix.java
index d6b97b0e7..0d80270b3 100644
--- a/src/linearAlgebra/Matrix.java
+++ b/src/linearAlgebra/Matrix.java
@@ -638,6 +638,12 @@ public static void copyTo(double[][] destination, double[][] matrix)
Vector.copyTo(destination[i], matrix[i]);
}
+ public static void copyTo(Double[][] destination, Double[][] matrix)
+ {
+ for ( int i = 0; i < matrix.length; i++ )
+ Vector.copyTo(destination[i], matrix[i]);
+ }
+
/**
* \brief Make a deep copy of the given matrix, placing the result
* into a new double[][].
diff --git a/src/linearAlgebra/Vector.java b/src/linearAlgebra/Vector.java
index 5abaad984..a989e2027 100644
--- a/src/linearAlgebra/Vector.java
+++ b/src/linearAlgebra/Vector.java
@@ -410,6 +410,12 @@ public static void copyTo(double[] destination, double[] source)
destination[i] = source[i];
}
+ public static void copyTo(Double[] destination, Double[] source)
+ {
+ for ( int i = 0; i < destination.length; i++ )
+ destination[i] = source[i];
+ }
+
/**
* \brief Copy the vector given to a new int[] array.
*
diff --git a/src/shape/Domain.java b/src/shape/Domain.java
new file mode 100644
index 000000000..00f8338ef
--- /dev/null
+++ b/src/shape/Domain.java
@@ -0,0 +1,5 @@
+package shape;
+
+public interface Domain {
+
+}
diff --git a/src/shape/Shape.java b/src/shape/Shape.java
index 0ac718651..0a73be599 100644
--- a/src/shape/Shape.java
+++ b/src/shape/Shape.java
@@ -66,7 +66,7 @@
*/
// TODO remove the last three sections by incorporation into Node construction.
public abstract class Shape implements
- CanPrelaunchCheck, Instantiable, Settable
+ CanPrelaunchCheck, Instantiable, Settable, Domain
{
/**
* Ordered dictionary of dimensions for this shape.
diff --git a/src/solver/PDEmultigrid.java b/src/solver/PDEmultigrid.java
index c865c4346..a84efe62f 100644
--- a/src/solver/PDEmultigrid.java
+++ b/src/solver/PDEmultigrid.java
@@ -676,6 +676,9 @@ private void relax(SpatialGrid variable, SpatialGrid commonGrid)
/*
* If this is a boundary that does not contribute (e.g. a
* solid boundary) then do not include it in the weighting.
+ *
+ * FIXME this might not be properly implemented for every
+ * boundary type
*/
bndryFlow = shape.nbhIteratorOutside()
.getDiffusiveFlow(variable);
diff --git a/src/solver/mgFas/DiffusionSolver.java b/src/solver/mgFas/DiffusionSolver.java
new file mode 100644
index 000000000..a939636ea
--- /dev/null
+++ b/src/solver/mgFas/DiffusionSolver.java
@@ -0,0 +1,220 @@
+/**
+ * \package diffusionSolver
+ * \brief Package of classes used to capture the diffusion solvers that can be
+ * defined in the protocol file
+ *
+ * Solvers are used to compute the solute profile within the computational
+ * domains. This package is part of iDynoMiCS v1.2, governed by the CeCILL
+ * license under French law and abides by the rules of distribution of free
+ * software. You can use, modify and/ or redistribute iDynoMiCS under the
+ * terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the
+ * following URL "http://www.cecill.info".
+ */
+package solver.mgFas;
+
+import java.util.*;
+
+/**
+ * NOTE we may wrap Mutigrid directly within process manager
+ *
+ * \brief An abstract class used as a parent for all diffusion solvers that
+ * could be defined.
+ *
+ * This class is used as a parent for all diffusion solvers that can be
+ * specified in the XML protocol file. This processes the SOLVER mark-up
+ * within the protocol file. Solvers are used to compute the steady-state
+ * solute profile within the computational domains.
+ *
+ * This class is a component class of iDynoMiCS, released under the CECIL
+ * license. Please see www.idynomics.bham.ac.uk for more information.
+ *
+ * @version 1.2
+ * @author Andreas Dötsch (andreas.doetsch@helmholtz-hzi.de), Helmholtz Centre
+ * for Infection Research (Germany)
+ * @author Laurent Lardon (lardonl@supagro.inra.fr), INRA, France
+ */
+public abstract class DiffusionSolver
+{
+ /**
+ * A name assigned to this solver. Specified in the XML protocol file.
+ */
+ public String solverName;
+
+ /**
+ * The position of this solver in the simulation dictionary.
+ */
+ public int solverIndex;
+
+ /**
+ * The computational domain that this solver is associated with. Specified
+ * in the XML protocol file.
+ */
+ public Domain myDomain;
+
+ /**
+ * Local copy of the array of solute grids - one for each solute specified
+ * in the simulation protocol file. Taken from simulator object.
+ */
+ protected SoluteGrid[] _soluteList;
+
+ /**
+ * List of solutes that are used by THIS solver.
+ */
+ protected ArrayList _soluteIndex = new ArrayList();
+
+ protected Double internTimeStep;
+
+ protected Double minimalTimeStep;
+
+ protected int internalIteration;
+
+ /**
+ * Boolean flag that determines whether this solver will actually be used.
+ * Specified in XML protocol file.
+ */
+ protected Boolean _active = false;
+
+
+ /*************************************************************************
+ * CLASS METHODS
+ ************************************************************************/
+
+ /**
+ * \brief Initialisation procedure for each diffusion solver specified in
+ * the XML protocol file.
+ *
+ * This method takes a solver specification from the XML file (as a set of
+ * XML tags) and initialises a solver object.
+ *
+ * @param aSim The simulation object used to simulate the conditions
+ * specified in the protocol file.
+ * @param xmlRoot The XML object containing the definition of one solver
+ * in the protocol file.
+ */
+ public void init(Domain domain)
+ {
+
+ // Get the computational domain that this solver is associated with.
+ myDomain = domain;
+
+ // Reference all the solutes declared in this system.
+ _soluteList = null;
+
+ /* Now for each solver, reactions are specified. Add these reactions
+ * and list the solutes that these modify.
+ */
+
+ // TODO handle idyno 2 reactions
+
+// for (String aReacName : xmlRoot.getChildrenNames("reaction"))
+// addReactionWithSolutes(aSim.getReaction(aReacName));
+ }
+
+ /**
+ * \brief Sets reference to a biochemical pathway this solver has to deal
+ * with.
+ *
+ * References to the solutes and agents of the diffusion/reaction-system
+ * are provided by the pathways.
+ *
+ * @param aReaction : the pathway to add to this solver.
+ */
+// protected void addReactionWithSolutes(Reaction aReaction)
+// {
+// // Used to store a reference to a solute in the simulation dictionary.
+// int aSoluteIndex;
+//
+// // Assign the reaction.
+//// _reactions.add(aReaction);
+//
+// // Collect references to SoluteGrids from the pathway and store them.
+// for (String aSoluteName : aReaction.declareSolutes())
+// {
+// // Get the index for this solute.
+// aSoluteIndex = mySim.getSoluteIndex(aSoluteName);
+//
+// /* Add this to the list of solutes affected by this solver if not
+// * already present.
+// */
+// if ( ! _soluteIndex.contains(aSoluteIndex) )
+// _soluteIndex.add(aSoluteIndex);
+// }
+// }
+
+ /**
+ * \brief Registers this solver in the simulation solver array for
+ * referencing later on.
+ *
+ * This method adds this solver object to the simulation variable
+ * solverList, an array of DiffusionSolver objects used in the simulation.
+ */
+
+
+ // TODO wrap in processManager
+// public void register()
+// {
+// try
+// {
+// // Get the position of this solver in the simulation dictionary.
+// solverIndex = mySim.getSolverIndex(solverName);
+//
+// // Add this to the simulation list of solvers.
+// mySim.solverList[solverIndex] = this;
+// }
+// catch(Exception e)
+// {
+// LogFile.writeError(e, "Error in DiffusionSolver.register()");
+// }
+// }
+
+ /**
+ * \brief Small routine to use if you have only one solver instead to add
+ * one by one all pathways.
+ */
+// public void addAllReactions()
+// {
+// for (Reaction reac : mySim.reactionList)
+// addReactionWithSolutes(reac);
+// }
+
+ /**
+ * \brief Determine if this solver is actually being used.
+ *
+ * Set in the protocol file.
+ *
+ * @return Boolean stating whether this solver is active.
+ */
+ public Boolean isActive()
+ {
+ return true;
+ }
+
+ /**
+ * \brief Create the solver, initialise the concentration fields, and
+ * solve the diffusion reaction equations.
+ */
+ public void initAndSolve()
+ {
+ if ( isActive() )
+ {
+ initializeConcentrationFields();
+ solveDiffusionReaction();
+ }
+ }
+
+ /**
+ * \brief Initialize the diffusion-reaction-system according to the solver.
+ *
+ * Creates and initializes internal data structure for solving.
+ * Called at each simulation step
+ */
+ public abstract void initializeConcentrationFields();
+
+ /**
+ * \brief Performs the solving algorithm on the diffusion reaction system.
+ *
+ * If needed, the time step is provided by the SimTimer.
+ */
+ public abstract void solveDiffusionReaction();
+
+}
diff --git a/src/solver/mgFas/Domain.java b/src/solver/mgFas/Domain.java
new file mode 100644
index 000000000..025a21aa8
--- /dev/null
+++ b/src/solver/mgFas/Domain.java
@@ -0,0 +1,832 @@
+/**
+ * \package simulator.geometry
+ * \brief Package of boundary utilities that aid the creation of the environment being simulated
+ *
+ * Package of boundary utilities that aid the creation of the environment being simulated. This package is
+ * part of iDynoMiCS v1.2, governed by the CeCILL license under French law and abides by the rules of distribution of free software.
+ * You can use, modify and/ or redistribute iDynoMiCS under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at
+ * the following URL "http://www.cecill.info".
+ */
+package solver.mgFas;
+
+import java.util.*;
+
+import shape.Shape;
+import utility.ExtraMath;
+
+/**
+ * \brief Define the computation domain: an evenly spaced rectilinear grid
+ * described by its dimensionality (2D or 3D), its size, geometry and the
+ * behaviour at its boundaries.
+ *
+ * See Figure 1 of the Lardon et al paper (2011) for a good description on how
+ * this is divided into several regions - the support, the bulk, the biofilm
+ * matrix, and the diffusion boundary layer.
+ *
+ * @since June 2006
+ * @version 1.2
+ * @author Andreas Dötsch (andreas.doetsch@helmholtz-hzi.de), Helmholtz Centre
+ * for Infection Research (Germany).
+ * @author Laurent Lardon (lardonl@supagro.inra.fr), INRA, France.
+ * @author Brian Merkey (brim@env.dtu.dk, bvm@northwestern.edu), Department of
+ * Engineering Sciences and Applied Mathematics, Northwestern University (USA).
+ * @author Sónia Martins (SCM808@bham.ac.uk), Centre for Systems Biology,
+ * University of Birmingham (UK).
+ * @author Kieran Alden (k.j.alden@bham.ac.uk), Centre for Systems Biology,
+ * University of Birmingham (UK).
+ */
+public class Domain
+{
+ /**
+ * Serial version used for the serialisation of the class.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Name of this computation domain, as supplied in the specified protocol
+ * file.
+ */
+ public String domainName;
+
+ private Shape _shape;
+
+ /**
+ * Domain X dimension in micrometers.
+ */
+ public double length_X;
+
+ /**
+ * Domain Y dimension in micrometers.
+ */
+ public double length_Y;
+
+ /**
+ * Domain Z dimension in micrometers.
+ */
+ public double length_Z;
+
+ /**
+ * Whether this computation domain is two or three dimensional.
+ */
+ public boolean is3D;
+
+ /**
+ * Number of grid elements in the x direction.
+ */
+ public int _nI;
+
+ /**
+ * Number of grid elements in the y direction.
+ */
+ public int _nJ;
+
+ /**
+ * Number of grid elements in the z direction.
+ */
+ public int _nK;
+
+ /**
+ *
+ */
+ protected int _i;
+
+ /**
+ *
+ */
+ protected int _j;
+
+ /**
+ *
+ */
+ protected int _k;
+
+ /**
+ * Width of each side of the grid element (in micrometres).
+ */
+ public double[] _resolution;
+
+ /**
+ * The solute grid that is a component of this computation domain.
+ */
+ protected SolverGrid _domainGrid;
+
+ /**
+ * Boundary layer between bulk and biofilm
+ */
+ protected SoluteGrid _boundaryLayer;
+
+ /**
+ * Diffusivity of solutes in each area of this domain
+ */
+ protected SoluteGrid _diffusivityGrid;
+
+ /**
+ * Array to hold the X position that is the top of the boundary layer in
+ * each of the Y and Z positions. Used for self-attach scenarios.
+ */
+ public int[][] _topOfBoundaryLayer;
+
+ /**
+ * Grid to hold total biomass in a particular area.
+ */
+ public SoluteGrid _biomassGrid;
+
+ /**
+ * Band between the boundary and bulk, capturing change in diffusivity and
+ * solute levels.
+ */
+ protected Double _dilationBand;
+
+ /**
+ * The ratio between the carrier surface (the substratum on which the
+ * biofilm grows) and the bulk compartment volume. The physical volume of
+ * the system that appears in the simulation definition. In m2/m3.
+ */
+ protected double specificArea;
+
+ /**
+ * Factor used to decrease solute diffusivity inside the biofilm.
+ * Multiplicative factor applied to the diffusivity in water.
+ */
+ protected double _biofilmDiffusivity = 1.0;
+
+ /*************************************************************************
+ * CLASS METHODS
+ ************************************************************************/
+
+ /**
+ * \brief Creates a computation domain compartment object with attributes
+ * specified in the protocol file.
+ *
+ * The definition within the computationDomain markup of the protocol file
+ * notes how these regions are set up. This constructor sets up each
+ * computation domain that is specified in the protocol file.
+ *
+ * @param aSim The simulation object upon which the scenario specified in
+ * the protocol file is being run.
+ * @param cdRoot The XML tag objects that sub-nodes of the 'Bulk' tag in
+ * the protocol file.
+ */
+ public Domain(Shape shape)
+ {
+ this._shape = shape;
+ // Now determine if this computation domain is 2D or 3D
+ is3D = shape.getNumberOfDimensions() == 3;
+ _resolution = new double[] {
+ shape.getResolutionCalculator(null, 0).getResolution(),
+ shape.getResolutionCalculator(null, 1).getResolution(),
+ shape.getResolutionCalculator(null, 2).getResolution() };
+
+ double[] lengths = (shape.getRealLengths());
+
+
+ _nI = (int) Math.ceil(lengths[0]/_resolution[0]);
+ _nJ = (int) Math.ceil(lengths[1]/_resolution[1]);
+ _nK = (is3D) ? (int) Math.ceil(lengths[1]/_resolution[2]) : 1;
+
+ // Now calculate the length of the grid in micrometres.
+ length_X = _nI * _resolution[0];
+ length_Y = _nJ * _resolution[1];
+ length_Z = _nK * _resolution[2];
+
+ // Create and initialise the domain grid.
+ _domainGrid = new SoluteGrid(_nI, _nJ, _nK, _resolution);
+
+ // Specific area is given in m2/m3.
+// specificArea = cdRoot.getParamDbl("specificArea");
+
+ // Create the boundary layer and initialise it at "inside everywhere".
+// _dilationBand = cdRoot.getParamLength("boundaryLayer");
+ _boundaryLayer = createGrid( "boundaryLayer", 1);
+
+ // Create the biomass MASS grid and initialise it empty.
+ _biomassGrid = createGrid( "totalBiomass", 0.0);
+
+ // Create the relative diffusivity grid and initialise it at "liquid
+ // everywhere".
+ _biofilmDiffusivity = 1.0;
+ _diffusivityGrid = createGrid( "diffusivityGrid", 1);
+
+ // Create the grid that is going to hold the top of the boundary layer.
+ // Note that the boundary layer is initialised with padding, then
+ // ignores it (and never calculates the padding).
+ // For consistency (for the moment), the top of the boundary layer
+ // array will work in the same way - thus we will be ignoring space at
+ // either end (_nJ and _nK=0 and _nJ+2 and _nK+2).
+ _topOfBoundaryLayer = new int[_nJ+2][_nK+2];
+
+ }
+
+ /**
+ * \brief Creates a solute or species grid and initialises the values
+ * within that grid.
+ *
+ * Used to create boundary and biomass grids.
+ *
+ * @param gridName The name of the grid being created (e.g. boundaryLayer /
+ * totalBioMass).
+ * @param defaultValue The default value to assign to all grid spaces.
+ * @return Initialised solute grid of the size required by the simulation,
+ * initialised to the given default value.
+ */
+ public SoluteGrid createGrid(String gridName, double defaultValue)
+ {
+ SoluteGrid aGrid = new SoluteGrid(_nI, _nJ, _nK, _resolution);
+ aGrid.setAllValueAt(defaultValue);
+ return aGrid;
+ }
+
+ /**
+ * \brief Applies all specified domain boundaries to this computation
+ * domain one by one.
+ *
+ * This method should be used when you have finished to register all
+ * boundary conditions; this function will populate a 3-D matrix. Apply all
+ * boundaries one after one ; a point is outside of the computational
+ * domain if it is declared outside by at least one of the Boundary
+ * Conditions.
+ */
+ public void applyAllBoundary()
+ {
+ /* TODO do boundaries */
+// DiscreteVector dC = new DiscreteVector();
+// ContinuousVector cC;
+//
+// // Reset all the computational domain to "inside";
+// _domainGrid.setAllValueAt( 1.0 );
+//
+// for (int i = 0; i < _domainGrid.getGridTotalSize(1); i++)
+// for (int j = 0; j < _domainGrid.getGridTotalSize(2); j++)
+// loop:
+// for (int k = 0; k < _domainGrid.getGridTotalSize(3); k++)
+// {
+// dC.set(i-1, j-1, k-1);
+// cC = _domainGrid.getContinuousCoordinates(dC);
+// for (AllBC aBC : _boundaryList)
+// {
+// // skip if this gridCell has already been updated
+// if ( _domainGrid.getValueAt(i, j, k) == -1.0 )
+// continue loop;
+// // Test if this grid cell is seen outside
+// if ( aBC.isOutside(dC, _domainGrid) )
+// {
+// _domainGrid.setValueAt(-1.0, i, j, k);
+// continue loop;
+// }
+// // label carrier part of the domain
+// if ( aBC.isSupport() &&
+// aBC.getDistance(cC) < _resolution )
+// _domainGrid.setValueAt(0.0, i, j, k);
+// }
+// }
+ }
+
+ /* _______________________ LOCATED AGENTS ______________________________ */
+
+ /**
+ * \brief Test if a given location is outside a boundary.
+ *
+ * Used to detect the crossed boundary when moving an agent.
+ *
+ * @param newLoc The location to test
+ * @return Boundary that the point has crossed (if applicable: null if no
+ * boundary crossed)
+ */
+
+
+// public AllBC testCrossedBoundary(Double radius, ContinuousVector newLoc)
+// {
+// // Test on the domain grid if the new location is inside the domain
+//// if (_domainGrid.isValid(newLoc) && _domainGrid.getPaddedValueAt(newLoc) >= 0)
+//// return null;
+//
+// // Find the first of the boundaries which has been crossed
+// for (AllBC aBoundary : _boundaryList) {
+// if ((aBoundary instanceof BoundaryCyclic ? aBoundary.overBoundary(0.0,newLoc) :
+// aBoundary.overBoundary(radius, newLoc)) != null)
+// {
+// /*
+// System.out.println("agent at "+newLoc.toString()+
+// " crossed boundary "+aBoundary.getSide());
+// */
+// return aBoundary;
+// }
+// }
+//
+// // If you are here, it means that no boundary is being crossed.
+// return null;
+// }
+
+ /**
+ * \brief Test if a given location is outside a boundary other than the
+ * bottom. Used in self-attach scenarios.
+ *
+ * For self-attachment, the simulation detects a swimming agent may have
+ * crossed the substratum boundary and will then assume that agent
+ * attaches. However we need to check that move has not crossed any of the
+ * other boundaries, else that move is invalid. To do this, all boundaries
+ * are checked. If using the method above, y0z could still be returned and
+ * thus we end up in a loop. Thus this has had to be adapted so this cannot
+ * be returned.
+ *
+ * @param newLoc The new location of this swimming agent.
+ * @return The boundary which this move crosses, if applicable. Null if no
+ * such boundary.
+ */
+// public AllBC testCrossedBoundarySelfAttach(ContinuousVector newLoc)
+// {
+// // Test on the domain grid if the new location is inside the domain.
+// if (_domainGrid.isValid(newLoc) && _domainGrid.getValueAt(newLoc) >= 0)
+// return null;
+//
+// // Find the first of the boundaries which has been crossed.
+// // Added a check to not return y0z - we know this has been crossed as
+// // the cell has met the substratum. We are only interested here in
+// // checking the other 7 boundaries.
+// for (AllBC aBoundary : _boundaryList)
+// if ( aBoundary.isOutside(newLoc) )
+// if ( ! aBoundary.getSideName().equals("y0z") )
+// return aBoundary;
+//
+// // If you are here, it means that no boundary is being crossed.
+// return null;
+// }
+
+ /**
+ * \brief Add a boundary condition to the list of boundaries on this domain.
+ *
+ * @param aBC Boundary condition to add to the list of boundaries.
+ */
+// public void addBoundary(AllBC aBC)
+// {
+// _boundaryList.add(aBC);
+// }
+
+// @Override
+// public LinkedList getAllBoundaries()
+// {
+// return _boundaryList;
+// }
+
+// public LinkedList getAllSupportBoundaries()
+// {
+// LinkedList out = new LinkedList();
+// for ( AllBC aBC : _boundaryList )
+// if ( aBC.isSupport() )
+// out.add(aBC);
+// return out;
+// }
+//
+// public LinkedList getAllConnectedBoundaries()
+// {
+// LinkedList out =
+// new LinkedList();
+// for ( AllBC aBC : _boundaryList )
+// if ( aBC instanceof ConnectedBoundary )
+// out.add((ConnectedBoundary) aBC);
+// return out;
+// }
+
+
+// public Bulk getChemostat()
+// {
+// Bulk aBulk;
+// for (ConnectedBoundary aBC : getAllConnectedBoundaries())
+// {
+// aBulk = aBC.getBulk();
+// if( aBulk != null && aBulk.nameEquals("chemostat") )
+// return aBulk;
+// }
+// return null;
+// }
+
+ /**
+ * \brief Creates an array list containing the 'i' coordinate of the
+ * computation domain that is the top of the boundary layer.
+ *
+ * Creates an array list containing the 'i' coordinate of the computation
+ * domain that is the top of the boundary layer. Note that this is in the
+ * resolution specified by the 'resolution' parameter in the computation
+ * domain section of the protocol file, and this may need to be adjusted
+ * if being used in calculations where the resolution differs.
+ */
+ public void calculateTopOfBoundaryLayer()
+ {
+ /* TODO idyno 2 well mixed */
+// for(int k = 1; k <= _boundaryLayer.getGridSizeK(); k++)
+// for(int j = 1; j <= _boundaryLayer.getGridSizeJ(); j++)
+// {
+// int i=1;
+// while(i <= _boundaryLayer.getGridSizeI() &&
+// _boundaryLayer.getValueAt(i, j, k) > 0.0 )
+// i++;
+// // Assume now we've reached the point where 'i' has become 0,
+// // and thus we are out of the boundary layer. Subtract 1 such
+// // that the top of the layer is noted, not the outside of the
+// // layer.
+// _topOfBoundaryLayer[j][k] = i - 1;
+// }
+ }
+
+ /**
+ * \brief Refresh relative diffusivity and boundary layer grids to ensure
+ * biomass updated this step is included.
+ *
+ * Used in the creation of output files.
+ */
+ public void refreshBioFilmGrids()
+ {
+ /* TODO idyno 2 biofilm */
+ // Build a grid with the concentration of agents skip the the
+ // refreshment of the position of the agents relative to the
+ // boundary layers.
+// _biomassGrid.setAllValueAt(0.0);
+// currentSim.agentGrid.fitAgentMassOnGrid( _biomassGrid );
+// if ( ! Simulator.isChemostat )
+// {
+// // Reset the grid
+// _boundaryLayer.setAllValueAt(0.0);
+//
+// // calculate the values in each of the grids
+// calculateComputationDomainGrids();
+//
+// _boundaryLayer.refreshBoundary();
+//
+// // Now calculate the positions that are at the top of the boundary layer
+// calculateTopOfBoundaryLayer();
+// _diffusivityGrid.refreshBoundary();
+// _biomassGrid.refreshBoundary();
+// }
+ }
+
+ /**
+ * \brief Calculates the diffusivity and boundary layer grid levels.
+ *
+ * In previous versions of iDynoMiCS this method could be found within
+ * refreshBioFilmGrids. This has been moved here as, with the addition of
+ * self attachment, this method needs to be called before agent
+ * initialisation. KA May 2013.
+ */
+ public void calculateComputationDomainGrids()
+ {
+ for (int i = 1; i <= _nI; i++)
+ for (int j = 1; j <= _nJ; j++)
+ for (int k = 1; k <= _nK; k++)
+ if ( _biomassGrid.grid[i][j][k] > 0.0 )
+ {
+ /*
+ * This is biomass.
+ */
+ _boundaryLayer.grid[i][j][k] = 1.0;
+ _diffusivityGrid.grid[i][j][k] = _biofilmDiffusivity;
+ }
+ else
+ {
+ /*
+ * This is liquid, check dilation sphere for biomass:
+ * checkDilationRadius will set the value to 1 if it is
+ * within the boundary layer.
+ */
+ _boundaryLayer.grid[i][j][k] = checkDilationRadius(i, j, k);
+ //LogFile.writeLog("_boundaryLayer["+i+"]["+j+"]["+k+"] = "+_boundaryLayer.grid[i][j][k]);
+ if ( _domainGrid.grid[i][j][k] == -1.0 )
+ _diffusivityGrid.grid[i][j][k] = Double.MIN_VALUE;
+ else
+ _diffusivityGrid.grid[i][j][k] = 1.0;
+ }
+ }
+
+
+ /**
+ * \brief Returns a list of discrete vectors that specify the limit of the
+ * boundary layer.
+ *
+ * @return LinkedList of DiscreteVectors with the limit of the boundary layer.
+ */
+// @Override
+// public LinkedList getBorder()
+// {
+// Double v;
+// LinkedList border = new LinkedList();
+// for (_i = 1; _i<_nI+1; _i++)
+// for (_j = 1; _j<_nJ+1; _j++)
+// for (_k = 1; _k<_nK+1; _k++)
+// {
+// v = _boundaryLayer.grid[_i][_j][_k];
+// if ( v.equals(1.0) && bdryHasFreeNbh() )
+// {
+// // add the location if it has biomass or is in the boundary layer (v==1) and
+// // if the neighboring points are free (not biomass or bdry layer)
+// border.addLast(new DiscreteVector(_i, _j, _k));
+// }
+// }
+// return border;
+// }
+
+ /**
+ * \brief Creates a list of doubles with the heights of the biofilm/liquid
+ * interface.
+ *
+ * Used for writing simulation statistics. This routine is very basic in
+ * that it just captures the overall height (x-position) of each point from
+ * the nearest carrier, but for most cases it should be sufficient.
+ *
+ * @return Array of double values of the heights of the biofilm/liquid
+ * interface.
+ */
+// public Double[] getInterface()
+// {
+// currentSim.agentGrid.getLevelSet().refreshBorder(false, currentSim);
+// LinkedList border =
+// currentSim.agentGrid.getLevelSet().getBorder();
+// /*
+// * Catch if there is no biomass for some reason; in that case return
+// * zero height.
+// */
+// if ( border.isEmpty() )
+// return ExtraMath.newDoubleArray(1);
+// // Now copy to regular array, but watch for infinite distances.
+// ListIterator iter = border.listIterator();
+// Double [] out = new Double[border.size()];
+// while ( iter.hasNext() )
+// {
+// out[iter.nextIndex()] = iter.next().distanceFromCarrier;
+// if ( out[iter.previousIndex()] == Double.MAX_VALUE )
+// out[iter.previousIndex()] = 0.0;
+// }
+// return out;
+// }
+
+ /**
+ * \brief Determines whether points in the boundary layer have free
+ * neighbours.
+ *
+ * @author BVM 161208
+ * @return Boolean noting whether the elements in the boundary layer have
+ * free neighbours.
+ */
+ private Boolean bdryHasFreeNbh()
+ {
+ if ( is3D() )
+ {
+ for (int i = -1; i < 2; i++)
+ for (int j = -1; j < 2; j++)
+ for (int k = -1; k < 2; k++)
+ if (_boundaryLayer.grid[_i+i][_j+j][_k+k] == 0.0 )
+ return true;
+ return false;
+ }
+ else
+ {
+ for (int i = -1; i < 2; i++)
+ for (int j = -1; j < 2; j++)
+ if (_boundaryLayer.grid[_i+i][_j+j][1] == 0.0 )
+ return true;
+ return false;
+ }
+ }
+
+ public Shape getShape()
+ {
+ return this._shape;
+ }
+
+ /**
+ * \brief Sets the value of a grid space in the boundary layer, indicating
+ * whether the space is part of the boundary layer, or biomass is present.
+ *
+ * @param n The N coordinate of the grid to check whether this square is
+ * in the boundary.
+ * @param m The M coordinate of the grid to check whether this square is
+ * in the boundary.
+ * @param l The L coordinate of the grid to check whether this square is
+ * in the boundary.
+ * @return Integer noting whether or not the square is in the boundary
+ * (1 if yes, 0 if not).
+ */
+ protected Double checkDilationRadius(int n, int m, int l)
+ {
+ /*
+ * For no boundary layer, liquid means it's outside the boundary
+ * (and this routine only checks the status of non-biomass elements).
+ */
+ if ( _dilationBand == 0.0 )
+ return 0.0;
+
+ int nInterval, mInterval, lInterval;
+ int jIndex, kIndex;
+ Double deltaN, deltaM;
+ Double dilationRadiusM, dilationRadiusL;
+
+ /* FIXME what is the dilationBand exactly? */
+// nInterval = (int) Math.floor(_dilationBand/_resolution);
+ nInterval = 1;
+
+ for (int i = -nInterval; i <= nInterval; i++)
+ {
+ // only proceed if neighbour is within computational
+ // volume top and bottom boundaries
+ if ( (n+i >= 0) && (n+i < _nI) )
+ {
+ deltaN = i*_resolution[0];
+ // This calculates the range in the j direction based on a right triangle
+ // with hypotenuse equal to the sphere's radius, so that the total area
+ // checked is a sphere
+ dilationRadiusM = ExtraMath.triangleSide(_dilationBand, deltaN);
+ mInterval = (int) Math.floor(dilationRadiusM/_resolution[0]);
+
+ for (int j = -mInterval; j <= mInterval; j++) {
+ if ( _nK == 1)
+ {
+ // 2D case
+ jIndex = cyclicIndex(m+j,_nJ+2);
+ if (_biomassGrid.grid[n+i][jIndex][1] > 0.0)
+ return 1.0;
+ if (_domainGrid.grid[n+i][jIndex][1] == 0.0)
+ return 1.0;
+ }
+ else
+ {
+ // 3D case
+ deltaM = j*_resolution[1];
+ // This calculates the range in the k direction based on
+ // a right triangle with hypotenuse equal to the sphere's
+ // radius, so that the total area checked is a sphere
+ dilationRadiusL = ExtraMath.triangleSide(_dilationBand, deltaN, deltaM);
+ lInterval = (int) Math.floor(dilationRadiusL/_resolution[1]);
+
+ for (int k = -lInterval; k <= lInterval; k++)
+ if ( (i != 0) || (j != 0) || (k != 0) )
+ {
+ jIndex = cyclicIndex(m+j, _nJ+2);
+ kIndex = cyclicIndex(l+k, _nK+2);
+ if (_biomassGrid.grid[n+i][jIndex][kIndex] > 0.0)
+ return 1.0;
+ if (_domainGrid.grid[n+i][jIndex][kIndex] == 0.0)
+ return 1.0;
+ }
+ }
+ }
+ }
+ }
+ return 0.0;
+ }
+
+ /**
+ * \brief For cyclic boundaries, returns the index of the grid space on the
+ * opposite side of the boundary.
+ *
+ * @param val The integer grid spqce to check.
+ * @param limit The limit of the grid.
+ * @return The integer of the grid square the opposite side of the
+ * boundary.
+ */
+ protected final int cyclicIndex(int val, int limit)
+ {
+ return (val<0 ? limit+val : (val>=limit ? val-limit : val));
+ }
+
+ /**
+ *
+ * @param coord
+ * @return
+ */
+ protected Boolean checkDilationCoord(int[] coord)
+ {
+ // TODO update biomassGrid
+// for (AllBC aBC : _boundaryList )
+// aBC.applyBoundary(coord);
+ /*
+ * Return true if this is biomass or substratum.
+ */
+ return ( _biomassGrid.getValueAt(coord) > 0.0 ) ||
+ ( _domainGrid.getValueAt(coord) == 0.0 );
+ }
+
+ /**
+ * \brief Return longest side of this domain.
+ *
+ * @return Double of the length of the longest side of this domain.
+ */
+ public Double getLongestSize()
+ {
+ return Math.max(Math.max(length_X, length_Y), length_Z);
+ }
+
+ /**
+ * \brief Return the resolution of this domain.
+ *
+ * @return Double value stating the resolution of this domain.
+ */
+ public double[] getResolution()
+ {
+ return _resolution;
+ }
+
+ /**
+ * \brief Returns the domain grid.
+ *
+ * @return SpatialGrid within this domain.
+ */
+ public SolverGrid getGrid()
+ {
+ return _domainGrid;
+ }
+
+ /**
+ * \brief Determine if the simulation is recreating a 3D environment.
+ *
+ * @return A boolean value stating whether or not the environment is 3D.
+ */
+ public Boolean is3D()
+ {
+ return _domainGrid.is3D();
+ }
+
+ /**
+ * \brief Return the diffusivity grid associated with this domain.
+ *
+ * @return SoluteGrid containing diffusivity grid statistics.
+ */
+ public SoluteGrid getDiffusivity()
+ {
+ return _diffusivityGrid;
+ }
+
+ /**
+ * \brief Return the boundary layer grid associated with this domain.
+ *
+ * @return SoluteGrid containing boundary between bulk and biofilm.
+ */
+ public SoluteGrid getBoundaryLayer()
+ {
+ return _boundaryLayer;
+ }
+
+ /**
+ * \brief Return the biomass grid associated with this domain.
+ *
+ * @return SoluteGrid containing biomass throughout this domain.
+ */
+ public SoluteGrid getBiomass()
+ {
+ return _biomassGrid;
+ }
+
+ /**
+ * \brief Used in testing to check the top of the boundary layer was calculated correctly
+ *
+ * @author KA 210513
+ */
+ public void printTopOfBoundaryLayerArray()
+ {
+ for(int k = 1; k <= _nK; k++)
+ {
+ for(int j = 1; j <= _nJ; j++)
+ {
+ System.out.print(_topOfBoundaryLayer[j][k]+" ");
+ }
+ System.out.println();
+ }
+ }
+
+ /**
+ * \brief Used in testing to view the boundary layer matrix for a set part
+ * of the domain.
+ *
+ * @author KA 210513
+ */
+ public void printBoundaryLayer()
+ {
+ // Printing the Boundary Layer Grid
+ for(int k = 1; k <= _boundaryLayer.getGridSizeK(); k++)
+ for(int i = 1; i <= _boundaryLayer.getGridSizeI(); i++)
+ {
+ for(int j = 1; j <= _boundaryLayer.getGridSizeJ(); j++)
+ {
+ System.out.print(_boundaryLayer.getValueAt(i, j, k)+" ");
+ }
+ System.out.println();
+ }
+ }
+
+ /**
+ * \brief Used in testing to view the biomass matrix for a set part of the
+ * domain.
+ *
+ * @author KA 210513
+ */
+ public void printBiomassGrid()
+ {
+ // Printing the Boundary Layer Grid
+ for(int k = 1; k <= _biomassGrid.getGridSizeK(); k++)
+ for(int i = 1; i <= _biomassGrid.getGridSizeI(); i++)
+ {
+ for(int j = 1; j <= _biomassGrid.getGridSizeJ(); j++)
+ {
+ System.out.print(_biomassGrid.getValueAt(i, j, k)+" ");
+ }
+ System.out.println();
+ }
+ }
+}
diff --git a/src/solver/mgFas/MultiGridFAS.java b/src/solver/mgFas/MultiGridFAS.java
new file mode 100644
index 000000000..b361e96db
--- /dev/null
+++ b/src/solver/mgFas/MultiGridFAS.java
@@ -0,0 +1,218 @@
+package solver.mgFas;
+
+import grid.SpatialGrid;
+import linearAlgebra.Array;
+import utility.ExtraMath;
+
+/**
+ *
+ * Work in progress, getting idyno 1 mgFas to idyno 2, testing
+ *
+ *
+ *
+ */
+public class MultiGridFAS {
+
+ protected final int NPRE = 1;
+ protected final int NPOST = 1;
+ protected final int NGMAX = 15;
+ protected final double ALPHA = 0.33;
+ public final Double BLTHRESH = 0.1;
+
+ private Double _referenceSystemSide;
+ private double maxOrder;
+ /* nI = gridlength / resolution */
+ private double _resolution;
+ private int _nK;
+
+ /* 1 per solute? */
+ private double[][][] _rhs = new double[1][1][1];
+
+
+ public void setReferenceSide(double[][][] grid)
+ {
+ int nI = Array.height(grid);
+ int nJ = Array.width(grid);
+ int nK = Array.depth(grid);
+ _nK = nK;
+
+ _referenceSystemSide = Double.valueOf(Math.min(nI, nJ));
+ if (nK>1) _referenceSystemSide = Math.min(_referenceSystemSide, nK);
+
+ maxOrder = ExtraMath.log2( _referenceSystemSide ).intValue();
+ _referenceSystemSide -= 1;
+ _referenceSystemSide *= _resolution;
+ }
+
+ public void mgfas(double u, int n, int maxcyc)
+ {
+ int j, jcycle, jj, jm1, jpost, jpre, nf, ng = 0, ngrid, nn;
+ double res, trerr;
+ SpatialGrid irho, irhs, itau, itemp;
+
+ }
+
+ /**
+ * This is meant to return the correct index value following the logic of
+ * setReferenceSide() above.
+ *
+ * @param i
+ * @param j
+ * @param k
+ * @return
+ */
+ private Double referenceIndex(int i, int j, int k)
+ {
+ if (_nK > 1)
+ return Double.valueOf(Math.min(i, Math.min(j, k)) - 1);
+ else
+ return Double.valueOf(Math.min(i, j) - 1);
+ }
+
+
+ private double[][][] fillDiff(double[][][] diffusivity, double[][][] rd)
+ {
+ int _i = 0, _j = 0, _k = 0;
+ double[][][] _diff = new double[3][3][3];
+ _diff[0][1][1] = diffusivity[_i-1][_j][_k]*rd[_i-1][_j][_k];
+ _diff[2][1][1] = diffusivity[_i+1][_j][_k]*rd[_i+1][_j][_k];
+ _diff[1][0][1] = diffusivity[_i][_j-1][_k]*rd[_i][_j-1][_k];
+ _diff[1][2][1] = diffusivity[_i][_j+1][_k]*rd[_i][_j+1][_k];
+ _diff[1][1][0] = diffusivity[_i][_j][_k-1]*rd[_i][_j][_k-1];
+ _diff[1][1][2] = diffusivity[_i][_j][_k+1]*rd[_i][_j][_k+1];
+ _diff[1][1][1] = diffusivity[_i][_j][_k]*rd[_i][_j][_k];
+
+ return _diff;
+ }
+
+ /**
+ * \brief Compute the L-operator
+ *
+ * @param order
+ * @param h2i
+ * @return
+ */
+ private double computeLop(int order, Double h2i, double[][][] _diff,
+ double[][][] u, double[][][] _reac)
+ {
+ int _i = 0, _j = 0, _k = 0;
+ return ( (_diff[2][1][1]+_diff[1][1][1])*(u[_i+1][_j][_k]-u[_i][_j][_k])
+ +(_diff[0][1][1]+_diff[1][1][1])*(u[_i-1][_j][_k]-u[_i][_j][_k])
+ +(_diff[1][2][1]+_diff[1][1][1])*(u[_i][_j+1][_k]-u[_i][_j][_k])
+ +(_diff[1][0][1]+_diff[1][1][1])*(u[_i][_j-1][_k]-u[_i][_j][_k])
+ +(_diff[1][1][2]+_diff[1][1][1])*(u[_i][_j][_k+1]-u[_i][_j][_k])
+ +(_diff[1][1][0]+_diff[1][1][1])*(u[_i][_j][_k-1]-u[_i][_j][_k]))
+ *h2i + _reac[_i][_j][_k];
+ }
+
+ private Double computeDiffLop(int order, Double h2i, double[][][] _diff, double[][][] _diffReac)
+ {
+ int _i = 0, _j = 0, _k = 0;
+ return -h2i
+ *(6.0f*_diff[1][1][1]
+ +_diff[2][1][1]+_diff[0][1][1]
+ +_diff[1][2][1]+_diff[1][0][1]
+ +_diff[1][1][2]+_diff[1][1][0])
+ +_diffReac[_i][_j][_k];
+ }
+
+ public double relax(int order, double[][][] _conc)
+ {
+ int _i, _j, _k;
+ int nI = Array.height(_conc);
+ int nJ = Array.width(_conc);
+ int nK = Array.depth(_conc);
+
+ double[][][] _bLayer = null;
+ double[][][] _relDiff = null;
+
+
+ /* h = 1.0 / (n - 1) */
+ Double h = _referenceSystemSide/referenceIndex(nI, nJ, nK);
+ Double h2i = 0.5f / ( h * h );
+
+ /* red-black relaxation
+ iterate through system
+ isw, jsw and ksw alternate between values 1 and 2 */
+
+ double[][][] u = _conc;
+ double[][][] bl = _bLayer;
+ double[][][] rd = _relDiff;
+
+ Double lop, dlop, res;
+
+ /* Apply an eventual modification of the local diffusivity for THIS
+ solute around the boundaries */
+
+ // TODO
+ /* refreshDiffBoundaries(order); */
+
+ Double totalRes = 0.0;
+
+ // bvm 22.12.09: now allows red-black for 2d AND 3d
+ int ksw = 1;
+ int isw, jsw;
+ for (int pass = 1; pass <= 2; pass++, ksw = 3-ksw)
+ {
+ jsw = ksw;
+ for (_k = 1; _k <= nK; _k++, jsw = 3-jsw)
+ {
+ isw = jsw;
+ for (_j = 1; _j <= nJ; _j++, isw = 3-isw)
+ {
+ for (_i = isw; _i <= nI; _i += 2)
+ {
+ if (bl[_i][_j][_k] >= BLTHRESH)
+ {
+ // Case: Inside boundary layer
+ // Equations must be solved here
+
+ // compute diffusivity values
+ // and that of surrounding neighbours
+
+ /* diffusivity, rd (relDiff) */
+ double[][][] _diff = fillDiff(new double[1][1][1], new double[1][1][1]);
+
+ /* production rate */
+ double[][][] _reac = new double[1][1][1];
+ // compute L operator
+ lop = computeLop(order, h2i, _diff, u, _reac);
+
+ /* ?? don't see where this is set in idyno 1 */
+ double[][][] _diffReac = new double[1][1][1];
+
+ // compute derivative of L operator
+ dlop = computeDiffLop(order, h2i, _diff, _diffReac);
+
+ // compute residual
+ res = (lop-_rhs[_i][_j][_k])/dlop;
+ totalRes += Math.abs(res);
+ // update concentration (test for NaN)
+ //LogFile.writeLog("NaN generated in multigrid solver "+"while computing rate for "+soluteName);
+ //LogFile.writeLog("location: "+_i+", "+_j+", "+_k);
+ //LogFile.writeLog("dlop: "+dlop+"; lop: "+lop+"; grid: "+_rhs[order].grid[_i][_j][_k]);
+
+ u[_i][_j][_k] -= res;
+ // if negative concentrations, put 0 value
+ u[_i][_j][_k] = (u[_i][_j][_k]<0 ? 0 : u[_i][_j][_k]);
+ }
+ }
+ }
+ }
+ // refresh the padding elements to enforce
+ // boundary conditions for all solutes
+ refreshBoundary(_conc);
+ }
+ return totalRes;
+ }
+
+ private void refreshBoundary(double[][][] _conc)
+ {
+ /*
+ * Examine all objects at the boundary of the grid, and adjusts
+ * them as specified by the boundary condition rules.
+ *
+ * iterates over all boundaries
+ */
+ }
+}
diff --git a/src/solver/mgFas/MultigridSolute.java b/src/solver/mgFas/MultigridSolute.java
new file mode 100644
index 000000000..3cc58b3aa
--- /dev/null
+++ b/src/solver/mgFas/MultigridSolute.java
@@ -0,0 +1,746 @@
+/**
+ * \package diffusionSolver.multigrid
+ * \brief Package of classes used to aid solver calculation for multi-grid scenarios.
+ *
+ * Package of classes used to capture the diffusion solvers that can be defined in the protocol file. This package is
+ * part of iDynoMiCS v1.2, governed by the CeCILL license under French law and abides by the rules of distribution of free software.
+ * You can use, modify and/ or redistribute iDynoMiCS under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at
+ * the following URL "http://www.cecill.info".
+ */
+package solver.mgFas;
+
+import utility.ExtraMath;
+import linearAlgebra.Array;
+
+/**
+ * \brief Implements static utility functions for used in multigrid method.
+ *
+ * @author João Xavier (xavierj@mskcc.org), Memorial Sloan-Kettering Cancer
+ * Center (NY, USA).
+ */
+public class MultigridSolute
+{
+ /**
+ * Name of the solute in this multigrid
+ */
+ public String soluteName;
+
+ /**
+ * The simulation solute grid containing the concentrations of this solute
+ */
+ public SoluteGrid realGrid;
+
+ /**
+ *
+ */
+ protected double _referenceSystemSide;
+
+ /**
+ *
+ */
+ protected double _diffusivity;
+
+ /**
+ * Maximum solute level in the connected bulk.
+ */
+ protected double sBulkMax;
+
+ /**
+ * Solute level in the connected bulk.
+ */
+ protected double sBulk;
+
+ /**
+ *
+ */
+ protected SoluteGrid[] _relDiff;
+
+ /**
+ *
+ */
+ protected SoluteGrid[] _bLayer;
+
+ /**
+ * Concentration of this solute.
+ */
+ public SoluteGrid[] _conc;
+
+ /**
+ *
+ */
+ public SoluteGrid[] _reac;
+
+ /**
+ *
+ */
+ public SoluteGrid[] _diffReac;
+
+ /**
+ *
+ */
+ protected SoluteGrid[] _rhs, _itemp;
+
+ /**
+ *
+ */
+ protected SoluteGrid[] _itau;
+
+ /**
+ *
+ */
+ public double truncationError;
+
+ /**
+ * \brief
+ *
+ * Should be ok not to fill this with zeros at initialisation, as it should
+ * be filled in fillDiff() before it's ever called.
+ */
+ private static final double[][][] _diff = new double[3][3][3];
+
+ /**
+ *
+ */
+ private static double[][][] u;
+
+ /**
+ *
+ */
+ private static double[][][] rd;
+
+ /**
+ *
+ */
+ private static double[][][] bl;
+
+ /**
+ *
+ */
+ private static int _i;
+
+ /**
+ *
+ */
+ private static int _j;
+
+ /**
+ *
+ */
+ private static int _k;
+
+ /**
+ *
+ */
+ public static final Double BLTHRESH = 0.1;
+
+ /**
+ *
+ */
+ private static int maxOrder;
+
+ /**
+ * Size of original solute grid in I direction
+ */
+ private static int _nI;
+
+ /**
+ * Size of original solute grid in J direction
+ */
+ private static int _nJ;
+
+ /**
+ * Size of original solute grid in K direction
+ */
+ private static int _nK;
+
+ /**
+ * \brief Create a Multigrid solute for each solute being processed by a
+ * solver.
+ *
+ * @param aSolute The solute grid containing the concentrations of this
+ * solute.
+ * @param relDiff Diffusivity grid for this solute.
+ * @param bLayer Boundary layer.
+ * @param sBulk Max level of this solute in the bulk.
+ */
+ public MultigridSolute(SoluteGrid aSolute, MultigridSolute relDiff,
+ MultigridSolute bLayer, Double sBulk)
+ {
+ realGrid = aSolute;
+ soluteName = realGrid.gridName;
+
+ _nI = realGrid.getGridSizeI();
+ _nJ = realGrid.getGridSizeJ();
+ _nK = realGrid.getGridSizeK();
+
+ setReferenceSide();
+
+ this.sBulkMax = sBulk;
+ this.sBulk = sBulk;
+
+ _relDiff = relDiff._conc;
+ _bLayer = bLayer._conc;
+
+ _conc = new SoluteGrid[maxOrder];
+ _rhs = new SoluteGrid[maxOrder];
+ _reac = new SoluteGrid[maxOrder];
+ _diffReac = new SoluteGrid[maxOrder];
+ _itemp = new SoluteGrid[maxOrder];
+ _itau = new SoluteGrid[maxOrder];
+
+ for (int iGrid = 0; iGrid= BLTHRESH)
+ {
+ // Case: Inside boundary layer
+ // Equations must be solved here
+
+ // compute diffusivity values
+ // and that of surrounding neighbours
+ fillDiff();
+
+ // compute L operator
+ lop = computeLop(order, h2i);
+
+ // compute derivative of L operator
+ dlop = computeDiffLop(order, h2i);
+
+ // compute residual
+ res = (lop-_rhs[order].grid[_i][_j][_k])/dlop;
+ totalRes += Math.abs(res);
+ // update concentration (test for NaN)
+ //LogFile.writeLog("NaN generated in multigrid solver "+"while computing rate for "+soluteName);
+ //LogFile.writeLog("location: "+_i+", "+_j+", "+_k);
+ //LogFile.writeLog("dlop: "+dlop+"; lop: "+lop+"; grid: "+_rhs[order].grid[_i][_j][_k]);
+
+ u[_i][_j][_k] -= res;
+ // if negative concentrations, put 0 value
+ u[_i][_j][_k] = (u[_i][_j][_k]<0 ? 0 : u[_i][_j][_k]);
+ }
+ }
+ }
+ }
+ // refresh the padding elements to enforce
+ // boundary conditions for all solutes
+ _conc[order].refreshBoundary();
+ }
+ return totalRes;
+ }
+
+ /**
+ *
+ */
+ private void fillDiff()
+ {
+ //TODO shouldn't this be a diffusivity grid?
+ _diff[0][1][1] = realGrid.diffusivity*rd[_i-1][_j][_k];
+ _diff[2][1][1] = realGrid.diffusivity*rd[_i+1][_j][_k];
+ _diff[1][0][1] = realGrid.diffusivity*rd[_i][_j-1][_k];
+ _diff[1][2][1] = realGrid.diffusivity*rd[_i][_j+1][_k];
+ _diff[1][1][0] = realGrid.diffusivity*rd[_i][_j][_k-1];
+ _diff[1][1][2] = realGrid.diffusivity*rd[_i][_j][_k+1];
+ _diff[1][1][1] = realGrid.diffusivity*rd[_i][_j][_k];
+ }
+
+ /**
+ * \brief Compute the L-operator
+ *
+ * @param order
+ * @param h2i
+ * @return
+ */
+ private double computeLop(int order, Double h2i)
+ {
+ return ( (_diff[2][1][1]+_diff[1][1][1])*(u[_i+1][_j][_k]-u[_i][_j][_k])
+ +(_diff[0][1][1]+_diff[1][1][1])*(u[_i-1][_j][_k]-u[_i][_j][_k])
+ +(_diff[1][2][1]+_diff[1][1][1])*(u[_i][_j+1][_k]-u[_i][_j][_k])
+ +(_diff[1][0][1]+_diff[1][1][1])*(u[_i][_j-1][_k]-u[_i][_j][_k])
+ +(_diff[1][1][2]+_diff[1][1][1])*(u[_i][_j][_k+1]-u[_i][_j][_k])
+ +(_diff[1][1][0]+_diff[1][1][1])*(u[_i][_j][_k-1]-u[_i][_j][_k]))
+ *h2i + _reac[order].grid[_i][_j][_k];
+ }
+
+ /**
+ *
+ * @param order
+ * @param h2i
+ * @return
+ */
+ private Double computeDiffLop(int order, Double h2i)
+ {
+ return -h2i
+ *(6.0f*_diff[1][1][1]
+ +_diff[2][1][1]+_diff[0][1][1]
+ +_diff[1][2][1]+_diff[1][0][1]
+ +_diff[1][1][2]+_diff[1][1][0])
+ +_diffReac[order].grid[_i][_j][_k];
+ }
+
+ /**
+ *
+ * @param res
+ * @param order
+ */
+ private void computeResidual(SoluteGrid[] res, int order)
+ {
+ int nI = res[order].getGridSizeI();
+ int nJ = res[order].getGridSizeJ();
+ int nK = res[order].getGridSizeK();
+
+ Double h = _referenceSystemSide/referenceIndex(nI,nJ,nK);
+ Double h2i = 0.5f/(h*h);
+ Double lop; // temporary variable for L-operator
+
+ u = _conc[order].grid;
+ bl = _bLayer[order].grid;
+ rd = _relDiff[order].grid;
+
+ // iterate through system
+ for (_k = 1; _k <= nK; _k++)
+ for (_j = 1; _j <= nJ; _j++)
+ for (_i = 1; _i <= nI; _i++)
+ // compute lop only inside boundary layer
+ if (bl[_i][_j][_k] >= BLTHRESH)
+ {
+ // compute diffusivity values and that of surrounding
+ // neighbours
+ fillDiff();
+
+ // compute L operator
+ lop = computeLop(order, h2i);
+
+ // update concentration (test for NaN)
+ //LogFile.writeLog("MultigridSolute.computeResidual: NaN generated"+soluteName);
+ res[order].grid[_i][_j][_k] = lop;
+ }
+ res[order].refreshBoundary();
+ }
+
+ /**
+ *
+ * TODO Why are we only doing this to concentrations in the boundary
+ * layer?
+ *
+ * @param order
+ */
+ public void truncateConcToZero(int order)
+ {
+ int nI = _conc[order].getGridSizeI();
+ int nJ = _conc[order].getGridSizeJ();
+ int nK = _conc[order].getGridSizeK();
+ double[][][] bl = _bLayer[order].grid;
+ double[][][] u = _conc[order].grid;
+
+ for (int _i = 1; _i <= nI; _i++)
+ for (int _j = 1; _j <= nJ; _j++)
+ for (int _k = 1; _k <= nK; _k++)
+ if (bl[_i][_j][_k] >= BLTHRESH)
+ u[_i][_j][_k] = Math.max(u[_i][_j][_k], 0.0);
+ }
+
+ /* _________________________ TOOLBOX ____________________________ */
+ /**
+ *
+ * @param value
+ */
+ public void resetMultigridCopies(Double value)
+ {
+ for (int order = 0; order < maxOrder; order++)
+ _conc[order].setAllValueAt(value);
+ }
+
+ /**
+ *
+ */
+ public void resetMultigridCopies()
+ {
+ for (int order = 0; order < maxOrder; order++)
+ {
+ setSoluteGridToBulk(order);
+ _itau[order].resetToZero();
+ _itemp[order].resetToZero();
+ _reac[order].resetToZero();
+ _diffReac[order].resetToZero();
+ _rhs[order].resetToZero();
+ }
+ }
+
+ /**
+ *
+ * @param value
+ */
+ public void resetFinest(Double value)
+ {
+ _conc[maxOrder-1].setAllValueAt(value);
+ }
+
+ /**
+ *
+ * @param order
+ */
+ public void resetReaction(int order)
+ {
+ _reac[order].resetToZero();
+ _diffReac[order].resetToZero();
+ }
+
+ /**
+ * Set all grids elements to the value defined for Bulk. For elements
+ * located in the convective part (i.e. outside the BLayer, we take the
+ * value defined in the BulkBoundary Class)
+ */
+ public void setSoluteGridToBulk(int order)
+ {
+ int maxI = _conc[order].getGridSizeI();
+ int maxJ = _conc[order].getGridSizeJ();
+ int maxK = _conc[order].getGridSizeK();
+
+ for (_i = 1; _i <= maxI; _i++)
+ for (_j = 1; _j <= maxJ; _j++)
+ for (_k = 1; _k <= maxK; _k++)
+ {
+ if (_bLayer[order].grid[_i][_j][_k] <= BLTHRESH)
+ {
+ // outside the boundary layer (will not be solved)
+ _conc[order].grid[_i][_j][_k] = sBulk;
+ }
+ else
+ {
+ // inside the biofilm (value is not really important
+ // now)
+ _conc[order].grid[_i][_j][_k] = sBulkMax;
+ }
+ }
+ /*
+ DiscreteVectorIterator dvIter = new DiscreteVectorIterator(
+ 1, _conc[order].getGridSizeI(),
+ 1, _conc[order].getGridSizeJ(),
+ 1, _conc[order].getGridSizeK());
+ while ( true )
+ {
+ if ( _bLayer[order].getValueAt(dvIter) <= BLTHRESH )
+ // Outside the boundary layer (will not be solved).
+ _conc[order].setValueAt(sBulk, dvIter);
+ else
+ // Inside the biofilm (value is not really important now).
+ _conc[order].setValueAt(sBulkMax, dvIter);
+ if ( ! dvIter.setNext() )
+ break;
+ }*/
+ }
+
+ /**
+ *
+ * @return
+ */
+ public SoluteGrid getFinest()
+ {
+ return _conc[maxOrder-1];
+ }
+
+ /**
+ * Called by the chemostat solver.
+ *
+ * @return
+ */
+ public SoluteGrid getGrid()
+ {
+ return _conc[0];
+ }
+
+ /**
+ *
+ * @param aGrid
+ */
+ public void setFinest(SoluteGrid aGrid)
+ {
+ _conc[maxOrder-1] = aGrid;
+ }
+
+ /**
+ *
+ */
+ public void restrictToCoarsest()
+ {
+ for (int order = maxOrder - 1; order > 0; order--)
+ {
+ _conc[order-1].resetToZero();
+ MultigridUtils.restrict(_conc[order], _conc[order-1]);
+ }
+ }
+
+ /**
+ * Determine order of the finest grid.
+ */
+ public void setReferenceSide()
+ {
+ _referenceSystemSide = Double.valueOf(Math.min(_nI, _nJ));
+ if (_nK>1) _referenceSystemSide = Math.min(_referenceSystemSide, _nK);
+
+ maxOrder = ExtraMath.log2(_referenceSystemSide).intValue();
+ _referenceSystemSide -= 1;
+ // FIXME ??
+// _referenceSystemSide *= realGrid.getResolution();
+ }
+
+ /**
+ * This is meant to return the correct index value following the logic of
+ * setReferenceSide() above.
+ *
+ * @param i
+ * @param j
+ * @param k
+ * @return
+ */
+ private Double referenceIndex(int i, int j, int k)
+ {
+ if (_nK > 1)
+ return Double.valueOf(Math.min(i, Math.min(j, k)) - 1);
+ else
+ return Double.valueOf(Math.min(i, j) - 1);
+ }
+
+ /**
+ *
+ */
+ public void refreshDiffBoundaries(int order)
+ {
+ /*
+ * refresh boundaries
+
+ for ( AllBC boundary : _domain.getAllBoundaries() )
+ boundary.refreshDiffBoundary(_relDiff[order], realGrid);
+ */
+ }
+
+ /**
+ *
+ */
+ public void applyComputation()
+ {
+ Array.copyTo(realGrid.grid, _conc[maxOrder-1].grid);
+ }
+
+ /**
+ *
+ */
+ public void readSoluteGrid()
+ {
+ Array.copyTo(_conc[maxOrder-1].grid, realGrid.grid);
+ }
+
+ /**
+ * Update bulk concentration.
+ *
+ * TODO Rob 13Mar2015: This just gets one of the bulk values, ignoring the
+ * case where there may be more than one bulk.
+ */
+ public void readBulk()
+ {
+
+ /*
+ * obtain the bulk concentration
+ *
+ for ( ConnectedBoundary aBC : _domain.getAllConnectedBoundaries() )
+ {
+ sBulk = aBC.getBulkValue(realGrid.soluteIndex);
+ return;
+ }
+ */
+ }
+}
\ No newline at end of file
diff --git a/src/solver/mgFas/MultigridUtils.java b/src/solver/mgFas/MultigridUtils.java
new file mode 100644
index 000000000..d18cbee78
--- /dev/null
+++ b/src/solver/mgFas/MultigridUtils.java
@@ -0,0 +1,579 @@
+/**
+ * \package diffusionSolver.multigrid
+ * \brief Package of classes used to aid solver calculation for multi-grid scenarios.
+ *
+ * Package of classes used to capture the diffusion solvers that can be defined in the protocol file. This package is
+ * part of iDynoMiCS v1.2, governed by the CeCILL license under French law and abides by the rules of distribution of free software.
+ * You can use, modify and/ or redistribute iDynoMiCS under the terms of the CeCILL license as circulated by CEA, CNRS and INRIA at
+ * the following URL "http://www.cecill.info".
+ */
+package solver.mgFas;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import utility.ExtraMath;
+
+public abstract class MultigridUtils {
+
+ // boundary layer threshold
+ private static final Double BLTHRESH = MultigridSolute.BLTHRESH;
+ public static final String SEPARATOR = " ";
+
+ /**
+ * \brief Calculates log2(n - 1).
+ *
+ * @param n Integer
+ * @return order of multigrid
+ * @throws InvalidValueException
+ */
+ public static int order(Integer n) throws Exception
+ {
+ Double out = ExtraMath.log2(n - 1.0);
+ //if (out%1==0)
+ if (out.equals(Math.floor(out)))
+ return out.intValue();
+ else
+ throw (new Exception("invalid grid value ("+n+") must be 2^i + 1"));
+ }
+
+ /**
+ * \brief Restricts the data in matrix u to a grid one order coarser. Restriction excludes border points.
+ *
+ * Restricts the data in matrix u to a grid one order coarser. Restriction excludes border points.
+ *
+ * @param fineGrid finer grid
+ * @param coarsegrid coarser grid
+ */
+ public static void restrict2(SoluteGrid fineGrid, SoluteGrid coarsegrid)
+ {
+ double[][][] uc = coarsegrid.grid;
+ double[][][] u = fineGrid.grid;
+
+ int lc = uc[0][0].length-2;
+ int mc = uc[0].length-2;
+ int nc = uc.length-2;
+
+ int i, j, k; // indexes for fine grid
+ int ic, jc, kc; // indexes for coarse grid
+
+ // implements 2D and 3D
+ float nfac = (lc==1 ? 1.0f/16.0f : 1.0f/32.0f); // pre-compute
+
+ for (k = 1, kc = 1; kc<=lc; kc++, k += 2)
+ for (j = 1, jc = 1; jc<=mc; jc++, j += 2)
+ for (i = 1, ic = 1; ic<=nc; ic++, i += 2)
+ {
+ // 4-connectivity weight
+ uc[ic][jc][kc] = 2*(u[i+1][j][k]+u[i-1][j][k]+u[i][j+1][k]+u[i][j-1][k]);
+ // 8-connectivity weight
+ uc[ic][jc][kc] += u[i+1][j+1][k]+u[i+1][j-1][k]+u[i-1][j+1][k]+u[i-1][j-1][k];
+ // 3rd dimension (4-C)
+ uc[ic][jc][kc] += 2*(lc==1 ? 0.0f : u[i][j][k+1]+u[i][j][k-1]);
+ // 3rd dimension (8-C)
+ uc[ic][jc][kc] += (lc==1 ? 0.0f : u[i-1][j-1][k-1]+u[i-1][j][k-1]+u[i-1][j+1][k-1]);
+ uc[ic][jc][kc] += (lc==1 ? 0.0f : u[i][j-1][k-1]+u[i][j+1][k-1]);
+ uc[ic][jc][kc] += (lc==1 ? 0.0f : u[i+1][j-1][k-1]+u[i+1][j][k-1]+u[i+1][j+1][k-1]);
+
+ uc[ic][jc][kc] += (lc==1 ? 0.0f : u[i-1][j-1][k+1]+u[i-1][j][k-1]+u[i-1][j+1][k+1]);
+ uc[ic][jc][kc] += (lc==1 ? 0.0f : u[i][j-1][k+1]+u[i][j+1][k+1]);
+ uc[ic][jc][kc] += (lc==1 ? 0.0f : u[i+1][j-1][k+1]+u[i+1][j][k-1]+u[i+1][j+1][k+1]);
+
+ uc[ic][jc][kc] += 4*u[i][j][k];
+ uc[ic][jc][kc] *= nfac;
+ }
+
+ coarsegrid.refreshBoundary();
+ }
+
+ public static void restrict(SoluteGrid fineGrid, SoluteGrid coarseGrid)
+ {
+ double[][][] uc = coarseGrid.grid;
+ double[][][] u = fineGrid.grid;
+
+ int lc = uc[0][0].length-2;
+ int mc = uc[0].length-2;
+ int nc = uc.length-2;
+
+ int i, j, k; // indexes for fine grid
+ int ic, jc, kc; // indexes for coarse grid
+
+ // implements 2D and 3D
+ float nfac = (lc==1 ? 1.0f/8.0f : 1.0f/12.0f); // pre-compute
+
+ for (k = 1, kc = 1; kc<=lc; kc++, k += 2)
+ for (j = 1, jc = 1; jc<=mc; jc++, j += 2)
+ for (i = 1, ic = 1; ic<=nc; ic++, i += 2)
+ {
+ // special case for 2D (when lc = 1)
+ uc[ic][jc][kc] = u[i+1][j][k]+u[i-1][j][k]+u[i][j+1][k]+u[i][j-1][k];
+ uc[ic][jc][kc] += (lc==1 ? 0.0f : u[i][j][k+1]+u[i][j][k-1]);
+ uc[ic][jc][kc] *= nfac;
+ uc[ic][jc][kc] += 0.5f*u[i][j][k];
+ if ( Double.valueOf( uc[ic][jc][kc] ).isNaN() )
+ System.out.print(1);
+ }
+ coarseGrid.refreshBoundary();
+ }
+
+ /**
+ * Restricts the data in matrix u to a grid one order coarser. Restriction
+ * excludes border points for points inside the boundary layer, defined by
+ * data in bl. Restriction excludes border points and points outside the
+ * boundary layer (where bl >= 0.5). Points outside boundary layer are
+ * skipped and, therefore, preserve their original value.
+ *
+ * @param fineGrid finer grid
+ * @param coarseGrid coarser grid
+ * @param bl boundary layer at coarser grid
+ */
+ public static void restrictBoundaryLayer2(SoluteGrid fineGrid, SoluteGrid coarseGrid,
+ Double[][][] bl)
+ {
+
+ double[][][] uc = coarseGrid.grid;
+ double[][][] u = fineGrid.grid;
+
+ int nK = uc[0][0].length-2;
+ int nJ = uc[0].length-2;
+ int nI = uc.length-2;
+
+ int i, j, k; // indexes for fine grid
+ int ic, jc, kc; // indexes for coarse grid
+
+ // implements 2D and 3D
+ float nfac = (nK==1 ? 1.0f/16.0f : 1.0f/32.0f); // pre-compute
+
+ for (k = 1, kc = 1; kc <= nK; kc++, k += 2)
+ for (j = 1, jc = 1; jc <= nJ; jc++, j += 2)
+ for (i = 1, ic = 1; ic <= nI; ic++, i += 2)
+ if ( bl[ic][jc][kc] >= BLTHRESH )
+ {
+ // 4-connectivity weight
+ uc[ic][jc][kc] = 2*(u[i+1][j][k]+u[i-1][j][k]+u[i][j+1][k]+u[i][j-1][k]);
+ // 8-connectivity weight
+ uc[ic][jc][kc] += u[i+1][j+1][k]+u[i+1][j-1][k]+u[i-1][j+1][k]+u[i-1][j-1][k];
+ // 3rd dimension (4-C)
+ uc[ic][jc][kc] += 2*(nK==1 ? 0.0f : u[i][j][k+1]+u[i][j][k-1]);
+ // 3rd dimension (8-C)
+ uc[ic][jc][kc] += (nK==1 ? 0.0f : u[i-1][j-1][k-1]+u[i-1][j][k-1]+u[i-1][j+1][k-1]);
+ uc[ic][jc][kc] += (nK==1 ? 0.0f : u[i][j-1][k-1]+u[i][j+1][k-1]);
+ uc[ic][jc][kc] += (nK==1 ? 0.0f : u[i+1][j-1][k-1]+u[i+1][j][k-1]+u[i+1][j+1][k-1]);
+
+ uc[ic][jc][kc] += (nK==1 ? 0.0f : u[i-1][j-1][k+1]+u[i-1][j][k-1]+u[i-1][j+1][k+1]);
+ uc[ic][jc][kc] += (nK==1 ? 0.0f : u[i][j-1][k+1]+u[i][j+1][k+1]);
+ uc[ic][jc][kc] += (nK==1 ? 0.0f : u[i+1][j-1][k+1]+u[i+1][j][k-1]+u[i+1][j+1][k+1]);
+
+ uc[ic][jc][kc] += 4*u[i][j][k];
+ uc[ic][jc][kc] *= nfac;
+ }
+ coarseGrid.refreshBoundary();
+ }
+
+ public static void restrictBoundaryLayer(SoluteGrid fineGrid, SoluteGrid coarseGrid,
+ double[][][] bl)
+ {
+ double[][][] uc = coarseGrid.grid;
+ double[][][] u = fineGrid.grid;
+
+ int nK = uc[0][0].length-2;
+ int nJ = uc[0].length-2;
+ int nI = uc.length-2;
+
+ int i, j, k; // indexes for fine grid
+ int ic, jc, kc; // indexes for coarse grid
+
+ // implements 2D and 3D
+ float nfac = (nK==1 ? 1.0f/8.0f : 1.0f/12.0f); // pre-compute
+
+ for (k = 1, kc = 1; kc <= nK; kc++, k += 2)
+ for (j = 1, jc = 1; jc <= nJ; jc++, j += 2)
+ for (i = 1, ic = 1; ic <= nI; ic++, i += 2)
+ if ( bl[ic][jc][kc] >= BLTHRESH )
+ {
+ // special case for 2D (when lc = 1)
+ uc[ic][jc][kc] = u[i+1][j][k]+u[i-1][j][k]+u[i][j+1][k]+u[i][j-1][k];
+ uc[ic][jc][kc] += (nK==1 ? 0.0f : u[i][j][k+1]+u[i][j][k-1]);
+ uc[ic][jc][kc] *= nfac;
+ uc[ic][jc][kc] += 0.5f*u[i][j][k];
+ }
+ coarseGrid.refreshBoundary();
+ }
+
+ /**
+ * Interpolates the data in matrix uc to a grid one order finner for cubic
+ * matrices. Interpolation excludes border points.
+ *
+ * @param u finer grid
+ * @param uc coarser grid
+ */
+ static void interpolate(SoluteGrid fineGrid, SoluteGrid coarsegrid)
+ {
+ double[][][] uc = coarsegrid.grid;
+ double[][][] u = fineGrid.grid;
+
+ int l = u[0][0].length-2;
+ int m = u[0].length-2;
+ int n = u.length-2;
+
+ int i, j, k; // indexes for fine grid
+ int ic, jc, kc; // indexes for coarse grid
+
+ // copy points
+ for (kc = 1, k = 1; k <= l; kc++, k += 2)
+ for (jc = 1, j = 1; j <= m; jc++, j += 2)
+ for (ic = 1, i = 1; i <= n; ic++, i += 2)
+ u[i][j][k] = uc[ic][jc][kc];
+
+ // interpolate vertically
+ for (k = 1; k <= l; k += 2)
+ for (j = 1; j <= m; j += 2)
+ for (i = 2; i < n; i += 2)
+ u[i][j][k] = 0.5f*(u[i+1][j][k]+u[i-1][j][k]);
+
+ // interpolate sideways
+ for (k = 1; k <= l; k += 2)
+ for (j = 2; j < m; j += 2)
+ for (i = 1; i <= n; i++)
+ u[i][j][k] = 0.5f*(u[i][j+1][k]+u[i][j-1][k]);
+
+ for (k = 2; k < l; k += 2)
+ for (j = 1; j <= m; j++)
+ for (i = 1; i <= n; i++)
+ u[i][j][k] = 0.5f*(u[i][j][k+1]+u[i][j][k-1]);
+
+ fineGrid.refreshBoundary();
+ }
+
+ static void interpolate2(SoluteGrid fineGrid, SoluteGrid coarsegrid)
+ {
+ double[][][] uc = coarsegrid.grid;
+ double[][][] u = fineGrid.grid;
+
+ int l = u[0][0].length - 2;
+ int m = u[0].length - 2;
+ int n = u.length - 2;
+
+ int i, j, k; // indexes for fine grid
+ int ic, jc, kc; // indexes for coarse grid
+
+ // copy points
+ for (kc = 1, k = 1; k <= l; kc++, k += 2)
+ for (jc = 1, j = 1; j <= m; jc++, j += 2)
+ for (ic = 1, i = 1; i <= n; ic++, i += 2)
+ u[i][j][k] = uc[ic][jc][kc];
+
+ // interpolate vertically
+ for (k = 1; k <= l; k += 2)
+ for (j = 1; j <= m; j += 2)
+ for (i = 2; i < n; i += 2)
+ u[i][j][k] = 0.5f*(u[i+1][j][k]+u[i-1][j][k]);
+
+ // interpolate sideways
+ for (k = 1; k <= l; k += 2)
+ for (j = 2; j < m; j += 2)
+ for (i = 1; i <= n; i++)
+ u[i][j][k] = 0.5f*(u[i][j+1][k]+u[i][j-1][k]);
+
+ for (k = 2; k < l; k += 2)
+ for (j = 1; j <= m; j++)
+ for (i = 1; i <= n; i++)
+ u[i][j][k] = 0.5f*(u[i][j][k+1]+u[i][j][k-1]);
+
+ fineGrid.refreshBoundary();
+ }
+
+ /**
+ * Interpolates the data in matrix uc to a grid one order finner for cubic
+ * matrices for points inside the boundary layer, defined by data in bl.
+ * Interpolation excludes border points and points outside the boundary
+ * layer (where bl >= 0.5). Points outside boundary layer are skipped and,
+ * therefore, preserve their original value.
+ *
+ * @param u finer grid
+ * @param uc coarser grid
+ * @param bl boundary layer at finer grid
+ */
+ static void interpolateBoundaryLayer(SoluteGrid fineGrid, SoluteGrid coarseGrid, double[][][] bl)
+ {
+ double[][][] uc = coarseGrid.grid;
+ double[][][] u = fineGrid.grid;
+
+ int nK = u[0][0].length - 2;
+ int nJ = u[0].length - 2;
+ int nI = u.length - 2;
+
+ int i, j, k; // indexes for fine grid
+ int ic, jc, kc; // indexes for coarse grid
+
+ // copy points
+ for (kc = 1, k = 1; k <= nK; kc++, k += 2)
+ for (jc = 1, j = 1; j <= nJ; jc++, j += 2)
+ for (ic = 1, i = 1; i <= nI; ic++, i += 2)
+ if (bl[i][j][k]>=BLTHRESH)
+ u[i][j][k] = uc[ic][jc][kc];
+
+ // interpolate verically
+ for (k = 1; k <= nK; k += 2)
+ for (j = 1; j <= nJ; j += 2)
+ for (i = 2; i < nI; i += 2)
+ if ( bl[i][j][k] >= BLTHRESH )
+ u[i][j][k] = 0.5f*(u[i+1][j][k]+u[i-1][j][k]);
+
+ // interpolate sideways
+ for (k = 1; k <= nK; k += 2)
+ for (j = 2; j < nJ; j += 2)
+ for (i = 1; i <= nI; i++)
+ if ( bl[i][j][k] >= BLTHRESH )
+ u[i][j][k] = 0.5f*(u[i][j+1][k]+u[i][j-1][k]);
+
+ for (k = 2; k < nK; k += 2)
+ for (j = 1; j <= nJ; j++)
+ for (i = 1; i <= nI; i++)
+ if ( bl[i][j][k] >= BLTHRESH )
+ u[i][j][k] = 0.5f*(u[i][j][k+1]+u[i][j][k-1]);
+
+ fineGrid.refreshBoundary();
+ }
+
+ /**
+ * Set all entries of a matrix to value val
+ *
+ * @param u
+ * @param val
+ */
+ public static void setValues(double u[][][], double val)
+ {
+ for (int i = 0; i < u.length; i++)
+ for (int j = 0; j < u[i].length; j++)
+ for (int k = 0; k < u[i][j].length; k++)
+ u[i][j][k] = val;
+ }
+
+ /**
+ * Set all entries of a boolean matrix to value val
+ *
+ * @param u
+ * @param val
+ */
+ public static void setValues(Boolean u[][][], Boolean val)
+ {
+ for (int i = 0; imax ? a[i][j][k] : max);
+ return max;
+ }
+
+ /**
+ * compute the norm of matrix (exceptuating padding)
+ *
+ * @param a
+ * @return the norm of the matrix
+ */
+ public static Double computeNorm(double[][][] a)
+ {
+ Double norm = 0.0;
+ for (int i = 1; i=1; i--) {
+ for (int j = 1; j<=m; j++) {
+ out.append(matrix[i][j][k]);
+ // change here for format (presently space separated values
+ out.append(SEPARATOR);
+ }
+ out.append("\n");
+ }
+ out.append("\n");
+ }
+ return out.toString();
+ }
+
+ /**
+ * Return values in a matrix (excluding boundaries) as a formatted string.
+ * This method is used for boolean matrices. Values in output are 1 (for
+ * true) or 0 (for false)
+ *
+ * @param matrix to output as string
+ * @return string output
+ */
+ public static String coreMatrixToString(boolean[][][] matrix) {
+ int n = matrix.length-2;
+ int m = matrix[0].length-2;
+ int l = matrix[0][0].length-2;
+ StringBuffer out = new StringBuffer();
+ for (int k = 1; k<=l; k++) {
+ for (int i = n; i>=1; i--) {
+ for (int j = 1; j<=m; j++) {
+ out.append(matrix[i][j][k] ? 1 : 0);
+ // change here for format (presently space separated values
+ out.append(SEPARATOR);
+ }
+ out.append("\n");
+ }
+ out.append("\n");
+ }
+ return out.toString();
+ }
+
+ /**
+ * Write the full matrix to a string
+ *
+ * @param matrix
+ * @return a string with the matrix (space separated values)
+ */
+ public static String matrixToString(float[][][] matrix) {
+ StringBuffer out = new StringBuffer();
+ for (int k = 0; k=0; i--) {
+ for (int j = 0; j=0)) {
+
+ } else if (i<-1) {
+
+ }
+ if (i>=0) {
+ // parse the data in the line into a matrix
+ for (int j = 0; j 0 to exclude padding?
+ *
+ * @param dC DiscreteVector to validate
+ * @return Boolean stating whether this location is valid (true) or
+ * outside the grid.
+ */
+ public Boolean isValid(int[] dC)
+ {
+ return (dC[0] >= 0) && (dC[0] < _nI) &&
+ (dC[1] >= 0) && (dC[1] < _nJ) &&
+ (dC[2] >= 0) && (dC[2] < _nK);
+ }
+
+ /**
+ * \brief Determine if a given voxel coordinate is valid or outside the
+ * grid.
+ *
+ * @param i I Coordinate of the grid location.
+ * @param j J Coordinate of the grid location.
+ * @param k K Coordinate of the grid location.
+ * @return Boolean stating whether this location is valid (true) or
+ * outside the grid.
+ */
+ public Boolean isValidOrPadded(int i, int j, int k)
+ {
+ return (i >= 0) && (i <= _nI) &&
+ (j >= 0) && (j <= _nJ) &&
+ (k >= 0) && (k <= _nK);
+ }
+
+ /**
+ * \brief Determine if a given continuous location is valid or outside the
+ * grid.
+ *
+ * @param position ContinuousVector to validate.
+ * @return Boolean stating whether this location is valid (true) or
+ * outside the grid (false).
+ */
+ public Boolean isValid(double[] position)
+ {
+ return isValid(getDiscreteCoordinates(position));
+ }
+
+ /**
+ * \brief Transform a location, expressed as a continuous vector into a
+ * discrete position on the basis of the resolution of the grid.
+ *
+ * TODO Check why this is different to
+ * DiscreteVector(ContinuousVector cV, Double res)
+ * which uses Math.ceil() instead of Math.floor()
+ *
+ * @param cC ContinuousVector to be transformed
+ * @return DiscreteVector created from this continuous location
+ */
+ public int[] getDiscreteCoordinates(double[] cC)
+ {
+ int i = (int) Math.floor(cC[0]/_reso[0]);
+ int j = (int) Math.floor(cC[1]/_reso[1]);
+ int k = (int) Math.floor(cC[2]/_reso[2]);
+ return new int[] {i, j, k};
+ }
+
+ /**
+ * \brief Transform a position, expressed as a discrete vector into a
+ * continuous location on the basis of the resolution of the grid.
+ *
+ * @param coord DiscreteVector to be transformed.
+ * @return ContinuousVector created from this discrete position.
+ */
+ public double[] getContinuousCoordinates(int[] coord)
+ {
+ double[] temp = new double[] {
+ Double.valueOf(coord[0]),
+ Double.valueOf(coord[1]),
+ Double.valueOf(coord[2]) };
+ Vector.addEquals(temp, 0.5);
+ Vector.timesEquals(temp, _reso);
+ return temp;
+ }
+
+ /**
+ * \brief Return the maximum value on this grid (padding included).
+ *
+ * @return Maximum value of the grid.
+ */
+ public Double getMax()
+ {
+ return Array.max(grid);
+ }
+
+ public Double getMaxUnpadded()
+ {
+ Double out = Double.NEGATIVE_INFINITY;
+ for ( int i = 0; i < _nI; i++ )
+ for ( int j = 0; j < _nJ; j++ )
+ for ( int k = 0; k < _nK; k++ )
+ {
+ out = Math.max(out, grid[i][j][k]);
+ }
+
+ return out;
+ }
+
+ /**
+ * \brief Return the average value on this grid (padding excluded).
+ *
+ * @return Average value of the grid.
+ */
+ public Double getAverage()
+ {
+ return Array.sum(grid)/(_nI)/(_nJ)/(_nK);
+ }
+
+ /**
+ * \brief Return the sum of this grid (padding included).
+ *
+ * @return The sum of the values in this spatial grid.
+ */
+ public Double getSum()
+ {
+ return Array.sum(grid);
+ }
+
+ /**
+ * \brief Return the minimum value on this grid (padding included)
+ *
+ * @return Minimum value of the grid
+ */
+ public Double getMin()
+ {
+ return Array.min(grid);
+ }
+
+ /**
+ * TODO Check and make sure this is used.
+ *
+ * @return
+ */
+ public Double getMinUnpadded()
+ {
+ Double out = Double.POSITIVE_INFINITY;
+ for ( int i = 0; i < _nI; i++ )
+ for ( int j = 0; j < _nJ; j++ )
+ for ( int k = 0; k < _nK; k++ )
+ out = Math.min(out, grid[i][j][k]);
+ return out;
+ }
+
+ /**
+ * \brief For a given location, calculate the 2nd spatial derivative
+ * according to X.
+ *
+ * @param i I position on the spatial grid
+ * @param j J position on the spatial grid
+ * @param k K position on the spatial grid
+ * @return 2nd spatial derivative according X
+ */
+ public Double diff2X(int i, int j, int k)
+ {
+ Double value = grid[i+1][j][k] + grid[i-1][j][k] - 2*grid[i][j][k];
+ value /= ExtraMath.sq(_reso[0]);
+ return Double.isFinite(value) ? value : 0.0;
+ }
+
+ /**
+ * \brief For a given location, expressed as a discrete vector, calculate
+ * the 2nd spatial derivative according to X.
+ *
+ * @param dV DiscreteVector containing the position of a grid location.
+ * @return 2nd spatial derivative according X.
+ */
+ public Double diff2X(int[] dV)
+ {
+ return diff2X(dV[0], dV[1], dV[2]);
+ }
+
+ /**
+ * \brief For a given location, calculate the 1st spatial derivative
+ * according to X.
+ *
+ * @param i I position on the spatial grid
+ * @param j J position on the spatial grid
+ * @param k K position on the spatial grid
+ * @return 1st spatial derivative according X
+ */
+ public Double diffX(int i, int j, int k)
+ {
+ Double value = (grid[i+1][j][k] - grid[i-1][j][k])/(2 * _reso[0]);
+ return Double.isFinite(value) ? value : 0.0;
+ }
+
+ /**
+ * \brief For a given location, expressed as a discrete vector, calculate
+ * the 1st spatial derivative according to X.
+ *
+ * @param dV DiscreteVector containing the position of a grid location.
+ * @return 1st spatial derivative according X.
+ */
+ public Double diffX(int[] dV)
+ {
+ return diffX(dV[0], dV[1], dV[2]);
+ }
+
+ /**
+ * \brief For a given location, calculate the 2nd spatial derivative
+ * according to Y.
+ *
+ * @param i I position on the spatial grid
+ * @param j J position on the spatial grid
+ * @param k K position on the spatial grid
+ * @return 2nd spatial derivative according Y
+ */
+ public Double diff2Y(int i, int j, int k)
+ {
+ Double value = grid[i][j+1][k] + grid[i][j-1][k] - 2*grid[i][j][k];
+ value /= ExtraMath.sq(_reso[1]);
+ return Double.isFinite(value) ? value : 0.0;
+ }
+
+ /**
+ * \brief For a given location, expressed as a discrete vector, calculate
+ * the 2nd spatial derivative according to Y.
+ *
+ * @param dV DiscreteVector containing the position of a grid location.
+ * @return 2nd spatial derivative according Y.
+ */
+ public Double diff2Y(int[] dV)
+ {
+ return diff2Y(dV[0], dV[1], dV[2]);
+ }
+
+ /**
+ * \brief For a given location, calculate the 1st spatial derivative
+ * according to Y.
+ *
+ * @param i I position on the spatial grid
+ * @param j J position on the spatial grid
+ * @param k K position on the spatial grid
+ * @return 1st spatial derivative according Y
+ */
+ public Double diffY(int i, int j, int k)
+ {
+ Double value = (grid[i][j+1][k] - grid[i][j-1][k])/(2 * _reso[1]);
+ return Double.isFinite(value) ? value : 0.0;
+ }
+
+ /**
+ * \brief For a given location, expressed as a discrete vector, calculate
+ * the 1st spatial derivative according to Y.
+ *
+ * @param dV DiscreteVector containing the position of a grid location.
+ * @return 1st spatial derivative according Y.
+ */
+ public Double diffY(int[] dV)
+ {
+ return diffY(dV[0], dV[1], dV[2]);
+ }
+
+ /**
+ * \brief For a given location, calculate the 2nd spatial derivative
+ * according to Z.
+ *
+ * @param i I position on the spatial grid
+ * @param j J position on the spatial grid
+ * @param k K position on the spatial grid
+ * @return 2nd spatial derivative according Z
+ */
+ public Double diff2Z(int i, int j, int k)
+ {
+ Double value = grid[i][j][k+1] + grid[i][j][k-1] - 2*grid[i][j][k];
+ value /= ExtraMath.sq(_reso[2]);
+ return Double.isFinite(value) ? value : 0.0;
+ }
+
+ /**
+ * \brief For a given location, expressed as a discrete vector, calculate
+ * the 2nd spatial derivative according to Z.
+ *
+ * @param dV DiscreteVector containing the position of a grid location.
+ * @return 2nd spatial derivative according Z.
+ */
+ public Double diff2Z(int[] dV)
+ {
+ return diff2Z(dV[0], dV[1], dV[2]);
+ }
+
+ /**
+ * \brief For a given location, calculate the 1st spatial derivative
+ * according to Z.
+ *
+ * @param i I position on the spatial grid
+ * @param j J position on the spatial grid
+ * @param k K position on the spatial grid
+ * @return 1st spatial derivative according Z
+ */
+ public Double diffZ(int i, int j, int k)
+ {
+ Double value = (grid[i][j][k+1] - grid[i][j][k-1])/(2 * _reso[2]);
+ return Double.isFinite(value) ? value : 0.0;
+ }
+
+ /**
+ * \brief For a given location, expressed as a discrete vector, calculate
+ * the 1st spatial derivative according to Z.
+ *
+ * @param dV DiscreteVector containing the position of a grid location.
+ * @return 1st spatial derivative according Z.
+ */
+ public Double diffZ(int[] dV)
+ {
+ return diffZ(dV[0], dV[1], dV[2]);
+ }
+
+ /**
+ * \brief Computes the average concentration seen in a sphere (or cube)
+ * centred around a given point.
+ *
+ * @param cC ContinuousVector containing the point to use as the centre
+ * of this search.
+ * @param extReso Resolution to use in this search.
+ * @return Average grid value seen around this point.
+ */
+ public Double getValueAround(double[] cC, Double extReso)
+ {
+ return getValueAt(cC);
+ }
+
+ /**
+ * \brief Returns a vector of the first spatial derivatives in x, y & z.
+ *
+ * Returns a vector of the first spatial derivatives in x, y & z
+ * (nabla cC - see http://en.wikipedia.org/wiki/Del). Does this by
+ * first converting the ContinuousVector to a DiscreteVector and then
+ * estimating then gradient using the Mean Value Theorem
+ * (http://en.wikipedia.org/wiki/Mean_value_theorem).
+ *
+ * @param cC ContinuousVector position used to calculate the gradient.
+ * @return Vector of spatial derivatives in X,Y,Z.
+ */
+ public double[] getGradient(double[] cC)
+ {
+ int[] dV = new int[] { (int) Math.ceil(cC[0]/_reso[0]),
+ (int) Math.ceil(cC[0]/_reso[1]),
+ (int) Math.ceil(cC[0]/_reso[2])};
+ return new double[] { diffX(dV), diffY(dV), diffZ(dV)};
+ }
+
+ /**
+ * \brief Returns a vector of the first spatial derivatives in x and y,
+ * for 2D simulations.
+ *
+ * Returns a vector of the first spatial derivatives in x and y
+ * (nabla cC - see http://en.wikipedia.org/wiki/Del). Does this by
+ * first converting the ContinuousVector to a DiscreteVector and then
+ * estimating then gradient using the Mean Value Theorem
+ * (http://en.wikipedia.org/wiki/Mean_value_theorem).
+ *
+ * @param cC ContinuousVector position used to calculate the gradient.
+ * @return Vector of spatial derivatives in X and Y.
+ */
+ public double[] getGradient2D(double[] cC)
+ {
+ int[] dV = new int[] { (int) Math.ceil(cC[0]/_reso[0]),
+ (int) Math.ceil(cC[0]/_reso[1]),
+ (int) Math.ceil(cC[0]/_reso[2])};
+ return new double[] { diffX(dV), diffY(dV), diffY(dV)};
+ }
+
+
+ /**
+ * \brief Return the value on the padded grid at a given position
+ * (the coordinates are NOT corrected).
+ *
+ * @param dV DiscreteVector containing the location of the grid
+ * whose value should be returned.
+ * @return The double value at that location.
+ */
+ public Double getValueAt(int[] dc)
+ {
+ return grid[dc[0]+1][dc[1]+1][dc[2]+1];
+ }
+
+ /**
+ * \brief Return the value stored at the location given by the stated
+ * continuous vector.
+ *
+ * @param cC ContinuousVector containing the grid location to return.
+ * @return Double value stored at that grid location.
+ */
+ public Double getValueAt(double[] cC)
+ {
+ return getValueAt(getDiscreteCoordinates(cC));
+ }
+
+ /**
+ * \brief Return the value on the padded grid at a given position.
+ *
+ * The coordinates are NOT corrected.
+ *
+ * @param i I Coordinate of the grid location to set
+ * @param j J Coordinate of the grid location to set
+ * @param k K Coordinate of the grid location to set
+ * @return The double value at that location
+ */
+ public Double getValueAt(int i, int j, int k)
+ {
+ if (isValidOrPadded(i, j, k))
+ return grid[i][j][k];
+ else
+ return Double.NaN;
+ }
+
+ /**
+ * \brief Set a grid location, expressed as a ContinuousVector, to a
+ * specified value.
+ *
+ * The coordinates are corrected.
+ *
+ * @param value Value to set the specified location to
+ * @param cC Continuous vector stating the location of the grid to be
+ * set to the given value.
+ */
+ public void setValueAt(Double value, double[] cC)
+ {
+ setValueAt(value, getDiscreteCoordinates(cC));
+ }
+
+ /**
+ * \brief Set a grid location, expressed as a DiscreteVector, to a
+ * specified value.
+ *
+ * The coordinates are corrected.
+ *
+ * @param value Value to set the specified location to
+ * @param dC Discrete vector stating the location of the grid to be set
+ * to the given value.
+ */
+ public void setValueAt(Double value, int[] dC)
+ {
+ grid[dC[0]+1][dC[1]+1][dC[2]+1] = value;
+ }
+
+ /**
+ * \brief Set a grid location to a specified value.
+ *
+ * Note the coordinates are NOT corrected.
+ *
+ * @param value Value to set the grid location to
+ * @param i I Coordinate of the grid location to set
+ * @param j J Coordinate of the grid location to set
+ * @param k K Coordinate of the grid location to set
+ */
+ public void setValueAt(Double value, int i, int j, int k)
+ {
+ grid[i][j][k] = value;
+ }
+
+ /**
+ * \brief Add a value to that contained at the given discrete coordinates
+ * of this grid.
+ *
+ * Coordinates are corrected for padding.
+ *
+ * @param value Value to add to the specified grid location
+ * @param cC Continuous vector expressing the location of the grid to
+ * be increased.
+ */
+ public void addValueAt(Double value, double[] cC)
+ {
+ addValueAt(value, getDiscreteCoordinates(cC));
+ }
+
+ /**
+ * \brief Add a value to that contained at the given discrete coordinates
+ * of this grid.
+ *
+ * Coordinates are corrected for padding.
+ *
+ * @param value Value to add to the specified grid location
+ * @param dC Discrete vector expressing the location of the grid to be
+ * increased.
+ */
+ public void addValueAt(Double value, int[] dC)
+ {
+ grid[dC[0]+1][dC[1]+1][dC[2]+1] += value;
+ }
+
+ /**
+ * \brief Add a value to all locations on this grid (including the
+ * padding).
+ *
+ * @param value Value to be added to the contents of all grid voxels.
+ */
+ public void addAllValues(Double value)
+ {
+ for (int i = 0; i < _nI+2; i++)
+ for (int j = 0; j < _nJ+2; j++)
+ for (int k = 0; k < _nK+2; k++)
+ grid[i][j][k] += value;
+ }
+
+ /**
+ * \brief Checks a value at a given location and sets it to zero if the
+ * value is negative.
+ *
+ * @param i Voxel coordinate in I direction
+ * @param j Voxel coordinate in J direction
+ * @param k Voxel coordinate in K direction
+ */
+ public void truncateValueAt(int i, int j, int k)
+ {
+ grid[i][j][k] = Math.max(grid[i][j][k], 0.0);
+ }
+
+ /**
+ * \brief Set all meshes of a grid with the same value, including the
+ * padding if not a chemostat simulation.
+ *
+ * @param value Value at which to set all the elements of the grid
+ */
+ public void setAllValueAt(Double value)
+ {
+ for (int i = 0; i < _nI+2; i++)
+ for (int j = 0; j < _nJ+2; j++)
+ for (int k = 0; k < _nK+2; k++)
+ grid[i][j][k] = value;
+ }
+
+ /**
+ * \brief Set all meshes of the grid to zero.
+ */
+ public void resetToZero()
+ {
+ setAllValueAt(0.0);
+ }
+
+ /**
+ * \brief Return the number of voxels in the X direction.
+ *
+ * Ignores the padding.
+ *
+ * @return Number of real voxels along X.
+ */
+ public int getGridSizeI()
+ {
+ return _nI;
+ }
+
+ /**
+ * \brief Return the number of voxels in the Y direction.
+ *
+ * Ignores the padding.
+ *
+ * @return Number of real voxels along Y.
+ */
+ public int getGridSizeJ()
+ {
+ return _nJ;
+ }
+
+ /**
+ * \brief Return the number of voxels in the Z direction.
+ *
+ * Ignores the padding.
+ *
+ * @return Number of real voxels along Z.
+ */
+ public int getGridSizeK()
+ {
+ return _nK;
+ }
+
+ /**
+ * \brief Return the number of voxels along a given direction.
+ *
+ * (axeCode):
+ * 1 - X,
+ * 2 - Y,
+ * 3 - Z.
+ *
+ * Includes padding.
+ *
+ * @param axeCode Integer noting the direction to query.
+ * @return The number of voxels along a direction including padding bands.
+ */
+ public int getGridTotalSize(int axeCode)
+ {
+ switch (axeCode)
+ {
+ case 1:
+ return _nI + 2;
+ case 2:
+ return _nJ + 2;
+ case 3:
+ return _nK + 2;
+ default:
+ return 0;
+ }
+ }
+
+ /**
+ * \brief Returns the length (in distance unit) along a given direction
+ *
+ * (axeCode):
+ * 1 - X,
+ * 2 - Y,
+ * 3 - Z.
+ *
+ * Does not include padding.
+ *
+ * @param axeCode The direction of which the length is required:
+ * 1-X, 2-Y, 3-Z
+ * @return Double value stating the length (in distance unit) along a
+ * direction ignoring padding bands.
+ */
+ public Double getGridLength(int axeCode)
+ {
+ switch (axeCode)
+ {
+ case 1:
+ return _nI*_reso[0];
+ case 2:
+ return _nJ*_reso[1];
+ case 3:
+ return _nK*_reso[2];
+ default:
+ return 0.0;
+ }
+ }
+
+ /**
+ * \brief Return the volume of one voxel of the spatial grid.
+ *
+ * @return Double value stating the volume of one voxel of the spatial
+ * grid.
+ */
+ public Double getVoxelVolume()
+ {
+ return Vector.normEuclid(_reso);
+ }
+
+ /**
+ * \brief Return the whole grid, including the padding.
+ *
+ * @return The spatial grid.
+ */
+ public double[][][] getGrid()
+ {
+ return grid;
+ }
+
+ /**
+ * \brief Return a clone of this spatial grid.
+ *
+ * @return A clone of this spatial grid.
+ */
+ public double[][][] getCloneGrid()
+ {
+ return Array.copy(grid);
+ }
+
+ /**
+ * \brief Returns the resolution of this spatial grid.
+ *
+ * @return Double value stating the resolution (in micrometers) of this
+ * grid.
+ */
+ public double[] getResolution()
+ {
+ return _reso;
+ }
+
+ /**
+ * \brief Determine if this spatial grid is 3D or 2D.
+ *
+ * @return Boolean noting whether this grid is 3D (true) or 2D (false).
+ */
+ public Boolean is3D()
+ {
+ return _is3D;
+ }
+
+ /**
+ * \brief Set the values of this spatial grid to those contained in the
+ * supplied grid.
+ *
+ * @param u Matrix of values which to set the spatial grid to.
+ */
+ public void setGrid(double[][][] u)
+ {
+ grid = Array.copy(u);
+ }
+
+ /**
+ * \brief Write the contents of this grid to the XML results files.
+ *
+ * This shows the level of solute in each of the grid spaces.
+ *
+ * @param bufferState The output buffer writing the env_state file for
+ * this iteration.
+ * @param bufferSummary The output buffer writing the env_sum file for
+ * this iteration.
+ * @throws Exception Exception thrown if these buffers cannot be opened
+ * for writing to.
+ */
+// public void writeReport(ResultFile bufferState, ResultFile bufferSummary)
+// throws Exception
+// {
+// /*
+// * Edit the markup for the solute grid
+// */
+// StringBuffer value = new StringBuffer();
+// value.append("\n");
+// /*
+// * Write the markup in the file
+// */
+// bufferState.write(value.toString());
+// /*
+// * Rob 3/3/11: Changed to fix bug in envState output files and improve
+// * code readability (plus efficiency... possibly). Note that for a
+// * chemostat, i=j=k=1 and that in 2D k=1. The main fix here however,
+// * is that grid is a Double[] and not an array, as previously coded
+// * (this reduces the amount of storage space taken by envState files
+// * by about a 2 thirds!)
+// */
+//
+// /*
+// * KA 06062013 - turned off the printing of the padding. Will need
+// * to ensure this is clear from v1.2
+// *
+// * Fill the mark-up.
+// */
+// if ( _nK == 1 )
+// for ( int i = 1; i < _nI + 1; i++ )
+// for ( int j = 1; j < _nJ + 1; j++ )
+// bufferState.write(String.valueOf(grid[i][j][1])+";\n");
+// else
+// for ( int i = 1; i < _nI + 1; i++ )
+// for ( int j = 1; j < _nJ + 1; j++ )
+// for ( int k = 1; k < _nK + 1; k++ )
+// bufferState.write(String.valueOf(grid[i][j][k])+";\n");
+//
+// /*
+// * Close the mark-up
+// */
+// bufferState.write("\n\n");
+// }
+}
diff --git a/src/solver/mgFas/Solver_multigrid.java b/src/solver/mgFas/Solver_multigrid.java
new file mode 100644
index 000000000..05f80feec
--- /dev/null
+++ b/src/solver/mgFas/Solver_multigrid.java
@@ -0,0 +1,363 @@
+/**
+ * \package diffusionSolver
+ * \brief Package of classes used to capture the diffusion solvers that can be
+ * defined in the protocol file
+ *
+ * Solvers are used to compute the solute profile within the computational
+ * domains. This package is part of iDynoMiCS v1.2, governed by the CeCILL
+ * license under French law and abides by the rules of distribution of free
+ * software. You can use, modify and/ or redistribute iDynoMiCS under the
+ * terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the
+ * following URL "http://www.cecill.info".
+ */
+package solver.mgFas;
+
+import idynomics.Idynomics;
+
+/**
+ *
+ * @author Andreas Dötsch (andreas.doetsch@helmholtz-hzi.de), Helmholtz Centre
+ * for Infection Research (Germany)
+ * @author Laurent Lardon (lardonl@supagro.inra.fr), INRA, France
+ * @author Brian Merkey (brim@env.dtu.dk, bvm@northwestern.edu), Department of
+ * Engineering Sciences and Applied Mathematics, Northwestern University (USA)
+ */
+public class Solver_multigrid extends DiffusionSolver
+{
+ protected MultigridSolute _bLayer;
+
+ protected MultigridSolute _diffusivity;
+ protected MultigridSolute[] _solute;
+
+// protected MultigridSolute[] _biomass;
+
+ protected SoluteGrid[] allSolute;
+
+// protected SoluteGrid[] allReac;
+
+ protected SoluteGrid[] allDiffReac;
+
+ protected static int iSolute;
+
+ protected static int order;
+ protected int maxOrder;
+
+ /**
+ * Number of solutes SOLVED by THIS solver
+ */
+ protected int nSolute;
+
+ /**
+ *
+ */
+// protected int nReaction;
+
+ /**
+ * Number of times to relax the coarsest grid. Set in the protocol file.
+ */
+ protected int nCoarseStep;
+
+ /**
+ * Number of V-cycles to perform during each time step. Set in the
+ * protocol file.
+ */
+ protected int vCycles;
+
+ /**
+ * Number of times to relax each multigrid during the downward stroke of a
+ * V-cycle. Set in the protocol file.
+ */
+ protected int nPreSteps;
+
+ /**
+ * Number of times to relax each multigrid during the upward stroke of a
+ * V-cycle. Set in the protocol file.
+ */
+ protected int nPostSteps;
+
+ /**
+ *
+ */
+ @Override
+ public void init(Domain domain)
+ {
+ super.init(domain);
+
+ nCoarseStep = 500;
+ vCycles = 5;
+ nPreSteps = 100;
+ nPostSteps = 100;
+
+ /* TODO get solutes */
+ _soluteList = null;
+ // Create the table of solute grids
+ nSolute = _soluteList.length;
+ _solute = new MultigridSolute[nSolute];
+ allSolute = new SoluteGrid[nSolute];
+// allReac = new SoluteGrid[nSolute];
+ allDiffReac = new SoluteGrid[nSolute];
+
+ _bLayer = new MultigridSolute(_soluteList[0], "boundary layer");
+ _diffusivity =
+ new MultigridSolute(_soluteList[0], "relative diffusivity");
+
+ Double sBulk;
+ for (int i = 0; i < nSolute; i++)
+ {
+ if (_soluteIndex.contains(i))
+ {
+ sBulk = 0.0; // initial value
+ _solute[i] = new MultigridSolute(_soluteList[i],
+ _diffusivity, _bLayer, sBulk);
+ }
+ else
+ _solute[i] = null;
+ }
+ /* From this moment, nSolute is the number of solutes SOLVED by THIS
+ * solver.
+ */
+ nSolute = _soluteIndex.size();
+// nReaction = _reactions.size();
+ maxOrder = _solute[_soluteIndex.get(0)]._conc.length;
+
+ // NOTE idyno 2 reaction handling
+ // Initialize array of reactive biomasses.
+// _biomass = new MultigridSolute[nReaction];
+// for (int i = 0; i < nReaction; i++)
+// {
+// _biomass[i] = new MultigridSolute(_soluteList[0],
+// _reactions.get(i).reactionName);
+// _biomass[i].resetMultigridCopies(0.0);
+// }
+ }
+
+ @Override
+ public void initializeConcentrationFields()
+ {
+ minimalTimeStep = 0.1*Idynomics.simulator.timer.getTimeStepSize();
+
+ // Refresh, then insert, the boundary layer and the diffusivity grid.
+ // NOTE not using Biofilm grids
+// myDomain.refreshBioFilmGrids();
+
+ // TODO eh?
+ _bLayer.setFinest(myDomain.getBoundaryLayer());
+ _bLayer.restrictToCoarsest();
+
+ // TODO this should be per solute no?
+ _diffusivity.setFinest(myDomain.getDiffusivity());
+ _diffusivity.restrictToCoarsest();
+
+ /* TODO we don't need to prepare anything here for the idyno 2
+ implementation do we? */
+ // Prepare a soluteGrid with catalyst CONCENTRATION.
+// for (int i = 0; i<_biomass.length; i++)
+// {
+// _biomass[i].resetFinest(0.0);
+// _reactions.get(i).fitAgentMassOnGrid(_biomass[i].getFinest());
+// _biomass[i].restrictToCoarsest();
+// }
+
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].readBulk();
+ /*
+ LogFile.writeLogAlways("Solver_multigrid.initializeConcentrationfields()");
+ LogFile.writeLogAlways("Padded range is "+_solute[0].getGrid().getMin()+
+ " to "+_solute[0].getGrid().getMax());
+ LogFile.writeLogAlways("Unpadded range is "+_solute[0].getGrid().getMinUnpadded()+
+ " to "+_solute[0].getGrid().getMaxUnpadded());
+ */
+ }
+
+ /**
+ * Solve by iterative relaxation.
+ */
+ @Override
+ public void solveDiffusionReaction()
+ {
+ Double timeToSolve = Idynomics.simulator.timer.getTimeStepSize();
+ internalIteration = 0;
+ internTimeStep = timeToSolve;
+
+ /* bvm note 13.7.09:
+ * This iterative loop is only passed through once because of the
+ * value of internTimeStep used above; we leave the loop as-is though
+ * to allow future use of iterates if needed.
+ */
+ while ( timeToSolve > 0 )
+ {
+ // Compute new equilibrium concentrations.
+ stepSolveDiffusionReaction();
+
+ // Update bulk concentration.
+ updateBulk();
+
+ // Manage iterations.
+ internalIteration += 1;
+ timeToSolve -= internTimeStep;
+ }
+
+ // Apply results on solute grids
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].applyComputation();
+
+ }
+
+ /**
+ * One step of the solver
+ */
+ public void stepSolveDiffusionReaction()
+ {
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].resetMultigridCopies();
+
+ // Solve chemical concentrations on coarsest grid.
+ solveCoarsest();
+
+ // Nested iteration loop.
+ for (int outer = 1; outer < maxOrder; outer++)
+ {
+ order = outer;
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].initLoop(order);
+
+ // V-cycle loop.
+ for (int v = 0; v < vCycles; v++)
+ {
+ // Downward stroke of V.
+ while ( order > 0 )
+ {
+ // Pre-smoothing.
+ relax(nPreSteps);
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].downward1(order, outer);
+
+ updateReacRateAndDiffRate(order-1);
+
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].downward2(order, outer);
+
+ // Reduce grid value _g for good.
+ order--;
+ }
+
+ // Bottom of V.
+ solveCoarsest();
+
+ // Upward stroke of V.
+ while ( order < outer )
+ {
+ order++;
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].upward(order);
+
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].truncateConcToZero(order);
+
+ // Post-smoothing.
+ relax(nPostSteps);
+ }
+
+ /* Break the V-cycles if remaining error is dominated
+ * by local truncation error (see p. 884 of Numerical Recipes)
+ */
+ boolean breakVCycle = true;
+
+ updateReacRateAndDiffRate(order);
+ for (int iSolute : _soluteIndex)
+ breakVCycle &= _solute[iSolute].breakVCycle(order, v);
+
+ if (breakVCycle)
+ break;
+ }
+ }
+ }
+
+ /**
+ * \brief Update concentration in the reactor.
+ */
+ public void updateBulk()
+ {
+ /* Update reaction rates.
+ * This yields solute change rates in fg.L-1.hr-1
+ */
+ updateReacRateAndDiffRate(maxOrder-1);
+
+ // TODO update boundaries?
+ // Find the connected bulks and agars and update their concentration.
+// for (AllBC aBC : myDomain.getAllBoundaries())
+// {
+// if ( aBC instanceof ConnectedBoundary )
+// {
+// ((ConnectedBoundary) aBC).
+// updateBulk(allSolute, allReac, internTimeStep);
+// }
+// if ( aBC instanceof BoundaryAgar )
+// {
+// ((BoundaryAgar) aBC).
+// updateAgar(allSolute, allReac, internTimeStep);
+// }
+// }
+
+ // Refresh the bulk concentration of the multigrids.
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].readBulk();
+ }
+
+ /**
+ * Solve the coarsest grid by relaxation Coarse grid is initialised to
+ * bulk concentration.
+ */
+ public void solveCoarsest()
+ {
+ order = 0;
+ // Reset coarsest grid to bulk concentration.
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].setSoluteGridToBulk(order);
+
+ // Relax NSOLVE times.
+ relax(nCoarseStep);
+ }
+
+ /**
+ * Apply nIter relaxations to the grid at the current resolution.
+ *
+ * @param nIter
+ */
+ public void relax(int nIter)
+ {
+ for (int j = 0; j < nIter; j++)
+ {
+ updateReacRateAndDiffRate(order);
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].relax(order);
+ }
+ }
+
+ /**
+ * Call all the agents and read their uptake-rate for the current
+ * concentration.
+ *
+ * @param resOrder
+ */
+ public void updateReacRateAndDiffRate(int resOrder)
+ {
+ // Reset rates and derivative rates grids.
+ for (int iSolute : _soluteIndex)
+ {
+ _solute[iSolute].resetReaction(resOrder);
+ allSolute[iSolute] = _solute[iSolute]._conc[resOrder];
+
+ // TODO reactions
+// allReac[iSolute] = _solute[iSolute]._reac[resOrder];
+ allDiffReac[iSolute] = _solute[iSolute]._diffReac[resOrder];
+ }
+
+ // TODO agent and environment reaction rate
+// // Calls the agents of the guild and sums their uptake-rate
+// for (int iReac = 0; iReac<_reactions.size(); iReac++)
+// _reactions.get(iReac).applyReaction(allSolute, allReac,
+// allDiffReac, _biomass[iReac]._conc[resOrder]);
+ }
+
+}
diff --git a/src/utility/ExtraMath.java b/src/utility/ExtraMath.java
index 8765e03b6..25c9696ff 100644
--- a/src/utility/ExtraMath.java
+++ b/src/utility/ExtraMath.java
@@ -241,7 +241,7 @@ public static double floorMod(double dividend, double divisor)
* @param x The double to take the logarithm of.
* @return double value of the logarithm (base 2) of x.
*/
- public static final double log2(double x)
+ public static final Double log2(double x)
{
return StrictMath.log(x) / StrictMath.log(2.0);
}
From 9c144f5f17fd88d3dd4d2002f0c18aea676d87c6 Mon Sep 17 00:00:00 2001
From: baseendje
Date: Thu, 3 Dec 2020 23:17:20 +0100
Subject: [PATCH 16/67] Updated outdated comments, including intelliJ files
---
.idea/.gitignore | 3 +
.idea/codeStyles/Project.xml | 7 +
.idea/codeStyles/codeStyleConfig.xml | 5 +
.idea/compiler.xml | 8 ++
.idea/misc.xml | 6 +
.idea/modules.xml | 8 ++
.idea/vcs.xml | 6 +
iDynoMiCS-2.iml | 180 ++++++++++++++++++++++++++
src/solver/mgFas/DiffusionSolver.java | 10 +-
src/solver/mgFas/Domain.java | 6 +-
10 files changed, 227 insertions(+), 12 deletions(-)
create mode 100644 .idea/.gitignore
create mode 100644 .idea/codeStyles/Project.xml
create mode 100644 .idea/codeStyles/codeStyleConfig.xml
create mode 100644 .idea/compiler.xml
create mode 100644 .idea/misc.xml
create mode 100644 .idea/modules.xml
create mode 100644 .idea/vcs.xml
create mode 100644 iDynoMiCS-2.iml
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 000000000..26d33521a
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 000000000..919ce1f1f
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 000000000..a55e7a179
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 000000000..c8bee71d8
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 000000000..44ae3bdbc
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 000000000..28c2a1165
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000..35eb1ddfb
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/iDynoMiCS-2.iml b/iDynoMiCS-2.iml
new file mode 100644
index 000000000..cf9899028
--- /dev/null
+++ b/iDynoMiCS-2.iml
@@ -0,0 +1,180 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/solver/mgFas/DiffusionSolver.java b/src/solver/mgFas/DiffusionSolver.java
index a939636ea..a83db964a 100644
--- a/src/solver/mgFas/DiffusionSolver.java
+++ b/src/solver/mgFas/DiffusionSolver.java
@@ -28,8 +28,8 @@
* This class is a component class of iDynoMiCS, released under the CECIL
* license. Please see www.idynomics.bham.ac.uk for more information.
*
- * @version 1.2
- * @author Andreas Dötsch (andreas.doetsch@helmholtz-hzi.de), Helmholtz Centre
+ * @version 1.2
+ * @author Andreas Dötsch (andreas.doetsch@helmholtz-hzi.de), Helmholtz Centre
* for Infection Research (Germany)
* @author Laurent Lardon (lardonl@supagro.inra.fr), INRA, France
*/
@@ -85,11 +85,7 @@ public abstract class DiffusionSolver
*
* This method takes a solver specification from the XML file (as a set of
* XML tags) and initialises a solver object.
- *
- * @param aSim The simulation object used to simulate the conditions
- * specified in the protocol file.
- * @param xmlRoot The XML object containing the definition of one solver
- * in the protocol file.
+ *
*/
public void init(Domain domain)
{
diff --git a/src/solver/mgFas/Domain.java b/src/solver/mgFas/Domain.java
index 025a21aa8..a7dd4414d 100644
--- a/src/solver/mgFas/Domain.java
+++ b/src/solver/mgFas/Domain.java
@@ -161,11 +161,7 @@ public class Domain
* The definition within the computationDomain markup of the protocol file
* notes how these regions are set up. This constructor sets up each
* computation domain that is specified in the protocol file.
- *
- * @param aSim The simulation object upon which the scenario specified in
- * the protocol file is being run.
- * @param cdRoot The XML tag objects that sub-nodes of the 'Bulk' tag in
- * the protocol file.
+ *
*/
public Domain(Shape shape)
{
From 711afe60b16071f025abedc10e446372ae6f8639 Mon Sep 17 00:00:00 2001
From: Bastiaan
Date: Fri, 4 Dec 2020 12:27:38 +0100
Subject: [PATCH 17/67] Implementing PDE wrapper to run FAS multigrid +
initiation from idyno 2
---
protocol/Strep/Eco Ego.xml | 4 +-
src/processManager/ProcessDiffusion.java | 7 +-
src/processManager/library/PDEWrapper.java | 115 +++++++++++++
src/shape/Domain.java | 5 -
src/shape/Shape.java | 3 +-
.../{Solver_multigrid.java => Multigrid.java} | 162 ++++++++++++++----
src/solver/mgFas/MultigridSolute.java | 5 +-
src/solver/mgFas/SoluteGrid.java | 17 +-
.../{mgFas => temp}/DiffusionSolver.java | 70 +-------
src/solver/{mgFas => temp}/MultiGridFAS.java | 2 +-
10 files changed, 265 insertions(+), 125 deletions(-)
create mode 100644 src/processManager/library/PDEWrapper.java
delete mode 100644 src/shape/Domain.java
rename src/solver/mgFas/{Solver_multigrid.java => Multigrid.java} (67%)
rename src/solver/{mgFas => temp}/DiffusionSolver.java (70%)
rename src/solver/{mgFas => temp}/MultiGridFAS.java (99%)
diff --git a/protocol/Strep/Eco Ego.xml b/protocol/Strep/Eco Ego.xml
index 63c5657c8..d68914438 100644
--- a/protocol/Strep/Eco Ego.xml
+++ b/protocol/Strep/Eco Ego.xml
@@ -58,8 +58,8 @@
-
-
+
+
diff --git a/src/processManager/ProcessDiffusion.java b/src/processManager/ProcessDiffusion.java
index 76aa39323..37476781d 100644
--- a/src/processManager/ProcessDiffusion.java
+++ b/src/processManager/ProcessDiffusion.java
@@ -219,8 +219,7 @@ protected void postStep()
/**
* \brief Iterate over all solute grids, applying any reactions that occur
* in the environment to the grids' {@code PRODUCTIONRATE} arrays.
- *
- * @param environment The environment container of a {@code Compartment}.
+ *
*/
protected void applyEnvReactions(Collection solutes)
{
@@ -552,8 +551,8 @@ public static void scale(HashMap coordMap, double newTotal)
* distribution maps.
*
*
This prevents unneeded clutter in XML output.
- *
- * @see #setupAgentDistributionMaps()
+ *
+ * @see #setupAgentDistributionMaps(Shape)
*/
public void removeAgentDistibutionMaps()
{
diff --git a/src/processManager/library/PDEWrapper.java b/src/processManager/library/PDEWrapper.java
new file mode 100644
index 000000000..0eb60d6d3
--- /dev/null
+++ b/src/processManager/library/PDEWrapper.java
@@ -0,0 +1,115 @@
+package processManager.library;
+
+import static grid.ArrayType.*;
+
+import java.util.Collection;
+
+import org.w3c.dom.Element;
+
+import compartment.AgentContainer;
+import compartment.EnvironmentContainer;
+import grid.SpatialGrid;
+import processManager.ProcessDiffusion;
+import referenceLibrary.AspectRef;
+import solver.PDEmultigrid;
+import solver.mgFas.Domain;
+import solver.mgFas.Multigrid;
+
+/**
+ * \brief wraps and runs PDE solver
+ *
+ * @author Bastiaan Cockx @BastiaanCockx (baco@env.dtu.dk), DTU, Denmark
+ */
+public class PDEWrapper extends ProcessDiffusion
+{
+ public static String ABS_TOLERANCE = AspectRef.solverAbsTolerance;
+
+ public static String REL_TOLERANCE = AspectRef.solverRelTolerance;
+
+ /**
+ *
+ * Initiation from protocol file:
+ *
+ * TODO verify and finalise
+ */
+ public void init(Element xmlElem, EnvironmentContainer environment,
+ AgentContainer agents, String compartmentName)
+ {
+ super.init(xmlElem, environment, agents, compartmentName);
+
+ double absTol = (double) this.getOr(ABS_TOLERANCE, 1.0e-9);
+ double relTol = (double) this.getOr(REL_TOLERANCE, 1.0e-3);
+
+ int vCycles = (int) this.getOr(AspectRef.vCycles, 5);
+ int preSteps = (int) this.getOr(AspectRef.preSteps, 100);
+ int coarseSteps = (int) this.getOr(AspectRef.coarseSteps, 100);
+ int postSteps = (int) this.getOr(AspectRef.postSteps, 100);
+
+ Domain domain = new Domain(environment.getShape());
+ Multigrid multigrid = new Multigrid();
+ multigrid.init(domain, environment, vCycles, preSteps, coarseSteps, postSteps);
+
+ this._solver.setUpdater(this);
+
+ this._solver.setAbsoluteTolerance(absTol);
+
+ this._solver.setRelativeTolerance(relTol);
+
+ }
+
+ /* ***********************************************************************
+ * STEPPING
+ * **********************************************************************/
+
+ @Override
+ protected void internalStep()
+ {
+ /*
+ * Do the generic set up and solving.
+ */
+ super.internalStep();
+
+ for ( SpatialGrid var : this._environment.getSolutes() )
+ {
+ var.reset(PRODUCTIONRATE);
+ }
+ /*
+ * Estimate agent growth based on the steady-state solute
+ * concentrations.
+ */
+// for ( Agent agent : this._agents.getAllLocatedAgents() )
+// this.applyAgentGrowth(agent);
+
+ for ( SpatialGrid var : this._environment.getSolutes() )
+ {
+ double massMove = var.getTotal(PRODUCTIONRATE);
+ var.increaseWellMixedMassFlow(massMove);
+ }
+ /*
+ * Estimate the steady-state mass flows in or out of the well-mixed
+ * region, and distribute it among the relevant boundaries.
+ */
+ this._environment.distributeWellMixedFlows(this._timeStepSize);
+
+
+ /* perform final clean-up and update agents to represent updated
+ * situation. */
+ this.postStep();
+ }
+
+ /**
+ * \brief The standard PDE updater method resets the solute
+ * {@code PRODUCTIONRATE} arrays, applies the reactions, and then tells
+ * {@code Agent}s to grow.
+ *
+ * @return PDE updater method.
+ */
+ public void prestep(Collection variables, double dt)
+ {
+// for ( SpatialGrid var : variables )
+// var.newArray(PRODUCTIONRATE);
+// applyEnvReactions(variables);
+// for ( Agent agent : _agents.getAllLocatedAgents() )
+// applyAgentReactions(agent, variables);
+ }
+}
diff --git a/src/shape/Domain.java b/src/shape/Domain.java
deleted file mode 100644
index 00f8338ef..000000000
--- a/src/shape/Domain.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package shape;
-
-public interface Domain {
-
-}
diff --git a/src/shape/Shape.java b/src/shape/Shape.java
index 0a73be599..012c474bf 100644
--- a/src/shape/Shape.java
+++ b/src/shape/Shape.java
@@ -66,8 +66,7 @@
*/
// TODO remove the last three sections by incorporation into Node construction.
public abstract class Shape implements
- CanPrelaunchCheck, Instantiable, Settable, Domain
-{
+ CanPrelaunchCheck, Instantiable, Settable {
/**
* Ordered dictionary of dimensions for this shape.
* TODO switch to a Shape._dimensions a Dimension[3] paradigm
diff --git a/src/solver/mgFas/Solver_multigrid.java b/src/solver/mgFas/Multigrid.java
similarity index 67%
rename from src/solver/mgFas/Solver_multigrid.java
rename to src/solver/mgFas/Multigrid.java
index 05f80feec..ea3f80c41 100644
--- a/src/solver/mgFas/Solver_multigrid.java
+++ b/src/solver/mgFas/Multigrid.java
@@ -12,7 +12,13 @@
*/
package solver.mgFas;
+import compartment.EnvironmentContainer;
+import grid.SpatialGrid;
import idynomics.Idynomics;
+import settable.Settable;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
/**
*
@@ -22,8 +28,47 @@
* @author Brian Merkey (brim@env.dtu.dk, bvm@northwestern.edu), Department of
* Engineering Sciences and Applied Mathematics, Northwestern University (USA)
*/
-public class Solver_multigrid extends DiffusionSolver
+public class Multigrid
{
+ /**
+ * A name assigned to this solver. Specified in the XML protocol file.
+ */
+ public String solverName;
+
+ /**
+ * The position of this solver in the simulation dictionary.
+ */
+ public int solverIndex;
+
+ /**
+ * The computational domain that this solver is associated with. Specified
+ * in the XML protocol file.
+ */
+ public Domain myDomain;
+
+ /**
+ * Local copy of the array of solute grids - one for each solute specified
+ * in the simulation protocol file. Taken from simulator object.
+ */
+ protected LinkedList _soluteList;
+
+ /**
+ * List of solutes that are used by THIS solver.
+ */
+ protected ArrayList _soluteIndex = new ArrayList();
+
+ protected Double internTimeStep;
+
+ protected Double minimalTimeStep;
+
+ protected int internalIteration;
+
+ /**
+ * Boolean flag that determines whether this solver will actually be used.
+ * Specified in XML protocol file.
+ */
+ protected Boolean _active = false;
+
protected MultigridSolute _bLayer;
protected MultigridSolute _diffusivity;
@@ -45,7 +90,7 @@ public class Solver_multigrid extends DiffusionSolver
/**
* Number of solutes SOLVED by THIS solver
*/
- protected int nSolute;
+ protected int nSolute;
/**
*
@@ -55,73 +100,102 @@ public class Solver_multigrid extends DiffusionSolver
/**
* Number of times to relax the coarsest grid. Set in the protocol file.
*/
- protected int nCoarseStep;
+ protected int nCoarseStep;
/**
* Number of V-cycles to perform during each time step. Set in the
* protocol file.
*/
- protected int vCycles;
+ protected int _vCycles;
/**
* Number of times to relax each multigrid during the downward stroke of a
* V-cycle. Set in the protocol file.
*/
- protected int nPreSteps;
+ protected int nPreSteps;
/**
* Number of times to relax each multigrid during the upward stroke of a
* V-cycle. Set in the protocol file.
*/
- protected int nPostSteps;
+ protected int nPostSteps;
/**
*
*/
- @Override
- public void init(Domain domain)
+ public void init(Domain domain, EnvironmentContainer environment,
+ int vCycles, int preSteps, int coarseSteps, int postSteps)
{
- super.init(domain);
-
- nCoarseStep = 500;
- vCycles = 5;
- nPreSteps = 100;
- nPostSteps = 100;
+ /* Get the computational domain that this solver is associated with. */
+ myDomain = domain;
+
+ /* Reference all the solutes declared in this system. */
+ _soluteList = new LinkedList();
+
+ /* TODO paradigm for if we only want to solve for a subset of solutes
+ * TODO did iDyno 1 store other things in the solute list? It seems
+ * that there are multiple lists all representing solutes..
+ */
+ for ( SpatialGrid s : environment.getSolutes() )
+ _soluteList.add( new SoluteGrid(domain, s.getName(), s, null ));
+
+ /* Now for each solver, reactions are specified. Add these reactions
+ * and list the solutes that these modify.
+ */
+
+ // TODO handle idyno 2 reactions
+
+// for (String aReacName : xmlRoot.getChildrenNames("reaction"))
+// addReactionWithSolutes(aSim.getReaction(aReacName));
- /* TODO get solutes */
- _soluteList = null;
+ nCoarseStep = coarseSteps;
+ _vCycles = vCycles;
+ nPreSteps = preSteps;
+ nPostSteps = postSteps;
+
// Create the table of solute grids
- nSolute = _soluteList.length;
+ nSolute = _soluteList.size();
_solute = new MultigridSolute[nSolute];
allSolute = new SoluteGrid[nSolute];
// allReac = new SoluteGrid[nSolute];
allDiffReac = new SoluteGrid[nSolute];
-
- _bLayer = new MultigridSolute(_soluteList[0], "boundary layer");
+
+ /* TODO both soluteList entry 0, eh? */
+ _bLayer = new MultigridSolute(_soluteList.get(0), "boundary layer");
_diffusivity =
- new MultigridSolute(_soluteList[0], "relative diffusivity");
+ new MultigridSolute(_soluteList.get(0), "relative diffusivity");
Double sBulk;
for (int i = 0; i < nSolute; i++)
{
- if (_soluteIndex.contains(i))
- {
+// if (_soluteIndex.contains(i))
+// {
sBulk = 0.0; // initial value
- _solute[i] = new MultigridSolute(_soluteList[i],
+ _solute[i] = new MultigridSolute(_soluteList.get(i),
_diffusivity, _bLayer, sBulk);
- }
- else
- _solute[i] = null;
+// }
+// else
+// _solute[i] = null;
}
+
/* From this moment, nSolute is the number of solutes SOLVED by THIS
* solver.
+ *
+ * TODO aha! this is actually useful so we may set different tolerances
+ * for low vs high concentration solutes, implement..
*/
+
nSolute = _soluteIndex.size();
// nReaction = _reactions.size();
- maxOrder = _solute[_soluteIndex.get(0)]._conc.length;
+ maxOrder = _solute[ _soluteIndex.get(0) ]._conc.length;
- // NOTE idyno 2 reaction handling
- // Initialize array of reactive biomasses.
+ /* TODO idyno 2 reaction handling
+ * TODO we do want a biomass grid to determine diffusivity regimes but
+ * we don't want them for their reactions as this will be handled the
+ * new way.
+ *
+ * Initialize array of reactive biomasses.
+ */
// _biomass = new MultigridSolute[nReaction];
// for (int i = 0; i < nReaction; i++)
// {
@@ -130,18 +204,27 @@ public void init(Domain domain)
// _biomass[i].resetMultigridCopies(0.0);
// }
}
-
- @Override
+
+ /**
+ * \brief Create the solver, initialise the concentration fields, and
+ * solve the diffusion reaction equations.
+ */
+ public void initAndSolve()
+ {
+ initializeConcentrationFields();
+ solveDiffusionReaction();
+ }
+
public void initializeConcentrationFields()
- {
+ {
minimalTimeStep = 0.1*Idynomics.simulator.timer.getTimeStepSize();
// Refresh, then insert, the boundary layer and the diffusivity grid.
// NOTE not using Biofilm grids
// myDomain.refreshBioFilmGrids();
- // TODO eh?
- _bLayer.setFinest(myDomain.getBoundaryLayer());
+ // TODO this is the region in which diffusion is solved?
+ _bLayer.setFinest( myDomain.getBoundaryLayer() );
_bLayer.restrictToCoarsest();
// TODO this should be per solute no?
@@ -149,7 +232,7 @@ public void initializeConcentrationFields()
_diffusivity.restrictToCoarsest();
/* TODO we don't need to prepare anything here for the idyno 2
- implementation do we? */
+ * implementation do we? */
// Prepare a soluteGrid with catalyst CONCENTRATION.
// for (int i = 0; i<_biomass.length; i++)
// {
@@ -172,10 +255,9 @@ public void initializeConcentrationFields()
/**
* Solve by iterative relaxation.
*/
- @Override
public void solveDiffusionReaction()
{
- Double timeToSolve = Idynomics.simulator.timer.getTimeStepSize();
+ Double timeToSolve = Idynomics.simulator.timer.getTimeStepSize();
internalIteration = 0;
internTimeStep = timeToSolve;
@@ -214,6 +296,8 @@ public void stepSolveDiffusionReaction()
// Solve chemical concentrations on coarsest grid.
solveCoarsest();
+ /* TODO order / outer representing finer and coarse grid for
+ * the active V-cycle. */
// Nested iteration loop.
for (int outer = 1; outer < maxOrder; outer++)
{
@@ -222,7 +306,7 @@ public void stepSolveDiffusionReaction()
_solute[iSolute].initLoop(order);
// V-cycle loop.
- for (int v = 0; v < vCycles; v++)
+ for (int v = 0; v < _vCycles; v++)
{
// Downward stroke of V.
while ( order > 0 )
@@ -275,6 +359,8 @@ public void stepSolveDiffusionReaction()
/**
* \brief Update concentration in the reactor.
+ *
+ * TODO boundaries update
*/
public void updateBulk()
{
diff --git a/src/solver/mgFas/MultigridSolute.java b/src/solver/mgFas/MultigridSolute.java
index 3cc58b3aa..9d5870738 100644
--- a/src/solver/mgFas/MultigridSolute.java
+++ b/src/solver/mgFas/MultigridSolute.java
@@ -62,6 +62,8 @@ public class MultigridSolute
/**
* Concentration of this solute.
+ *
+ * Grids stored from finest [0] to coarsest [length]
*/
public SoluteGrid[] _conc;
@@ -481,7 +483,8 @@ private void computeResidual(SoluteGrid[] res, int order)
int nI = res[order].getGridSizeI();
int nJ = res[order].getGridSizeJ();
int nK = res[order].getGridSizeK();
-
+
+ /* TODO I haven't yet got a grasp of this reference system / index */
Double h = _referenceSystemSide/referenceIndex(nI,nJ,nK);
Double h2i = 0.5f/(h*h);
Double lop; // temporary variable for L-operator
diff --git a/src/solver/mgFas/SoluteGrid.java b/src/solver/mgFas/SoluteGrid.java
index a1f7c2144..0e9286610 100644
--- a/src/solver/mgFas/SoluteGrid.java
+++ b/src/solver/mgFas/SoluteGrid.java
@@ -14,7 +14,6 @@
import grid.ArrayType;
import grid.SpatialGrid;
import settable.Settable;
-import shape.Domain;
import shape.Shape;
/**
@@ -70,12 +69,8 @@ public class SoluteGrid extends SolverGrid
* createSolutes (in the Simulator class) to create the grids for each
* solute. Once created, the grid is populated with the initial
* concentration value of this solute.
- *
- * @param aSim The simulator object in which the conditions specified in
- * the protocol file are being created.
- * @param xmlRoot The solute XML element being processed.
*/
- public SoluteGrid(Shape shape, String name, SpatialGrid grid, Settable parent)
+ public SoluteGrid(Domain domain, String name, SpatialGrid grid, Settable parent)
{
/*
* Name the grid
@@ -90,7 +85,7 @@ public SoluteGrid(Shape shape, String name, SpatialGrid grid, Settable parent)
* Get the computation domain in which this solute exists and store
* locally.
*/
- _domain = shape;
+ _domain = domain;
/*
* Now to set the resolution and create the grid. First check whether
* a specific resolution has been set for this grid.
@@ -221,7 +216,7 @@ public void useExternalSoluteGrid(SoluteGrid aSolG)
*/
public void useDomaingrid()
{
- double[] lengths = ((Shape) _domain).getRealLengths();
+ double[] lengths = _domain.getShape().getRealLengths();
_reso = getRes();
_nI = (int) Math.ceil(lengths[0]/_reso[0]);
@@ -232,9 +227,9 @@ public void useDomaingrid()
public double[] getRes()
{
return new double[] {
- ((Shape) _domain).getResolutionCalculator(null, 0).getResolution(),
- ((Shape) _domain).getResolutionCalculator(null, 1).getResolution(),
- ((Shape) _domain).getResolutionCalculator(null, 2).getResolution() };
+ _domain.getShape().getResolutionCalculator(null, 0).getResolution(),
+ _domain.getShape().getResolutionCalculator(null, 1).getResolution(),
+ _domain.getShape().getResolutionCalculator(null, 2).getResolution() };
}
/*************************************************************************
diff --git a/src/solver/mgFas/DiffusionSolver.java b/src/solver/temp/DiffusionSolver.java
similarity index 70%
rename from src/solver/mgFas/DiffusionSolver.java
rename to src/solver/temp/DiffusionSolver.java
index a939636ea..c2e6f058e 100644
--- a/src/solver/mgFas/DiffusionSolver.java
+++ b/src/solver/temp/DiffusionSolver.java
@@ -10,7 +10,9 @@
* terms of the CeCILL license as circulated by CEA, CNRS and INRIA at the
* following URL "http://www.cecill.info".
*/
-package solver.mgFas;
+package solver.temp;
+
+import solver.mgFas.Domain;
import java.util.*;
@@ -28,51 +30,14 @@
* This class is a component class of iDynoMiCS, released under the CECIL
* license. Please see www.idynomics.bham.ac.uk for more information.
*
- * @version 1.2
- * @author Andreas Dötsch (andreas.doetsch@helmholtz-hzi.de), Helmholtz Centre
+ * @version 1.2
+ * @author Andreas Dötsch (andreas.doetsch@helmholtz-hzi.de), Helmholtz Centre
* for Infection Research (Germany)
* @author Laurent Lardon (lardonl@supagro.inra.fr), INRA, France
*/
public abstract class DiffusionSolver
{
- /**
- * A name assigned to this solver. Specified in the XML protocol file.
- */
- public String solverName;
-
- /**
- * The position of this solver in the simulation dictionary.
- */
- public int solverIndex;
-
- /**
- * The computational domain that this solver is associated with. Specified
- * in the XML protocol file.
- */
- public Domain myDomain;
-
- /**
- * Local copy of the array of solute grids - one for each solute specified
- * in the simulation protocol file. Taken from simulator object.
- */
- protected SoluteGrid[] _soluteList;
-
- /**
- * List of solutes that are used by THIS solver.
- */
- protected ArrayList _soluteIndex = new ArrayList();
-
- protected Double internTimeStep;
-
- protected Double minimalTimeStep;
-
- protected int internalIteration;
-
- /**
- * Boolean flag that determines whether this solver will actually be used.
- * Specified in XML protocol file.
- */
- protected Boolean _active = false;
+
/*************************************************************************
@@ -85,29 +50,12 @@ public abstract class DiffusionSolver
*
* This method takes a solver specification from the XML file (as a set of
* XML tags) and initialises a solver object.
- *
- * @param aSim The simulation object used to simulate the conditions
- * specified in the protocol file.
- * @param xmlRoot The XML object containing the definition of one solver
- * in the protocol file.
+ *
*/
- public void init(Domain domain)
+ public void init(Domain domain)
{
- // Get the computational domain that this solver is associated with.
- myDomain = domain;
-
- // Reference all the solutes declared in this system.
- _soluteList = null;
-
- /* Now for each solver, reactions are specified. Add these reactions
- * and list the solutes that these modify.
- */
-
- // TODO handle idyno 2 reactions
-
-// for (String aReacName : xmlRoot.getChildrenNames("reaction"))
-// addReactionWithSolutes(aSim.getReaction(aReacName));
+
}
/**
diff --git a/src/solver/mgFas/MultiGridFAS.java b/src/solver/temp/MultiGridFAS.java
similarity index 99%
rename from src/solver/mgFas/MultiGridFAS.java
rename to src/solver/temp/MultiGridFAS.java
index b361e96db..525092e21 100644
--- a/src/solver/mgFas/MultiGridFAS.java
+++ b/src/solver/temp/MultiGridFAS.java
@@ -1,4 +1,4 @@
-package solver.mgFas;
+package solver.temp;
import grid.SpatialGrid;
import linearAlgebra.Array;
From c6b9b186ea8223345e8b613ae316034b7a4a51e6 Mon Sep 17 00:00:00 2001
From: Bastiaan
Date: Fri, 4 Dec 2020 17:35:58 +0100
Subject: [PATCH 18/67] communication between iDyno 1 and 2 grid classes for
solver compatibility.
---
src/processManager/library/PDEWrapper.java | 148 ++++++++++++++++++++-
src/solver/mgFas/Multigrid.java | 29 +++-
src/solver/mgFas/SoluteGrid.java | 36 +++++
src/solver/mgFas/SolverGrid.java | 20 ++-
4 files changed, 220 insertions(+), 13 deletions(-)
diff --git a/src/processManager/library/PDEWrapper.java b/src/processManager/library/PDEWrapper.java
index 0eb60d6d3..2a14778dc 100644
--- a/src/processManager/library/PDEWrapper.java
+++ b/src/processManager/library/PDEWrapper.java
@@ -3,14 +3,23 @@
import static grid.ArrayType.*;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import agent.Agent;
import org.w3c.dom.Element;
import compartment.AgentContainer;
import compartment.EnvironmentContainer;
import grid.SpatialGrid;
import processManager.ProcessDiffusion;
+import processManager.ProcessMethods;
+import reaction.Reaction;
import referenceLibrary.AspectRef;
+import referenceLibrary.XmlRef;
+import shape.Shape;
+import shape.subvoxel.IntegerArray;
import solver.PDEmultigrid;
import solver.mgFas.Domain;
import solver.mgFas.Multigrid;
@@ -26,6 +35,7 @@ public class PDEWrapper extends ProcessDiffusion
public static String REL_TOLERANCE = AspectRef.solverRelTolerance;
+// private AgentContainer _agents;
/**
*
* Initiation from protocol file:
@@ -47,7 +57,8 @@ public void init(Element xmlElem, EnvironmentContainer environment,
Domain domain = new Domain(environment.getShape());
Multigrid multigrid = new Multigrid();
- multigrid.init(domain, environment, vCycles, preSteps, coarseSteps, postSteps);
+ multigrid.init(domain, environment, agents, this,
+ vCycles, preSteps, coarseSteps, postSteps);
this._solver.setUpdater(this);
@@ -99,6 +110,9 @@ protected void internalStep()
/**
* \brief The standard PDE updater method resets the solute
+ *
+ * TODO this method would benefit from renaming
+ *
* {@code PRODUCTIONRATE} arrays, applies the reactions, and then tells
* {@code Agent}s to grow.
*
@@ -106,10 +120,132 @@ protected void internalStep()
*/
public void prestep(Collection variables, double dt)
{
-// for ( SpatialGrid var : variables )
-// var.newArray(PRODUCTIONRATE);
-// applyEnvReactions(variables);
-// for ( Agent agent : _agents.getAllLocatedAgents() )
-// applyAgentReactions(agent, variables);
+ for ( SpatialGrid var : variables )
+ var.newArray(PRODUCTIONRATE);
+ applyEnvReactions(variables);
+ for ( Agent agent : _agents.getAllLocatedAgents() )
+ applyAgentReactions(agent, variables);
+ }
+
+ /**
+ * \brief Apply the reactions for a single agent.
+ *
+ *
Note: this method assumes that the volume distribution map
+ * of this agent has already been calculated. This is typically done just
+ * once per process manager step, rather than at every PDE solver
+ * relaxation.
+ *
+ * @param agent Agent assumed to have reactions (biomass will not be
+ * altered by this method).
+ * @param variables Collection of spatial grids assumed to be the solutes.
+ */
+ private void applyAgentReactions(
+ Agent agent, Collection variables)
+ {
+ /*
+ * Get the agent's reactions: if it has none, then there is nothing
+ * more to do.
+ */
+ @SuppressWarnings("unchecked")
+ List reactions =
+ (List) agent.getValue(XmlRef.reactions);
+ if ( reactions == null )
+ return;
+ /*
+ * Get the distribution map and scale it so that its contents sum up to
+ * one.
+ */
+ Shape shape = variables.iterator().next().getShape();
+ @SuppressWarnings("unchecked")
+ Map> mapOfMaps =
+ (Map>)
+ agent.getValue(VOLUME_DISTRIBUTION_MAP);
+
+ HashMap distributionMap = mapOfMaps.get(shape);
+ /*
+ * Get the agent biomass kinds as a map. Copy it now so that we can
+ * use this copy to store the changes.
+ */
+ Map biomass = ProcessMethods.getAgentMassMap(agent);
+ /*
+ * Now look at all the voxels this agent covers.
+ */
+ Map concns = new HashMap();
+ SpatialGrid solute;
+ double concn, productRate, volume, perVolume;
+ for ( IntegerArray coord : distributionMap.keySet() )
+ {
+ volume = shape.getVoxelVolume(coord.get());
+ perVolume = 1.0/volume;
+ for ( Reaction r : reactions )
+ {
+ /*
+ * Build the dictionary of variable values. Note that these
+ * will likely overlap with the names in the reaction
+ * stoichiometry (handled after the reaction rate), but will
+ * not always be the same. Here we are interested in those that
+ * affect the reaction, and not those that are affected by it.
+ */
+ concns.clear();
+ for ( String varName : r.getConstituentNames() )
+ {
+ solute = FindGrid(variables, varName);
+ if ( solute != null )
+ concn = solute.getValueAt(CONCN, coord.get());
+ else if ( biomass.containsKey(varName) )
+ {
+ concn = biomass.get(varName) *
+ distributionMap.get(coord) * perVolume;
+ }
+ else if ( agent.isAspect(varName) )
+ {
+ /*
+ * Check if the agent has other mass-like aspects
+ * (e.g. EPS).
+ */
+ concn = agent.getDouble(varName) *
+ distributionMap.get(coord) * perVolume;
+ }
+ else
+ {
+ // TODO safety?
+ concn = 0.0;
+ }
+ concns.put(varName, concn);
+ }
+ /*
+ * Now that we have the reaction rate, we can distribute the
+ * effects of the reaction. Note again that the names in the
+ * stoichiometry may not be the same as those in the reaction
+ * variables (although there is likely to be a large overlap).
+ */
+
+ for ( String productName : r.getReactantNames() )
+ {
+ solute = FindGrid(variables, productName);
+ if ( solute != null )
+ {
+ productRate = r.getProductionRate(concns, productName);
+ solute.addValueAt( PRODUCTIONRATE, coord.get(), volume *
+ productRate );
+ }
+ /*
+ * Unlike in a transient solver, we do not update the agent
+ * mass here.
+ */
+ }
+ }
+ }
+ /* debugging */
+// Log.out(Tier.NORMAL , " -- " +
+// this._environment.getSoluteGrid("glucose").getAverage(PRODUCTIONRATE));
+ }
+
+ private SpatialGrid FindGrid(Collection grids, String name)
+ {
+ for ( SpatialGrid grid : grids )
+ if ( grid.getName().equals(name) )
+ return grid;
+ return null;
}
}
diff --git a/src/solver/mgFas/Multigrid.java b/src/solver/mgFas/Multigrid.java
index ea3f80c41..6c9e44902 100644
--- a/src/solver/mgFas/Multigrid.java
+++ b/src/solver/mgFas/Multigrid.java
@@ -12,9 +12,13 @@
*/
package solver.mgFas;
+import compartment.AgentContainer;
import compartment.EnvironmentContainer;
+import grid.ArrayType;
import grid.SpatialGrid;
import idynomics.Idynomics;
+import processManager.ProcessDiffusion;
+import processManager.ProcessManager;
import settable.Settable;
import java.util.ArrayList;
@@ -119,16 +123,24 @@ public class Multigrid
* V-cycle. Set in the protocol file.
*/
protected int nPostSteps;
-
+
+ protected ProcessDiffusion _manager;
+
+ protected EnvironmentContainer _environment;
/**
*
*/
public void init(Domain domain, EnvironmentContainer environment,
+ AgentContainer agents, ProcessDiffusion manager,
int vCycles, int preSteps, int coarseSteps, int postSteps)
{
/* Get the computational domain that this solver is associated with. */
myDomain = domain;
+ this._manager = manager;
+
+ this._environment = environment;
+
/* Reference all the solutes declared in this system. */
_soluteList = new LinkedList();
@@ -444,6 +456,21 @@ public void updateReacRateAndDiffRate(int resOrder)
// for (int iReac = 0; iReac<_reactions.size(); iReac++)
// _reactions.get(iReac).applyReaction(allSolute, allReac,
// allDiffReac, _biomass[iReac]._conc[resOrder]);
+ /*
+ * computes uptake rate per solute ( mass*_specRate*this._soluteYield[iSolute]; )
+ * reactionGrid += uptakeRateGrid
+ * diffReactionGrid += diffUptakeRate ( no diffusion mediated by agents)
+ */
+ this._manager.prestep( this._environment.getSolutes(), 0.0 );
+
+ /* TODO flash current concentration to iDyno 2 concentration grids */
+
+ for( MultigridSolute s : _solute )
+ {
+ /* set the net production to the finest grid */
+ s._reac[ 0 ] = new SoluteGrid(this.myDomain, s.soluteName,
+ ArrayType.PRODUCTIONRATE, this._environment.getSoluteGrid( s.soluteName ) );
+ }
}
}
diff --git a/src/solver/mgFas/SoluteGrid.java b/src/solver/mgFas/SoluteGrid.java
index 0e9286610..1595b5405 100644
--- a/src/solver/mgFas/SoluteGrid.java
+++ b/src/solver/mgFas/SoluteGrid.java
@@ -112,6 +112,42 @@ public SoluteGrid(Domain domain, String name, SpatialGrid grid, Settable parent)
grid.getArray(ArrayType.CONCN);
}
+
+ public SoluteGrid(Domain domain, String name, ArrayType type, SpatialGrid grid)
+ {
+ /*
+ * Name the grid
+ */
+ gridName = name;
+ /*
+ * All solute names are stored in a simulation dictionary. Get the
+ * position of this solute in this list.
+ */
+// soluteIndex = aSim.getSoluteIndex(gridName);
+ /*
+ * Get the computation domain in which this solute exists and store
+ * locally.
+ */
+ _domain = domain;
+ /*
+ * Now to set the resolution and create the grid. First check whether
+ * a specific resolution has been set for this grid.
+ */
+ useDomaingrid();
+
+ /*
+ * Set the diffusivity - if specified in the XML file
+ */
+
+ /*
+ * copy from iDyno 2 grid.
+ */
+ this.grid = grid.getArray(type);
+ /*
+ * Now initialise the grid - setting the grid to the required size
+ */
+ initGrids();
+ }
/**
* \brief Constructor used to establish a solute grid when creating
diff --git a/src/solver/mgFas/SolverGrid.java b/src/solver/mgFas/SolverGrid.java
index 549450b7a..1e508ab49 100644
--- a/src/solver/mgFas/SolverGrid.java
+++ b/src/solver/mgFas/SolverGrid.java
@@ -135,9 +135,17 @@ public SolverGrid(int nI, int nJ, double[] resolution)
*/
protected void initGrids()
{
- _is3D = ! ( _nK == 1 );
- grid = Array.array(_nI+2, _nJ+2, _nK+2, 0.0);
-
+ if( grid == null ) {
+ grid = Array.array(_nI + 2, _nJ + 2, _nK + 2, 0.0);
+ }
+ else
+ {
+ /* if we already flashed the grid in set I, J, K, accordingly. */
+ _nI = grid.length;
+ _nJ = grid[0].length;
+ _nK = grid[0][0].length;
+ }
+ _is3D = !(_nK == 1);
}
/**
@@ -517,7 +525,7 @@ public double[] getGradient2D(double[] cC)
* \brief Return the value on the padded grid at a given position
* (the coordinates are NOT corrected).
*
- * @param dV DiscreteVector containing the location of the grid
+ * @param dc DiscreteVector containing the location of the grid
* whose value should be returned.
* @return The double value at that location.
*/
@@ -769,8 +777,8 @@ public Double getGridLength(int axeCode)
return _nJ*_reso[1];
case 3:
return _nK*_reso[2];
- default:
- return 0.0;
+ default:
+ return 0.0;
}
}
From 50c3b8b66efaf38c2435f6a1d8d55dbb71b91979 Mon Sep 17 00:00:00 2001
From: baseendje
Date: Mon, 7 Dec 2020 19:38:36 +0100
Subject: [PATCH 19/67] First set of multigrid matrices transfered + test
protocol
---
protocol/Strep/Eco Ego.xml | 4 +-
protocol/testing/Solver test.xml | 159 +++++++++++++++++++++
src/processManager/library/PDEWrapper.java | 33 ++++-
src/referenceLibrary/ClassRef.java | 7 +
src/solver/mgFas/Multigrid.java | 1 +
5 files changed, 198 insertions(+), 6 deletions(-)
create mode 100644 protocol/testing/Solver test.xml
diff --git a/protocol/Strep/Eco Ego.xml b/protocol/Strep/Eco Ego.xml
index d68914438..be0f0bbb8 100644
--- a/protocol/Strep/Eco Ego.xml
+++ b/protocol/Strep/Eco Ego.xml
@@ -58,7 +58,7 @@
-
+
@@ -143,7 +143,7 @@
-
+
diff --git a/protocol/testing/Solver test.xml b/protocol/testing/Solver test.xml
new file mode 100644
index 000000000..2188e440e
--- /dev/null
+++ b/protocol/testing/Solver test.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/processManager/library/PDEWrapper.java b/src/processManager/library/PDEWrapper.java
index 2a14778dc..64978ed74 100644
--- a/src/processManager/library/PDEWrapper.java
+++ b/src/processManager/library/PDEWrapper.java
@@ -20,9 +20,11 @@
import referenceLibrary.XmlRef;
import shape.Shape;
import shape.subvoxel.IntegerArray;
+import solver.PDEexplicit;
import solver.PDEmultigrid;
import solver.mgFas.Domain;
import solver.mgFas.Multigrid;
+import utility.Helper;
/**
* \brief wraps and runs PDE solver
@@ -55,16 +57,34 @@ public void init(Element xmlElem, EnvironmentContainer environment,
int coarseSteps = (int) this.getOr(AspectRef.coarseSteps, 100);
int postSteps = (int) this.getOr(AspectRef.postSteps, 100);
+ /* TODO initial diffusivity */
+
+ /* gets specific solutes from process manager aspect registry if they
+ * are defined, if not, solve for all solutes.
+ */
+ this._soluteNames = (String[]) this.getOr(SOLUTES,
+ Helper.collectionToArray(this._environment.getSoluteNames()));
+ /*
+ * Set up the relevant arrays in each of our solute grids: diffusivity
+ * & well-mixed need only be done once each process manager time step,
+ * but production rate must be reset every time the PDE updater method
+ * is called.
+ */
+ for ( String soluteName : this._soluteNames )
+ {
+ SpatialGrid solute = this._environment.getSoluteGrid(soluteName);
+ solute.updateDiffusivity(this._environment, this._agents);
+ }
+
Domain domain = new Domain(environment.getShape());
Multigrid multigrid = new Multigrid();
multigrid.init(domain, environment, agents, this,
vCycles, preSteps, coarseSteps, postSteps);
- this._solver.setUpdater(this);
+ super.init(xmlElem, environment, agents, compartmentName);
- this._solver.setAbsoluteTolerance(absTol);
+ // TODO Let the user choose which ODEsolver to use.
- this._solver.setRelativeTolerance(relTol);
}
@@ -78,7 +98,9 @@ protected void internalStep()
/*
* Do the generic set up and solving.
*/
- super.internalStep();
+// super.internalStep();
+
+ prestep(this._environment.getSolutes(), 0.0);
for ( SpatialGrid var : this._environment.getSolutes() )
{
@@ -123,6 +145,9 @@ public void prestep(Collection variables, double dt)
for ( SpatialGrid var : variables )
var.newArray(PRODUCTIONRATE);
applyEnvReactions(variables);
+
+ setupAgentDistributionMaps(this._agents.getShape());
+
for ( Agent agent : _agents.getAllLocatedAgents() )
applyAgentReactions(agent, variables);
}
diff --git a/src/referenceLibrary/ClassRef.java b/src/referenceLibrary/ClassRef.java
index 51a9aff71..056aca07e 100644
--- a/src/referenceLibrary/ClassRef.java
+++ b/src/referenceLibrary/ClassRef.java
@@ -378,6 +378,13 @@ public static String path(String name)
*/
public final static String solveDiffusionSteadyState =
processManager.library.SolveDiffusionSteadyState.class.getName();
+
+ /**
+ * solve steady state diffusion process manager
+ */
+ public final static String PDEWrapper =
+ processManager.library.PDEWrapper.class.getName();
+
/**
* solve chemostat process manager
*/
diff --git a/src/solver/mgFas/Multigrid.java b/src/solver/mgFas/Multigrid.java
index 6c9e44902..8b0fa0ecc 100644
--- a/src/solver/mgFas/Multigrid.java
+++ b/src/solver/mgFas/Multigrid.java
@@ -185,6 +185,7 @@ public void init(Domain domain, EnvironmentContainer environment,
sBulk = 0.0; // initial value
_solute[i] = new MultigridSolute(_soluteList.get(i),
_diffusivity, _bLayer, sBulk);
+ _soluteIndex.add(i); //TODO figure out how solute index was used, adding it here to help program run
// }
// else
// _solute[i] = null;
From be1a88d01f5fcc80338a5fb1b7d0c8a4ee81fbaa Mon Sep 17 00:00:00 2001
From: baseendje
Date: Wed, 9 Dec 2020 19:02:41 +0100
Subject: [PATCH 20/67] Further work on implementing mgFAS
---
protocol/testing/Solver test.xml | 22 ++++----
src/processManager/library/PDEWrapper.java | 7 ++-
src/solver/mgFas/Domain.java | 66 +++++++++++-----------
src/solver/mgFas/Multigrid.java | 19 ++++---
src/solver/mgFas/MultigridSolute.java | 7 +--
src/solver/mgFas/SoluteGrid.java | 23 ++++----
src/solver/mgFas/SolverGrid.java | 59 ++++++++-----------
7 files changed, 100 insertions(+), 103 deletions(-)
diff --git a/protocol/testing/Solver test.xml b/protocol/testing/Solver test.xml
index 2188e440e..85147c64a 100644
--- a/protocol/testing/Solver test.xml
+++ b/protocol/testing/Solver test.xml
@@ -82,11 +82,11 @@
-
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Present: Bastiaan Cockx, Stefan Lang
-
-
non-cartesian shapes
-
-
Stefan has been investigating the maximum mini time step for the pde solver for different compartment shapes. non-cartesian shapes require much finer pde mini timesteps, resulting in far longer evaluation times (see figure).
-
-
-
-
-
-
-
Agents in non-cartesian shapes are still not behaving properly, Bas will look into this after Stefan’s pull request has been merged.
-
The shape iterator can not be used on multiple threads simultaniously (not thread safe). Therefor the iterator cannot be used to render the shape or solute grids in the openGL render window. Two solutions are proposed:
-
-
-
We could use an third-party library to generate the quad-strips for the compartment shape. This however would still not allow us to render solute grids.
-
We could have iterator as a seperate object, new iterators can be requested by the gl renderer to have multiple threads iterate over the grid simultaniously.
-
-
-
Bas will share the pov-ray header file used for the MEWE renders, the render settings can be used as an iDynoMiCS 2 render style for “nice” presentations and posters.
-
-
-
-
profiling
-
-
Bas has investigated the iDynoMiCS memory usage. Memory usage seems to be correlated more with time than with domain size or agent count and iDynoMiCS 2 memory usage tends to run into gigabyte range very fast. This could indicate a lot of objects are created only for single time usage. Most used object classes are int[] and char[] outranking other classes with an order of magnitude or more.