diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 000000000..f6ee0922c
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,4 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+/idea/vcs.xml
\ No newline at end of file
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/libraries/hamcrest_core_1_3.xml b/.idea/libraries/hamcrest_core_1_3.xml
new file mode 100644
index 000000000..4b0c52c5b
--- /dev/null
+++ b/.idea/libraries/hamcrest_core_1_3.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/junit_4_13_2.xml b/.idea/libraries/junit_4_13_2.xml
new file mode 100644
index 000000000..8fc914f23
--- /dev/null
+++ b/.idea/libraries/junit_4_13_2.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ 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/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 000000000..e96534fb2
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ 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/AuthorTags.md b/AuthorTags.md
deleted file mode 100644
index 8b87cb630..000000000
--- a/AuthorTags.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# Authorship tags
-
-Put here for easy use when writing `Javadoc`.
-
-## Robert Clegg:
-```
- * @author Robert Clegg (r.j.clegg.bham.ac.uk) University of Birmingham, U.K.
-```
-
-## Bastiaan Cockx:
-```
- * @author Bastiaan Cockx @BastiaanCockx (baco@env.dtu.dk), DTU, Denmark
-```
-
-## Stefan Lang:
-```
- * @author Stefan Lang (stefan.lang@uni-jena.de)
- * Friedrich-Schiller University Jena, Germany
-```
\ No newline at end of file
diff --git a/DevelopmentMeetingNotes/2015-06-09_meetingsummary.md b/DevelopmentMeetingNotes/2015-06-09_meetingsummary.md
deleted file mode 100644
index ba3e1967c..000000000
--- a/DevelopmentMeetingNotes/2015-06-09_meetingsummary.md
+++ /dev/null
@@ -1,29 +0,0 @@
-Present: Jan-Ulrich Kreft, Robert Clegg and Bastiaan Cockx.
-
-Bugs with overlap/clones largely resolved, but difficulty integrating into iDynoMiCS
-- New cells were being placed in exactly same position, fixed by moving immediately after division
-- Would stochastic noise movement term work also? Not yet included, but wouldn't be difficult
-- Cloneable interface may cause problems, possible Bas has just misinterpreted it
-- Mass points being thrown away, then recalculated, at the beginning of each time step instead of just updating. Cheap compared to relaxation step? Bas will try updating now that it's running
-- Boundaries mostly implemented, by not cyclic
-
-Sphere-swept volume, bendable cell. Overlap between line segments?
-- Mass points stored as LinkedList
-- rest lengths stored as array of Doubles
-
-How exactly should iDynoMiCS deal with rod-shaped cells
-- Trigger volume for division? Change from radius? Convert at start of simulation, make clear to user.
-- Sampling voxels: find all possible voxels, sample with resolution smaller than the radius. Bas will try out method & report on how fast/accurate it is.
-- Finding neighbours within a certain distance. Scaffolding there, may be implemented easily(?)
-- Writing/reading body shapes to/from output. Data structure will become more complicated but it's unavoidable.
-Polarity of rod-shaped cells may influence motility and/or attachment
-- Branching filaments have angular torsion spring between every pair of line segments branching from a mass point
-- Cell swims along length of access, apply forces to all mass points equally? Modify velocities? Or just move the cell? Should be easy to do either
-
-iDyno2
-- Activities, reactions, species, solute info, etc contained within each compartment. Better for parallel computing. Can have in "include" line in protocol file that reads in separate file, but prints it in full in the output directory.
-- Can infer activities an agent performs by its state variables, often by their absence/presence
-- "Soft" activities that have fixed set of arguments, "hard" activities that need to be hard coded with special arguments.
-- Sporulation requires inactivation of most reactions
-- Pick and pick of activities, preferably hard coded
-- Change "mechanism" to "ProcessManager"? "ActivityManager"?
diff --git a/DevelopmentMeetingNotes/2015-06-10_meetingsummary.md b/DevelopmentMeetingNotes/2015-06-10_meetingsummary.md
deleted file mode 100644
index 9740f82ec..000000000
--- a/DevelopmentMeetingNotes/2015-06-10_meetingsummary.md
+++ /dev/null
@@ -1,74 +0,0 @@
-2015-06-16
-
-This is a short summary of the 2015-06-10 iDynoMiCS meeting at the center for computational biology in Birmingham. Present at the meeting: Jan-Ulrich Kreft, Robert Clegg and Bastiaan Cockx.
-
-iDynoMiCS
----
-
-Encountered issues
-After division agent _movement was updated, not _location. This caused problems in the mechanical relaxation because it is not able to handle cells that are in exactly the same location. (Resolved)
-In some cases object implementing the cloneable interface seem to cause issues, some sources recommend not using this interface, this needs some further investigation. (Problem resolved by avoiding cloning mass points).
-Currently mass-points are recreated before each mechanical time step to avoid problems with cloning. Now the mechanical module seems to run reliably the issues with cloneables may be resolved so this is no longer necessary. (Pending)
-
-The implementation of cyclic boundaries with the mechanical relaxation module was not yet finished. (Was pending, but is now implemented).
-
-Agent morphologies and mechanical relaxation
---
-
-'Mass'-points
-Points are currently stored as a linked list in the locatedAgent class.
-
-Rest lengths and angles for multi-point cells (rods, filaments) are also stored within the locatedAgent class however as an array of Doubles.
-
-An RTree is creating when the mechanical relaxation is initiated and updated during the relaxation. A cyclic search method was implemented so that the RTree can be used with cyclic domains.
-
-Forces and velocities:
---
-Currently only simple forces are implemented (attraction, repulsion and internal spring forces).
-Stochastic movement can be implemented as force, velocity or position. We think a change in velocity or position is probably the best approach. A change in position would achieve the aim of 'shaking' the particles a bit to avoid stalemates, where cells are caught in local minima. A change of force is in principle more correct but more difficult to tune to achieve the shake up.
-
-Small movement steps required for small particles: having small EPS particles forces us to make small timesteps so that particles don't jump through others during one timestep.
-Range of attachment force 80 nm.
-
-Rod-cells:
---
-Shape of rod cells given by sphere-swept volume, not sphere - cylinder- sphere.
-Kinks in filaments pose special issues.
-Distribution of biomass over grid
-Two options:
-- Work out overlap of bounding box/ rectangle with grid cells to determine distribution
-- Determine distribution via point sampling
-o Point sampling can be done on a cell by cell basis
-
-Conjugation
-The current conjugation method is written for coccoid type cells, the method needs to be updated to also take rod-cells into account.
-
-Excretion
-For excretion we first need to work out whether the particle needs to be excreted on the caps or on the cylinder part of the rod cell. This can be done by calculating % surface area of the caps and cylinder. The relative surface area determines the probability the excreted particle ends up on that body part. The next step is to find where on the cap or where on the cylinder the particle needs to be excreted. The caps require two random angles to determine the point of excretion. The cylinder requires one random angle and a random fraction along the length of the cylinder.
-
-Input/ output files
-Current input/ output files cannot handle complex(er) body structures. An option would be to switch to xml input/output files . However this may cause complications with some software tools.
-
-Motility
-Cell motility for rod cells can be achieved by adding/distributing a force or velocity on the points of the cell body. Rod cells swim along their body length.
-
-Branching filaments
-Branching filaments can maintain their relative position by creating torsion springs between every connected rod cell that attaches in a single point.
-
-Cell-cell attachment
-Cell membranes behave as fluids thus attached particles moving 'freely' over each other surface due to the fact there is not angular orientation of the cells is not a bug but a feature and resembles what is expected in natural systems.
-Division
-The division module for rod shaped cells is ready, however not yet implemented in iDynoMiCS.
-Polarity
-Polarity of rod shape cells needs to be taken into account; this can play an important role with motility and division.
-2D versus 3D. What to do with rod cells in 2D?
-Note that unforeseen issues may be discovered with the implementation of multi-point agent morphologies.
-
-iDynoMiCS 2.0
---
-
-Activities:
---
-Static objects managed by 'mechanisms'
-Activities hard coded as library in iDynoMiCS
-Additional activities: Signalling, chemotaxis
diff --git a/DevelopmentMeetingNotes/2015-08-28_meetingsummary.md b/DevelopmentMeetingNotes/2015-08-28_meetingsummary.md
deleted file mode 100644
index e90ac64c6..000000000
--- a/DevelopmentMeetingNotes/2015-08-28_meetingsummary.md
+++ /dev/null
@@ -1,52 +0,0 @@
-Present: Jan-Ulrich Kreft, Robert Clegg
-
-# SBML
-SBML namespace within iDyno namespace, or vice versa? Look at how BioNetGen, etc, have done it?
-
-Use Systems Biology Ontology in protocol file generator?
-
-E.g. occurring entity representation > encapsulating process > biomass production
-
-Haven't found cell division/death!
-
-SBO doesn't deal with units
-
-CellMLOntologies is only intended at the moment
-
-"Boundary conditions" have very different meaning in SBML: reactants whose values are not determined by kinetic laws (Section 7.7, p. 114). The "spatial" package uses them in the same way that we do though.
-
-"lumen" is a unit! Obviously also "mole"
-
-Careful about time units (SI is seconds)
-
-Need to cater for rational numbers as constants, initial values, etc
-
-Compartment sizes can vary, but not number of compartments
-
-Events: trigger and execution separate (may be a delay). Reassess all event triggers whenever an event is executed
-
-Need to implement discrete solver? Could be stochastic or discrete (Section 7.4, p. 107)
-
-Need to combine steady-state solver with transient (for ODEs)?
-
-Do we want to wed ourselves to the SBML way?
-If so...
-
-# New package?
-iDyno2 mark-up include SBML, or extend it?
-
-Could make an "ibm" package in SMBL, like "spatial", that could allow exchange of models.
- • spatial deals with diffusion, advection, etc
- • Ibm could deal with multiple compartments on the fly
-
-Setting spatial: required="false" makes it a chemostat simulation
-
-Setting ibm: required="false" makes it a PDE simulation
-
-Setting both to be unrequired makes it an ODE simulation
-
-
-# Jan's comments:
-Check if we can link 2 spatial compartments, as would be needed for eGut
-
-Read up on CellML
diff --git a/DevelopmentMeetingNotes/2015-11-13_meetingsummary.md b/DevelopmentMeetingNotes/2015-11-13_meetingsummary.md
deleted file mode 100644
index b6ea6f1a5..000000000
--- a/DevelopmentMeetingNotes/2015-11-13_meetingsummary.md
+++ /dev/null
@@ -1,29 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx, Stefan Lang
-
-**Bas** is making good progress on agent states
-- States as "primary" (simple values) and "secondary" (calculated from primary states)
-- No speed loss in this approach (1 million made in 200 ms)!
-Next needs to focus on
-- Agent-boundary interactions
-- Agent-grid interactions (finding the voxel that contains the agent centre is already possible)
-
-**Stefan** has nice-looking diagrams of cylindrical voxels
-- Written in MatLab, will port into Java once it's working well
-
-Next challenges are
-- Iterating through neighbour voxels of a focal voxel
-- Calculating the surface area neighbouring voxels share
-
-![Circle Voxels](CircleVoxels.png)
-
-**Rob** has ODE and PDE solvers up and running
-- So far only Dirichlet and Neumann boundaries
-- So far only explicit solver for PDEs, Rosenbrock solver for ODEs
-- So far no way of setting the domain/diffusivity to differ over a compartment
-- Compartments are able to take a total size and decide a way of dividing it up into a grid
-- Test run fine in a "Simulator" object with multiple compartments, although the compartments are not yet joined together
-
-Next challenges are
-- Cyclic boundaries for solutes
-- Implementing more complex PDE solvers
-- Implementing domain/diffusivity methods (e.g. diffusivity reduced inside biofilm)
diff --git a/DevelopmentMeetingNotes/2015-12-03_meetingsummary.md b/DevelopmentMeetingNotes/2015-12-03_meetingsummary.md
deleted file mode 100644
index e9305bcff..000000000
--- a/DevelopmentMeetingNotes/2015-12-03_meetingsummary.md
+++ /dev/null
@@ -1,16 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx, Stefan Lang
-
-**Bas** explained rebasing, merging, etc
-
-**Stefan** has CylindricalGrid and SphericalGrid working, but they need neighbour iterator and cleaning/commenting. Note: they should each extend SpatialGrid, not CartesianGrid! Resolution will become grid-specific, as it needs to be different in Cartesian vs Cylindrical, etc
-
-**Bas** has re-implemented the shoving algorithm, for comparison with iDyno1 simulations.
-He is also making good progress with the agent "states" and "events", particularly with the input & output. `dataIO.PovExport` is stable, so Rob will check, clean and comment it.
-New "ones" methods in `linearAlgebra.Vector` needs commenting
-Bas will speed up collision detection by initialising with the number of dimensions, so that the difference vector will be overwritten rather than recreated each time
-
-**Bas**'s idea: viscosity grid in environment container? This would need an updater method (constant everywhere by default)
-
-**Rob** is busy polishing the linearAlgebra package - Vector is practically done, just needs checking. He will make his own git branch to help the rest of the team, and will replace "float"s with "double"s in the RTree. MTRandom integration is probably fine, but needs checking
-
-The test classes are proving a useful way of checking that changes in one part of the code haven't broken anything anywhere else, but so far they are quite manual… Rob will look into automation, particularly of the more deterministic classes
diff --git a/DevelopmentMeetingNotes/2015-12-14_meetingsummary.md b/DevelopmentMeetingNotes/2015-12-14_meetingsummary.md
deleted file mode 100644
index 15cb9c3ec..000000000
--- a/DevelopmentMeetingNotes/2015-12-14_meetingsummary.md
+++ /dev/null
@@ -1,15 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx, Stefan Lang
-
-**Stefan** has rearranged class hierarchies of SpatialGrids as we discussed last time. He has location-coordinate mapping sorted but is still working on the neighbour iterator. He's also getting used to GitHub and will put in a pull request soon.
-
-We discussed cyclic boundaries in sections of circular/cylindrical/spherical compartments
-
-![Cyclic Corner](CyclicCorner.png)
-
-Stefan thinks that limiting the size of sections to multiples of 90 degrees would be best, which is absolutely fine with Bas and Rob.
-
-We also discussed how best to distribute cell mass over grid voxels for the purpose of performing reactions (especially important when modelling filaments that span multiple voxels). Bas would like to get the centres of voxels to put into his collision class - but if the resolution is too coarse then he would need voxels to be divided up into subvoxels for this purpose. In polar grids, most of the voxels are almost cuboid so a regular subdivision should be good enough.
-
-**Rob** is still waiting for a book to arrive before he gets the PDE stuff going properly, so has been working on tidying the linear algebra package instead.
-
-Use the word "clade" instead of "species"? It avoids confusion with the chemical use of "species". Rob also suggested "breed" as used in NetLogo.
diff --git a/DevelopmentMeetingNotes/2016-01-08_meetingsummary.md b/DevelopmentMeetingNotes/2016-01-08_meetingsummary.md
deleted file mode 100644
index 14bde4a18..000000000
--- a/DevelopmentMeetingNotes/2016-01-08_meetingsummary.md
+++ /dev/null
@@ -1,19 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx, Stefan Lang
-
-**Bas** has realised that the Species class should become a collection of shared modules - in the "classic" case there would just be one, unique module for each species. SpeciesModule seems like an appropriate name, but we can always change it later if needed.
-
-XML-able and Check-able interfaces seem like a good idea, so Rob will have a play around with them. They would make it a) easier to read and write protocol files in a consistent manner within iDynoMiCS, and b) allow a pre-launch check (as in NetLogo).
-
-Math expressions would be useful, so worth pursuing. The benefit of an in-house method is that we can make this differentiable
-
-**Rob** has started playing around with unit testing and is finding it useful (one bug in the linear algebra found already!). Using jUnit in Eclipse also shows how quickly code runs. It should become more and more powerful as we use apply it to higher-level code.
-
-**Stefan** has everything working in cylinders but not spheres. It's also quite slow but this is low priority for now. Rob will have a look at the tidiness on Monday (11th Jan) and push to a new branch of Stefan's branch so it doesn't interfere with his work.
-
-**Bas** has been using SmartGit and recommends it for rebasing
-
-`GuideForDevelopers.md` is growing steadily, and should become essential reading for anyone who wants to join the team!
-
-**Rob** and **Bas** have arranged a joint coding session on agent-grid and agent-boundary interactions next Friday (15th Jan)
-
-Once we have something running, we should change our branch structure: "master" will always work, "develop" will branch this and is only ever pushed to "master" if we're certain it works. All our development branches then branch off "develop"
diff --git a/DevelopmentMeetingNotes/2016-01-22_meetingsummary.md b/DevelopmentMeetingNotes/2016-01-22_meetingsummary.md
deleted file mode 100644
index b0b3da64d..000000000
--- a/DevelopmentMeetingNotes/2016-01-22_meetingsummary.md
+++ /dev/null
@@ -1,30 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx
-
-
-Sister papers: Jan not keen for practical purposes
-- Difficult to get reviewers to read two papers
-- Problems managing the editor
-- Can cause big delays if one needs more work than the other
-
-Rob has made the XMLable interface:
-- JUnit test case made and working
-- Careful initialisation implemented for Shapes
-
-Further work:
-- Make an init(Node) method?
-- Lists of required and optional attributes for making a protocol file within the iDyno2 GUI?
-
-Agent boundaries: what info do they need, how should they act?
-- We could do with some kind of boundary surface object for collision detection (solid boundaries) in all geometries - Rob will look into this
-- Bas has made a first attempt at cyclic boundaries in Cartesian geometry - it works but much is hard-coded that we want to be flexible
-- Periodic boundaries in non-Cartesian will need more thought - Rob will look at Bas's work in Cartesian and come up with an approach for generalising it
-- Control of cyclic responses might need to move from grids to the compartment shape. A method for finding minimum point-point distances?
-
-Bas has come up with the idea of making output to file a process manager. This would work rather nicely, but we need to do several things:
-- Check if the process manager initialisation would need to change much. Making the output folder path a public static in Simulator could solve this issue. We would need to ensure that compartment names are unique (and of acceptable format for a sub-folder name) for this to work
-- Make it possible for Simulator to create output process managers in all compartments at the same time period as a default, so that the user doesn't need to specific them all individually
-- Perhaps make process managers able to "own" other process managers, to ensure that they happen in a specified order. This may or may not be necessary
-
-Bas has managed to get agents to write their biomass to grids, but not yet got them to read from grids. This shouldn't be much trouble. At the moment the agent just uses its cell centre, as in iDyno 1
-
-Stefan and Rob have resolved a number of issues in Cylindrical and Spherical grids, and Stefan is hoping to polish them off in the near future.
diff --git a/DevelopmentMeetingNotes/2016-01-26_meetingsummary.md b/DevelopmentMeetingNotes/2016-01-26_meetingsummary.md
deleted file mode 100644
index 84571e94f..000000000
--- a/DevelopmentMeetingNotes/2016-01-26_meetingsummary.md
+++ /dev/null
@@ -1,11 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx
-
-Coords for discrete, location for continuous in GuideForDevelopers.md
-
-Shape "owns" all (continuous) geometry. Shortest distance between two points? Line segments?
-
-Modularity and customisability very much linked
-
-Hard-coded state names out of states
-
-Line-endings and encoding check as part of the pull request routine?
diff --git a/DevelopmentMeetingNotes/2016-02-05_meetingsummary.md b/DevelopmentMeetingNotes/2016-02-05_meetingsummary.md
deleted file mode 100644
index 99fc17809..000000000
--- a/DevelopmentMeetingNotes/2016-02-05_meetingsummary.md
+++ /dev/null
@@ -1,19 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx, Stefan Lang
-
-**Bas** has made great progress with the collision methods, particularly with the boundaries as the agent-agent collisions were already largely finished. This has been helped by Rob developing a Dimension class that handles cyclic dimensions in a much easier way than using boundary objects for it. This also helps unify the agent container and solute grids. The downside is that cyclic boundaries must always be parallel to one another (i.e. extremes of the same dimension) but this should satisfy 99% of potential users!
-
-**Rob** has tidied the Cartesian and cylindrical grids, but they need testing. Spherical is not done yet so Stefan will try to finish this off soon.
-
-Polar geometries: agent locations given in polar dimensions, or need converting? Should be able to keep these consistent across all of iDynoMiCS2
-
-**Bas** has also has console launch working: just type in the path to the protocol file and the simulation runs. Rob will develop the XMLable interface further soon, but needs to check Bas's XMLload class as this may do a lot of what we need already.
-
-Process managers should be allowed to access global parameters, but also overwrite these if needed. Bas can use a lot of the methods already developed for agents/species to achieve this.
-
-**Rob** has started work on the manuscript. **Stefan** will update the ODD protocol reference to the revised article
-
-**Reactions**: these need to be done. Rob's mathematical expressions package can be used for rates, but needs polishing first. It can calculate differentials of expressions, so making the numerics smoother.
-
-Since we are approaching a working, stable version, we are spending the afternoon merging all our branches into the "master" branch. We'll then make a "develop" branch off the master, and make our branches branch off this. Only fully working code in the "develop" branch will be allowed into the "master" branch
-
-This will also be an opportunity to switch default line endings from Windows to Unix. This has been the bane of Rob's life the last few weeks, so hopefully Unix endings will behave better!
diff --git a/DevelopmentMeetingNotes/2016-02-19_meetingsummary.md b/DevelopmentMeetingNotes/2016-02-19_meetingsummary.md
deleted file mode 100644
index 97a0e39aa..000000000
--- a/DevelopmentMeetingNotes/2016-02-19_meetingsummary.md
+++ /dev/null
@@ -1,28 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx, Stefan Lang
-
-**Rob** and **Bas** have managed to get the PDE solver up and running with reactions mediated by agents. These agents grow and divide accordingly. Agent biomass is distributed over all voxels that the agent covers. Bas & Rob need to fine tune this in how it deals with mini-timesteps and growth rate contributions of the different voxels.
-
-The code is also rather messy at the moment, so we'll work on tidying and documenting it. Rob needs to fix the periodic boundaries for solutes - these already work for agents.
-The PDE solver is time-dependent explicit, and Rob has plans to implement more sophisticated solvers (including steady-state), but this is a big hurdle overcome!
-
-**Stefan** has the PDE solver running in polar grids, but hasn't yet tried with agents. This will be tested in the next few days or so
-
-Surface objects and their bounding boxes make collision detection very quick
-
-A lot of the code can be initialised from an XML protocol file, and we have a few example protocols that run (including the PDE test case above). XMl handler and XMLhelper classes
-Bas has also made a central collection of standard state names
-
-Reactions are very flexible in the mathematical expressions they can take, and can be built from a simple string input. There is an agent state that also uses this capability
-
-**Bas** has generalised the AspectRegistry so that it can store states for more than just agents. This works very nicely for storing parameters of process managers. Bas will write up best practice of using this in the GuideForDevelopers.md
-
-**ResCalcFactory** is overly complicated, and doesn’t even read in from XML. Stefan and Rob will sort this out together on Tuesday
-
-**Stefan** has developed very nice visualisation of polar grids inside Java, and Bas has a process manager for writing solutes and agents together to SVG.
-
-Diffusion setters and Domain setters are written but not yet implemented.
-
-**Bas** flagged up the name "domain", defining where the solver should include for diffusion-reaction, as being rather vague. Rob suggested flipping the problem on its head and inside finding where is "well-mixed", and so where the solver should ignore.
-
-
-TreeMap for process managers in Compartment?
diff --git a/DevelopmentMeetingNotes/2016-04-15_meetingsummary.md b/DevelopmentMeetingNotes/2016-04-15_meetingsummary.md
deleted file mode 100644
index 292dca1f4..000000000
--- a/DevelopmentMeetingNotes/2016-04-15_meetingsummary.md
+++ /dev/null
@@ -1,52 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx, Jan-Ulrich Kreft, Barth Smets
-
-1. The release features of iDynoMiCS 2.0 (What must be included, what parts still need to be finished or made, which features are of lower priority and can wait until a post release patch).
- - High priorities
- * Saving model states/XML output. Need to be careful about file size (try serialisation… might be larger! Also look at compression). Already have SVG and POV exporters. Ability to change default names could be source of mistakes.
- * Loading solute grid that does not have a homogeneous concentration
- * Boundaries, especially agent methods. Specific area-type scaling factors, but clearer. Need to be in case study
- * Grid diffusivitySetter and wellmixedSetter ("alpha curve"?)
- * Initiation and behaviour/peripherals (division, cyclic boundaries, graphical output) of non-coccoid agents - prioritise rod-shaped
- * Gui simulation construction/editing
- * A lot of parts need cleaning and more extensive commenting
- - Low priorities
- * PDE solvers (ADI 1st, multigrid 2nd, etc), currently only explicit solver. Iterating over all agents a bit slow… but much better (stick with higher quality results, can use larger timesteps).
- * Agents and solute input/output in grids other than Cartesian grid
- * Expansion manager (need to think about licensing - must make source code available?)
- * Compartment manager for dynamic creation/destruction
-2. The general structure, content, story and author list of the manuscript.
- - British English - but American spelling (modelling, etc) in keywords
- - Switch to writing in Word
- - Try Mendeley for reference management
- - Statement of joint contribution for Rob & Bas
- - Corresponding authors: both Rob & Bas
- - Aim for 6,000 words and no more than 10 figures/tables
- § Half on model description
-3. The timeline towards the submission of our manuscript
- - Aim for end of May, so we can check things and have a buffer. Focus on model description
-
-
-Need to contact Stefan about whether or not to include polar stuff - could wait until a later paper with his own research topic as case study. If on this paper, would also need Stefan Schuster
-
-
-
-## Rob's tasks
-Convert manuscript to Word, put on Dropbox
-Solute boundaries
-Reading/writing spatial grids
-diffusivitySetter and wellMixedSetter?
-Restructure/clarify resolution setting
-Solidify PDE stuff: voxel-voxel fluxes
-
-## Bas's tasks
-Set up Mendeley, import citations
-Complex agent morphology - discuss with Cristian?
-XML/GUI editor - but coordinate with Rob
-Library management - e.g. ProcessManager
-Use expressions in surface-surface force functions, may want to use sine, cosine, etc!
-
-## Joint tasks
-Agent boundaries
-Units
-Writing paper
-Cleaning and commenting
diff --git a/DevelopmentMeetingNotes/2016-04-25_meetingsummary.md b/DevelopmentMeetingNotes/2016-04-25_meetingsummary.md
deleted file mode 100644
index 475b951a3..000000000
--- a/DevelopmentMeetingNotes/2016-04-25_meetingsummary.md
+++ /dev/null
@@ -1,17 +0,0 @@
-Present: Robert Clegg, Stefan Lang
-
-Moving resolution and iterators from grid to shapes
-
-Local vs global (Cartesian) coords
-
-Write unit tests
-
-Manuscript
- - Dropbox
- - Word
- - Mendeley
- - British English
- - Stefan's middle initial?
- - Stefan Schuster: affiliation, add to Dropbox?
-
-Meeting with Bas on 3rd May
diff --git a/DevelopmentMeetingNotes/2016-05-03_meetingsummary.md b/DevelopmentMeetingNotes/2016-05-03_meetingsummary.md
deleted file mode 100644
index 025d90ea8..000000000
--- a/DevelopmentMeetingNotes/2016-05-03_meetingsummary.md
+++ /dev/null
@@ -1,14 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx, Stefan Lang
-
-**Bas** has the library-as-a-subpackage implementation working, so Rob will clean up the ProcessManagers. Bas will write about it in the GuideForDevelopers
-
-**Stefan** will test the shape stuff following Rob's restructuring, and create the getNewGrid() method in Shape (currently just a TODO)
-
-**Bas** will start assigning manuscript writing roles, replace the citations in the Word file, and will add Stefan to the Mendeley group
-
-**Rob** has asked Bas to implement the Cube surface object, but as low priority: this may be useful later in the eGUT project.
-
-Some relevant things Rob has become aware of recently, that the others may be interested in:
- - The SOLID principles of object-oriented programming
- - JSON as a lightweight alternative to XML
- - The Constructor> class in Java
diff --git a/DevelopmentMeetingNotes/2016-05-16_meetingsummary.md b/DevelopmentMeetingNotes/2016-05-16_meetingsummary.md
deleted file mode 100644
index 23d53486d..000000000
--- a/DevelopmentMeetingNotes/2016-05-16_meetingsummary.md
+++ /dev/null
@@ -1,55 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx, Stefan Lang
-
-# Manuscript writing
-Figure formats: VSD (Microsoft Visual?), SVG?
-
-Where to discuss the Process Managers? Fitting into the ODD protocol. Will want to adapt the ODD protocol, not stick to it exactly.
-
-**Bas** has entered citations, switch to author-date while writing.
-Bas has assigned some roles
- - Introduction (**Bas** to organise, will need input from all authors)
- - Simulator-compartment (**Rob**)
- - Agents (**Bas**)
- - Environment (**Rob**)
- - Shape, grids, etc (**Stefan**)
- - Process overview and scheduling (**Rob**)
- - Design concepts (**Stefan** will look into these)
- * Observation (**Bas**)
- * Write about intended uses, but emphasise flexibility.
- - Initialisation, Input (**Bas**)
- - Submodels
- * Agent relaxation (**Bas**)
- * PDE solver (**Rob**)
- * ODE solver (**Rob**)
- * Boundaries/connections (**Rob**)
- - Case studies (**Bas** & **Stefan**)
- * Need to be careful about word count, maybe merge some
- - Discussion & Conclusion (**Rob** to organise, will need input from all authors)
-
-Sections 4.2, 4.3 and 4.7 are top priorities
-
-"Collectives": what are they?
-
-We should get into the habit of letting others know when we're writing
-
-**Rob** will delete manuscript folder in GitHub repository
-
-# Other notes
-
-Cyclic neighbour: use -1 or correct coord
-
-**Stefan** will move iterator tests from manual to automated
-
-Need to check that the Shape iterator is not null before calling updateNVoxel
-
-Default resolution should be for one voxel, expect to be overwritten
-
-Coordinates in Shape should always be 3D - transfer over from Grid
-
-Stuff should be stripped out of Grid, give it reference to the Shape
-
-Output to XML is in progress, should be done once **Bas** gets back from Newcastle
-
-**Rob** will put his meeting notes on GitHub
-
-Set up larger group meeting for beginning of next week(?)
diff --git a/DevelopmentMeetingNotes/2016-05-23_meetingsummary.md b/DevelopmentMeetingNotes/2016-05-23_meetingsummary.md
deleted file mode 100644
index 29bfe2f09..000000000
--- a/DevelopmentMeetingNotes/2016-05-23_meetingsummary.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Morning meeting
-
-Present: Robert Clegg, Bastiaan Cockx
-
-### Bas's visit to Newcastle
-- Very positive, people there keen to use iDyno2
-- IBM in microbiology wiki, with iDyno2 as a sub-wiki?
-
-### Output as XML
-- Bas has finished the structure, but is still implementing it throughout the source code
-- Currently working on `Reaction` stoichiometry
-- `Shape` classes are done, but not `Dimension`
-- Much of the stuff in `ObjectFactory` is being replaced with `NodeConstructer` approach
-- Bas is uncertain about how to read/write concentration arrays. **Rob will check this**
-
-### Removing aspect interface from process managers?
-- Leave for now, but needs to be done using XML output/input.
-- Obligatory aspects, requirements?
-
-### Reaction Library
-- Use as default, allow extra/exclude in a `Compartment`
-- Should be easy to code, as follows the `SpeciesLib` approach
-- Solutes could also be done, needs more thought
-
-### Process managers
-- `SolveDiffusionTransient`: Need to clarify how the agents grow
-- `SolveChemostat`: Need to do agent growth!
-
-### Boundaries
-- Rob has been working on Agent and soute boundary methods, getting there!
-- Tricky defining what is attached (i.e. biofilm) and what is floating in boundary layer
- - Boolean flag for sloughing on boundary layer
-- Poorly defined boundaries specifying solute concentrations on adjacent boundaries?
- - Spatially structured compartment with well-mixed sub-regions
- - Could we prohibit this?
- - Or flag a message and make not well-mixed?
-
-### Agent events for Toledo group
-- run other events?
-- change species (death, etc)
-
-# Afternoon meeting
-
-Present: Robert Clegg, Stefan Lang
-
-### Restructure from Grid to Shape
-- Rob started restructure, Stefan has been continuing it
-- Making great progress but not quite done yet: errors
-- Resolution calculator: scale resolution instead of setting length as arc length - Rob agrees
-- Initialise with UniformResolution by default.. should we set this in the XML?
-- Enter into XML as degrees? Or read in "pi" string? Should be sorted when we introduce units
-- Grid types: strip away old grids and make SpatialGrid non-abstract
-- Iterator has switched from `Grid` to `Shape` elsewhere in code
-- Move stuff in `linearAlgebra.PolarArray` into `CylindricalShape` and `SphericalShape`
-- Stefan will let Rob know if any of the `checkDimensions` methods in `Matrix` or `Array` are causing problems, so he can fix it.
-- Rob will check Stefan's new approach to storing current boundary in `CartesianShape`
-- Setting the number of voxels per shell/ring is still unclear, especially the `N_ZERO_FACTOR` stuff. Stefan will clarify what is going on here!
-
-### Manuscript
-- Design concepts: ODD uses grid cell to mean many things, we should use "voxel"
-- Sub-voxel points: `shape.subvoxel` package and `SolveDiffusionTransient` ~lines 150-250
diff --git a/DevelopmentMeetingNotes/2016-06-14_meetingsummary.md b/DevelopmentMeetingNotes/2016-06-14_meetingsummary.md
deleted file mode 100644
index 679ceeb11..000000000
--- a/DevelopmentMeetingNotes/2016-06-14_meetingsummary.md
+++ /dev/null
@@ -1,83 +0,0 @@
-Present: Robert Clegg, Bastiaan Cockx, Stefan Lang, Jan Kreft
-
-
-# XML output
-Keep in Simulator - do we allow settable period? Could be iteration or timestep. The group agreed on an integer number of global steps.
-
-Issue with random seed - could there be uses of Java random.
-
-Bas will make a jUnit test to check random seed re-initialisation. Jan suggested that this may not work due to different processors being strict FP or not.
-
-# Graphical output
-Keep graphical output as a compartment-level process, as this depends on the compartment shape.
-
-Bas and Stefan have achieved graphical output of rod-shaped cells. Jan suggested that Jamie Luo may be best placed to extends this to filaments, and will email him.
-
-Solute output is already in the SVG output, could be in the POVRay output. The GL render is on a separate thread, so would need the solute grids to be thread-safe. Copying the grids would get around this, but they would likely be a bit out of date.
-
-# Units
-Bas has already started on a unit conversion class:
-- First attempt forcing everything to SI units.
-- Could set output format for output files? Stefan suggested "simplest form". Jan suggested same as input.
-
-Jan suggests sticking with internal units that are most applicable to microbial systems: micrometer, etc.
-
-Bas will write a jUnit test to check operations with doubles with very large/small exponents.
-
-Jan suggests using `%g` in Java to format numbers to string.
-
-Need to be careful about mass-mole conversions.
-
-Bas has incorporated unit input to the ExpressionB class.
-
-# Agent growth
-Keep flexibility of one mass OR map of masses?
-
-Issue arises when evaluating reaction rates and stoichiometries. Also pops up in Agent division.
-
-Should keep flexibility but structure the manual so that beginners only see simplest case.
-
-# Agent radius in 2D, 1D
-Bas had previously questioned the use of cylinders in 2D, etc.
-
-Stefan has noticed that the voxel volume does not include the dummy dimension in 2D, but this may be out of date. Rob will check on his branch.
-
-Bas suggests calculating the third dimension size from the user's target x- and y- sizes, plus the desired volume.
-
-Bas has suggested using "ghost" masses for agents in 2D. This will require further thinking by members of the group and discussion at the next meeting.
-
-# Agents insertion/removal at biofilm boundaries
-Use random walk even for non-motile cells, failed attempts repeated? Depends on purpose of model.
-
-Cell attachment probability dependent on biofilm size? Calculate attachment probability upon arrival?
-
-Rob suggested breaking the problem into rate of compartment entry and let success/failure of attachment emerge.
-
-Jan suggests this will all depend a lot on the purpose of the model, and the state of the bulk liquid. Experimental observations are of rate of attachment (failed attempts are not observed).
-
-Jan thinks we may have 5 or 10 different reasonable options, varying with scenario. Do we model these as separate boundary objects, or as parameters within one? We need to compile a list of possibilities, and rank priority. Start with iDyno1 approach, i.e. specific area. Can calculate volume and surface area of each compartment. Need to specify representative volume size. Will need to copy/destroy agents crossing different sized compartments.
-
-This may lead to very random behavior at bottlenecks, etc. Worth warning the user about this!
-
-By default assume that the compartment size is the same as the realistic volume. Introduce the scaling factor later in manual, etc.
-
-Do we re-implement the detachment schemes of iDyno1? Re-implement DS_SolGrad? Dummy detachment solute? Could use the well-mixed setter to determine probability of detachment. Rob has an idea inspired by gravity, but needs to clarify details before persuading the rest of the group. Topic for discussion at the next meeting!
-
-# The `input` option in Event
-About to be removed, so don't use!
-
-# Delete `modelBuilder` stuff now that it has been/is being replaced by `nodeFactory`?
-Bas has removed some, but has left bits that still need to be implemented.
-
-Bas has implemented everything that is used by the protocol files.
-
-Rob and Bas will arrange an afternoon of going through the code and cleaning initialization class by class.
-
-# Manuscript
-Figures as separate files, tables at the end. Figure legends.
-
-Rob has flagged the issue of many names for "aspect" - we should simplify this. Bas will take a look at this and think about a solution. Jan has suggested the use of "module".
-
-The section on spatial units focusses too much on the technical details - move around to focus more on concentrations and the need for discretisation. Mention polar coordinates, but leave the details for somewhere else.
-
-Rob will move over to V1 and filter over the comments.
diff --git a/DevelopmentMeetingNotes/2016-07-08_agenda.md b/DevelopmentMeetingNotes/2016-07-08_agenda.md
deleted file mode 100644
index 52c6514aa..000000000
--- a/DevelopmentMeetingNotes/2016-07-08_agenda.md
+++ /dev/null
@@ -1,94 +0,0 @@
-### new
-Welcome to Jamie Luo from Warwick University
-
-* Jamie's focus the coming months - filaments
-
-Progress on iDyno 2 the past few weeks
-
-### Coding general keypoints
-
-* Random number usage
-* Units
-* well mixed boundary
-* steady state reaction diffusion
-* full non-cartesian simulation
-* Clean-up
-* Hunting and eliminating bugs
-
-### Unfinished coding parts
-
-agent package
-
-* Agent register death method
-* Make body relocate robust for relocations between 2d and 3d domains
-* Adding complex body types with gui
-
-aspect package
-
-* Aspect redirerecting stored in output and editable in gui
-* Thinkover - radii and agent size in 2d representation
-* Remove or finish filial linkage methods
-* in some scenarios eps cumulative seems to cause a stack overflow error
-* investigate the usage of the internal production event now that rob has intergrated it (partly?) in transient diffusion solver
-* level pull distance rather than adding up
-* clean-up rod division and make sure rods perform tip-tip divide
-
-Boundary package
-
-* proper initiation from protocol file
-* node construction
-* detachment, attachment
-* biofilm boudary implemenentation, uses aspects thus should become redirectable or restructured in an other way
-* Membrane boundary layers are unfinished
-
-dataIO
-
-* Log: allow for different display and log file log levels
-
-grid
-
-* setting difusivity other than 1
-
-guiTools
-
-* A lot of classes are not implementing the model node structure yet and thus are not loaded in the gui yet.
-* A lot of classes do not allow for editing (set node method missing or unfinished)
-
-Agent container
-
-* move all aspect related methods out of the agent container they should be in redirectable classes and angent container should remain general
-* make rtree / splittree settable
-
-JSBML
-
-* is not used, leave out of release version if not used
-
-nodeFactory
-
-* finish replacing newBlank paradigm with constructable paradigm
-* finish Bundle and Pile implementation
-
-ProcessManagers
-
-* upon event processManagers?
-
-Shape
-
-* what is still to be done for non-Cartesian shapes
-
-Spatial registry
-
-* splittree is faster but still has some glitches: artefacts with rods in periodic domains, high amount of overlap in one point will cause stack overflow
-* spatial registry interface is biassed towards rTree
-
-surface
-
-* bounding volumes for non cartesian domains?
-* Collision and adhesion functions settable from protocol file
-
-### Writing: what is our status
-
-* Good progress on general framework description
-* case studies are hold back by unfinished code.
-
-### Planning
diff --git a/DevelopmentMeetingNotes/2016-07-08_meetingsummary.md b/DevelopmentMeetingNotes/2016-07-08_meetingsummary.md
deleted file mode 100644
index 88c1024ad..000000000
--- a/DevelopmentMeetingNotes/2016-07-08_meetingsummary.md
+++ /dev/null
@@ -1,128 +0,0 @@
-Participants: Jan-Ulrich Kreft, Stefan Lang, Jamie Luo, Munehiro Asally, Bastiaan Cockx
-
-### Opening
-
-discussing models with complex morphologies and physical interactions.
-
-* Streptomyces
-* Filamentous fungi
-* Myxobacteria (Cell Flexibility Affects the Alignment of Model Myxobacteria)
-
-### code discussion
-
-(GUI = Graphical User Interface)
-
-* the Collision package now uses separate class to pass variables for clarity.
-
-* With the new ClassRef (and also PackageRef) we now have 5 reference classes. Reference classes allow to make changes in aspect names, change xml labels and rename classes in a single place and thus we do not have to go trough all code to make those changes. Also the ClassRef allows us to query all classes within a specific package, ObjectRef can list all objects that are allowed to be a Primary aspect.
-
-* A lot of bug fixes have been done. A big one is that there is now no longer an growthrate artefact when changing the target resolution to values <1
-
-* Stephan and Rob will discuss what still needs to be done to get all boundary types (connected compartments, wellmixed) working and fully implemented
-
-* In order to model diffusion from and in an agar plate we should have an additional region specification that defines the agar. In the protocol file the concentration of the region and it's diffusivity can be set to properly model agar. Multiple compartments for agar have also been discussed but are probably less feasible if the agar regions are connected directly
-
-* To prevent confusion and prevent "missed" components on division or missed components when the user implements both, as well as to reduce code complexity: all agent mass component will be stored in a HashMap data structure, the added computational cost is estimated to be insignificant.
-* Take note of checking for Log.level before constructing an output string
-* The splitTree delivers a speed improvement important in order to model larger scale systems. There are still some issues with rods in periodic domains. The approach is very similar to BacSim's quad tree.
-
-* the modelNode newBlank method is now deprecated, we are switching to implementing the Instantiatable interface for all classes that need to be instantiated from the protocol file. Possible child classes are defined as Constructable in the modelNode structure. This also allows for easy construction from the gui.
-
-* Two new classes: Bundle and Pile (to be renamed to ModelMap and ModelList) are extensions of the Java HashMap and LinkedList classes and implement the instantiatable and NodeConstructor interfaces. Because these classes self manage their modelNode structure XmlOutput and GUI intergration of Maps and Lists is now very easy (automated). This prevents us from writing iterative methods for every list and map implemented in iDynoMiCS that needs to be saved or requires user interaction.
-
-Issue with non-identical simulations with identical seed:
-* Bas will write a unit test to check for inconsistencies with random number generator
-* Stephan will write a script to check for instances of the java default Math.random
-
-* A steady-state solver is an essential part of iDynoMiCS 2 and should be included, especially for simulations with realistic agent growth rates. It should be feasible to port the multi-grid solver for cartesian domains. For other domains we will need the ADI solver or alternatives. BacSim had an ADI solver implemented and can be used for inspiration.
-
-* For non-cartesian simulations with agents the agent-tree should use the same none cartesian coordinate system to work properly, conversion to cartesian will not work for periodic dimensions. There may be some adjustments required to the bounding volumes to make this work, Stefan will investigate.
-
-
-### planning
-
-Bas has indicated that he has to put more focus on the other aspects of his PhD project. Stefan has offered to pick up and discuss with Rob the unfinished tasks Rob has been working on. Jamie has indicated that he can probably pick up some small and clear task packages and may also be able to write some missing Java doc while he goes trough the code.
-
-The total time spent on coding should be 3 to max 4 weeks full time coding. In order to achieve this tasks have been put on the postpone list (see below this section).
-
-Completing the paper would probably take a similar amount of time.
-
-The tasks have been distributed as follows:
-
-###Rob:
-* radii and agent size in 2d and representation, scaling mass/concentration/density? cylinder representation? what are the artefacts that we will introduce with our approach? Discuss with Jan and Bas
-* Assist and advise Stefan on unfinished implementations.
-* finish work on steady state reaction diffusion solver.
-
-###Stefan:
-
-grid
-
-* setting difusivity other than 1 and settable from xml
-* dimension min other than 0
-
-Boundary package (together with Rob)
-
-* proper initiation from protocol file
-* node construction
-* detachment, attachment
-* biofilm boudary implemenentation, uses aspects thus should become redirectable or restructured in an other way
-* Membrane boundary layers are unfinished
-
-Shape
-
-* what is still to be done for non-Cartesian shapes
-
-surface
-
-* check bounding volumes for non cartesian domains
-
-###Bas:
-
-agent package
-
-* Agent register death method
-* Make body relocate robust for relocations between 2d and 3d domains
-* Adding complex body types with gui
-
-aspect package
-
-* Aspect redirecting stored in output and editable in gui
-* Remove filial linkage methods
-* in some scenarios eps cumulative seems to cause a stack overflow error
-* investigate the usage of the internal production event now that rob has intergrated it (partly?) in transient diffusion solver
-* level pull distance rather than adding up
-* clean-up rod division and make sure rods perform tip-tip divide
-* internal products are currently ignored for volume calculation
-
-guiTools
-
-* A lot of classes are not implementing the model node structure yet and thus are not loaded in the gui yet.
-* A lot of classes do not allow for editing (set node method missing or unfinished)
-
-Agent container
-
-* move all aspect related methods out of the agent container they should be in redirectable classes and agent container should remain general
-* make rtree / splittree settable
-
-nodeFactory
-
-* finish replacing newBlank paradigm with constructable paradigm
-* finish Bundle and Pile implementation
-
-surface
-
-* Collision and adhesion functions settable from protocol file
-
-###Jamie
-
-Will communicate with Stefan, Bas and Rob when he has some time to spend on small tasks for iDynoMiCS 2.
-Jamie happy to review code and test code.
-
-### topics / elements that will **not** be included in iDynoMiCS 2 release (postponed)
-
-* Units
-* Log allowing for different display and log file log levels
-* JSBML
-* on demand agent / surface trees (we keep the agent tree central in the agent container)
-* upon event processManagers
\ No newline at end of file
diff --git a/DevelopmentMeetingNotes/2016-07-29_meetingsummary.md b/DevelopmentMeetingNotes/2016-07-29_meetingsummary.md
deleted file mode 100644
index e81ca0830..000000000
--- a/DevelopmentMeetingNotes/2016-07-29_meetingsummary.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-output: word_document
----
-iDynoMiCS developer meeting 29-07-2016 - present: Stefan, Jan, Jamie, Bas
-
-### issue's with pde solver in spherical grid
-
-* Increasing flux between grid cells in the same shell (should be 0.0)
-wave propagation after a while, increasing error
-
-* The issue already occurs with only diffusion, this is strange since diffusion should damp this effect. The issue does not occur on cylindrical or Cartesian grids
-
-* Smaller time-step gives better results
-
-* Stability criterion - Courant condition helped to resolve time-step previously for pde solver Jan
-
-* Could be an issue due to non-continues distances between grid cells
-
-* Implicit method may help
-
-### planning, next
-* Jan has started implementing plasmid transfer from iDyno 1 to 2 and has a new student who may be able to help with plasmid transfer
-
-* Stefan arranges a meeting with Rob, others join if they are available at that time.
-
-* General note: focus on the essentials and keep the momentum
\ No newline at end of file
diff --git a/DevelopmentMeetingNotes/2016-08-29_meetingsummary.rmd b/DevelopmentMeetingNotes/2016-08-29_meetingsummary.rmd
deleted file mode 100644
index a7be9f3c2..000000000
--- a/DevelopmentMeetingNotes/2016-08-29_meetingsummary.rmd
+++ /dev/null
@@ -1,51 +0,0 @@
----
-title: "iDynoMiCS 2 meeting"
-output: html_document
-csl: american-physics-society.csl
----
-
-present: Robert, Stefan, Bas
-
-### Agenda:
-
-Diffusion issues
-Case studies
-
-### Diffusion
-
-- now stable on non-cartesian grids.
-- Investigating maximum time-step
-
-Stefan currently implements:
-$$ \frac{1}{var.getMin(DIFFUSIVITY) * var.getShape().getMaxFluxPotential() * 3}$$
-
-Rob:
-
-$$\frac{1}{Diffusivity_{max} * flux_{potential.max}}$$
-
-CFL condition, must be strictly less than? (check)
-
-- explicit solver is very slow, additional solvers can be implemented post publication.
-
-- Stefan will check time step and conditions
-- Non zero minimum dimensions
-
-- Rob will look into the diffusivity
-
-- Bas will look into agents in non-cartesian domains
-
-- thinking about setting multiple diffusivity regions
-
-### case studies
-
-meeting Thursday at 14.00 on case studies
-
-multi compartment?
-
-digester coupled with nitrogen removal
-
-### discussion
-
-bounding volumes non-cartesian domains
-
-- Bas and Stefan will look into issues together
\ No newline at end of file
diff --git a/DevelopmentMeetingNotes/2016-09-29_meetingsummary.html b/DevelopmentMeetingNotes/2016-09-29_meetingsummary.html
deleted file mode 100644
index c1c9e3f90..000000000
--- a/DevelopmentMeetingNotes/2016-09-29_meetingsummary.html
+++ /dev/null
@@ -1,211 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
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).
-
-
-
-
-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.
-
-
-
-
-
-
-
-int[]
-5612544
-39064
-
-
-char[]
-2394480
-25507
-
-
-java.awt.Rectangle
-679584
-21237
-
-
-java.lang.Object[]
-632432
-14387
-
-
-java.lang.String
-591984
-24666
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/DevelopmentMeetingNotes/2016-09-29_meetingsummary.md b/DevelopmentMeetingNotes/2016-09-29_meetingsummary.md
deleted file mode 100644
index 9c4fe5fb0..000000000
--- a/DevelopmentMeetingNotes/2016-09-29_meetingsummary.md
+++ /dev/null
@@ -1,27 +0,0 @@
-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).
-
-![](maximum_miniTimestep_shapes.png "mini time step analysis")
-
-- 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:
-(1) 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.
-(2) 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.
-
-| object | size (bytes) | count |
-|---|---|---|
-| int[] | 5612544 | 39064 |
-| char[] | 2394480 | 25507 |
-| java.awt.Rectangle | 679584 | 21237 |
-| java.lang.Object[] | 632432 | 14387 |
-| java.lang.String | 591984 | 24666 |
diff --git a/DevelopmentMeetingNotes/CircleVoxels.png b/DevelopmentMeetingNotes/CircleVoxels.png
deleted file mode 100644
index 6be2d9373..000000000
Binary files a/DevelopmentMeetingNotes/CircleVoxels.png and /dev/null differ
diff --git a/DevelopmentMeetingNotes/CyclicCorner.png b/DevelopmentMeetingNotes/CyclicCorner.png
deleted file mode 100644
index d177400cb..000000000
Binary files a/DevelopmentMeetingNotes/CyclicCorner.png and /dev/null differ
diff --git a/DevelopmentMeetingNotes/maximum_miniTimestep_shapes.png b/DevelopmentMeetingNotes/maximum_miniTimestep_shapes.png
deleted file mode 100644
index 60a619381..000000000
Binary files a/DevelopmentMeetingNotes/maximum_miniTimestep_shapes.png and /dev/null differ
diff --git a/DevelopmentMeetingNotes/topics2discuss.md b/DevelopmentMeetingNotes/topics2discuss.md
deleted file mode 100644
index 866616463..000000000
--- a/DevelopmentMeetingNotes/topics2discuss.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Uniqueness of aspects in species modules
-
-Agent radius in 2D, 1D
\ No newline at end of file
diff --git a/GuideForDevelopers.md b/GuideForDevelopers.md
deleted file mode 100644
index 12b209701..000000000
--- a/GuideForDevelopers.md
+++ /dev/null
@@ -1,520 +0,0 @@
-# Coding
-
-Useful links:
-- [Java code conventions (Oracle)](http://www.oracle.com/technetwork/java/codeconventions-150003.pdf)
-- [SOLID principles for object-oriented design](https://en.wikipedia.org/wiki/SOLID_(object-oriented_design))
-
-## General tips
-A few extra **spaces** can make a huge difference to how human-readable code is. For example, this
-``` java
-if(i<3)x=x+Math.PI*2;
-```
-is a lot less readable than this
-``` java
-if ( i < 3 )
- x += Math.PI * 2;
-```
-despite being the same from the compiler's point of view.
-
-## Setting up a class file
-**Copyright information** should go at the very top of the file
-
-**Import statements** should be split into two groups with an empty line between, and ordered alphabetically within these groups. The first group is of external imports, i.e. those not written as part of iDynoMiCS 2; the second group is, of course, those written as part of iDynoMiCS 2. For example:
-``` java
-import java.math.BigInteger;
-import java.util.LinkedList;
-
-import agent.Agent;
-import agent.Species;
-import compartment.Compartment;
-```
-
-## Line lengths
-Please keep line lengths to a maximum of 80 characters wherever possible. This makes it easier to reading code on small screens, and to compare code side-by-side on one wider screen. To make this easier, you can set up Eclipse to show a margin guide:
-
-![Eclipse editor margin column](Docs/EclipseEditorMarginColumn.png)
-
-
-TODO wrapping lines
-
-## Naming conventions
-Constants should always be in capitals, with words separated by underscores (known as [SCREAMING_SNAKE_CASE](https://en.wikipedia.org/wiki/Snake_case)). For example:
-``` java
-public final static int ONE = 1;
-public final static double ONE_POINT_ZERO = 1.0;
-```
-
-Classes and interfaces should be in lower case, except the first letter of each word which should be a capital (known as [CamelCase](https://en.wikipedia.org/wiki/CamelCase)). For example:
-``` java
-public interface AnInterface
-{
- ...
-}
-private Class()
-{
- ...
-}
-```
-
-Packages and public variables should use the slightly different _CamelBack_ convention: the first letter is lowercase. For example:
-``` java
-package packageName;
-public int variable;
-public double nextVariable;
-```
-
-Protected and private variables should be the same as public, except that we place an underscore at the start. However, this can be cumbersome if the variable name is a single letter, and so can be omitted. For example:
-``` java
-protected double _protectedVariable;
-private int _privateVariable;
-private double a;
-```
-
-As a general rule of thumb: the more widely a name is used, the more descriptive (and therefore longer) it should be. So the single letter name is OK for a private variable, since all references to it will be in the file where it is defined. If you would like to abbreviate a long variable name, please explain the abbreviation in the javadoc at initialization. For example:
-``` java
-public double aLongVariableNameWithASpecificPurpose;
-```
-could become
-``` java
-/**
- * A variable with the specific purpose of demonstrating how to explain yourself
- * to other programmers with different backgrounds to your own.
- */
-public double specPurp;
-```
-
-## Commenting
-Commenting is your friend, whether you're writing code, reading someone else's, or even reading your own several weeks/months/years later. That said, the best code needs little in the way of comments as it is clear through good naming and layout.
-
-**Block comments** span several lines, and are useful for long comments. Classes, variables, expressions, etc., should be described using **Javadoc** comments starting with a `/**` (shown in blue in Eclipse), whereas all others start with `/*' (green).
-``` java
-/**
- * \brief Short description about what this method does.
- *
- * A bit more information about what this method does.
- *
- * @param number An integer number required as a parameter.
- * @returns A double number calculated from the input.
- */
-public double aMethod(int number)
-{
- /*
- * Long internal comments should go here. These are useful for those who want
- * to understand how a method works, rather than what it does.
- */
- return 1.0 * number;
-}
-```
-
-**End-of-line comments** are best kept for temporary comments that you intend to be deleted at some stage. For instance:
-``` java
-// FIXME Harry [11July1979]: This is broken!
-int two = 1 + 1;
-// TODO Sally [12July1979]: Is this better?
-// int two = 1 + 0;
-```
-This approach may become redundant as we use GitHub's commenting more and more.
-
-The [Java code conventions (Oracle)](http://www.oracle.com/technetwork/java/codeconventions-150003.pdf) gives advice on trailing comments (p. 8), but we strongly discourage their use. They often lead to developers breaking the 80 character line-length rule (see above).
-
-## Comparing strings
-Whenever you want to check if two strings have the same value, use
-``` java
-str.equals(otherStr);
-```
-rather than
-``` java
-str == otherStr
-```
-as the latter will instead check if the two strings are the same object (i.e. if they occupy the same position in memory).
-
-## Returning booleans
-This is unnecessarily messy
-``` java
-if ( booleanVariableOrExpression )
-{
- return true;
-}
-else
-{
- return false;
-}
-```
-when this returns exactly the same result
-``` java
-return booleanVariableOrExpression;
-```
-
-## `int` vs `Integer`, `double` vs `Double`
-This is a confusing aspect of Java, but worth learning the distinction. All data types with a lower-case name are [primitives](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html), and in iDynoMiCS we tend only to use `int`, `double` and `boolean` the vast majority of the time. On the other hand, data types in _CamelCase_ are [objects](https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html) and many familiar ones act as "wrappers" for primitives: `Integer`, `Double`, `Boolean`, and `String` (for `char`).
-
-## Use of `instanceof`
-
-## Everything should be possible to initialise through XML
-
-## Visualisation should be the same regardless of whether it's during the simulation or from results
-
-## Using modulo
-
-We often need to use [modulo](https://en.wikipedia.org/wiki/Modulo_operation), for example when dealing with periodic boundaries or circular geometries. The in-built Java modulus is specified using the `%` sign:
-``` java
-// dividend % divisor = remainder
-1 % 3 ; // = 1
-5 % 3 ; // = 2
--2 % 3 ; // = -2
-```
-Note that the sign of the answer is always that of the dividend. If you want it to be the same sign as the divisor (as is often the case), use `Math.floorMod(int dividend, int divisor)`:
-``` java
-// dividend % divisor = remainder
-Math.floorMod(1, 3) ; // = 1
-Math.floorMod(5, 3) ; // = 2
-Math.floorMod(-2, 3) ; // = 1
-```
-
-The `Math.floorMod(x,y)` method only works for `int`s, so for `double`s use `ExtraMath.floorMod(x,y)` in the `utility` package.
-
-## Using random numbers
-The random number generator (RNG) in iDynoMiCS 2 is initialized with a random seed, meaning that a simulation can be re-run in exactly the same way so long as the same random seed is used. However, this is only possible because we use a defined random number generator, namely the `MTRandom` that is initialized in `ExtraMath`. If a different RNG is used by mistake, it may no longer be possible to reproduce simulations in the way we would like. Furthermore, uses of a different RNG are very hard to locate in the code.
-
-Please, please, please do not use methods like
-``` java
-Math.random()
-```
-or
-``` java
-Random rand = new Random();
-rand.nextInt(bound);
-```
-
-## Using aspects
-
-### What is an aspect (and why)?
-Aspects are introduced to have a flexible way of handling and storing properties
-and behavior of the java object that hosts them, as well as to ensure sub-models
-always work with up-to-date information. An aspect can be any java object, yet
-when creating an aspect (stored in an Aspect object) a distinction is made
-between three different types: PRIMARY, CALCULATED and EVENT.
-
-
-#### primary
-Primary aspects store information or properties and are preferable the only
-place this information is stored (such as a double that represents an Agent's
-mass or a String that tells an output writer what solute should be displayed).
-The following example shows the creation of a simple primary state in xml:
-
-``` XML
-
-```
-
-Here 'name' is the name other aspects use to refer to this aspect. 'type'
-indicates what type of aspect should be created and stored, value is the String
-representation of the content of the stored object. This is generally the
-scenario to store simple objects like primitive types or simple java objects
-that are easily represented in a string. including simple arrays (see example
-bellow).
-
-``` XML
-
-```
-
-When storing arrays (indicated with the appended []) the individual array
-values are always comma-separated.
-
-More complex objects may also be stored as a primary aspect, when such an object
-is stored no value is indicated but instead the child nodes of the parent node
-are passed to the java object. These child nodes are object specific and are
-handled by the object's XMLable implementation (see paragraph XMLable interface).
-
-``` XML
-
-
-
-```
-
-#### calculated
-Calculated aspects are used to calculate a property that depends on other
-aspects. For example calculated aspect may define an agents volume based on it's
-mass and density. Calculated aspects do not store any information except for on what primary
-aspects they depend on. There are two way's of defining a calculated aspect: 1)
-calling a pre-made calculated aspect:
-
-``` XML
-
-```
-Here 'name' is the name other aspects use to refer to this aspect. 'type'
-indicates what type of aspect should be created. 'class' indicates what the
-java class name of the calculated object is that should be created. 'input'
-set the required input aspects and 'package' indicate the java package in which
-this java class is stored. When the java class has been added to the
-general/classLibrary.xml no package specification is required in the protocol
-file.
-
-2) defining the calculated state as a mathematical expression:
-
-``` XML
-
-```
-
-This type of calculated aspect always has "StateExpression" as it's defined
-class, yet in stead of defining it's input as a comma separated list of aspects
-it's input is directly defined as a mathematical expression (see paragraph Using
-expressions). Whenever this calculated state is called it will always evaluate
-this expression with the up-to-date value's and thus return an up to date double
-value.
-
-NOTE: the input aspects of an StateExpression should always be or castable as
-java double value.
-
-#### event
-The third type of aspects are event aspects. This type of aspect does not store
-or return any information, but instead when it is called it can mutate primary
-agent states. For example create a new sibling and adjusting the cell sizes when
-a coccoid cell divides:
-
-``` XML
-
-```
-
-As can be seen in the above expression aspects of the event type can be defined
-in a similar way as calculated states where the only difference is that the
-'name' attribute now reads event rather than 'calculated'.
-
-Note that, if the object that implements the aspect interface is Copyable all
-of it's aspects should be Copyable to (the Copier.copy(Object) should be able
-to return a deep copy of the aspect).
-
-### The aspect interface - Using aspects in your object
-Only one thing is required to use aspect with your java object. Your object
-needs to implement the AspectInteface. This interface requires you to add one
-field and one method to your class
-
-``` java
-/* The aspect registry can be used to store any java object: , but can
-* also be use to store more specific objects types: */
-public AspectReg aspectRegistry = new AspectReg();
-
-/* Allows for direct access to the aspect registry */
-public AspectReg> reg() {
- return aspectRegistry;
-}
-```
-
-The aspect interface itself implements all methods to further work with aspects,
-the following three are essential when working with aspects:
-
-``` java
-void loadAspects(Node xmlNode)
-```
-This method loads all aspects from the given parent node, this method should be
-called where you implement the XMLable interface.
-
-``` java
-boolean isAspect(String aspect)
-```
-This method returns true if the aspect exists in the root registry or in any of
-it's branches (see branched aspect registries). Since every agent/aspect owner
-may be unique check whether the called aspect is defined in this aspect registry
-or in one of it's branches
-
-``` java
-Object getValue(String aspect)
-```
-This method returns any aspect as java object if the aspect exists in the root
-registry or in any of it's branches (see branched aspect registries). If the
-aspect cannot be identified it will return null.
-
-Apart from the getValue method there is a set of methods that directly return's
-(or attempts to) in the specified form (thus it does no longer require additional
-casting). These method's work for any primary or calculated aspect that can be
-returned in the requested form.
-
-``` java
-Double getDouble(String aspect)
-Double[] getDoubleA(String aspect)
-
-String getString(String aspect)
-String[] getStringA(String aspect)
-
-Integer getInt(String aspect)
-Integer[] getIntA(String aspect)
-
-Float getFloat(String aspect)
-Float[] getFloatA(String aspect)
-
-Boolean getBoolean(String aspect)
-Boolean[] getBooleanA(String aspect)
-```
-
-### The aspect registry
-The aspect registry is what hold's the aspect's linked to a key (String), an
-aspect registry can also have modules or branches. These are additional aspect
-registries which are included in the root aspect registry. This approach is
-used to allow direct access of species aspect's trough an agent. Any aspect
-registry can have any number of branches with any number of branches out of
-those branches, though agents will always have only a single branch/module
-which is the species aspect registry, this species aspect registry may than
-have any additional species modules which are handy to store specific behavior
-and parameters in a single place.
-
-Typical species modules would be: the behavior of a coccoid cell, the
-metabolism of this subgroup, or specific features/changes of a mutant strain.
-
-There is one GOLDEN RULE concerning branched aspect registry, when duplicate
-named aspects exist within the aspect tree the aspect closest to the root will
-override the further branch, but if two separate, independent branches use the
-same aspect name the first one encountered will be used, hence:
-
-You can overrule aspects of submodules, but individual submodules cannot
-override each other!
-
-This approach can be used for example if an agent wants to vary it's individual
-parameter from what is defined in the species aspect registry. Or, when you want
-to implement a species submodule which fit's you needs except for a single
-parameter or behavior.
-
-Typically you should not interact with the aspect registry directly unless:
-you are all are creating a new AspectInterface implementing object which has
-mutable aspects, in that scenario you would implements:
-
-``` java
-/* setting an aspect in the root aspect registry */
-public void set(String key, Object aspect)
-{
- aspectRegistry.set(key, aspect);
-}
-
-/* performing an event (which may result in mutating aspects in the root registry */
-public void event(aspectObject compliant, double timestep, String event)
-{
- aspectRegistry.doEvent(this, compliant, timestep, event);
-}
-```
-
-Some aspect interface implementing objects deliberately have no set method since
-they are not intended to be mutated (for example species).
-
-### Creating custom aspects
-In order to create a custom calculated state (apart from a direct
-StateExpression calculated state) you need to create a new method extending
-the Calculated class. Any calculated state only needs one method:
-
-``` java
-public Object get(AspectInterface aspectOwner)
-{
- return someOperation(input[0], input[1])
-}
-```
-
-hence a calculated state has excess to all of the agent's other aspects, but
-only call's the ones that are specifically assigned in the protocol file
-(available as String[] input). NOTE: this may be changed to be a hashMap instead
-in the future.
-
-Like calculated aspects also Event aspects only require the extending the Event
-class and implementing a single method:
-
-``` java
-public void start(AspectInterface initiator, AspectInterface compliant, Double timeStep)
- {
- /* do some event here /*
- }
-```
-
-Note that it may be useful to cast the initiator and compliant to their native
-object class if you want to call methods that are specific for those objects,
-(or the set method). For example:
-
-``` java
-Agent mother = (Agent) initiator;
-Agent daughter = (Agent) compliant;
-
-mother.set(input[0], initiator.getDouble(input[0])/2.0);
-/* etc. */
-```
-
-#### classes currently implementing the aspect interface
-- Agent
-- Species
-- ProcessManager
-
-## Using the helper class
-
-## Using XmlHandler and XmlLoad classes
-
-## Using NameReferences
-
-## using expressions
-
-## using reactions
-
-## Solute dynamics
-Some definitions:
-- *Concentration* is the amount of substance dissolved per volume. There are two ways of quantifying this substance - mass or moles - and the *relative molecular mass* (RMM) of a substance is needed to convert between the two. Examples of units of concentration are kg m-3 and mol L-1 (also known as molar, M).
-- *Flow* is the rate of transfer from one spatial region to another, and the term is often used to describe the transfer of dissolved solutes (mass flow) and of the bulk liquid (volume flow).
- - *Mass flow* is given in units of substance per unit time (e.g. kg h-1 or mol s-1 ).
- - *Volume flow* is given in units of volume per unit time (e.g. m3 h-1 or L s-1 ).
-- *Dilution* is the rate at which volume of bulk liquid enters/leaves a volume, and is essentially the volume flow normalized by the volume: D = F/V. Dilution rate has units of per time (e.g. h-1 or s-1 ).
-- *Flux* is the rate of transfer of substance from one spatial region to another across an area, and is given in units of substance per unit area per unit time (e.g. kg m-2 h-1 ).
-
-# Testing
-
-Useful links:
-- [Unit testing with JUnit](http://www.vogella.com/tutorials/JUnit/article.html)
-
-# Teamwork
-
-Useful links:
-- [Atlassian Git Tutorial: Workflows](https://www.atlassian.com/git/tutorials/comparing-workflows)
-- [A Visual Git Reference](http://marklodato.github.io/visual-git-guide/index-en.html)
-- [Code Tuts+](http://code.tutsplus.com/tutorials/focusing-on-a-team-workflow-with-git--cms-22514)
-- [A Quick Introduction to Version Control with Git and GitHub](http://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1004668)
-
-## Using Git, GitHub and eGit
-
-### Forking vs branching
-
-### Merging vs rebasing
-
-#### Merging with SmartGit
-1. Commit and push all changes you have made in your branch.
-2. Close all editors/IDEs and open SmartGit.
-3. Make sure the branches you want to merge are up to date by:
- - Check-out branch A (yours) and pull (ctrl+shift+7 to view your branches).
- - Check-out branch B (Master) and pull.
-4. Check-out the branch that will receive the merge commit (your branch).
-5. Select the branch you want to merge on top of that (Master) and click merge.
-6. **If there are conflicts**, open all files with the 'conflicts' tag and resolve conflicts (the conflicts
-resolve tool can be used to view your file on the left, the file from master on
-right and the result in the middle). Per conflict you can pick either the
-changes from your file or from master or write something new all together, you
-need to look carefully which side has the correct code.
-7. After resolving the conflicts in a file, 'stage' the file.
-8. After all conflicts in all files are resolved and all the changes have been
-staged commit the changes.
-9. **If there are (no more) conflicts** push the merge-commit.
-10. now there should be no more conflicts between your branch and the master
-branch and you can create a pull-request in GitHub.
-
-## Communication
-GitHub enables discussion of issues and aspects of specific code, but there's nothing quite like a face-to-face conversation to resolve these and more general topics. We hold a [Google hangout](https://hangouts.google.com/) roughly every week or two
-
-## Git configuration
-### Line endings
-Please set the git configuration setting `core.autocrlf` to `false` for contributing to iDynoMiCS 2. It's generally a good idea to do this for your global settings if you are working on projects that are developed in both Windows and in Unix (Mac/Linux) environments. This only needs to be set once.
-
-To set this in Eclipse with eGit installed, go to *Preferences > Team > Git > Configuration*:
-![eGit line endings](Docs/eGit_line_endings.png)
-
-In the command line, this is done like so:
-``` bash
-git config --global core.autocrlf false
-```
-
-## GitHub hacks
-If you've configured Git nicely and yet it still misbehaves, try these little hacks in your URL bar...
-
-| Problem | Fix |
-| ------------------- | ----- |
-| Ignore whitespace | ?w=1 |
-| Change the tab size | ?ts=4 |
diff --git a/Matlab_scripts/analyseConvergence.m b/Matlab_scripts/analyseConvergence.m
new file mode 100644
index 000000000..b8561529e
--- /dev/null
+++ b/Matlab_scripts/analyseConvergence.m
@@ -0,0 +1,30 @@
+function analyseConvergence (folderName)
+
+ fileList = dir(fullfile(folderName, '*.csv'));
+
+ number = numel(fileList);
+ norms = zeros(number,1);
+ maxes = zeros(number,1);
+ mins = zeros(number,1);
+ means = zeros(number,1);
+
+ for k = 1:number
+ file = fullfile(folderName,fileList(k).name);
+ data = table2array(readtable(file));
+
+ norms(k,:) = norm(data(:));
+ maxes(k,:) = max(data(:));
+ mins(k,:) = min(data(:));
+ means(k,:) = mean(data(:));
+ end
+
+ plot(norms);
+ hold on;
+ plot(maxes)
+ hold on;
+ plot (mins);
+ hold on;
+ plot (means);
+ legend('norm-2','max value','min value', 'mean value');
+ hold off;
+end
\ No newline at end of file
diff --git a/Matlab_scripts/plotConcentrations.m b/Matlab_scripts/plotConcentrations.m
new file mode 100644
index 000000000..afca36eaa
--- /dev/null
+++ b/Matlab_scripts/plotConcentrations.m
@@ -0,0 +1,23 @@
+function plotConcentrations (folderName)
+
+ fileList = dir(fullfile(folderName, '*.csv'));
+
+ number = numel(fileList);
+
+ firstFile = fullfile(folderName,fileList(1).name);
+ firstArray = table2array(readtable(firstFile));
+ arraySize = size(firstArray);
+ allData = zeros(arraySize(1), arraySize(2), number);
+
+ for k = 1:number
+ file = fullfile(folderName,fileList(k).name);
+ data = table2array(readtable(file));
+ allData(:,:,k) = data;
+ end
+
+ singleLayer = squeeze(allData(1,:,:));
+
+
+ surf (singleLayer);
+ %zlim([5.995e-6 6.005e-6]);
+end
\ No newline at end of file
diff --git a/README.md b/README.md
index 18988d6c7..073203f38 100644
--- a/README.md
+++ b/README.md
@@ -1,71 +1,8 @@
-# iDynoMiCS 2
+# iDynoMiCS 2 readme
-## Compartments
-In iDynoMiCS 2, the building blocks of a simulation are compartments. Any simulation must have at least one of these, and if it has multiple compartments then these should be somehow connected to one another. Examples of compartments include, but are not limited to:
-- a chemostat, also known as a CSTR (i.e. a well-mixed container, where fluid is added and removed at the same rate to ensure fixed volume; a chemostat without any fluid flow is known as a batch culture)
-- an aqueous biofilm (i.e. a spatially-structured region, where solute transport is diffusion-limited and cells aggregate)
-- a gut mucosal layer (similar to an aqueous biofilm, but where structural support is given by host epithelial cells; these may produce mucous and other substances)
-- a Petri dish (another spatially-structured region, but where nutrients are provided by a layer of Agar below the biofilm and there is air above).
+## Licence
-Each compartment has four main components:
-- a **shape** (this includes physical size, and any boundaries)
-- an **environment container** (this holds any dissolved solutes modelled as continuous concentration fields)
-- an **agent container** (this holds any agents - be they live or inert - modelled as discrete particles)
-- an ordered list of **process managers**.
+iDynoMiCS 2 will be published under the [CeCILL license V2](http://www.cecill.info/index.en.html). iDynoMiCS 2 makes use of other third libraries and software, these libraries and software are referenced in the Java documentation as well as summorized in our [licence](LICENCE) file. The [CeCILL license V2](http://www.cecill.info/index.en.html) follows the principles of the [GNU general public license (GPL)](http://www.gnu.org/licenses/gpl-3.0.en.html) and of the [BSD license](https://opensource.org/licenses/BSD-3-Clause).
-![compartment structure](ReadMeFigs/Slide2.png)
-
-**Figure 1. General structure of iDynoMiCS 2.**
-
-Within each simulation time-step, each compartment functions as a self-contained unit. Agents that were queued to enter the compartment in the previous time-step are dealt with first, then the processes are executed without any reference to other compartments. When all compartments have been iterated over, all outgoing agents are pushed to their destined compartments and the simulation moves on to the next time-step.
-
-### Compartment shape
-Compartment shapes must be drawn from a list of pre-defined shapes; users are encouraged to define further shapes in Java source code if necessary, but should not attempt to define them in protocol files alone. Different compartment shapes have different requirements regarding boundaries, and will specify different SpatialGrid types depending on what is appropriate (there may be some choice in this; see Table 1). Note that one-dimensional shapes are not typically well suited to agent-based modeling, and are included so that the user may run a population-based model (typically a set of partial differential equations, or PDEs) for comparison.
-
-| Name | Dimensions | Required (and *optional*) boundary sides | SpatialGrid type |
-| ------------- |:----------:| ---------------------------------------------------------- | ----------------------------- |
-| Dimensionless | 0 | none | none |
-| Line | 1 | XMIN, XMAX | CartesianGrid |
-| Rectangle | 2 | XMIN, XMAX, YMIN, YMAX | CartesianGrid |
-| Cuboid | 3 | XMIN, XMAX, YMIN, YMAX, ZMIN, ZMAX | CartesianGrid |
-| Radius | 1 | (*RMIN*), RMAX | SphericalGrid/CylindricalGrid |
-| Circle | 2 | (*RMIN*), RMAX, (*THETAMIN, THETAMAX*) | SphericalGrid/CylindricalGrid |
-| Sphere | 3 | (*RMIN*), RMAX, (*THETAMIN, THETAMAX*), (*PHIMIN, PHIMAX*) | SphericalGrid |
-| Cylinder | 3 | (*RMIN*), RMAX, (*THETAMIN, THETAMAX*), ZMIN, ZMAX | CylindricalGrid |
-
-**Table 1. Compartment shapes available.**
-
-Boundaries must contain two types of method: one relating to the agents, and one for each solute. In simpler cases (e.g. zero flux) the method may be identical for each solute, but for generality we keep open the option of setting each solute separately. The agent methods are then passed to the agent container, and the solute methods to the environment container (on the correct boundary side). The logic behind this is that the agents do not need to know what is happening to the solutes at these boundaries, and vice versa.
-
-### Environment container
-The environment container is primarily a collection of spatial grids; these, in turn, are primarily a collection of arrays of real numbers representing aspects of a dissolved solute: concentration, diffusivity, etc. The environment container also holds all of the reactions that are not catalysed by agents - from here on, these are referred to as extracellular reactions. The environment inherits the shape of the compartment, including the lengths of each dimension. It is the job of the environment container to decide how this should be best divided in the spatial grids, and there may even be potential to have this vary as the simulation proceeds (i.e. adaptive grids).
-
-Common boundary grid methods include:
-- [Dirchlet](https://en.wikipedia.org/wiki/Dirichlet_boundary_condition) boundaries, i.e. those where the concentration of each solute is kept fixed as the diffusion-reaction is solved within a compartment time step. This need not be constant across the length of the boundary, but could instead depend on position along the boundary. One practical usage of the Dirichlet boundary is in boundaries that connect the focal compartment to another compartment: the concentration across this connection is assumed not to change within a compartment time step, and is only updated when all compartments are synced with one another.
-- [Neumann](https://en.wikipedia.org/wiki/Neumann_boundary_condition) boundaries, i.e. those where the concentration gradient is kept fixed as the diffusion-reaction is solved within a compartment time step. As for a Dirichlet boundary, this need not be constant along the length of the boundary. One practical usage of the Neumann boundary is in an impermeable boundary, where a solute cannot diffuse through and so the concentration gradient is set to zero.
-- Cyclic boundaries (also known as [Periodic](https://en.wikipedia.org/wiki/Periodic_boundary_conditions) boundaries), i.e. those where any solute diffusing across reappears instantly at the equivalent position on the partner boundary.
-
-### Agent container
-The agent container manages all the agents in the compartment: it has a list of all agents that do not have a location (or just a list of all agents, if the compartment is a chemostat), and a spatial registry for all located agents. The spatial registry detects collisions between agents (or between an agent and a boundary), and finds the agents within a certain distance of a given point.
-
-### Process managers
-Process managers work on the agent container and/or the environment container. Examples include, but are not limited to:
-- solving solute transport using a numerical solving algorithm (typically an ODE solver in a dimensionless compartment, and a PDE solver in all other compartment shapes) and querying agents for their impact on their local environment
-- stepping through agents in the agent container; these will often need to query their local environment during this process.
-- resolving agent-agent overlaps in spatially structured environments.
-
-Each process manager is initialised with its own time-step and time point at which it should next be executed. The compartment it belongs to is responsible for executing processes at the correct time and in the correct order, but a process is itself responsible for managing when it should next be executed. When there is a clash between two (or more) processes due to be executed at the same time, the compartment chooses the one with the higher *priority*, another parameter that may be set by the user.
-
-
-
-
-
-
-
-
-
-
-## Notes
-
-### Relative diffusivity
-[This paper](http://journals.plos.org/plosone/article?id=10.1371/journal.pone.0146093) might be useful
+## getting started
+read more about iDynoMiCS 2 in the iDynoMiCS 2 [wiki](https://github.com/kreft/iDynoMiCS-2/wiki).
\ No newline at end of file
diff --git a/README.pdf b/README.pdf
deleted file mode 100644
index 16cf9486a..000000000
Binary files a/README.pdf and /dev/null differ
diff --git a/ReadMeFigs.pptx b/ReadMeFigs.pptx
deleted file mode 100644
index a83459f7c..000000000
Binary files a/ReadMeFigs.pptx and /dev/null differ
diff --git a/ReadMeFigs/Slide1.png b/ReadMeFigs/Slide1.png
deleted file mode 100644
index 0bd04d851..000000000
Binary files a/ReadMeFigs/Slide1.png and /dev/null differ
diff --git a/ReadMeFigs/Slide2.png b/ReadMeFigs/Slide2.png
deleted file mode 100644
index 63a4bc5b5..000000000
Binary files a/ReadMeFigs/Slide2.png and /dev/null differ
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/colourPalettes/rainbow.xml b/colourPalettes/rainbow.xml
new file mode 100644
index 000000000..48ad9b51e
--- /dev/null
+++ b/colourPalettes/rainbow.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/version/current.cfg b/config/version/current.cfg
index 996c63ee4..5c48a1587 100644
--- a/config/version/current.cfg
+++ b/config/version/current.cfg
@@ -1,3 +1,3 @@
# general
version_number=2.0
-version_description=alpha build 2019.07.31
\ No newline at end of file
+version_description=developer build sept 2021
\ No newline at end of file
diff --git a/iDynoMiCS-2.iml b/iDynoMiCS-2.iml
new file mode 100644
index 000000000..d881d43c7
--- /dev/null
+++ b/iDynoMiCS-2.iml
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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
diff --git a/protocol/Strep/Eco Ego.xml b/protocol/Strep/Eco Ego.xml
new file mode 100644
index 000000000..be0f0bbb8
--- /dev/null
+++ b/protocol/Strep/Eco Ego.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/benchmark_3.xml b/protocol/benchmark_3.xml
index 322a2830e..cd0c0da32 100644
--- a/protocol/benchmark_3.xml
+++ b/protocol/benchmark_3.xml
@@ -6,10 +6,6 @@
-
-
-
-
-
-
+ firstStep="0.0">
@@ -193,7 +185,7 @@
+ firstStep="0.0">
diff --git a/protocol/biofilmCumulative.xml b/protocol/biofilmCumulative.xml
index 6a6dcba19..011dd7eb6 100644
--- a/protocol/biofilmCumulative.xml
+++ b/protocol/biofilmCumulative.xml
@@ -12,6 +12,7 @@
both on species level and on agent level, the agent state will be used in
the simulation. small test -->
+
@@ -31,6 +32,7 @@
+
@@ -140,7 +142,8 @@
-
+
+
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/protocol/catalyst_systems/adjusted2_biofilm_no_growth_constant_bulk_smaller.xml b/protocol/catalyst_systems/adjusted2_biofilm_no_growth_constant_bulk_smaller.xml
new file mode 100644
index 000000000..046b95304
--- /dev/null
+++ b/protocol/catalyst_systems/adjusted2_biofilm_no_growth_constant_bulk_smaller.xml
@@ -0,0 +1,382 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/catalyst_systems/adjusted_biofilm_no_growth_constant_bulk_smaller.xml b/protocol/catalyst_systems/adjusted_biofilm_no_growth_constant_bulk_smaller.xml
new file mode 100644
index 000000000..9af18d5f0
--- /dev/null
+++ b/protocol/catalyst_systems/adjusted_biofilm_no_growth_constant_bulk_smaller.xml
@@ -0,0 +1,382 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/catalyst_systems/biofilm_no_growth_constant_bulk.xml b/protocol/catalyst_systems/biofilm_no_growth_constant_bulk.xml
new file mode 100644
index 000000000..ae4c5ea49
--- /dev/null
+++ b/protocol/catalyst_systems/biofilm_no_growth_constant_bulk.xml
@@ -0,0 +1,628 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/catalyst_systems/biofilm_no_growth_constant_bulk_smaller.xml b/protocol/catalyst_systems/biofilm_no_growth_constant_bulk_smaller.xml
new file mode 100644
index 000000000..fb42d2b0b
--- /dev/null
+++ b/protocol/catalyst_systems/biofilm_no_growth_constant_bulk_smaller.xml
@@ -0,0 +1,387 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/catalyst_systems/biofilm_no_growth_constant_bulk_smaller_3D.xml b/protocol/catalyst_systems/biofilm_no_growth_constant_bulk_smaller_3D.xml
new file mode 100644
index 000000000..ed5f369d9
--- /dev/null
+++ b/protocol/catalyst_systems/biofilm_no_growth_constant_bulk_smaller_3D.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/catalyst_systems/chemostat_population_with_growth.xml b/protocol/catalyst_systems/chemostat_population_with_growth.xml
new file mode 100644
index 000000000..81e942817
--- /dev/null
+++ b/protocol/catalyst_systems/chemostat_population_with_growth.xml
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/catalyst_systems/chemostat_single_agent.xml b/protocol/catalyst_systems/chemostat_single_agent.xml
new file mode 100644
index 000000000..5dafad529
--- /dev/null
+++ b/protocol/catalyst_systems/chemostat_single_agent.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/catalyst_systems/equilibrium_test.xml b/protocol/catalyst_systems/equilibrium_test.xml
new file mode 100644
index 000000000..b65bf42cb
--- /dev/null
+++ b/protocol/catalyst_systems/equilibrium_test.xml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/catalyst_systems/thick_biofilm_no_growth_constant_bulk.xml b/protocol/catalyst_systems/thick_biofilm_no_growth_constant_bulk.xml
new file mode 100644
index 000000000..f79aebad8
--- /dev/null
+++ b/protocol/catalyst_systems/thick_biofilm_no_growth_constant_bulk.xml
@@ -0,0 +1,127 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/catalyst_systems/thick_biofilm_with_growth.xml b/protocol/catalyst_systems/thick_biofilm_with_growth.xml
new file mode 100644
index 000000000..e77ed137b
--- /dev/null
+++ b/protocol/catalyst_systems/thick_biofilm_with_growth.xml
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/demo/3D_strep_unlink.xml b/protocol/demo/3D_strep_unlink.xml
new file mode 100644
index 000000000..789251295
--- /dev/null
+++ b/protocol/demo/3D_strep_unlink.xml
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/demo/BM3_example.xml b/protocol/demo/BM3_example.xml
new file mode 100644
index 000000000..2b03bef7d
--- /dev/null
+++ b/protocol/demo/BM3_example.xml
@@ -0,0 +1,214 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/demo/rods.xml b/protocol/demo/bacilli.xml
similarity index 92%
rename from protocol/demo/rods.xml
rename to protocol/demo/bacilli.xml
index 57cd899da..be21274af 100644
--- a/protocol/demo/rods.xml
+++ b/protocol/demo/bacilli.xml
@@ -1,7 +1,8 @@
-
+
@@ -31,7 +32,7 @@
-
+
@@ -41,6 +42,7 @@
+
@@ -50,8 +52,8 @@
-
-
+
+
diff --git a/protocol/demo/single fillament 3D.xml b/protocol/demo/single fillament 3D.xml
new file mode 100644
index 000000000..be8b08c8d
--- /dev/null
+++ b/protocol/demo/single fillament 3D.xml
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/demo/stochastic_movement.xml b/protocol/demo/stochastic_movement.xml
deleted file mode 100644
index fbdfe5717..000000000
--- a/protocol/demo/stochastic_movement.xml
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/protocol/demo/test.xml b/protocol/demo/test.xml
deleted file mode 100644
index bd5a9b659..000000000
--- a/protocol/demo/test.xml
+++ /dev/null
@@ -1,158 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/protocol/ecoli tests/ecoli.xml b/protocol/ecoli tests/ecoli.xml
index bf32b1a1d..f41787b37 100644
--- a/protocol/ecoli tests/ecoli.xml
+++ b/protocol/ecoli tests/ecoli.xml
@@ -19,7 +19,6 @@
-
diff --git a/protocol/ecoli tests/ecoli2D.xml b/protocol/ecoli tests/ecoli2D.xml
index f01a4a80f..8b6c42760 100644
--- a/protocol/ecoli tests/ecoli2D.xml
+++ b/protocol/ecoli tests/ecoli2D.xml
@@ -132,8 +132,8 @@
-
-
+
+
@@ -153,14 +153,14 @@
+ firstStep="0.0" >
+ firstStep="0.0" >
diff --git a/protocol/mgfas_tests/nodes_test_periodic_batch.xml b/protocol/mgfas_tests/nodes_test_periodic_batch.xml
new file mode 100644
index 000000000..7dbd50805
--- /dev/null
+++ b/protocol/mgfas_tests/nodes_test_periodic_batch.xml
@@ -0,0 +1,357 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/mgfas_tests/nodes_test_periodic_long_auto_adjust.xml b/protocol/mgfas_tests/nodes_test_periodic_long_auto_adjust.xml
new file mode 100644
index 000000000..f348b5780
--- /dev/null
+++ b/protocol/mgfas_tests/nodes_test_periodic_long_auto_adjust.xml
@@ -0,0 +1,357 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/mgfas_tests/nodes_test_solid.xml b/protocol/mgfas_tests/nodes_test_solid.xml
new file mode 100644
index 000000000..aeec6275b
--- /dev/null
+++ b/protocol/mgfas_tests/nodes_test_solid.xml
@@ -0,0 +1,366 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/mgfas_tests/nodes_test_solid2.xml b/protocol/mgfas_tests/nodes_test_solid2.xml
new file mode 100644
index 000000000..2a9a5f9f5
--- /dev/null
+++ b/protocol/mgfas_tests/nodes_test_solid2.xml
@@ -0,0 +1,369 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Eco Ego_mgFas.xml b/protocol/testing/Eco Ego_mgFas.xml
new file mode 100644
index 000000000..b465da6d6
--- /dev/null
+++ b/protocol/testing/Eco Ego_mgFas.xml
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - empty.xml b/protocol/testing/Solver tests/Solver test - empty.xml
new file mode 100644
index 000000000..1105561c3
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - empty.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - larger 1 step 5V.xml b/protocol/testing/Solver tests/Solver test - larger 1 step 5V.xml
new file mode 100644
index 000000000..a8b87245c
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - larger 1 step 5V.xml
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - larger 1 step.xml b/protocol/testing/Solver tests/Solver test - larger 1 step.xml
new file mode 100644
index 000000000..26a08a663
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - larger 1 step.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - larger 10 step.xml b/protocol/testing/Solver tests/Solver test - larger 10 step.xml
new file mode 100644
index 000000000..71f3971b3
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - larger 10 step.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - larger 3 step 15V.xml b/protocol/testing/Solver tests/Solver test - larger 3 step 15V.xml
new file mode 100644
index 000000000..4f5c305a3
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - larger 3 step 15V.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - larger 3 step 50V.xml b/protocol/testing/Solver tests/Solver test - larger 3 step 50V.xml
new file mode 100644
index 000000000..f1d285b44
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - larger 3 step 50V.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - larger s30 v50 lower diff.xml b/protocol/testing/Solver tests/Solver test - larger s30 v50 lower diff.xml
new file mode 100644
index 000000000..66ff6773b
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - larger s30 v50 lower diff.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - medium 10 step.xml b/protocol/testing/Solver tests/Solver test - medium 10 step.xml
new file mode 100644
index 000000000..6d1c1b1ef
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - medium 10 step.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - medium 3 step.xml b/protocol/testing/Solver tests/Solver test - medium 3 step.xml
new file mode 100644
index 000000000..2d2506c62
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - medium 3 step.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - small 1 step.xml b/protocol/testing/Solver tests/Solver test - small 1 step.xml
new file mode 100644
index 000000000..37e97f35a
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - small 1 step.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - small 10 step.xml b/protocol/testing/Solver tests/Solver test - small 10 step.xml
new file mode 100644
index 000000000..a4651054b
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - small 10 step.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - small 3 step 50V.xml b/protocol/testing/Solver tests/Solver test - small 3 step 50V.xml
new file mode 100644
index 000000000..947f53f7f
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - small 3 step 50V.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test - various settings.xml b/protocol/testing/Solver tests/Solver test - various settings.xml
new file mode 100644
index 000000000..93ddaa22c
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test - various settings.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test.xml b/protocol/testing/Solver tests/Solver test.xml
new file mode 100644
index 000000000..ecea8c4a1
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test_even dist.xml b/protocol/testing/Solver tests/Solver test_even dist.xml
new file mode 100644
index 000000000..24d0d4e20
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test_even dist.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test_even dist2.xml b/protocol/testing/Solver tests/Solver test_even dist2.xml
new file mode 100644
index 000000000..53ee76cd3
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test_even dist2.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver tests/Solver test_even dist3.xml b/protocol/testing/Solver tests/Solver test_even dist3.xml
new file mode 100644
index 000000000..71f3971b3
--- /dev/null
+++ b/protocol/testing/Solver tests/Solver test_even dist3.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Solver_test_even_dist_record.xml b/protocol/testing/Solver_test_even_dist_record.xml
new file mode 100644
index 000000000..cee6e94bb
--- /dev/null
+++ b/protocol/testing/Solver_test_even_dist_record.xml
@@ -0,0 +1,153 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego.xml b/protocol/testing/Vmax_eco_ego.xml
new file mode 100644
index 000000000..5552096f7
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego2.xml b/protocol/testing/Vmax_eco_ego2.xml
new file mode 100644
index 000000000..e6522ce31
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego2.xml
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego_v4_c3.xml b/protocol/testing/Vmax_eco_ego_v4_c3.xml
new file mode 100644
index 000000000..d9487bdb8
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego_v4_c3.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego_v4_d3.xml b/protocol/testing/Vmax_eco_ego_v4_d3.xml
new file mode 100644
index 000000000..658cf39b7
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego_v4_d3.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego_v4_e3.xml b/protocol/testing/Vmax_eco_ego_v4_e3.xml
new file mode 100644
index 000000000..448682143
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego_v4_e3.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego_v4_e3_2.5D.xml b/protocol/testing/Vmax_eco_ego_v4_e3_2.5D.xml
new file mode 100644
index 000000000..2294f84d7
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego_v4_e3_2.5D.xml
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego_v4_e3_SHOVING.xml b/protocol/testing/Vmax_eco_ego_v4_e3_SHOVING.xml
new file mode 100644
index 000000000..2da84ae1f
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego_v4_e3_SHOVING.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego_v4_e3b.xml b/protocol/testing/Vmax_eco_ego_v4_e3b.xml
new file mode 100644
index 000000000..d5dd5c6d3
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego_v4_e3b.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego_v5_c3_10w.xml b/protocol/testing/Vmax_eco_ego_v5_c3_10w.xml
new file mode 100644
index 000000000..f33e0ae8e
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego_v5_c3_10w.xml
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego_v5_d3_10w.xml b/protocol/testing/Vmax_eco_ego_v5_d3_10w.xml
new file mode 100644
index 000000000..46b764861
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego_v5_d3_10w.xml
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego_v5_e3.xml b/protocol/testing/Vmax_eco_ego_v5_e3.xml
new file mode 100644
index 000000000..303274aec
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego_v5_e3.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego_v5_e3_10w.xml b/protocol/testing/Vmax_eco_ego_v5_e3_10w.xml
new file mode 100644
index 000000000..694f656f2
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego_v5_e3_10w.xml
@@ -0,0 +1,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/Vmax_eco_ego_v5_e3_10w_fast.xml b/protocol/testing/Vmax_eco_ego_v5_e3_10w_fast.xml
new file mode 100644
index 000000000..f7f5e40a7
--- /dev/null
+++ b/protocol/testing/Vmax_eco_ego_v5_e3_10w_fast.xml
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/benchmark_3_modified.xml b/protocol/testing/benchmark_3_modified.xml
new file mode 100644
index 000000000..b412135c1
--- /dev/null
+++ b/protocol/testing/benchmark_3_modified.xml
@@ -0,0 +1,197 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/benchmark_3_modified_3D.xml b/protocol/testing/benchmark_3_modified_3D.xml
new file mode 100644
index 000000000..b68521049
--- /dev/null
+++ b/protocol/testing/benchmark_3_modified_3D.xml
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/benchmark_3_modified_huge_3D.xml b/protocol/testing/benchmark_3_modified_huge_3D.xml
new file mode 100644
index 000000000..68486cabd
--- /dev/null
+++ b/protocol/testing/benchmark_3_modified_huge_3D.xml
@@ -0,0 +1,189 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/multigrid _ cell layer.xml b/protocol/testing/multigrid _ cell layer.xml
new file mode 100644
index 000000000..8ced80fed
--- /dev/null
+++ b/protocol/testing/multigrid _ cell layer.xml
@@ -0,0 +1,159 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/reaction_diffusion_eco_ego.xml b/protocol/testing/reaction_diffusion_eco_ego.xml
new file mode 100644
index 000000000..4f78b220a
--- /dev/null
+++ b/protocol/testing/reaction_diffusion_eco_ego.xml
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/testing/reaction_diffusion_eco_ego_double_spaced.xml b/protocol/testing/reaction_diffusion_eco_ego_double_spaced.xml
new file mode 100644
index 000000000..7ec40cc76
--- /dev/null
+++ b/protocol/testing/reaction_diffusion_eco_ego_double_spaced.xml
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/unit-tests/reaction_diffusion.xml b/protocol/unit-tests/reaction_diffusion.xml
index 012273164..824fcd342 100644
--- a/protocol/unit-tests/reaction_diffusion.xml
+++ b/protocol/unit-tests/reaction_diffusion.xml
@@ -37,7 +37,6 @@
-
@@ -70,6 +69,10 @@
+
+
+
+
diff --git a/protocol/unit-tests/reaction_diffusion_mgFas.xml b/protocol/unit-tests/reaction_diffusion_mgFas.xml
new file mode 100644
index 000000000..ae79f8a24
--- /dev/null
+++ b/protocol/unit-tests/reaction_diffusion_mgFas.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/unit-tests/reaction_diffusion_mgFas_ecoli.xml b/protocol/unit-tests/reaction_diffusion_mgFas_ecoli.xml
new file mode 100644
index 000000000..d8da66199
--- /dev/null
+++ b/protocol/unit-tests/reaction_diffusion_mgFas_ecoli.xml
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/unit-tests/reaction_diffusion_smooth_distribution.xml b/protocol/unit-tests/reaction_diffusion_smooth_distribution.xml
new file mode 100644
index 000000000..492d28809
--- /dev/null
+++ b/protocol/unit-tests/reaction_diffusion_smooth_distribution.xml
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/protocol/unit-tests/reaction_diffusion_smooth_distribution_0_boundry.xml b/protocol/unit-tests/reaction_diffusion_smooth_distribution_0_boundry.xml
new file mode 100644
index 000000000..20c96e432
--- /dev/null
+++ b/protocol/unit-tests/reaction_diffusion_smooth_distribution_0_boundry.xml
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/agent/Agent.java b/src/agent/Agent.java
index 49a64f562..8ad5565a6 100644
--- a/src/agent/Agent.java
+++ b/src/agent/Agent.java
@@ -2,6 +2,7 @@
import java.util.LinkedList;
import java.util.List;
+import debugTools.SegmentTimer;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@@ -89,7 +90,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() ) );
@@ -113,21 +115,24 @@ 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);
}
- this.init();
+ this.initiate();
}
private void number(Integer in)
{
-
if(in != null)
{
if ( UNIQUE_ID <= in )
UNIQUE_ID++;
- if( Idynomics.simulator.findAgent(Integer.valueOf(in)) == null)
+ if( Idynomics.simulator.active() || //IMPORTANT prevent searching for duplicate number assignment in running simulations for efficiency.
+ Idynomics.simulator.findAgent(Integer.valueOf(in)) == null )
this._uid = Integer.valueOf(in);
else
{
@@ -143,12 +148,11 @@ private void number(Integer in)
/**
* Assign the correct species from the species library
*/
- public void init()
+ public void initiate()
{
- String species;
if( this._uid == 0)
this.number(null);
-
+ String species;
species = this.getString(XmlRef.species);
this._aspectRegistry.addModule( (Species)
Idynomics.simulator.speciesLibrary.get(species), species);
@@ -162,7 +166,7 @@ public void instantiate(Element xmlElement, Settable parent)
((Compartment) parent.getParent()).addAgent(this);
this._compartment = (Compartment) parent.getParent();
loadAspects(xmlElement);
- this.init();
+ this.initiate();
this._parentNode = parent;
}
@@ -183,7 +187,7 @@ public Agent(Node xmlNode, Body body)
{
this.loadAspects(xmlNode);
this.set(AspectRef.agentBody, body);
- this.init();
+ this.initiate();
}
/**
@@ -194,14 +198,14 @@ public Agent(Node xmlNode, Body body)
public Agent(Node xmlNode, boolean boo)
{
this.loadAspects(xmlNode);
- this.init();
+ this.initiate();
}
public Agent(String species, Compartment comp)
{
this.set(XmlRef.species, species);
this._compartment = comp;
- this.init();
+ this.initiate();
}
public Agent(String species, Body body, Compartment comp)
@@ -209,7 +213,7 @@ public Agent(String species, Body body, Compartment comp)
this.set(XmlRef.species, species);
this.set(AspectRef.agentBody, body);
this._compartment = comp;
- this.init();
+ this.initiate();
}
/**
@@ -220,7 +224,7 @@ public Agent(String species, Body body, Compartment comp)
public Agent(Agent agent)
{
this._aspectRegistry.duplicate(agent);
- this.init();
+ this.initiate();
this._compartment = agent.getCompartment();
}
@@ -393,7 +397,7 @@ public Module getModule()
public void setModule(Module node)
{
Settable.super.setModule(node);
- this.init(); // Updates species module if changed
+ this.initiate(); // Updates species module if changed
}
/**
diff --git a/src/agent/Body.java b/src/agent/Body.java
index 6a1ae0772..9155f12a3 100644
--- a/src/agent/Body.java
+++ b/src/agent/Body.java
@@ -353,7 +353,6 @@ public void instantiate(Element xmlElem, Settable parent)
constructBody();
}
-
}
/*************************************************************************
diff --git a/src/analysis/quantitative/DistanceVector.java b/src/analysis/quantitative/DistanceVector.java
new file mode 100644
index 000000000..b4638bd2a
--- /dev/null
+++ b/src/analysis/quantitative/DistanceVector.java
@@ -0,0 +1,21 @@
+package analysis.quantitative;
+
+import linearAlgebra.Vector;
+
+public class DistanceVector {
+
+ int[] vector;
+
+ public DistanceVector(int[] vector)
+ {
+ this.vector = Vector.copy(vector);
+ }
+
+ public void set(int[] vector) {
+ this.vector = Vector.copy(vector);
+ }
+
+ public int[] get() {
+ return this.vector;
+ }
+}
diff --git a/src/analysis/quantitative/Raster.java b/src/analysis/quantitative/Raster.java
index b48655359..2284078fb 100644
--- a/src/analysis/quantitative/Raster.java
+++ b/src/analysis/quantitative/Raster.java
@@ -75,8 +75,11 @@ public class Raster {
/* analysis */
protected SpatialMap _agentDistanceMap;
+ public SpatialMap _agentMap;
+
protected SpatialMap _edgeDistanceMap;
- private SpatialMap _edgeDistanceMapDbl;
+ public SpatialMap _edgeDistanceMapDbl;
+
private double _voxelLength;
/* header for default analysis output */
@@ -88,6 +91,10 @@ public class Raster {
"fraction encapsulated void space"
};
+ protected int[][][] biofilmDepth;
+ protected int[][][] edgeMatrix;
+ protected int[][][] diffusionDistance;
+
private enum Region
{
GAP, EDGE, BOUNDARY, CUSTOM
@@ -191,6 +198,8 @@ public void rasterize( double voxelLength )
int[][][] edge = Array.copy( agents );
agents = this.distanceMatrix( agents );
+ this._agentMap = euclideanMapDbl( agents );
+
long millis = System.currentTimeMillis();
if ( this._verbose )
this.plotArray(agents, "ag" + millis );
@@ -206,9 +215,9 @@ public void rasterize( double voxelLength )
/* plot edge euclidean distance */
this._edgeDistanceMap = euclideanMap( edge );
-
+
this._edgeDistanceMapDbl = euclideanMapDbl( edge );
-
+
/* NOTE for testing: looking for co-ocurance
traitLocalization("species=CanonicalAOB", "species=CanonicalNOB" ); */
}
@@ -647,7 +656,7 @@ public SpatialMap agentMap()
out.put(c, 1);
return out;
}
-
+
public SpatialMap agentDistanceMap()
{
return this._agentDistanceMap;
@@ -1082,6 +1091,20 @@ public SpatialMap euclideanMap( int[][][] matrix)
this.plot( distance, 1, "eucliMap" + millis, Helper.giveMeAGradient( max+1 ) );
return distance;
}
+
+ public SpatialMap euclideanMapDbl()
+ {
+ int[][][] agents = new int[rX][rY][2];
+
+ /* fill matrix, add spacers for non periodic. */
+ agents = this.presenceMapToArray( agents, this.agentMap(), true, true);
+
+ agents = this.distanceMatrix( agents );
+ agents = this.edgeMatrix( agents );
+ agents = this.distanceMatrix( agents );
+
+ return euclideanMapDbl( agents );
+ }
public SpatialMap euclideanMapDbl( int[][][] matrix )
{
diff --git a/src/aspect/AspectInterface.java b/src/aspect/AspectInterface.java
index 0b1eb5d26..8fcb54563 100644
--- a/src/aspect/AspectInterface.java
+++ b/src/aspect/AspectInterface.java
@@ -46,8 +46,11 @@ public default void loadAspects(Node xmlNode)
for (int j = 0; j < stateNodes.getLength(); j++)
{
Element s = (Element) stateNodes.item(j);
- key = s.getAttribute( XmlRef.nameAttribute );
- aspectReg.add( key, ObjectFactory.loadObject( s ) );
+ if(s.getParentNode() == e)
+ {
+ key = s.getAttribute( XmlRef.nameAttribute );
+ aspectReg.add( key, ObjectFactory.loadObject( s ) );
+ }
}
}
}
@@ -223,7 +226,7 @@ public default Boolean getBoolean(String aspect)
{
Boolean out = (Boolean) this.reg().getValue(this, aspect);
if( out == null )
- return false;
+ return null;
return out;
}
diff --git a/src/aspect/event/CoccoidDivision.java b/src/aspect/event/CoccoidDivision.java
index 494169ce2..2167ec357 100644
--- a/src/aspect/event/CoccoidDivision.java
+++ b/src/aspect/event/CoccoidDivision.java
@@ -3,6 +3,7 @@
import agent.Agent;
import agent.Body;
import aspect.methods.DivisionMethod;
+import debugTools.SegmentTimer;
import linearAlgebra.Vector;
import referenceLibrary.AspectRef;
import surface.Point;
@@ -29,11 +30,11 @@ protected void shiftBodies(Agent mother, Agent daughter)
{
Body momBody = (Body) mother.get(AspectRef.agentBody);
Body daughterBody = (Body) daughter.get(AspectRef.agentBody);
-
+
double[] originalPos = momBody.getPosition(0);
double[] shift = Vector.randomPlusMinus(originalPos.length,
0.5*mother.getDouble(AspectRef.bodyRadius));
-
+
Point p = momBody.getPoints().get(0);
p.setPosition(Vector.add(originalPos, shift));
Point q = daughterBody.getPoints().get(0);
diff --git a/src/aspect/methods/DivisionMethod.java b/src/aspect/methods/DivisionMethod.java
index 98944b10c..a8b68bc7b 100644
--- a/src/aspect/methods/DivisionMethod.java
+++ b/src/aspect/methods/DivisionMethod.java
@@ -9,6 +9,7 @@
import aspect.Aspect.AspectClass;
import dataIO.Log;
import dataIO.Log.Tier;
+import debugTools.SegmentTimer;
import referenceLibrary.AspectRef;
import utility.ExtraMath;
import utility.Helper;
@@ -23,8 +24,10 @@ public void start(AspectInterface initiator,
/* Make one new agent, copied from the mother.*/
compliant = new Agent((Agent) initiator);
+
/* Transfer an appropriate amount of mass from mother to daughter. */
DivisionMethod.transferMass(initiator, compliant);
+
/* Update their bodies, if they have them. */
if ( initiator.isAspect(AspectRef.agentBody) &&
initiator.isAspect(AspectRef.bodyRadius) )
diff --git a/src/bookkeeper/KeeperEntry.java b/src/bookkeeper/KeeperEntry.java
index 1393501d5..453e09698 100644
--- a/src/bookkeeper/KeeperEntry.java
+++ b/src/bookkeeper/KeeperEntry.java
@@ -64,7 +64,7 @@ public Module getModule()
modelNode.add( new Attribute(XmlRef.valueAttribute,
String.valueOf( this._value ), null, true ) );
-
+
if( this._settable != null )
modelNode.add( this._settable.getModule() );
diff --git a/src/boundary/WellMixedBoundary.java b/src/boundary/WellMixedBoundary.java
index fffe5c3ae..86014bc7c 100644
--- a/src/boundary/WellMixedBoundary.java
+++ b/src/boundary/WellMixedBoundary.java
@@ -47,8 +47,11 @@ public double getConcentration(String soluteName)
}
catch (Exception e)
{
- Log.out(Tier.CRITICAL, "Error getting solute \""+soluteName+"\"");
- throw e;
+ Log.out(Tier.CRITICAL, "Error getting solute \""+soluteName+"\" \n" +
+ "Check whether all WellMixed boundaries are properly initialized.");
+ Thread.dumpStack();
+ return 0.0;
+// throw e;
}
}
}
diff --git a/src/boundary/spatialLibrary/BiofilmBoundaryLayer.java b/src/boundary/spatialLibrary/BiofilmBoundaryLayer.java
index 0f1e0575a..fa1239808 100644
--- a/src/boundary/spatialLibrary/BiofilmBoundaryLayer.java
+++ b/src/boundary/spatialLibrary/BiofilmBoundaryLayer.java
@@ -2,6 +2,9 @@
import static grid.ArrayType.WELLMIXED;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import agent.Agent;
@@ -15,9 +18,12 @@
import linearAlgebra.Vector;
import referenceLibrary.AspectRef;
import shape.Shape;
+import spatialRegistry.SpatialRegistry;
+import spatialRegistry.splitTree.SplitTree;
import surface.Ball;
import surface.BoundingBox;
import surface.Surface;
+import surface.Voxel;
import surface.collision.Collision;
/**
@@ -51,7 +57,7 @@ public class BiofilmBoundaryLayer extends WellMixedBoundary
*/
// NOTE This is not a permanent solution.
public static double MOVE_TSTEP = 1.0;
-
+
/* ***********************************************************************
* CONSTRUCTOR
* **********************************************************************/
@@ -131,10 +137,8 @@ protected double calcDiffusiveFlow(SpatialGrid grid)
double concn = this._concns.get(grid.getName());
return this.calcDiffusiveFlowFixed(grid, concn);
}
-
- @SuppressWarnings("unchecked")
- @Override
- public void updateWellMixedArray()
+
+ public void updateWellMixedArrayOld()
{
Shape aShape = this._environment.getShape();
SpatialGrid grid = this._environment.getCommonGrid();
@@ -168,7 +172,12 @@ public void updateWellMixedArray()
double[] voxelCenterTrimmed = Vector.zerosDbl(numDim);
List neighbors;
BoundingBox box;
- while ( aShape.isIteratorValid() )
+ Voxel innerBox = new Voxel(Vector.vector(numDim,0.0),
+ Vector.vector(numDim,0.0));
+
+ /* naming parent loop so that we can break
+ out of it instantly when we hit and agent */
+ shapeloop : while ( aShape.isIteratorValid() )
{
aShape.voxelCentreTo(voxelCenter, coords);
Vector.copyTo(voxelCenterTrimmed, voxelCenter);
@@ -179,6 +188,7 @@ public void updateWellMixedArray()
*/
box = this._gridSphere.boundingBox(this._agents.getShape());
neighbors = this._agents.treeSearch(box);
+
for ( Agent a : neighbors )
for (Surface s : (List) ((Body)
a.get( AspectRef.agentBody )).getSurfaces() )
@@ -186,13 +196,83 @@ public void updateWellMixedArray()
{
grid.setValueAt(WELLMIXED, coords,
WellMixedConstants.NOT_MIXED);
- break;
+ coords = aShape.iteratorNext();
+ continue shapeloop;
}
coords = aShape.iteratorNext();
}
}
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public void updateWellMixedArray()
+ {
+ Shape aShape = this._environment.getShape();
+ SpatialGrid grid = this._environment.getCommonGrid();
+ int numDim = aShape.getNumberOfDimensions();
+ /*
+ * Iterate over all voxels, checking if there are agents nearby.
+ */
+ double[] min = Vector.zerosDbl( aShape.getNumberOfDimensions() );
+
+ SpatialRegistry voxelRegistry =
+ new SplitTree( 1 + (2 << min.length) ,
+ min, Vector.add( min, aShape.getDimensionLengths() ),
+ aShape.getIsCyclicNaturalOrder() );
+
+ HashMap reiterate = new HashMap();
+
+ int[] coords = aShape.resetIterator();
+ while ( aShape.isIteratorValid() )
+ {
+ double[] voxelOrigin = aShape.getVoxelOrigin(coords);
+ double[] voxelUpper = aShape.getVoxelUpperCorner(coords);
+ Voxel box = new Voxel( Vector.subset(voxelOrigin, aShape.getNumberOfDimensions()),
+ Vector.subset(voxelUpper, aShape.getNumberOfDimensions()) );
+ if ( ! this._agents.treeSearch(box.boundingBox(aShape)).isEmpty() )
+ {
+ grid.setValueAt(WELLMIXED, coords,
+ WellMixedConstants.NOT_MIXED);
+ voxelRegistry.insert(box.boundingBox(aShape), box);
+ }
+ else
+ {
+ reiterate.put(box,coords);
+ }
+ coords = aShape.iteratorNext();
+ }
+
+ if (this._layerThickness > 0.0 )
+ {
+ coords = aShape.resetIterator();
+ double[] voxelCenter = aShape.getVoxelCentre(coords);
+ double[] voxelCenterTrimmed = Vector.zerosDbl(numDim);
+
+ /* naming parent loop so that we can break
+ out of it instantly when we hit and agent */
+ shapeloop : while ( aShape.isIteratorValid() ) {
+ aShape.voxelCentreTo(voxelCenter, coords);
+ Vector.copyTo(voxelCenterTrimmed, voxelCenter);
+ this._gridSphere.setCenter(voxelCenterTrimmed);
+ /*
+ * Find all nearby agents. Set the grid to zero if an agent is
+ * within the grid's sphere
+ */
+ BoundingBox box = this._gridSphere.boundingBox(this._agents.getShape());
+
+ for (Voxel v : voxelRegistry.search(box))
+ if (this._gridSphere.distanceTo(v) < 0.0) {
+ grid.setValueAt(WELLMIXED, coords,
+ WellMixedConstants.NOT_MIXED);
+// coords = aShape.iteratorNext();
+ break;
+ }
+ coords = aShape.iteratorNext();
+ }
+ }
+ }
+
@Override
public void additionalPartnerUpdate()
{
@@ -200,7 +280,7 @@ public void additionalPartnerUpdate()
for ( String soluteName : this._environment.getSoluteNames() )
this._concns.put(soluteName, p.getSoluteConcentration(soluteName));
}
-
+
public boolean isSolid()
{
return false;
diff --git a/src/colour/Colour.java b/src/colour/Colour.java
index 00a3ef4d3..73d1ea74c 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.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 f0718f333..b215552c1 100644
--- a/src/colour/ColourSpecification.java
+++ b/src/colour/ColourSpecification.java
@@ -26,9 +26,14 @@ 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] );
+ }
+
+ 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/compartment/AgentContainer.java b/src/compartment/AgentContainer.java
index 277e97fa5..e533c57f6 100644
--- a/src/compartment/AgentContainer.java
+++ b/src/compartment/AgentContainer.java
@@ -21,6 +21,7 @@
import gereralPredicates.IsSame;
import idynomics.Global;
import idynomics.Idynomics;
+import instantiable.object.InstantiableList;
import linearAlgebra.Vector;
import physicalObject.PhysicalObject;
import referenceLibrary.AspectRef;
@@ -714,6 +715,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 0e08b4eb4..35ae38e05 100644
--- a/src/compartment/Compartment.java
+++ b/src/compartment/Compartment.java
@@ -11,6 +11,7 @@
import org.w3c.dom.Element;
import agent.Agent;
+
import bookkeeper.Bookkeeper;
import bookkeeper.KeeperEntry.EventType;
import boundary.Boundary;
@@ -107,21 +108,21 @@ public class Compartment implements CanPrelaunchCheck, Instantiable, Settable, C
*/
protected LinkedList _processes =
new LinkedList();
-
+
/**
* List of arrival processes, to be carried out of the beginning of a
* global timestep.
*/
- protected LinkedList _arrivalProcesses =
+ protected LinkedList _arrivalProcesses =
new LinkedList();
-
+
/**
* List of departure processes, to be carried out at the end of a global
* timestep.
*/
- protected LinkedList _departureProcesses =
+ protected LinkedList _departureProcesses =
new LinkedList();
-
+
/**
* ProcessComparator orders Process Managers by their time priority.
*/
@@ -148,13 +149,13 @@ public class Compartment implements CanPrelaunchCheck, Instantiable, Settable, C
*
*/
private int _priority = Integer.MAX_VALUE;
-
+
/**
* Collection of arrival nodes
*/
- private LinkedList _arrivals =
+ private LinkedList _arrivals =
new LinkedList();
-
+
/* ***********************************************************************
* CONSTRUCTORS
* **********************************************************************/
@@ -346,20 +347,20 @@ else if (simulatedLengths.length != 0)
(ProcessManager) Instance.getNew(e, this, (String[])null));
}
- for ( Element e : XmlHandler.getElements(
+ for ( Element e : XmlHandler.getElements(
xmlElem, XmlRef.arrivalProcesses) )
{
this.addProcessManager(
(ProcessManager) Instance.getNew(e, this, (String[])null));
}
-
- for ( Element e : XmlHandler.getElements(
+
+ for ( Element e : XmlHandler.getElements(
xmlElem, XmlRef.departureProcesses) )
{
this.addProcessManager(
(ProcessManager) Instance.getNew(e, this, (String[])null));
}
-
+
for ( Element e : XmlHandler.getElements(xmlElem,XmlRef.physicalObject))
{
this.addPhysicalObject( (PhysicalObject) Instance.getNew(e, this,
@@ -377,7 +378,7 @@ else if (simulatedLengths.length != 0)
this.getShape().setOrientation( (Orientation) Instance.getNew( elem,
this, Orientation.class.getName() ) );
}
-
+
/**
* Add the arrivals lounge(s)
*/
@@ -464,6 +465,7 @@ else if (aProcessManager instanceof ProcessDeparture)
}
// TODO Rob [18Apr2016]: Check if the process's next time step is
// earlier than the current time.
+ Collections.sort(this._processes, this._procComp);
}
/**
@@ -533,7 +535,7 @@ public SpatialGrid getSolute(String soluteName)
/* ***********************************************************************
* AGENT TRANSFER
* **********************************************************************/
-
+
/**
* This method accepts new agents into an arrival lounge. It is called by a
* departure method.
@@ -558,7 +560,7 @@ public void acceptAgents(String origin, LinkedList agents)
this._arrivals.add(a);
a.addAgents(agents);
}
-
+
/**
* This method gets a list of arriving agents that originated in a
* particular compartment. It is typically called by arrival processes.
@@ -577,15 +579,15 @@ public LinkedList getArrivals (String origin)
return arrivals;
}
}
-
+
//Return empty list if no departures have been received from the origin
//in the last timestep.
return arrivals;
-
+
}
-
-
-
+
+
+
/* ***********************************************************************
* STEPPING
* **********************************************************************/
@@ -593,7 +595,7 @@ public LinkedList getArrivals (String origin)
public void runProcesses(LinkedList processes)
{
ProcessManager currentProcess = processes.getFirst();
- while ( (this._localTime = currentProcess.getTimeForNextStep() )
+ while ( (this._localTime = currentProcess.getTimeForNextStep() )
< Idynomics.simulator.timer.getEndOfCurrentIteration() &&
Idynomics.simulator.active() )
{
@@ -601,7 +603,7 @@ public void runProcesses(LinkedList processes)
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.
@@ -617,7 +619,7 @@ public void runProcesses(LinkedList processes)
currentProcess = processes.getFirst();
}
}
-
+
/**
* \brief Connects any disconnected boundaries to a new partner boundary on
* the appropriate compartment.
@@ -664,40 +666,46 @@ public void checkAgentDeparture()
{
if (this._departureProcesses.isEmpty())
{
- ProcessDeparture defaultDepartureProcess = (ProcessDeparture)
- Instance.getNew(ClassRef.floatingAgentDeparture, null);
- defaultDepartureProcess.set(
- AspectRef.collisionSearchDistance,
- Global.default_attachment_pull_distance);
- defaultDepartureProcess.setPriority(0);
- defaultDepartureProcess.setDepartureType(
- ProcessDeparture.DepartureType.REMOVAL);
- defaultDepartureProcess.setShape(this._shape);
- defaultDepartureProcess.setAgentContainer(this.agents);
- defaultDepartureProcess.setTimeStep(
- Idynomics.simulator.timer.getTimeStepSize());
- this._departureProcesses.add(defaultDepartureProcess);
+ Log.out(Tier.CRITICAL, "Warning: no departure process set.");
+// ProcessDeparture defaultDepartureProcess = (ProcessDeparture)
+// Instance.getNew(ClassRef.floatingAgentDeparture, null);
+// defaultDepartureProcess.set(
+// AspectRef.collisionSearchDistance,
+// Global.default_attachment_pull_distance);
+// defaultDepartureProcess.setPriority(0);
+// defaultDepartureProcess.setDepartureType(
+// ProcessDeparture.DepartureType.REMOVAL);
+// defaultDepartureProcess.setShape(this._shape);
+// defaultDepartureProcess.setAgentContainer(this.agents);
+// defaultDepartureProcess.setTimeStep(
+// Idynomics.simulator.timer.getTimeStepSize());
+// this._departureProcesses.add(defaultDepartureProcess);
}
}
}
-
+
/**
* \brief Do all inbound agent & solute transfers.
*/
public void preStep()
{
this._bookKeeper.clear();
-
+
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._arrivalProcesses.isEmpty() )
- this.runProcesses(this._arrivalProcesses);
+ this.runProcesses(this._arrivalProcesses);
+ else
+ {
+ // is there any default way to accept arriving agents?
+ // if not there should be at least a warning
+ }
this.agents.sortLocatedAgents();
}
@@ -710,7 +718,7 @@ public void step()
{
this._localTime = Idynomics.simulator.timer.getCurrentTime();
-
+
if (! this._processes.isEmpty() )
this.runProcesses(this._processes);
}
@@ -729,7 +737,18 @@ public void postStep()
if( Global.csv_bookkeeping)
this.writeEventLog();
}
-
+
+ /**
+ * For stepping non-timebased processes (eg post processing).
+ * @param process
+ */
+ public void process(String process)
+ {
+ for ( ProcessManager p : this._processes )
+ if( p.getName().equals(process) )
+ p.step();
+ }
+
/* ***********************************************************************
* PRE-LAUNCH CHECK
* **********************************************************************/
@@ -769,7 +788,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());
}
@@ -847,25 +867,25 @@ private LinkedList getProcessNodes()
/* The process managers node. */
Module processNode = new Module( XmlRef.processManagers, this );
processNode.setRequirements( Requirements.EXACTLY_ONE );
-
+
Module arrivalNode = new Module( XmlRef.arrivalProcesses, this );
arrivalNode.setRequirements( Requirements.EXACTLY_ONE );
-
+
Module departureNode = new Module( XmlRef.departureProcesses, this );
departureNode.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
*/
- processNode.addChildSpec( ClassRef.processManager,
- Helper.collectionToArray( ProcessManager.getAllOptions() ),
+ processNode.addChildSpec( ClassRef.processManager,
+ Helper.collectionToArray( ProcessManager.getAllOptions() ),
Module.Requirements.ZERO_TO_MANY );
-
- arrivalNode.addChildSpec( ClassRef.processArrival,
- Helper.collectionToArray( ProcessManager.getAllOptions() ),
+
+ arrivalNode.addChildSpec( ClassRef.processArrival,
+ Helper.collectionToArray( ProcessManager.getAllOptions() ),
Module.Requirements.ZERO_TO_MANY );
-
- departureNode.addChildSpec( ClassRef.processDeparture,
+
+ departureNode.addChildSpec( ClassRef.processDeparture,
Helper.collectionToArray( ProcessManager.getAllOptions() ),
Module.Requirements.ZERO_TO_MANY );
@@ -876,12 +896,12 @@ private LinkedList getProcessNodes()
departureNode.add(p.getModule());
for (ProcessManager p : this._processes)
processNode.add(p.getModule());
-
+
LinkedList modules = new LinkedList();
modules.add(processNode);
modules.add(arrivalNode);
modules.add(departureNode);
-
+
return modules;
}
diff --git a/src/compartment/EnvironmentContainer.java b/src/compartment/EnvironmentContainer.java
index 29a0b8af1..691522f26 100644
--- a/src/compartment/EnvironmentContainer.java
+++ b/src/compartment/EnvironmentContainer.java
@@ -8,16 +8,19 @@
import java.util.LinkedList;
import java.util.Map;
+import analysis.quantitative.Raster;
import boundary.Boundary;
import boundary.SpatialBoundary;
import boundary.WellMixedBoundary;
import dataIO.Log;
import dataIO.Log.Tier;
+import debugTools.SegmentTimer;
import generalInterfaces.CanPrelaunchCheck;
import grid.SpatialGrid;
import grid.WellMixedConstants;
import idynomics.Idynomics;
import instantiable.object.InstantiableList;
+import linearAlgebra.Vector;
import reaction.Reaction;
import reaction.RegularReaction;
import referenceLibrary.ClassRef;
@@ -26,6 +29,7 @@
import settable.Module.Requirements;
import settable.Settable;
import shape.Shape;
+import spatialRegistry.SpatialMap;
/**
* \brief Manages the solutes in a {@code Compartment}.
@@ -164,7 +168,9 @@ public SpatialGrid getSoluteGrid(String soluteName)
if ( sg.getName().equals(soluteName) )
return sg;
Log.out(Tier.CRITICAL,
- "EnvironmentContainer can't find grid for \""+soluteName+"\"");
+ "EnvironmentContainer can't find grid for \""+soluteName+"\" " +
+ this.getClass().getSimpleName());
+ Thread.dumpStack();
return null;
}
@@ -411,7 +417,7 @@ public void updateWellMixed()
this.getShape().getWellMixedBoundaries();
if ( bndrs.isEmpty() )
{
- commonGrid.setAllTo(WELLMIXED, WellMixedConstants.NOT_MIXED);
+// commonGrid.setAllTo(WELLMIXED, WellMixedConstants.NOT_MIXED); // should already be 0.0 ( NOT_MIXED )
return;
}
/*
@@ -449,7 +455,45 @@ public void updateWellMixed()
*/
for ( WellMixedBoundary b: bndrs )
{
- b.updateWellMixedArray();
+ if( this._shape.getSignificantDimensions().size() > 2 && this._shape.getDimensionVoxelCount(2) > 2 )
+ b.updateWellMixedArray();
+ else
+ {
+ //FIXME prototype code, currently we assume extra node is always periodic, but this could be hard boundary too!!!
+ Shape aShape = this._shape;
+ int[] coords = aShape.resetIterator();
+ Raster map = this.distanceMap();
+ SpatialGrid grid = this.getCommonGrid();
+
+ double[] temp = new double[]{0,0,0};
+ this.getShape().getVoxelSideLengthsTo( temp, new int[]{0,0,0});
+ double voxelSideLength = temp[0];
+
+ while ( aShape.isIteratorValid() ) {
+ int[] loc = Vector.copy(coords);
+ // handle periodic nodes
+ if( coords[0] >= aShape.getDimensionLengths()[0]/voxelSideLength )
+ loc[0] = 0;
+ if( coords[1] >= aShape.getDimensionLengths()[1]/voxelSideLength )
+ loc[1] = 0;
+
+ double l = map._edgeDistanceMapDbl.get(
+ Vector.subset(loc, new int[]{ 0, 1}) ) * voxelSideLength;
+ double d = b.getLayerThickness();
+ double a = map._agentMap.get(
+ Vector.subset(loc, new int[]{ 0, 1}) );
+
+ if( Log.shouldWrite( Tier.DEBUG ) )
+ Log.out( Tier.DEBUG, this.getClass().getSimpleName() +
+ " " + coords[0] + " " + coords[1] + " " + l + " " + d);
+ if( l < d || a > 0.0 )
+ {
+ grid.setValueAt(WELLMIXED, coords,
+ WellMixedConstants.NOT_MIXED);
+ }
+ coords = aShape.iteratorNext();
+ }
+ }
if ( b.needsToUpdateWellMixed() )
{
double sAreaFactor = b.getTotalSurfaceArea() * scaleFactor;
@@ -478,6 +522,17 @@ public void updateWellMixed()
}
}
}
+
+ public Raster distanceMap()
+ {
+ // 2D only!
+ Raster distanceMap = new Raster( ((Compartment) this._parentNode).agents, false);
+ double[] temp = new double[]{0,0,0};
+ this.getShape().getVoxelSideLengthsTo( temp, new int[]{0,0,0});
+ distanceMap.rasterize( temp[0] );
+ return distanceMap;
+ }
+
/* ***********************************************************************
* REPORTING
diff --git a/src/compartment/agentStaging/DistributedSpawner.java b/src/compartment/agentStaging/DistributedSpawner.java
index ced23369b..dff9fb540 100644
--- a/src/compartment/agentStaging/DistributedSpawner.java
+++ b/src/compartment/agentStaging/DistributedSpawner.java
@@ -61,9 +61,9 @@ public void spawn()
for( double d : positions(_orient[0],_spacing[0], _max[0]))
locations.add( new double[] {d} );
- LinkedList temp = new LinkedList();
for(int i = 1; i < _orient.length; i++)
{
+ LinkedList temp = new LinkedList();
for( double d : positions(_orient[i],_spacing[i], _max[i]))
{
for( double[] loc : locations )
@@ -74,8 +74,15 @@ public void spawn()
}
locations = (LinkedList) temp.clone();
}
+ int i = 0;
for ( double[] loc : locations )
+ {
+ /* break if the target number is reached */
+ if( i >= this._numberOfAgents)
+ break;
this.spawnAgent(loc);
+ i++;
+ }
}
/**
diff --git a/src/dataIO/CumulativeLoad.java b/src/dataIO/CumulativeLoad.java
new file mode 100644
index 000000000..e2f34714d
--- /dev/null
+++ b/src/dataIO/CumulativeLoad.java
@@ -0,0 +1,72 @@
+package dataIO;
+
+import java.util.Collection;
+import java.util.List;
+
+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;
+
+public class CumulativeLoad {
+
+ Element document;
+
+ public CumulativeLoad()
+ {
+
+ }
+
+ public CumulativeLoad(String xml)
+ {
+ document = XmlHandler.loadDocument(xml);
+ }
+
+ public Collection getProcessNodes()
+ {
+ return XmlHandler.getElements( document ,XmlRef.process );
+ }
+
+ public String test()
+ {
+
+ return "";
+ }
+
+ public void postProcess(int num)
+ {
+ Compartment comp = null;
+ for ( Element e : XmlHandler.getElements( document, XmlRef.process) )
+ {
+ 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);
+
+ }
+ }
+
+ 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/DrawMediator.java b/src/dataIO/DrawMediator.java
index d33d08dfb..1b3c1fbec 100644
--- a/src/dataIO/DrawMediator.java
+++ b/src/dataIO/DrawMediator.java
@@ -160,6 +160,8 @@ else if (_shape instanceof CylindricalShape)
/* Identify exact voxel location and size. */
origin = _shape.getVoxelOrigin(coord);
_shape.getVoxelSideLengthsTo(dimension, coord);
+ if( _shape.isNodeSystem() )
+ Vector.minusEquals( origin, _shape.getVoxelSideLengths( coord ) );
/*
* Scale the solute concentration for coloring.
* First, map the concentration to the real interval [0, 1].
@@ -186,7 +188,7 @@ else if (_shape instanceof CylindricalShape)
else
pigment = "rgb(" + c + "," + c + "," + c + ")";
if (_shape instanceof CartesianShape)
- _graphics.rectangle(Vector.subset(origin, nDim),
+ _graphics.rectangle(Vector.subset(origin, nDim),
Vector.subset(dimension, nDim),pigment);
else if (_shape instanceof CylindricalShape)
_graphics.circleElement(Vector.zerosDbl(2), origin,
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/dataIO/GraphicalExporter.java b/src/dataIO/GraphicalExporter.java
index 0e4dbe831..dc68104dd 100644
--- a/src/dataIO/GraphicalExporter.java
+++ b/src/dataIO/GraphicalExporter.java
@@ -194,5 +194,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 dcd361853..62d8e9813 100644
--- a/src/dataIO/PovExport.java
+++ b/src/dataIO/PovExport.java
@@ -84,7 +84,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 ea47e4706..66b973e8c 100644
--- a/src/dataIO/SvgExport.java
+++ b/src/dataIO/SvgExport.java
@@ -109,6 +109,12 @@ public void closeFile()
*
*/
+
+ public void setFileNumber(Integer number)
+ {
+ this._filewriterfilenr = number;
+ }
+
/**
*
*/
diff --git a/src/dataIO/XmlExport.java b/src/dataIO/XmlExport.java
index 6d9a307a5..3792e975e 100644
--- a/src/dataIO/XmlExport.java
+++ b/src/dataIO/XmlExport.java
@@ -90,7 +90,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
@@ -123,4 +135,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/dataIO/XmlHandler.java b/src/dataIO/XmlHandler.java
index 3c2e935f5..aeff3f82c 100644
--- a/src/dataIO/XmlHandler.java
+++ b/src/dataIO/XmlHandler.java
@@ -309,6 +309,16 @@ public static Double gatherDouble (Element xmlElement, String attribute)
}
}
}
+
+ public static Boolean gatherBoolean (Element xmlElement, String attribute)
+ {
+ String string;
+ if ( xmlElement != null && xmlElement.hasAttribute(attribute) )
+ string = xmlElement.getAttribute(attribute);
+ else
+ return (Boolean) null;
+ return Boolean.parseBoolean(string);
+ }
/**
* Redirects to gatherDouble (Element xmlElement, String attribute)
diff --git a/src/debugTools/QuickCSV.java b/src/debugTools/QuickCSV.java
new file mode 100644
index 000000000..c3b24c7f0
--- /dev/null
+++ b/src/debugTools/QuickCSV.java
@@ -0,0 +1,102 @@
+package debugTools;
+
+import dataIO.CsvExport;
+import linearAlgebra.Matrix;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class QuickCSV {
+
+
+ public static Map writers =
+ new HashMap();
+
+ static int numberOfWriters = 0;
+
+ private CsvExport exporter = new CsvExport();
+
+ private String _name = "QuickCSV writer";
+
+ private boolean _verbose = false;
+
+ /**
+ * create numbered writer
+ */
+ public QuickCSV()
+ {
+
+ QuickCSV.numberOfWriters++;
+ }
+
+ /**
+ * create named writer
+ * @param name
+ */
+ public QuickCSV(String name)
+ {
+ this._name = name;
+ QuickCSV.numberOfWriters++;
+ }
+
+ /**
+ * add unnamed writer
+ * @return
+ */
+ public static int add()
+ {
+ int temp = numberOfWriters;
+ writers.put(String.valueOf( temp ), new QuickCSV() );
+ return temp;
+ }
+
+ public static String add(String name)
+ {
+ writers.put(name , new QuickCSV(name));
+ return name;
+ }
+
+ public static QuickCSV select(int i)
+ {
+ return writers.get(String.valueOf(i));
+ }
+
+
+ public static QuickCSV select(String name)
+ {
+ return writers.get(name);
+ }
+
+ public void write(double[][] matrix)
+ {
+ this.write( Matrix.toString( matrix ) );
+ }
+
+ public void write(String content)
+ {
+ this.exporter.createFile( this._name );
+ this.exporter.writeLine( content );
+ this.exporter.closeFile();
+ }
+
+ public static void write(String name, double[][] matrix)
+ {
+ //lot's of other programs don't work nice with , and ; delimiters mixed
+ write( name, Matrix.toString( matrix , "\n") );
+ }
+
+ public static void write(String name, String content)
+ {
+ if ( !writers.containsKey(name) )
+ {
+ add(name);
+ }
+ writers.get(name).write( content );
+ }
+
+ public void verbose(boolean verbose)
+ {
+ this._verbose = verbose;
+ }
+
+}
diff --git a/src/debugTools/SegmentTimer.java b/src/debugTools/SegmentTimer.java
index 024af8b89..4f37ef4b9 100644
--- a/src/debugTools/SegmentTimer.java
+++ b/src/debugTools/SegmentTimer.java
@@ -148,9 +148,9 @@ public static void start(String name)
*/
public long pause()
{
+ this._netTime += tock();
if ( this._verbose)
this.report();
- this._netTime += tock();
return this._netTime;
}
@@ -169,7 +169,10 @@ public static void pause(String name)
*/
public long stop()
{
- return this.reportNet();
+ this._netTime += tock();
+ long out = this.reportNet();
+ this._netTime = 0;
+ return out;
}
/**
diff --git a/src/grid/SpatialGrid.java b/src/grid/SpatialGrid.java
index efed488fa..b99e13284 100644
--- a/src/grid/SpatialGrid.java
+++ b/src/grid/SpatialGrid.java
@@ -121,7 +121,16 @@ public double voxelVolume()
return this.getShape().getCurrVoxelVolume();
}
-
+ /**
+ * Temporary get diff for pde wrapper
+ * @return
+ */
+ @Deprecated
+ public double getDiffusivity()
+ {
+ return this._defaultDiffusivity;
+ }
+
public void updateDiffusivity(
EnvironmentContainer env, AgentContainer agents)
{
diff --git a/src/gui/GuiActions.java b/src/gui/GuiActions.java
index 53c7192f7..dd0454e5b 100644
--- a/src/gui/GuiActions.java
+++ b/src/gui/GuiActions.java
@@ -1,211 +1,393 @@
-/**
- *
- */
-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!
- Log.out("simulation stopping by user request...");
- Idynomics.simulator.stopAction = true;
- }
-
- /*************************************************************************
- * 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 dataIO.Log.Tier;
+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 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. */
+ JFileChooser chooser = new JFileChooser("" +
+ System.getProperty("user.dir")+"/"+relPath);
+ 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) {
+ Log.out(Tier.NORMAL, "unable to aquire protocol from url: " + url);
+ }
+
+
+ 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");
+ File in = new File(local);
+ openFile(in);
+ } catch (IOException | NullPointerException e) {
+ Log.out(Tier.NORMAL, "File download failed");
+ }
+ }
+
+ 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 : finalFiles )
+ {
+ boolean exi = false;
+ String out = null;
+ String path = f.getAbsolutePath();
+ if( path.toLowerCase().contains(".xml"))
+ {
+ exi = true;
+ out = path.toLowerCase().replaceAll(".xml", "");
+ } else if( path.toLowerCase().contains(".exi"))
+ {
+ exi = false;
+ out = path.toLowerCase().replaceAll(".exi", "");
+ }
+ 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 )
+ {
+ 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!
+ Log.out("simulation stopping by user request...");
+ Idynomics.simulator.stopAction = true;
+ }
+
+ /*************************************************************************
+ * 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/GuiConsole.java b/src/gui/GuiConsole.java
index 04e5c582a..26c503710 100644
--- a/src/gui/GuiConsole.java
+++ b/src/gui/GuiConsole.java
@@ -240,7 +240,7 @@ private static void write(String message, AttributeSet a)
//TODO this causes crash when running from command prompt
public static void scroll()
{
- if ( _autoScroll )
+ if ( _autoScroll && _console != null )
{
Document doc = _console.getDocument();
_console.setCaretPosition(doc.getLength());
diff --git a/src/gui/GuiMenu.java b/src/gui/GuiMenu.java
index f2b87c255..aee641248 100644
--- a/src/gui/GuiMenu.java
+++ b/src/gui/GuiMenu.java
@@ -1,521 +1,597 @@
-/**
- *
- */
-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);
+
+
+ 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.
+ */
+ 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 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;
+
+ /**
+ * 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/Global.java b/src/idynomics/Global.java
index 59bc215e1..902761a0a 100644
--- a/src/idynomics/Global.java
+++ b/src/idynomics/Global.java
@@ -166,6 +166,12 @@ public void updateSettings()
*/
public static boolean csv_bookkeeping = true;
+ /**
+ * 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 = "species";
+
/**
* enable xml bookkeeping (also logging complete agent xml)
* Warning: very slow
@@ -366,6 +372,14 @@ public void updateSettings()
* Default decompression parameters
*/
public static double damping_factor = 0.9;
-
+
+ /**
+ * Used to determine if a residual in multigrid is becoming negligibly small.
+ */
+ public static double negligible_change = 1e-13;
+
+ /**
+ * Number of digits (including leading zeros) in file numbering
+ */
public static int file_number_of_digits = 5;
}
diff --git a/src/idynomics/Idynomics.java b/src/idynomics/Idynomics.java
index d431fe4f3..39a563f93 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..8881485cc
--- /dev/null
+++ b/src/idynomics/PostProcess.java
@@ -0,0 +1,41 @@
+package idynomics;
+
+import java.io.File;
+import java.util.List;
+
+import dataIO.CumulativeLoad;
+
+public class PostProcess implements Runnable {
+
+ /**
+ * Files to be post processed
+ */
+ private List _files;
+
+ /**
+ * 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
+ 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/idynomics/Simulator.java b/src/idynomics/Simulator.java
index 7f40c908a..cb3f92e51 100644
--- a/src/idynomics/Simulator.java
+++ b/src/idynomics/Simulator.java
@@ -71,6 +71,8 @@ public strictfp class Simulator implements CanPrelaunchCheck, Runnable,
private long _timeSpentOnXmlOutput = 0;
private int _outputTicker = 1;
+
+ private double tic;
/**
* Simulator is the top node in iDynoMiCS and stores its own modelNode and
@@ -353,8 +355,8 @@ public void step()
Log.step();
}
-
- public void run()
+
+ public void initialRun()
{
/* start storing log on disk */
if( Log.shouldWrite(Tier.EXPRESSIVE) )
@@ -363,13 +365,18 @@ public void run()
/*
* Start timing just before simulation starts.
*/
- double tic = System.currentTimeMillis();
+ tic = System.currentTimeMillis();
/* Check if any boundary connections need to be made. */
for ( Compartment c : this._compartments )
{
c.checkBoundaryConnections(this._compartments);
c.environment.updateSoluteBoundaries();
}
+ }
+
+ public void run()
+ {
+ this.initialRun();
/* Run the simulation. */
while ( this.timer.isRunning() && !this.interupt && !this.stopAction )
@@ -635,6 +642,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)
diff --git a/src/lib/JUnit/hamcrest-core-1.3.jar b/src/lib/JUnit/hamcrest-core-1.3.jar
new file mode 100644
index 000000000..9d5fe16e3
Binary files /dev/null and b/src/lib/JUnit/hamcrest-core-1.3.jar differ
diff --git a/src/lib/JUnit/junit-4.13.2.jar b/src/lib/JUnit/junit-4.13.2.jar
new file mode 100644
index 000000000..6da55d8b8
Binary files /dev/null and b/src/lib/JUnit/junit-4.13.2.jar differ
diff --git a/src/linearAlgebra/Array.java b/src/linearAlgebra/Array.java
index 9f801ae95..7da50be00 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 .
*
@@ -1285,7 +1296,15 @@ public static void elemDivideTo(
for ( int i = 0; i < a.length; i++ )
Matrix.elemDivideTo(destination[i], a[i], b[i]);
}
-
+
+ public static void elemRatioTo(
+ double[][][] destination, double[][][] a, double[][][] b)
+ {
+ checkDimensionsSame(destination, a, b);
+ for ( int i = 0; i < a.length; i++ )
+ Matrix.elemRatioTo(destination[i], a[i], b[i]);
+ }
+
/**
* \brief Multiply one array by another, element-by-element.
*
@@ -1299,6 +1318,7 @@ public static double[][][] elemDivide(double[][][] a, double[][][] b)
elemDivideTo(out, a, b);
return a;
}
+
/**
* \brief Multiply one array by another, element-by-element, writing the
@@ -1422,6 +1442,50 @@ public static double[][][] subarray(double[][][] array, int iStart,
out[i - iStart][j - jStart][k - kStart] = array[i][j][k];
return out;
}
+
+ public static double[][] slice(double[][][] array, int dim, int num )
+ {
+ int a = 0, b = 0, c = 0;
+ int d = height(array);
+ int e = width(array);
+ int f = depth(array);
+ double[][] out;
+
+ if( dim == 0 )
+ {
+ out = new double[e][f];
+ for ( int j = b; j < e; j++ )
+ for ( int k = c; k < f; k++ )
+ out[j][k] = array[num][j][k];
+ }
+ else if ( dim == 1 )
+ {
+ out = new double[d][f];
+ for ( int i = a; i < d; i++ )
+ for ( int k = c; k < f; k++ )
+ out[i][k] = array[i][num][k];
+ }
+ else
+ {
+ out = new double[d][e];
+ for ( int i = a; i < d; i++ )
+ for ( int j = b; j < e; j++ )
+ out[i][j] = array[i][j][num];
+ }
+ return out;
+ }
+
+ /**
+
+ public static double[][] meanSlice(double[][][] array, int dim)
+ {
+ if (dim == 2)
+ {
+
+ }
+ }
+
+ **/
/**
* \brief TODO
@@ -1443,6 +1507,36 @@ public static int[][][] subarray(int[][][] array, int iStart, int iStop,
out[i - iStart][j - jStart][k - kStart] = array[i][j][k];
return out;
}
+
+ public static double[][][] rotate(double[][][] array, int i, int j, int k)
+ {
+ int[] old = new int[] { array.length, array[0].length, array[0][0].length };
+ int[] size = new int[] { old[i], old[j], old[k]};
+ double[][][] out = Array.array(size, 0.0);
+
+ int[] pos;
+ for ( int l = 0; l < old[0]; l++ )
+ for ( int m = 0; m < old[1]; m++ )
+ for ( int n = 0; n < old[2]; n++ )
+ {
+ pos = new int[] { l, m, n };
+ out[pos[i]][pos[j]][pos[k]] = array[l][m][n];
+ }
+ return out;
+ }
+
+ public static double[][][] superarray(double[][][] array,
+ int iStart, int iStop,
+ int jStart, int jStop,
+ int kStart, int kStop)
+ {
+ double[][][] out = new double[iStop+1 - iStart][jStop+1 - jStart][kStop+1 - kStart];
+ for ( int i = Math.max(0, iStart); i < Math.min(iStop-iStart, array.length); i++ )
+ for ( int j = Math.max(0, jStart); j < Math.min(jStop-jStart, array[0].length); j++ )
+ for ( int k = Math.max(0, kStart); k < Math.min(kStop-kStart, array[0][0].length); k++ )
+ out[i-iStart][j-jStart][k-kStart] = array[i][j][k];
+ return out;
+ }
/*************************************************************************
* SCALARS FROM ARRAYS
* Any input arrays should be unaffected.
diff --git a/src/linearAlgebra/Matrix.java b/src/linearAlgebra/Matrix.java
index d6b97b0e7..a1811b5fb 100644
--- a/src/linearAlgebra/Matrix.java
+++ b/src/linearAlgebra/Matrix.java
@@ -422,6 +422,13 @@ public static String toString(double[][] matrix)
toString(matrix, out);
return out.toString();
}
+
+ public static String toString(double[][] matrix, String delimiter)
+ {
+ StringBuffer out = new StringBuffer();
+ toString(matrix, out, delimiter);
+ return out.toString();
+ }
/**
* \brief Converts the given matrix to {@code String}
@@ -448,16 +455,21 @@ public static void toString(int[][] matrix, StringBuffer buffer)
* @param matrix Two-dimensional array of doubles (preserved).
* @param buffer String buffer (faster than String).
*/
- public static void toString(double[][] matrix, StringBuffer buffer)
+ public static void toString(double[][] matrix, StringBuffer buffer, String delimiter)
{
int n = matrix.length - 1;
for ( int i = 0; i < n; i++ )
{
Vector.toString(matrix[i], buffer);
- buffer.append(DELIMITER);
+ buffer.append(delimiter);
}
Vector.toString(matrix[n], buffer);
}
+
+ public static void toString(double[][] matrix, StringBuffer buffer)
+ {
+ toString(matrix, buffer, DELIMITER);
+ }
/*************************************************************************
* DIMENSIONS
@@ -638,6 +650,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[][].
@@ -2033,6 +2051,15 @@ public static void elemDivideTo(
for ( int i = 0; i < rowDim(a); i++ )
Vector.divideTo(destination[i], a[i], b[i]);
}
+
+ public static void elemRatioTo(
+ double[][] destination, double[][] a, double[][] b)
+ {
+ checkDimensionsSame(destination, a, b);
+ for ( int i = 0; i < rowDim(a); i++ )
+ Vector.ratioTo(destination[i], a[i], b[i]);
+ }
+
/**
* \brief For each element of a matrix a , divide by the
diff --git a/src/linearAlgebra/Vector.java b/src/linearAlgebra/Vector.java
index 5abaad984..9ade67585 100644
--- a/src/linearAlgebra/Vector.java
+++ b/src/linearAlgebra/Vector.java
@@ -410,6 +410,20 @@ 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++ )
+ for ( int j = 0; j < destination[0].length; j++ )
+ for ( int k = 0; k < destination[0][0].length; k++ )
+ destination[i][j][k] = source[i][j][k];
+ }
+
+ 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.
*
@@ -444,6 +458,14 @@ public static double[] copy(double[] vector)
return out;
}
+ public static double[][][] copy(double[][][] vector)
+ {
+ double[][][] out =
+ new double[vector.length][vector[0].length][vector[0][0].length];
+ copyTo(out, vector);
+ return out;
+ }
+
public static double[] replace(int field, double value, double[] source)
{
double[] out = new double[source.length];
@@ -1077,6 +1099,13 @@ public static void addTo(double[] destination, double[] source,
for ( int i = 0; i < destination.length; i++ )
destination[i] = source[i] + value;
}
+
+ public static void addTo(float[] destination, float[] source,
+ float value)
+ {
+ for ( int i = 0; i < destination.length; i++ )
+ destination[i] = source[i] + value;
+ }
/**
* \brief Add a scalar value to every element of a vector ,
@@ -1096,6 +1125,13 @@ public static double[] add(double[] vector, double value)
addTo(out, vector, value);
return out;
}
+
+ public static float[] add(float[] vector, float value)
+ {
+ float[] out = new float[vector.length];
+ addTo(out, vector, value);
+ return out;
+ }
/**
* \brief Add a scalar value to every element of a vector ,
@@ -1179,6 +1215,14 @@ public static void addTo(double[] destination, double[] a, double[] b)
destination[i] = a[i] + b[i];
}
}
+
+ public static void addTo(float[] destination, float[] a, float[] b)
+ {
+ for ( int i = 0; i < a.length; i++ )
+ {
+ destination[i] = a[i] + b[i];
+ }
+ }
/**
* \brief Add two vectors together, writing the result into a new vector.
@@ -1196,6 +1240,13 @@ public static double[] add(double[] a, double[] b)
addTo(out, a, b);
return out;
}
+
+ public static float[] add(float[] a, float[] b)
+ {
+ float[] out = new float[a.length];
+ addTo(out, a, b);
+ return out;
+ }
/**
* \brief Add two vectors together, writing the result into a .
@@ -1671,7 +1722,14 @@ public static void divideTo(double[] destination, double[] a, double[] b)
for ( int i = 0; i < a.length; i++ )
destination[i] = a[i] / b[i];
}
-
+
+ public static void ratioTo(double[] destination, double[] a, double[] b)
+ {
+ checkLengths(destination, a, b);
+ for ( int i = 0; i < a.length; i++ )
+ destination[i] = Math.abs(a[i]) / Math.abs(b[i]);
+ }
+
/**
* \brief divide destination vector elements by divisor.
* @param destination
diff --git a/src/processManager/ProcessDeparture.java b/src/processManager/ProcessDeparture.java
index 633da6304..d5071d1c3 100644
--- a/src/processManager/ProcessDeparture.java
+++ b/src/processManager/ProcessDeparture.java
@@ -100,11 +100,11 @@ protected void internalStep()
case REMOVAL:
{
this._departureLounge = this.agentsDepart();
-
- LinkedList agentsOutsideOrLeaving =
+
+ LinkedList agentsOutsideOrLeaving =
this.agentsOutsideOrLeavingDomain();
-
- if (!agentsOutsideOrLeaving.isEmpty() &&
+
+ if (!agentsOutsideOrLeaving.isEmpty() &&
!(this instanceof AgentsOutsideDomainDepart))
{
if (Log.shouldWrite(Tier.NORMAL))
@@ -112,16 +112,16 @@ protected void internalStep()
" encountered agents leaving the computational "
+ "domain. Adding to departure lounge.");
}
-
+
this._departureLounge.addAll(agentsOutsideOrLeaving);
-
- this._agents.registerRemoveAgents(this._departureLounge,
+
+ this._agents.registerRemoveAgents(this._departureLounge,
EventType.REMOVED, "Removed from simulation by departure "
+ "process" + this.getName(), null);
this._departureLounge.clear();
break;
}
-
+
case TRANSFER:
{
@@ -238,16 +238,16 @@ protected void internalStep()
//Remove departing agents from this compartment's
//AgentContainer.
//TODO - ask Bas what parameters event and value are for.
- this._agents.registerRemoveAgents(this._departureLounge,
- EventType.TRANSFER, "Transferred from compartment " +
+ this._agents.registerRemoveAgents(this._departureLounge,
+ EventType.TRANSFER, "Transferred from compartment " +
this._compartmentName + " to new compartment, " +
destinations.get(destinations.size()-1).getName()
+ " by departure process " + this._name, null);
-
+
//Send departing agents to their destination
destinations.get(destinations.size()-1).acceptAgents(
this._compartmentName, this._departureLounge);
-
+
this._departureLounge.clear();
}
@@ -268,34 +268,37 @@ protected void internalStep()
protected LinkedList agentsOutsideOrLeavingDomain()
{
LinkedList agentsToDepart = new LinkedList();
-
+
if (this._shape.getNumberOfDimensions() > 0)
{
for (Agent a : this._agents.getAllAgents())
{
-
+
/*
* Find agents that are outside the computational domain.
*/
Body body = (Body) a.get(AspectRef.agentBody);
-
+
for (Point p : body.getPoints())
{
this._shape.applyBoundaries(p.getPosition());
-
+
if (!this._shape.isInside(p.getPosition()))
{
agentsToDepart.add(a);
}
}
-
+
/*
* Find agents colliding with spatial boundaries that are not
* solid.
+ *
+ * FIXME: this may be better handled by the boundary themselves eg: ask a boundary
+ * whether an agent should be considered for removal.
*/
- Collection collidingBoundaries =
+ Collection collidingBoundaries =
this._agents.boundarySearch(a, 0.0);
-
+
for (SpatialBoundary boundary : collidingBoundaries)
{
if (!boundary.isSolid())
@@ -303,7 +306,7 @@ protected LinkedList agentsOutsideOrLeavingDomain()
agentsToDepart.add(a);
}
}
-
+
}
}
diff --git a/src/processManager/ProcessDiffusion.java b/src/processManager/ProcessDiffusion.java
index 17660b4aa..5d8240272 100644
--- a/src/processManager/ProcessDiffusion.java
+++ b/src/processManager/ProcessDiffusion.java
@@ -5,10 +5,12 @@
import java.util.Collection;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
+import debugTools.SegmentTimer;
import org.w3c.dom.Element;
import agent.Agent;
@@ -18,19 +20,25 @@
import compartment.AgentContainer;
import compartment.EnvironmentContainer;
import dataIO.Log;
+import dataIO.XmlHandler;
import dataIO.Log.Tier;
import grid.SpatialGrid;
import idynomics.Global;
import idynomics.Idynomics;
+import instantiable.Instance;
import linearAlgebra.Vector;
import reaction.Reaction;
import reaction.RegularReaction;
import referenceLibrary.AspectRef;
+import referenceLibrary.XmlRef;
+import settable.Module;
import shape.CartesianShape;
import shape.Shape;
import shape.subvoxel.IntegerArray;
import shape.subvoxel.SubvoxelPoint;
import solver.PDEsolver;
+import solver.PDEupdater;
+import solver.mgFas.RecordKeeper;
import surface.Point;
import surface.Surface;
import surface.Voxel;
@@ -90,6 +98,10 @@ public abstract class ProcessDiffusion extends ProcessManager
* voxels a located {@code Agent} covers.
*/
private static final String VD_TAG = AspectRef.agentVolumeDistributionMap;
+
+ public LinkedList _recordKeepers =
+ new LinkedList();
+
/**
* When choosing an appropriate sub-voxel resolution for building agents'
* {@code coordinateMap}s, the smallest agent radius is multiplied by this
@@ -116,6 +128,11 @@ public void init(Element xmlElem, EnvironmentContainer environment,
AgentContainer agents, String compartmentName)
{
super.init(xmlElem, environment, agents, compartmentName);
+ for ( Element e : XmlHandler.getElements( xmlElem, XmlRef.record) )
+ {
+ this._recordKeepers.add(
+ (RecordKeeper) Instance.getNew(e, this, (String[])null));
+ }
}
/* ***********************************************************************
@@ -192,11 +209,13 @@ protected void postStep()
* Clear agent mass distribution maps.
*/
this.removeAgentDistibutionMaps();
- /**
+
+ /*
* act upon new agent situations
*/
for(Agent agent: this._agents.getAllAgents())
agent.event(DIVIDE);
+
for(Agent agent: this._agents.getAllAgents())
{
agent.event(EXCRETE_EPS);
@@ -217,8 +236,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)
{
@@ -273,13 +291,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 );
}
@@ -322,7 +341,6 @@ public void setupAgentDistributionMaps(Shape shape)
case MIDPOINT:
for ( Agent a : this._agents.getAllLocatedAgents() )
{
-
IntegerArray coordArray = new IntegerArray(
shape.getCoords(shape.getVerifiedLocation(((Body) a.get(AspectRef.agentBody)).getCenter(shape))));
mapOfMaps = (Map>) a.getValue(VD_TAG);
@@ -550,12 +568,31 @@ 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()
{
for ( Agent a : this._agents.getAllLocatedAgents() )
a.reg().remove(VD_TAG);
}
+
+ public LinkedList getRecordKeepers()
+ {
+ return this._recordKeepers;
+ }
+
+
+ @Override
+ public Module getModule()
+ {
+ Module modelNode = super.getModule();
+
+ for (RecordKeeper r: this._recordKeepers)
+ modelNode.add(r.getModule());
+
+ return modelNode;
+
+ }
+
}
diff --git a/src/processManager/ProcessManager.java b/src/processManager/ProcessManager.java
index cf6611301..c7c7ae95f 100644
--- a/src/processManager/ProcessManager.java
+++ b/src/processManager/ProcessManager.java
@@ -429,12 +429,12 @@ public void setAgentContainer(AgentContainer ac)
{
this._agents = ac;
}
-
+
public void setTimeStep(double timeStep)
{
this._timeStepSize = timeStep;
}
-
+
@Override
public Settable getParent()
{
diff --git a/src/processManager/library/AgentDetachment.java b/src/processManager/library/AgentDetachment.java
index c0d0aad85..4ccf22b48 100644
--- a/src/processManager/library/AgentDetachment.java
+++ b/src/processManager/library/AgentDetachment.java
@@ -51,7 +51,7 @@ public void init( Element xmlElem, EnvironmentContainer environment,
this.getDouble( RASTER_SCALE ), 0.2 );
this._regionDepth = Helper.setIfNone(
- this.getInt( REGION_DEPTH ), 10 );
+ this.getInt( REGION_DEPTH ), 10 );
}
/**
@@ -63,7 +63,7 @@ public void init( Element xmlElem, EnvironmentContainer environment,
*
* We only consider removal from the biofilm surface and refer to this as
* detachment.
- * @return
+ * @return
*/
@Override
protected LinkedList agentsDepart()
diff --git a/src/processManager/library/AgentRelaxation.java b/src/processManager/library/AgentRelaxation.java
index 903e9f542..8ddf236df 100644
--- a/src/processManager/library/AgentRelaxation.java
+++ b/src/processManager/library/AgentRelaxation.java
@@ -1,7 +1,7 @@
package processManager.library;
import java.util.Collection;
-import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import org.w3c.dom.Element;
@@ -15,14 +15,12 @@
import expression.Expression;
import idynomics.Global;
import idynomics.Idynomics;
-import linearAlgebra.Array;
import linearAlgebra.Vector;
import physicalObject.PhysicalObject;
import processManager.ProcessManager;
import referenceLibrary.AspectRef;
import shape.Shape;
import surface.Point;
-import surface.Rod;
import surface.Surface;
import surface.collision.Collision;
import surface.collision.Decompress;
@@ -107,7 +105,7 @@ private enum Method
/**
* Base time step, time step that will be used in mechanical relaxation
* unless it is over ruled due to the use of {@link #_maxMove},
- * {@link #_timeLeap} or {@link #_stressThreshold}. {@link #_dtStatic}
+ * {@link #_fastRelaxation} or {@link #_stressThreshold}. {@link #_dtStatic}
* forces the use of the base time step.
*/
protected double _dtBase;
@@ -134,7 +132,7 @@ private enum Method
private boolean _fastRelaxation;
/**
- * Selected stepping {@link #Method}
+ * Selected stepping
*/
private Method _method;
@@ -191,8 +189,22 @@ private enum Method
private Decompress decompressionMatrix;
+ double moveScalar = this._maxMove;
+ /* start with initial base time step than adjust */
+ double dtMech = this._dtBase;
+ /* agent radius */
+ double radius;
+ /* highest velocity in the system squared */
+ double vs;
+ /* highest force in the system */
+ double st;
+
+ double maxAgentOverlap = 0.1;
+
+ double moveGranularity = 0.3;
+
+ double shoveFactor = 1.25;
-
/* ************************************************************************
* Initiation
* ***********************************************************************/
@@ -202,7 +214,16 @@ public void init(Element xmlElem, EnvironmentContainer environment,
AgentContainer agents, String compartmentName)
{
super.init(xmlElem, environment, agents, compartmentName);
-
+
+ this.maxAgentOverlap = Helper.setIfNone( this.getDouble(AspectRef.maxAgentOverlap),
+ 0.1 );
+
+ this.moveGranularity = Helper.setIfNone( this.getDouble(AspectRef.moveGranularity),
+ 0.3 );
+
+ this.shoveFactor = Helper.setIfNone( this.getDouble(AspectRef.shoveFactor),
+ 1.25 );
+
/* Obtaining relaxation parameters.
* Base time step */
this._dtBase = Helper.setIfNone( this.getDouble(BASE_DT),
@@ -219,13 +240,8 @@ public void init(Element xmlElem, EnvironmentContainer environment,
/* Set relaxation method, set default if none */
this._method = Method.valueOf( Helper.setIfNone(
this.getString(RELAXATION_METHOD), Method.EULER.toString() ) );
-
- /* Time leaping */
- this._fastRelaxation = Helper.setIfNone(
- this.getBoolean(FAST_RELAXATION), false );
-
- /* force static dt (ignores maxMovement, timeleap, stress thresholds
- * but thereby does not has to evaluate these constituants either */
+
+ /* force static dt */
this._dtStatic = Helper.setIfNone(
this.getBoolean(STATIC_TIMESTEP), false );
@@ -235,6 +251,12 @@ public void init(Element xmlElem, EnvironmentContainer environment,
/* Surface objects of compartment, FIXME discovered circle returns a
* rod type shape (2 points) instead of circle (2d sphere, 1 point). */
this._shapeSurfs = this._shape.getSurfaces();
+
+ /* FIXME: we have to initiate collision scalar different, currently it is only possible trough globals. */
+ if( this._method == Method.SHOVE )
+ {
+ Global.collision_scalar = 1.0;
+ }
/* Collision iterator */
this._iterator = new Collision( this.getString(COLLISION_FUNCTION),
@@ -262,7 +284,6 @@ public void init(Element xmlElem, EnvironmentContainer environment,
/* Include decompression */
this._decompression = Helper.setIfNone( this.getBoolean(DECOMPRESSION),
false);
-
if ( this._decompression )
decompressionMatrix = new Decompress(
@@ -273,7 +294,6 @@ public void init(Element xmlElem, EnvironmentContainer environment,
this._agents.getShape().getIsCyclicNaturalOrderIncludingVirtual(),
(double) this.getOr(AspectRef.traversingFraction, Global.traversing_fraction),
(double) this.getOr(AspectRef.dampingFactor, Global.damping_factor));
-
}
/* ************************************************************************
@@ -283,23 +303,11 @@ public void init(Element xmlElem, EnvironmentContainer environment,
@Override
protected void internalStep()
{
- /* current step of mechanical relaxation */
int nstep = 0;
- /* current time in mechanical relaxation. */
tMech = 0.0;
- /* start with initial base time step than adjust */
- double dtMech = this._dtBase;
- /* agent radius */
- double radius;
- /* highest velocity in the system squared */
- double vs;
- /* highest force in the system */
- double st;
- /* All located agents in this compartment */
Collection allAgents = this._agents.getAllLocatedAgents();
- /* if higher order ODE solvers are used we need additional space to
- * write. */
+ /* With higher order ODE solvers, we need additional space to write. */
switch ( _method )
{
case HEUN :
@@ -307,122 +315,26 @@ protected void internalStep()
for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
point.initialiseC(2);
default:
+ //by default, we do nothing.
}
/* Mechanical relaxation */
while( tMech < this.getTimeStepSize() && nstep < this._maxIter)
{
this._agents.refreshSpatialRegistry();
- this.updateForces( this._agents );
+ this._iterator.resetOverlap();
+
+ this.updateForces( this._agents.getAllAgents(), this._agents );
+ dtMech = sizeStep( allAgents );
+
if ( this._decompression )
decompressionMatrix.buildDirectionMatrix();
-
- /* adjust step size unless static step size is forced */
- if( !this._dtStatic || this._method == Method.SHOVE )
- {
- /* obtain current highest particle velocity and highest force */
- vs = 0.0;
- st = 0.0;
- for(Agent agent : allAgents )
- {
- radius = agent.getDouble(RADIUS);
- for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
- {
- if ( Vector.normSquare( point.dxdt( radius ) ) > vs )
- vs = Vector.normSquare( point.dxdt( radius ) );
- if ( Vector.normSquare( point.getForce() ) > st )
- st = Vector.normSquare( point.getForce() );
- }
- }
-
- /* Stress Threshold allows finishing relaxation early if the
- * mechanical stress is low. Default value is 0.0 -> only skip
- * if there is no mechanical stress in the system at all.
- * */
- if ( _stressThreshold != 0.0 && ( this.tMech > this.compresionDuration || compresionDuration == 0.0 ) )
- {
- if ( Math.sqrt(st) * Global.agent_stress_scaling <
- _stressThreshold )
- break;
- } else if ( this._method == Method.SHOVE )
- {
- if (_stressThreshold == 0.0)
- {
- Log.out(Tier.CRITICAL, AspectRef.stressThreshold + " must "
- + "be set for relaxation method " +
- Method.SHOVE.toString() );
- Idynomics.simulator.interupt(null);
- return;
- }
- }
-
- /* When stochastic movement is enabled update vs to represent
- * the highest velocity object in the system accounting for
- * stochastic movement to. */
- for( Agent agent : allAgents )
- if ( agent.isAspect( STOCHASTIC_DIRECTION ) )
- {
- double[] move =
- (double[]) agent.get( STOCHASTIC_DIRECTION );
- vs = Math.max( Vector.dotProduct( move, move ), vs );
- }
-
- /* fast relaxation: set the time step to match 'maxMovement'
- * with the the fastest object, for a 'fast' run. */
- if ( this._fastRelaxation || this._method == Method.SHOVE)
- dtMech = this._maxMove / ( Math.sqrt(vs) +
- Global.agent_move_safety );
- /* no fast relaxation: adjust the time step with the fastest
- * object yet cap the maximum dtMech */
- else
- dtMech = this._maxMove / Math.max( Math.sqrt(vs) +
- Global.agent_move_safety, 1.0 );
- /* TODO we may want to make the dt cap settable as well */
- }
-
- /* prevent to relaxing longer than the global _timeStepSize */
- if (dtMech > this._timeStepSize - tMech )
- dtMech = this._timeStepSize - tMech;
- /* If stochastic movement is enabled for the agent, update the agent
- * perform the stochastic movement. */
for(Agent agent : allAgents )
if ( agent.isAspect(STOCHASTIC_STEP) )
agent.event(STOCHASTIC_MOVE, dtMech);
- /* perform the step using (method) */
- switch ( this._method )
- {
- case SHOVE :
- {
- for ( Agent agent : allAgents )
- for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
- point.shove( dtMech, agent.getDouble(RADIUS) );
- /* NOTE: is stopped when {@link _stressThreshold} is reached
- * TODO add max iter for shove? */
- break;
- }
- case EULER :
- {
- for ( Agent agent : allAgents )
- for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
- point.euStep( dtMech, agent.getDouble(RADIUS) );
- tMech += dtMech;
- break;
- }
- /* NOTE : higher order ODE solvers don't like time Leaping..
- * be careful. */
- case HEUN :
- for(Agent agent : allAgents )
- for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
- point.heun1( dtMech, agent.getDouble(RADIUS) );
- this.updateForces( this._agents );
- for(Agent agent : allAgents )
- for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
- point.heun2( dtMech, agent.getDouble(RADIUS) );
- tMech += dtMech;
- break;
- }
+ move( allAgents, dtMech );
if( Log.shouldWrite(Tier.DEBUG) )
{
@@ -434,29 +346,21 @@ protected void internalStep()
/* NOTE that with proper boundary surfaces for any compartment
* shape this should never yield any difference, it is here as a
- * fail safe
- *
+ * fail safe
+ *
* FIXME this seems to result in crashes
* */
for(Agent agent : allAgents)
for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
point.setPosition( this._shape.applyBoundaries( point.getPosition() ) );
-
+
nstep++;
+ if( dtMech == 0.0 )
+ break;
}
-
- if( Log.shouldWrite( Tier.DEBUG ))
- {
- for ( Agent agent : allAgents )
- for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
- if ( Double.isNaN(point.getPosition()[0]))
- Log.out(Tier.DEBUG, String.valueOf( point.getPosition()[0] ));
- }
-
/* Leave with a clean spatial tree. */
this._agents.refreshSpatialRegistry();
-
- /* Notify user */
+
if( Log.shouldWrite( Tier.EXPRESSIVE ) )
{
if (nstep == this._maxIter )
@@ -464,34 +368,124 @@ protected void internalStep()
" stop condition iterations: " + this._maxIter);
else
Log.out( Tier.EXPRESSIVE, this.getName() +
- " stop condition stress threshold");
+ " reached relaxation criteria, iterations: " + nstep );
}
- if( Log.shouldWrite( Tier.DEBUG ) )
- Log.out( Tier.DEBUG, "Relaxed " + this._agents.getNumAllAgents() +
- " agents after " + nstep + " iterations" );
}
-
-
+
+ private void move(Collection agents, double dtMech)
+ {
+ /* perform the step using (method) */
+ switch ( this._method )
+ {
+ case SHOVE :
+ {
+ for ( Agent agent : agents )
+ for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
+ point.shove( this.maxAgentOverlap, this.shoveFactor, agent.getDouble(RADIUS) );
+ /* NOTE: is stopped when {@link _stressThreshold} is reached
+ * TODO add max iter for shove? */
+ break;
+ }
+ case EULER :
+ {
+ for ( Agent agent : agents )
+ for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
+ point.euStep( dtMech, agent.getDouble(RADIUS) );
+ tMech += dtMech;
+ break;
+ }
+ /* NOTE : higher order ODE solvers don't like time Leaping..
+ * be careful. */
+ case HEUN :
+ for(Agent agent : agents )
+ for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
+ point.heun1( dtMech, agent.getDouble(RADIUS) );
+ this.updateForces( agents, this._agents ); // subset
+ for(Agent agent : agents )
+ for ( Point point: ( (Body) agent.get(BODY) ).getPoints() )
+ point.heun2( dtMech, agent.getDouble(RADIUS) );
+ tMech += dtMech;
+ break;
+ }
+ }
+
+ private double sizeStep(Collection agents)
+ {
+ /* adjust step size unless static step size is forced */
+ if( !this._dtStatic || this._method == Method.SHOVE )
+ {
+ /* obtain current highest particle velocity. */
+ double ts;
+ vs = 0.0;
+ for(Agent agent : agents ) {
+ radius = agent.getDouble(RADIUS);
+ for ( Point point : ( (Body) agent.get(BODY) ).getPoints() ) {
+ if ( ( ts = Vector.normSquare( point.dxdt(radius) ) ) > vs )
+ vs = ts;
+ }
+ }
+
+ if ( this._iterator.maxOverlap() > -maxAgentOverlap)
+ {
+ // system relaxed can stop loop
+ return 0.0;
+ }
+
+ /* NOTE: stochastic movement really should only be used with static dt.
+ *
+ * When stochastic movement is enabled update vs to represent
+ * the highest velocity object in the system accounting for
+ * stochastic movement to. */
+ for( Agent agent : agents )
+ if ( agent.isAspect( STOCHASTIC_DIRECTION ) )
+ {
+ double[] move =
+ (double[]) agent.get( STOCHASTIC_DIRECTION );
+ vs = Math.max( Vector.dotProduct( move, move ), vs );
+ }
+
+ /* Scale dt such that the fastest moving object is moving a fraction of the
+ * largest overlap. */
+ moveScalar = Math.min( -this.moveGranularity *
+ _iterator.maxOverlap(), this._maxMove );
+ dtMech = moveScalar / (Math.sqrt(vs) + 1e-9 );
+ }
+
+ /* prevent to relaxing longer than the global _timeStepSize */
+ if (dtMech > this._timeStepSize - tMech )
+ dtMech = this._timeStepSize - tMech;
+
+ return dtMech;
+ }
+
/**
* \brief Update all forces on all agent mass points.
- *
- * @param environment
* @param agents
+ * @param aContainer
*/
- private void updateForces(AgentContainer agents)
+ private Collection updateForces(Collection agents,
+ AgentContainer aContainer, boolean hs)
{
+ Collection out = new LinkedList();
/* Calculate forces. */
- for ( Agent agent: agents.getAllLocatedAgents() )
+ for ( Agent agent: agents )
{
Body body = (Body) agent.get(AspectRef.agentBody);
List agentSurfs = body.getSurfaces();
+
+ if( hs )
+ {
+ for( Point p : ((Body) agent.get(BODY)).getPoints())
+ {
+ p.resetForce();
+ }
+ }
/* spring operations */
springEvaluation(agent, body);
/* Look for neighbors and resolve collisions */
- neighboorhoodEvaluation(agent, agentSurfs, agents);
-
+ neighboorhoodEvaluation(agent, agentSurfs, aContainer);
/*
* Collisions with other physical objects and
* Boundary collisions
@@ -501,7 +495,6 @@ private void updateForces(AgentContainer agents)
this._iterator.collision(p.getSurface(), p, agentSurfs, agent, 0.0);
}
-
/* NOTE: testing purposes only */
if (this._gravity)
gravityEvaluation(agent, body);
@@ -520,29 +513,43 @@ private void updateForces(AgentContainer agents)
*/
this._iterator.collision(this._shapeSurfs, null, agentSurfs, agent, 0.0);
}
+ return out;
+ }
+
+
+ private Collection updateForces(Collection agents,
+ AgentContainer aContainer) {
+ return updateForces(agents, aContainer, false);
+ }
+
+ private void updateShapeForceOnly(Collection agents, AgentContainer aContainer)
+ {
+ for ( Agent agent: agents ) {
+ Body body = (Body) agent.get(AspectRef.agentBody);
+ List agentSurfs = body.getSurfaces();
+ this._iterator.collision(this._shapeSurfs, null, agentSurfs, agent, 0.0);
+ }
}
-
/**
- * \brief Perform neighborhood search and perform collision detection and
+ * \brief Perform neighborhood search and perform collision detection and
* response.
- *
+ *
* interaction for consideration is passed to the collision iterator, the
* collision iterator evaluates both push and pull interactions (within
* the pull distance).
- *
+ *
* @param agent the vocal agent (only once per time step per agent).
* @param surfaces (the surfaces of the agent).
- * @param agents (all agents in the compartment).
+ * @param agentContainer (all agents in the compartment).
*/
- private void neighboorhoodEvaluation(Agent agent, List surfaces,
- AgentContainer agents)
+ private Collection neighboorhoodEvaluation(Agent agent, List surfaces,
+ AgentContainer agentContainer, boolean hs)
{
double searchDist = (agent.isAspect(SEARCH_DIST) ?
agent.getDouble(SEARCH_DIST) : 0.0);
-
+ Collection nhbs = agentContainer.treeSearch(agent, searchDist);
/* Perform neighborhood search and perform collision detection and
* response. */
- Collection nhbs = agents.treeSearch(agent, searchDist);
for ( Agent neighbour: nhbs )
if ( agent.identity() > neighbour.identity() )
{
@@ -563,6 +570,13 @@ private void neighboorhoodEvaluation(Agent agent, List surfaces,
((Body) neighbour.get(BODY)).getSurfaces(), neighbour,
pull);
}
+ return nhbs;
+ }
+
+ private Collection neighboorhoodEvaluation(Agent agent, List surfaces,
+ AgentContainer agentContainer)
+ {
+ return neighboorhoodEvaluation(agent, surfaces, agentContainer, false);
}
/**
@@ -570,7 +584,7 @@ private void neighboorhoodEvaluation(Agent agent, List surfaces,
* connecting spinal spring of rod type agents.
*
* @param a the vocal agent (once per step per surface of the agent)
- * @param s surface of the agent
+ * @param b Body of the agent
*/
private void springEvaluation(Agent a, Body b)
{
diff --git a/src/processManager/library/AgentsOutsideDomainDepart.java b/src/processManager/library/AgentsOutsideDomainDepart.java
index 31916266b..188589bc5 100644
--- a/src/processManager/library/AgentsOutsideDomainDepart.java
+++ b/src/processManager/library/AgentsOutsideDomainDepart.java
@@ -8,8 +8,11 @@
/**
* Any agents that are outside the computational domain are removed. Furthermore
- * any agents that are colliding with a non-solid boundary are removed. This
- * process manager simply returns an empty list, allowing the super-class
+ * any agents that are colliding with a non-solid boundary are removed.
+ *
+ * //FIXME [Bas] periodic boundaries are also non-solid! those agents should not be removed!
+ *
+ * This process manager simply returns an empty list, allowing the super-class
* ProcessDeparture to remove these agents as it does by default. However, using
* this class allows users to direct these agents to a particular destination,
* and prevents the generation of warning messages when the super class finds
diff --git a/src/processManager/library/GraphicalOutput.java b/src/processManager/library/GraphicalOutput.java
index 253c53223..50c0eb380 100644
--- a/src/processManager/library/GraphicalOutput.java
+++ b/src/processManager/library/GraphicalOutput.java
@@ -137,7 +137,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 );
@@ -146,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));
}
@@ -166,6 +168,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);
@@ -203,6 +207,8 @@ else if (_shape instanceof CylindricalShape)
/* Identify exact voxel location and size. */
origin = _shape.getVoxelOrigin(coord);
_shape.getVoxelSideLengthsTo(dimension, coord);
+ if( _shape.isNodeSystem() )
+ Vector.minusEquals( origin, Vector.times( dimension, 0.5 ) );
/*
* Scale the solute concentration for coloring.
* First, map the concentration to the real interval [0, 1].
diff --git a/src/processManager/library/PDEWrapper.java b/src/processManager/library/PDEWrapper.java
new file mode 100644
index 000000000..931b16156
--- /dev/null
+++ b/src/processManager/library/PDEWrapper.java
@@ -0,0 +1,456 @@
+package processManager.library;
+
+import static grid.ArrayType.*;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import agent.Agent;
+import agent.Body;
+import bookkeeper.KeeperEntry;
+import boundary.Boundary;
+import boundary.WellMixedBoundary;
+import dataIO.ObjectFactory;
+import debugTools.SegmentTimer;
+import idynomics.Global;
+import linearAlgebra.Vector;
+import org.w3c.dom.Element;
+
+import compartment.AgentContainer;
+import compartment.EnvironmentContainer;
+import grid.SpatialGrid;
+import processManager.ProcessDiffusion;
+import processManager.ProcessMethods;
+import reaction.Reaction;
+import reaction.RegularReaction;
+import referenceLibrary.AspectRef;
+import referenceLibrary.XmlRef;
+import shape.Shape;
+import shape.subvoxel.IntegerArray;
+import solver.mgFas.Domain;
+import solver.mgFas.Multigrid;
+import solver.mgFas.MultigridUtils;
+import solver.mgFas.SolverGrid;
+import solver.mgFas.*;
+import utility.Helper;
+
+/**
+ * \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;
+
+ private Multigrid multigrid;
+
+ public double absTol;
+
+ public double relTol;
+
+ public double solverResidualRatioThreshold;
+
+// private AgentContainer _agents;
+ /**
+ *
+ * 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);
+
+ /* TODO move values to global defaults */
+ this.absTol = (double) this.getOr(ABS_TOLERANCE, 1.0e-12);
+ this.relTol = (double) this.getOr(REL_TOLERANCE, 1.0e-6);
+
+ this.solverResidualRatioThreshold = (double) this.getOr(
+ AspectRef.solverResidualRatioThreshold, 1.0e-4);
+
+ int vCycles = (int) this.getOr(AspectRef.vCycles, 15);
+ int preSteps = (int) this.getOr(AspectRef.preSteps, 5);
+ int coarseSteps = (int) this.getOr(AspectRef.coarseSteps, 5);
+ int postSteps = (int) this.getOr(AspectRef.postSteps, 5);
+
+ boolean autoVcycleAdjust = (boolean) this.getOr(AspectRef.autoVcycleAdjust, false);
+
+ /* 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(), this._environment);
+ this.multigrid = new Multigrid();
+ multigrid.init(domain, environment, agents, this,
+ vCycles, preSteps, coarseSteps, postSteps, autoVcycleAdjust);
+
+ // TODO Let the user choose which ODEsolver to use.
+
+
+ }
+
+ public double fetchBulk(String solute)
+ {
+ for( Boundary b : this._environment.getShape().getAllBoundaries() )
+ {
+ if (b instanceof WellMixedBoundary )
+ return ((WellMixedBoundary) b).getConcentration(solute);
+ }
+ return 0.0;
+ }
+
+ /* ***********************************************************************
+ * STEPPING
+ * **********************************************************************/
+
+ @Override
+ protected void internalStep()
+ {
+ /*
+ * Do the generic set up and solving.
+ */
+// super.internalStep();
+ for ( Boundary b : this._environment.getShape().getAllBoundaries() )
+ {
+ b.resetMassFlowRates();
+ }
+ /* 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()));
+
+ prestep(this._environment.getSolutes(), 0.0);
+
+ for ( SpatialGrid var : this._environment.getSolutes() )
+ {
+ var.reset(PRODUCTIONRATE);
+ }
+ multigrid.initAndSolve();
+ /*
+ * 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
+ *
+ * TODO this method would benefit from renaming
+ *
+ * {@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)
+ {
+ /* TODO should env reactions be aplied here? */
+ for ( SpatialGrid var : variables )
+ var.newArray(PRODUCTIONRATE);
+ applyEnvReactions(variables);
+
+ setupAgentDistributionMaps(this._agents.getShape());
+ }
+
+ public void applyReactions(MultigridSolute[] sols, int resorder, SolverGrid[] reacGrid, double[] resolution,
+ double voxelVolume)
+ {
+ for( Agent agent : this._agents.getAllAgents() )
+ applyAgentReactions(agent, sols, resorder, reacGrid, resolution, voxelVolume);
+ }
+
+ /**
+ * \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).
+ */
+ private void applyAgentReactions(
+ Agent agent, MultigridSolute[] concGrid, int resorder, SolverGrid[] reacGrid, double[] resolution,
+ double voxelVolume)
+ {
+ /*
+ * 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 = this._agents.getShape();
+
+ /*
+ * 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();
+ SolverGrid solute;
+ MultigridSolute mGrid;
+ double concn, productRate, volume, perVolume;
+
+ double[] center = ((Body) agent.get(AspectRef.agentBody)).getCenter(shape);
+
+ IntegerArray coord = new IntegerArray(
+ shape.getCoords( center, null, resolution ));
+
+
+
+ volume = voxelVolume;
+ 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() )
+ {
+ mGrid = FindGrid(concGrid, varName);
+ if ( mGrid != null ) {
+ solute = mGrid._conc[resorder];
+ concn = solute.getValueAt(coord.get(), true);
+ }
+ else if ( biomass.containsKey(varName) )
+ {
+ concn = biomass.get(varName) * perVolume;
+ }
+ else if ( agent.isAspect(varName) )
+ {
+ /*
+ * Check if the agent has other mass-like aspects
+ * (e.g. EPS).
+ */
+ concn = agent.getDouble(varName) * 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() )
+ {
+ mGrid = FindGrid(concGrid, productName);
+ if ( mGrid != null )
+ {
+ solute = mGrid._reac[resorder];
+ productRate = r.getProductionRate(concns, productName);
+ solute.addValueAt( productRate, coord.get() , true );
+ }
+ }
+ }
+ }
+
+ private void applyAgentGrowth(Agent agent)
+ {
+ /*
+ * 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;
+
+ Shape shape = this._agents.getShape();
+ double[] center = ((Body) agent.get(AspectRef.agentBody)).getCenter(shape);
+
+ IntegerArray coord = new IntegerArray(
+ shape.getCoords( center ));
+ /*
+ * 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);
+ @SuppressWarnings("unchecked")
+ Map newBiomass = (HashMap)
+ ObjectFactory.copy(biomass);
+ /*
+ * Now look at all the voxels this agent covers.
+ */
+ Map concns = new HashMap();
+ SpatialGrid solute;
+ double concn, productRate, volume, perVolume;
+
+ volume = this._agents.getShape().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() )
+ {
+ if ( this._environment.isSoluteName( varName ) )
+ {
+ solute = this._environment.getSoluteGrid( varName );
+ concn = solute.getValueAt( CONCN, coord.get() );
+ }
+ else if ( biomass.containsKey( varName ) )
+ {
+ concn = biomass.get( varName ) * perVolume;
+
+ }
+ else if ( agent.isAspect( varName ) )
+ {
+ /*
+ * Check if the agent has other mass-like aspects
+ * (e.g. EPS).
+ */
+ concn = agent.getDouble( varName ) * 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() )
+ {
+ /* FIXME: it is probably faster if we get the reaction rate
+ * once and then calculate the rate per product from that
+ * for each individual product
+ */
+ productRate = r.getProductionRate(concns,productName);
+ double quantity;
+
+ if ( this._environment.isSoluteName(productName) )
+ {
+ solute = this._environment.getSoluteGrid(productName);
+ quantity =
+ productRate * volume * this.getTimeStepSize();
+ solute.addValueAt(PRODUCTIONRATE, coord.get(), quantity
+ );
+ }
+ else if ( newBiomass.containsKey(productName) )
+ {
+ quantity =
+ productRate * this.getTimeStepSize() * volume;
+ newBiomass.put(productName, newBiomass.get(productName)
+ + quantity );
+ }
+ /* FIXME this can create conflicts if users try to mix mass-
+ * maps and simple mass aspects */
+ else if ( agent.isAspect(productName) )
+ {
+ /*
+ * Check if the agent has other mass-like aspects
+ * (e.g. EPS).
+ */
+ quantity =
+ productRate * this.getTimeStepSize() * volume;
+ newBiomass.put(productName, agent.getDouble(productName)
+ + quantity);
+ }
+ else
+ {
+ quantity =
+ productRate * this.getTimeStepSize() * volume;
+ //TODO quick fix If not defined elsewhere add it to the map
+ newBiomass.put(productName, quantity);
+ System.out.println("agent reaction catched " +
+ productName);
+ // TODO safety?
+
+ }
+ if( Global.bookkeeping )
+ agent.getCompartment().registerBook(
+ KeeperEntry.EventType.REACTION,
+ productName,
+ String.valueOf( agent.identity() ),
+ String.valueOf( quantity ), null );
+ }
+ }
+ ProcessMethods.updateAgentMass(agent, newBiomass);
+ }
+
+ private MultigridSolute FindGrid(MultigridSolute[] grids, String name)
+ {
+ for ( MultigridSolute grid : grids )
+ if ( grid.soluteName.equals(name) ) {
+// Quick debug check to see which grid (coarse/fine) we are handling
+// System.out.println( grid.getVoxelVolume() );
+ return grid;
+ }
+ return null;
+ }
+}
diff --git a/src/processManager/library/SolveDiffusionSteadyState.java b/src/processManager/library/SolveDiffusionSteadyState.java
index 4dfd116a8..06040d44c 100644
--- a/src/processManager/library/SolveDiffusionSteadyState.java
+++ b/src/processManager/library/SolveDiffusionSteadyState.java
@@ -55,9 +55,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/reaction/RegularReaction.java b/src/reaction/RegularReaction.java
index d14c72371..586844e41 100644
--- a/src/reaction/RegularReaction.java
+++ b/src/reaction/RegularReaction.java
@@ -309,7 +309,7 @@ private void checkNegatives( Map concentrations )
for ( String s : concentrations.keySet() )
{
if( concentrations.get(s) < 0.0 )
- System.out.println( s + " " + concentrations.get(s) );
+ System.out.println( this.getClass().getSimpleName() + " detecteded negative concentration "+ s + " " + concentrations.get(s) );
}
}
@@ -320,7 +320,6 @@ private void checkNegatives( Map concentrations )
* @param withRespectTo
* @return
*/
- // TODO never used, consider deletion
public double getDiffRate(HashMap concentrations,
String withRespectTo)
{
diff --git a/src/referenceLibrary/AspectRef.java b/src/referenceLibrary/AspectRef.java
index a0328cb29..16692cdb5 100644
--- a/src/referenceLibrary/AspectRef.java
+++ b/src/referenceLibrary/AspectRef.java
@@ -301,6 +301,22 @@ public static String[] getAllOptions()
*/
public final static String collisionRelaxationMethod = "relaxationMethod";
+ /**
+ * Maximum amount of overlap in microns that may exist for a scenario
+ * to be considered relaxed.
+ */
+ public final static String maxAgentOverlap = "maxAgentOverlap";
+
+ /**
+ * determines coarseness of agentRelaxation stepSize .
+ */
+ public final static String moveGranularity = "moveGranularity";
+
+ /**
+ * determines coarseness of agentRelaxation stepSize .
+ */
+ public final static String shoveFactor = "shoveFactor";
+
/**
* TODO
*/
@@ -345,7 +361,12 @@ public static String[] getAllOptions()
* TODO
*/
public final static String solverRelTolerance = "relativeTolerance";
-
+
+ /**
+ *
+ */
+ public final static String solverResidualRatioThreshold = "solverResidualRatioThreshold";
+
/**
* TODO
*/
@@ -623,6 +644,8 @@ public static String[] getAllOptions()
public static final String coarseSteps = "coarseSteps";
public static final String postSteps = "postSteps";
+
+ public static final String record = "record";
public static final String disableBulkDynamics = "disableBulkDynamics";
@@ -649,5 +672,20 @@ public static String[] getAllOptions()
public static final String transientRadius = "transientRadius";
public static final String linearFunction = "linearFunction";
+
+ public static final String fileNumber = "fileNumber";
+
+ public static final String colourSpecification = "colourSpecification";
+ public static final String order = "order";
+
+ public static final String solute = "solute";
+
+ public static final String recordType = "type";
+
+ public static final String interval = "interval";
+
+ public static final String autoVcycleAdjust = "autoVcycleAdjust";
+
+ public static final String absoluteValue = "absoluteValue";
}
diff --git a/src/referenceLibrary/ClassRef.java b/src/referenceLibrary/ClassRef.java
index eaa2d2807..6a86b260b 100644
--- a/src/referenceLibrary/ClassRef.java
+++ b/src/referenceLibrary/ClassRef.java
@@ -389,6 +389,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
*/
@@ -629,6 +636,13 @@ public static String path(String name)
*/
public final static String multigridResolution =
shape.resolution.MultigridResolution.class.getName();
+
+ /**
+ * MgFAS resolution class, used in combination with {@link
+ * shape.resolution.ResolutionCalculator}
+ */
+ public final static String MgFASResolution =
+ shape.resolution.MgFASResolution.class.getName();
/* ************************************************************************
* miscellaneous
@@ -747,5 +761,8 @@ public static String path(String name)
public static final String expression =
expression.Expression.class.getName();
+
+ public static final String recordKeeper =
+ solver.mgFas.RecordKeeper.class.getName();
}
diff --git a/src/referenceLibrary/XmlRef.java b/src/referenceLibrary/XmlRef.java
index d768daed3..0b463a39c 100644
--- a/src/referenceLibrary/XmlRef.java
+++ b/src/referenceLibrary/XmlRef.java
@@ -15,7 +15,7 @@
*/
public class XmlRef
{
- public static String[] getAllOptions()
+ public static String[] getAllOptions()
{
Field[] fields = XmlRef.class.getFields();
String[] options = new String[fields.length];
@@ -671,4 +671,8 @@ public static String[] getAllOptions()
public static final String spring = "spring";
public static final String member = "member";
+
+ public static final String record = "record";
+
+ public static String nodeSystem = "nodeSystem";
}
diff --git a/src/render/AgentMediator.java b/src/render/AgentMediator.java
index 11db8dba8..de4aa83fe 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)
@@ -155,7 +185,7 @@ public double[] orientation()
public void colStep()
{
- if (activeCol > soluteColors.size())
+ if (activeCol == soluteColors.size())
activeCol = 0;
else
activeCol += 1;
@@ -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
@@ -414,29 +452,32 @@ private void draw(Shape shape){
max[i++] = (float) grid.getMax(ArrayType.CONCN);
}
}
-
for (int[] cur = it.resetIterator(); it.isIteratorValid(); cur = it.iteratorNext())
- {
+ {
_gl.glPushMatrix();
/* print solutes */
if (soluteColors.values().size() > 0){
float[] col = new float[] { 0f, 0f, 0f };
j = 0;
- if (this.activeCol == 1)
- {
- for (String s : soluteColors.keySet()){
- SpatialGrid grid = _compartment.getSolute(soluteColors.get(s));
- conc = (float)grid.getValueAt(ArrayType.CONCN,
- it.iteratorCurrent()) / max[j];
- col[j++] = conc;
- }
- }
- else
+ /* NOTE: disabled multicolor view */
+// if (this.activeCol == 1)
+// {
+// for (String s : soluteColors.keySet()){
+// SpatialGrid grid = _compartment.getSolute(soluteColors.get(s));
+// conc = (float)grid.getValueAt(ArrayType.CONCN,
+// it.iteratorCurrent()) / max[j];
+// col[j++] = conc;
+//
+//// System.out.println( (float)grid.getValueAt(ArrayType.CONCN,
+//// it.iteratorCurrent()) );
+// }
+// }
+// else
{
for (String s : soluteColors.keySet())
{
- if(j == this.activeCol-2)
+ if(j == this.activeCol-1)
{
SpatialGrid grid = _compartment.getSolute(soluteColors.get(s));
conc = (float)grid.getValueAt(ArrayType.CONCN,
@@ -446,7 +487,6 @@ private void draw(Shape shape){
j++;
}
}
-
_rgba=col;
applyCurrentColor(_soluteTranparancy);
}
@@ -549,14 +589,14 @@ private void drawVoxel(Shape shape, int[] coord)
// Vector3f norm = new Vector3f(0f,0f,1f);
double[] in = new double[]{0,0,0};
- double[] p1 = shape.getGlobalLocation(shape.getLocation(coord, in)); in[1]++; // [0 0 0]
- double[] p2 = shape.getGlobalLocation(shape.getLocation(coord, in)); in[2]++; // [0 1 0]
- double[] p3 = shape.getGlobalLocation(shape.getLocation(coord, in)); in[1]--; // [0 1 1]
- double[] p4 = shape.getGlobalLocation(shape.getLocation(coord, in)); in[0]++; in[1]++; // [0 0 1]
- double[] p5 = shape.getGlobalLocation(shape.getLocation(coord, in)); in[1]--; // [1 1 1]
- double[] p6 = shape.getGlobalLocation(shape.getLocation(coord, in)); in[2]--; // [1 0 1]
- double[] p7 = shape.getGlobalLocation(shape.getLocation(coord, in)); in[1]++; // [1 0 0]
- double[] p8 = shape.getGlobalLocation(shape.getLocation(coord, in)); // [1 1 0]
+ double[] p1 = shape.getRenderLocation(coord, in); in[1]++; // [0 0 0]
+ double[] p2 = shape.getRenderLocation(coord, in); in[2]++; // [0 1 0]
+ double[] p3 = shape.getRenderLocation(coord, in); in[1]--; // [0 1 1]
+ double[] p4 = shape.getRenderLocation(coord, in); in[0]++; in[1]++; // [0 0 1]
+ double[] p5 = shape.getRenderLocation(coord, in); in[1]--; // [1 1 1]
+ double[] p6 = shape.getRenderLocation(coord, in); in[2]--; // [1 0 1]
+ double[] p7 = shape.getRenderLocation(coord, in); in[1]++; // [1 0 0]
+ double[] p8 = shape.getRenderLocation(coord, in); // [1 1 0]
_gl.glBegin(GL2.GL_QUADS);
// r==0
@@ -603,11 +643,12 @@ private void drawsquare(Shape shape, int[] coord)
// Vector3f norm = new Vector3f(0f,0f,1f);
double[] in = new double[]{0,0,0};
- double[] p1 = shape.getGlobalLocation(shape.getLocation(coord, in)); in[1]++; // [0 0 0]
- double[] p2 = shape.getGlobalLocation(shape.getLocation(coord, in)); in[0]++; // [0 1 0]
- double[] p7 = shape.getGlobalLocation(shape.getLocation(coord, in)); in[1]--; // [1 1 0]
- double[] p8 = shape.getGlobalLocation(shape.getLocation(coord, in)); // [1 0 0]
-
+ double[] p1 = shape.getRenderLocation(coord, in); in[1]++; // [0 0 0]
+ double[] p2 = shape.getRenderLocation(coord, in); in[0]++; // [0 1 0]
+ double[] p7 = shape.getRenderLocation(coord, in); in[1]--; // [1 1 0]
+ double[] p8 = shape.getRenderLocation(coord, in);
+ // [1 0 0]
+
_gl.glBegin(GL2.GL_QUADS);
// p==0
_gl.glVertex3fv(Vector.toFloat(p1), 0);
@@ -661,4 +702,5 @@ public void solutTranparancy() {
_soluteTranparancy += 0.05f;
}
+
}
diff --git a/src/render/Render.java b/src/render/Render.java
index 6decd367c..71063ce57 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;
@@ -150,8 +152,14 @@ public void display(GLAutoDrawable drawable) {
* the open GL2 drawable
*/
final GL2 gl = drawable.getGL().getGL2();
+
+ /* line disabled because:
+ Currently squares are seen from backside so this would hide them, it also seems to
+ make very little difference in terms of frame rate
+ gl.glEnable(GL2.GL_CULL_FACE);
+ */
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
-
+
// fps
double currentTime = System.currentTimeMillis();
nbFrames++;
@@ -789,5 +797,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 );
}
}
diff --git a/src/shape/CartesianShape.java b/src/shape/CartesianShape.java
index 6f3052bef..b4e11597a 100644
--- a/src/shape/CartesianShape.java
+++ b/src/shape/CartesianShape.java
@@ -62,11 +62,12 @@ public CartesianShape()
@Override
public double[][][] getNewArray(double initialValue)
{
- int[] nVoxel = new int[3];
+
+ int[] nElement = new int[3];
/* We need at least length 1 in each dimension for the array. */
for ( int dim = 0; dim < 3; dim ++ )
- nVoxel[dim] = Math.max(this._resCalc[dim].getNVoxel(), 1);
- return Array.array(nVoxel, initialValue);
+ nElement[dim] = Math.max(this._resCalc[dim].getNElement(), 1);
+ return Array.array(nElement, initialValue);
}
@Override
diff --git a/src/shape/Dimension.java b/src/shape/Dimension.java
index 6093b88b1..310f39492 100644
--- a/src/shape/Dimension.java
+++ b/src/shape/Dimension.java
@@ -34,24 +34,29 @@ public class Dimension implements CanPrelaunchCheck, Settable,
*/
public enum DimName
{
- X(false),
- Y(false),
- Z(false),
- R(false),
- THETA(true),
- PHI(true);
+ X(false, 0),
+ Y(false, 1),
+ Z(false, 2),
+ R(false, 0),
+ THETA(true, 1),
+ PHI(true,2);
private boolean _isAngular;
+
+ private int _dimNum;
- DimName(boolean isAngular)
+ DimName(boolean isAngular, int dimNum)
{
this._isAngular = isAngular;
+ this._dimNum = dimNum;
}
public boolean isAngular()
{
return this._isAngular;
}
+
+ public int dimNum() { return this._dimNum; }
}
diff --git a/src/shape/Shape.java b/src/shape/Shape.java
index 7ff925a62..42c3c2a84 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
-{
+ CanPrelaunchCheck, Instantiable, Settable {
/**
* Ordered dictionary of dimensions for this shape.
* TODO switch to a Shape._dimensions a Dimension[3] paradigm
@@ -99,6 +98,11 @@ public abstract class Shape implements
new LinkedList();
protected ShapeIterator _it;
+
+ /**
+ * This shape represents a node based system (true) or a voxel based system (false).
+ */
+ private Boolean _nodes = false;
/**
* TODO
@@ -147,6 +151,9 @@ public Module getModule()
* editable to false */
modelNode.add( new Attribute(XmlRef.classAttribute,
this.getName(), null, false ) );
+
+ modelNode.add( new Attribute(XmlRef.nodeSystem, this._nodes.toString(), null, false) );
+
/** Add resolution calculator specification */
modelNode.add( new Attribute(XmlRef.resolutionCalculator,
this.resCal, null, false ) );
@@ -206,6 +213,12 @@ public void instantiate(Element xmlElem, Settable parent )
dbl = XmlHandler.gatherDouble(xmlElem, "insignificantDimsLength");
if ( dbl != null )
insignificantDimsLength = dbl;
+
+ this._nodes = XmlHandler.gatherBoolean(xmlElem,
+ XmlRef.nodeSystem);
+ if ( this._nodes == null )
+ this._nodes = false;
+
/* Set up the dimensions. */
Dimension dim;
ResolutionCalculator rC;
@@ -227,6 +240,7 @@ public void instantiate(Element xmlElem, Settable parent )
/* Initialise resolution calculators */
rC = (ResolutionCalculator) Instance.getNew(xmlElem, this,
resCal );
+ rC.setNodeSystem(this._nodes);
rC.setDimension(dim);
rC.setResolution(dim._targetRes);
this.setDimensionResolution(dimName, rC);
@@ -568,6 +582,16 @@ public void setDimensionLengths(double[] lengths)
}
}
+ public int getDimensionVoxelCount( int dimension )
+ {
+ DimName d = this.getDimensionName( dimension );
+ if( d != null && this instanceof CartesianShape )
+ {
+ return ((CartesianShape) this)._resCalc[2].getNVoxel();
+ }
+ return 0;
+ }
+
/**
* \brief Try to initialise a resolution calculator from storage, for a
* dimension that is dependent on another.
@@ -737,6 +761,16 @@ public double[] getGlobalLocation(double[] local)
this.getGlobalLocationTo(out, local);
return out;
}
+
+ public double[] getRenderLocation(int[] coord, double[] in)
+ {
+ double out[] = this.getGlobalLocation(this.getLocation(coord, in));
+ //FIXME quickfix shift by half a voxel to represent nodes
+ // for better representation side nodes need to be resized.
+ if( this.isNodeSystem() )
+ Vector.minusEquals( out, Vector.times(this.getVoxelSideLengths( coord ), 0.5) );
+ return out;
+ }
/**
* \brief Convert a spatial position from the local coordinate scheme to
@@ -1304,7 +1338,7 @@ public int[] getCoords(double[] loc, double[] inside)
if( loc.length < dim+1)
coord[dim] = 0;
else
- coord[dim] = rC.getVoxelIndex(loc[dim]);
+ coord[dim] = rC.getElementIndex(loc[dim]);
if ( inside != null )
{
inside[dim] = loc[dim] -
@@ -1313,6 +1347,28 @@ public int[] getCoords(double[] loc, double[] inside)
}
return coord;
}
+
+ public int[] getCoords(double[] loc, double[] inside, double[] resolution)
+ {
+ int[] coord = new int[3];
+ ResolutionCalculator rC;
+ for ( int dim = 0; dim < 3; dim++ )
+ {
+ rC = this.getResolutionCalculator(coord, dim);
+ /* if the location comes from a 1D or 2D system set the coordinate
+ * index for additional dimensions to 0. */
+ if( loc.length < dim+1)
+ coord[dim] = 0;
+ else
+ coord[dim] = rC.getElementIndex(loc[dim], resolution[dim]);
+ if ( inside != null )
+ {
+ inside[dim] = loc[dim] -
+ rC.getCumulativeResolution(coord[dim] - 1, resolution[dim]);
+ }
+ }
+ return coord;
+ }
/**
* \brief For a voxel given by its coordinates, find the global location
@@ -1447,6 +1503,13 @@ public void getVoxelSideLengthsTo(double[] destination, int[] coord)
destination[dim] = rC.getResolution();
}
}
+
+ public double[] getVoxelSideLengths( int[] coord )
+ {
+ double[] out = new double[coord.length];
+ getVoxelSideLengthsTo( out, coord );
+ return out;
+ }
/* ***********************************************************************
* SHAPE AND VOXEL PROPERTIES
@@ -1694,7 +1757,12 @@ public int[] nbhIteratorNext()
{
return this._it.nbhIteratorNext();
}
-
+
+ public boolean isNodeSystem()
+ {
+ return this._nodes;
+ }
+
public boolean isNbhIteratorValid(){
return this._it.isNbhIteratorValid();
}
diff --git a/src/shape/iterator/PolarShapeIterator.java b/src/shape/iterator/PolarShapeIterator.java
index db77f0231..bcb95abab 100644
--- a/src/shape/iterator/PolarShapeIterator.java
+++ b/src/shape/iterator/PolarShapeIterator.java
@@ -73,7 +73,7 @@ protected boolean setNbhFirstInNewShell(int shellIndex)
double cur_min = rC.getCumulativeResolution(this._currentCoord[1] - 1);
rC = this._shape.getResolutionCalculator(this._currentNeighbor, 1);
- int new_index = rC.getVoxelIndex(cur_min);
+ int new_index = rC.getElementIndex(cur_min);
this._currentNeighbor[1] = new_index;
diff --git a/src/shape/iterator/SphericalShapeIterator.java b/src/shape/iterator/SphericalShapeIterator.java
index 20dca934d..ca806f4e9 100644
--- a/src/shape/iterator/SphericalShapeIterator.java
+++ b/src/shape/iterator/SphericalShapeIterator.java
@@ -254,7 +254,7 @@ protected boolean setNbhFirstInNewRing(int ringIndex)
*/
double theta = rC.getCumulativeResolution(this._currentCoord[2] - 1);
rC = this._shape.getResolutionCalculator(this._currentNeighbor, 2);
- int new_index = rC.getVoxelIndex(theta);
+ int new_index = rC.getElementIndex(theta);
this._currentNeighbor[2] = new_index;
return true;
diff --git a/src/shape/resolution/MgFASResolution.java b/src/shape/resolution/MgFASResolution.java
new file mode 100644
index 000000000..2aed7508d
--- /dev/null
+++ b/src/shape/resolution/MgFASResolution.java
@@ -0,0 +1,48 @@
+package shape.resolution;
+
+import shape.Dimension;
+import shape.ShapeConventions.SingleVoxel;
+import utility.ExtraMath;
+
+/**
+ * TODO description and author information
+ * @author Stefan Lang @ Robert Clegg?
+ *
+ */
+public class MgFASResolution extends ResolutionCalculator
+{
+ public MgFASResolution()
+ {
+ super();
+ }
+
+ public MgFASResolution(Dimension dimension)
+ {
+ super(dimension);
+ }
+
+ @Override
+ protected void init(double targetResolution, double min, double max)
+ {
+ this._targetRes = targetResolution;
+ /* Single-voxel test to start with. */
+ this._nVoxel = 1;
+ this._resolution = this.getTotalLength();
+ /* Variables to test splitting the grid into more voxels. */
+ int exponent = 1;
+ int altNVoxel = 2;
+ double altRes = this.getTotalLength() / altNVoxel;
+ /* Testing loop. */
+ while( isAltResBetter(this._resolution, altRes, targetResolution) )
+ {
+ this._nVoxel = altNVoxel;
+ exponent++;
+ altNVoxel = ExtraMath.exp2(exponent);
+ this._resolution = altRes;
+ altRes = this.getTotalLength() / (altNVoxel);
+ }
+
+ this._nVoxel++;
+ }
+
+}
diff --git a/src/shape/resolution/ResolutionCalculator.java b/src/shape/resolution/ResolutionCalculator.java
index 96f9b20fb..a63a71c56 100644
--- a/src/shape/resolution/ResolutionCalculator.java
+++ b/src/shape/resolution/ResolutionCalculator.java
@@ -34,6 +34,8 @@ public abstract class ResolutionCalculator implements Copyable, Instantiable
*/
protected double _targetRes;
+ protected Boolean _nodeSystem = false;
+
/* ***********************************************************************
* CONSTRUCTION
* **********************************************************************/
@@ -71,6 +73,11 @@ public int getNVoxel()
{
return this._nVoxel;
}
+
+ public int getNElement()
+ {
+ return this._nVoxel;
+ }
public double getTotalLength()
{
@@ -105,10 +112,20 @@ public double getCumulativeResolution(int voxelIndex)
return min;
return min + this._resolution * (voxelIndex + 1);
}
+
+ public double getCumulativeResolution(int voxelIndex, double resolution)
+ {
+ if ( voxelIndex >= this._nVoxel )
+ throw new IllegalArgumentException("Voxel index out of range");
+ double min = this._dimension.getExtreme(0);
+ if ( voxelIndex < 0 )
+ return min;
+ return min + resolution * (voxelIndex + 1);
+ }
/**
* \brief TODO
- *
+ *
* @param voxelIndex
* @param inside
* @return
@@ -120,6 +137,10 @@ public double getPosition(int voxelIndex, double inside)
out += this._resolution * inside;
return out;
}
+
+ /*
+ FIXME: I think the following 4 methods may yield issues with sub 1 micron resolutions
+ */
/**
* \brief Calculates which voxel the given location lies inside.
@@ -138,6 +159,59 @@ public int getVoxelIndex(double location)
return (int) ((location - this._dimension.getExtreme(0))
/ this._resolution);
}
+
+ public int getVoxelIndex(double location, double resolution)
+ {
+ if ( location < this._dimension.getExtreme(0) ||
+ location >= this._dimension.getExtreme(1) )
+ {
+ throw new IllegalArgumentException("Location out of range");
+ }
+ return (int) ((location - this._dimension.getExtreme(0))
+ / resolution);
+ }
+
+ public int getNodeIndex(double location)
+ {
+ if ( location < this._dimension.getExtreme(0) ||
+ location >= this._dimension.getExtreme(1) )
+ {
+ throw new IllegalArgumentException("Location out of range");
+ }
+ if( this.getNVoxel() > 1 )
+ return (int) ((( location + 0.5*this._resolution ) -
+ this._dimension.getExtreme(0)) / this._resolution);
+ else
+ return 0;
+ }
+
+ public int getNodeIndex(double location, double resolution)
+ {
+ if ( location < this._dimension.getExtreme(0) ||
+ location >= this._dimension.getExtreme(1) )
+ {
+ throw new IllegalArgumentException("Location out of range");
+ }
+ if( this.getNVoxel() > 1 )
+ return (int) ((( location + 0.5*resolution) -
+ this._dimension.getExtreme(0)) / resolution);
+ else
+ return getVoxelIndex(location, resolution);
+ }
+
+ public int getElementIndex(double location)
+ {
+ return( this._nodeSystem ?
+ getNodeIndex(location) :
+ getVoxelIndex(location) );
+ }
+
+ public int getElementIndex(double location, double resolution)
+ {
+ return( this._nodeSystem ?
+ getNodeIndex(location, resolution) :
+ getVoxelIndex(location, resolution) );
+ }
public Object copy()
{
@@ -155,13 +229,17 @@ public Object copy()
}
return out;
}
-
@Override
public void instantiate(Element xmlElement, Settable parent) {
// TODO Auto-generated method stub
}
+
+ public void setNodeSystem(Boolean nodes)
+ {
+ this._nodeSystem = nodes;
+ }
/*************************************************************************
* USEFUL STATIC METHODS
@@ -177,4 +255,5 @@ protected static boolean isAltResBetter(double res, double altRes,
{
return resDiff(altRes, targetRes) < resDiff(res, targetRes);
}
+
}
diff --git a/src/solver/PDEmultigrid.java b/src/solver/PDEmultigrid.java
index 195cde8e5..e5eb550cd 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
@@ -100,7 +103,9 @@ public class PDEmultigrid extends PDEsolver
/**
* Enable stopping relaxation when stop conditions are met
*/
- private boolean _enableEarlyStop = false;
+ private boolean _enableEarlyStop = true;
+
+ private double ALPHA = 0.33;
/**
* Warn for large differences between Vcycle residuals (Debugging tool)
*/
@@ -113,6 +118,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)
*/
@@ -185,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 */
@@ -334,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;
@@ -347,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
@@ -416,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
@@ -480,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);
@@ -499,6 +484,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 +516,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 +536,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,23 +558,33 @@ 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 "
+ 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.DEBUG) )
{
- Log.out(Tier.DEBUG, i + " " + Vector.max(this.tempRes) + " > " +
- this._absToleranceLevel );
+ if( Log.shouldWrite(Tier.DEBUG))
+ if( Vector.max(this.tempRes) > this._absToleranceLevel )
+ {
+ Log.out(Tier.DEBUG, (i+1) + " " + Vector.max(this.tempRes) +
+ " > " + this._absToleranceLevel + " in: " + this.getClass().getSimpleName());
+ }
+ else
+ {
+ Log.out(Tier.DEBUG, (i+1) + " " + Vector.max(this.tempRel) +
+ " > " + this._relToleranceLevel + " in: " + this.getClass().getSimpleName());
+ }
}
}
+
/* update reaction rate matrix at current concn */
this._updater.prestep(currentGrids, 0.0);
@@ -679,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);
@@ -727,6 +727,19 @@ 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 ) /* 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. */
concn += residual;
if (Math.abs(residual) > this._absToleranceLevel &&
@@ -743,6 +756,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);
}
}
@@ -762,126 +776,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;
- /* 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);
@@ -890,7 +805,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();
@@ -929,7 +843,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
@@ -947,36 +860,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;
- double relChange = residual / concn;
- /* Prepare to update the local concentration. */
- concn += residual;
- if (Math.abs(residual) > this._absToleranceLevel &&
- Math.abs(relChange) > this._relToleranceLevel)
+ diffusiveFlow = lop;
+ /*diffusiveFlow = 0.0;
+ for ( shape.resetNbhIterator(); shape.isNbhIteratorValid();
+ shape.nbhIteratorNext() )
{
- 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;
- /* Update the value and continue to the next voxel. */
+ 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
diff --git a/src/solver/mgFas/Domain.java b/src/solver/mgFas/Domain.java
new file mode 100644
index 000000000..877a3a446
--- /dev/null
+++ b/src/solver/mgFas/Domain.java
@@ -0,0 +1,640 @@
+/**
+ * \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 compartment.EnvironmentContainer;
+import dataIO.Log;
+import debugTools.SegmentTimer;
+import grid.ArrayType;
+import linearAlgebra.Array;
+import linearAlgebra.Vector;
+import shape.Shape;
+import solver.mgFas.boundaries.AllBC;
+import solver.mgFas.utils.ContinuousVector;
+import solver.mgFas.utils.DiscreteVector;
+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;
+
+ /**
+ * List of all boundaries defined on this computation domain.
+ */
+ private LinkedList _boundaryList = new LinkedList();
+
+ /**
+ * 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 = 0.0; //I've set this default to 0 for now
+
+ /**
+ * 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;
+
+ private EnvironmentContainer _environment;
+
+ /*************************************************************************
+ * 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.
+ *
+ */
+ public Domain(Shape shape, EnvironmentContainer environment)
+ {
+ this._shape = shape;
+ // Now determine if this computation domain is 2D or 3D
+ is3D = shape.getSignificantDimensions().size() == 3;
+
+ /* FIXME enforce all dimensions to be of the same resolution. */
+ _resolution = Math.min(
+ shape.getResolutionCalculator(null, 0).getResolution(),
+ shape.getResolutionCalculator(null, 1).getResolution() );
+ // shape.getResolutionCalculator(null, 2).getResolution() );
+
+ double[] lengths = (shape.getRealLengths());
+
+ this._environment = environment;
+
+ _nI = (int) Math.ceil(lengths[0]/_resolution) +1;
+ _nJ = (int) Math.ceil(lengths[1]/_resolution) +1;
+ _nK = (is3D) ? (int) Math.ceil(lengths[2]/_resolution) +1: 1;
+
+ String message = "unsupported mgFAS.md resolution, use n = 1+2^x";
+ if( isDiscretizationCompatible(_nI))
+ Log.out(Log.Tier.CRITICAL, message);
+ if( isDiscretizationCompatible(_nJ))
+ Log.out(Log.Tier.CRITICAL, message);
+ if( is3D && isDiscretizationCompatible(_nK))
+ Log.out(Log.Tier.CRITICAL, message);
+
+ // Now calculate the length of the grid in micrometres.
+ length_X = _nI * _resolution;
+ length_Y = _nJ * _resolution;
+ length_Z = _nK * _resolution;
+
+ // Create and initialise the domain grid.
+ _domainGrid = new SoluteGrid(_nI, _nJ, _nK, _resolution, "domainGrid", this);
+
+ // 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);
+
+ // Now comes the definition of the behavior at the boundaries.
+ // In general, there are 6 boundaries that must be addressed: y0z, yNz,
+ // x0z, xNz, x0y, xNy. These represent the edges of the domain along
+ // the non-named direction (i.e. y0z is the face at x=0, and yNz is the
+ // face at x=N). (For 2D simulations the x0y and xNy directions are
+ // included, but are made periodic.) Each also
+ // includes a mark-up to define the shape of the boundary.
+ // The below call combines all boundary conditions in the XML file,
+ // then processes each.
+
+ /** Building
+ for (XMLParser aBCMarkUp : cdRoot.getChildrenParsers("boundaryCondition"))
+ AllBC.staticBuilder(aBCMarkUp, aSim, this);
+ **/
+
+ // Note the above has added all the boundaries to the array _boundaryList
+ // Now apply these boundaries
+
+ // Build the domain grid : 0 outside, 1 inside, -1 carrier
+
+ applyAllBoundary();
+ // KA May 2013
+ // Now we're going to initialise all these grids.
+ // Note this wasn't previously done, but with self attachment we need
+ // to know where the boundary layer is before any agents are added. The
+ // function below was part of the refreshBioFilmGrids method - this now
+ // exists independently and is called whenever these grids need to be
+ // refreshed.
+ }
+
+ /**
+ * \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(this, _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);
+ }
+ }
+ }
+
+ /**
+ * \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()
+ {
+ // Reset the grid
+ _boundaryLayer.setAllValueAt(0.0);
+
+ // calculate the values in each of the grids
+ calculateComputationDomainGrids2();
+
+ // update padding
+ _boundaryLayer.refreshBoundary();
+ _diffusivityGrid.refreshBoundary();
+
+ /* TODO biomass region diffusivity */
+
+ }
+
+ /**
+ * work in progress method, updated to use updateWellMixed
+ *
+ * Todo: segregation between different diffusivity zones (biomass & fluid), efficiency, cleanup
+ */
+ public void calculateComputationDomainGrids2()
+ {
+ /* note well mixed should already be up-to-date here and should not be updated again for
+ * efficiency. */
+ double[][][] temp = this._environment.getCommonGrid().getArray( ArrayType.WELLMIXED );
+ /* bLayer is the opposite part of wellMixed */
+ temp = Array.minus( Array.add( Array.zeros(temp), 1.0 ) , temp);
+ /* add padding, padding will be filled by refreshBoundary */
+ double[][][] bLayer = MultigridUtils.addPadding(temp);
+ for (int i = 1; i <= _nI; i++)
+ for (int j = 1; j <= _nJ; j++)
+ for (int k = 1; k <= _nK; k++)
+ // Note padding will be updated when .refreshBoundaryLayer() method is called.
+ if ( ( bLayer[i][j][k] > 0.0 ) ) {
+ /*
+ * This is biomass.
+ */
+ _boundaryLayer.grid[i][j][k] = 1.0;
+ _diffusivityGrid.grid[i][j][k] = _biofilmDiffusivity;
+ } else {
+// _boundaryLayer.grid[i][j][k] = 1.0;
+ /*
+ * 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.
+ */
+ 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 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;
+
+// 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;
+ // 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);
+
+ 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;
+ // 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);
+
+ 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));
+ }
+
+ /**
+ * \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 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 return true if chosen discretization is compatible with mgFAS.md
+ */
+ public boolean isDiscretizationCompatible(int nCells)
+ {
+ return isDiscretizationCompatible(nCells, 2);
+ }
+
+ public boolean isDiscretizationCompatible(int nCells, int t)
+ {
+ if ( nCells == t+1 )
+ return true;
+ else if (nCells > t )
+ return false;
+ else return isDiscretizationCompatible(nCells, (int) Math.round( Math.pow(t,2) ) );
+ }
+}
\ No newline at end of file
diff --git a/src/solver/mgFas/Multigrid.java b/src/solver/mgFas/Multigrid.java
new file mode 100644
index 000000000..022084bc2
--- /dev/null
+++ b/src/solver/mgFas/Multigrid.java
@@ -0,0 +1,602 @@
+/**
+ * \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 compartment.AgentContainer;
+import compartment.EnvironmentContainer;
+import dataIO.Log;
+import debugTools.SegmentTimer;
+import grid.ArrayType;
+import grid.SpatialGrid;
+import idynomics.Idynomics;
+import linearAlgebra.Array;
+import linearAlgebra.Vector;
+import processManager.ProcessDiffusion;
+import processManager.library.PDEWrapper;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+
+/**
+ *
+ * @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 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;
+ 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;
+
+ private HashMap _relaxationMap = new HashMap();
+
+ /**
+ *
+ */
+// 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;
+
+ /**
+ * Set Vcycle convergence mode to reporting only or auto adjusting
+ */
+ private boolean autoVcycleAdjust = false;
+
+ protected ProcessDiffusion _manager;
+
+ protected EnvironmentContainer _environment;
+
+ protected LinkedList _recordKeepers;
+
+ private boolean initialGuess = false;
+ /**
+ *
+ */
+ public void init(Domain domain, EnvironmentContainer environment,
+ AgentContainer agents, PDEWrapper manager,
+ int vCycles, int preSteps, int coarseSteps, int postSteps, boolean autoAdjust)
+ {
+ /* Get the computational domain that this solver is associated with. */
+ myDomain = domain;
+
+ this._manager = manager;
+
+ this._recordKeepers = manager.getRecordKeepers();
+
+ this._environment = environment;
+
+ /* 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.
+ */
+
+ nCoarseStep = coarseSteps;
+ _vCycles = vCycles;
+ nPreSteps = preSteps;
+ nPostSteps = postSteps;
+
+ this.autoVcycleAdjust = autoAdjust;
+
+ // Create the table of solute grids
+ nSolute = _soluteList.size();
+ _solute = new MultigridSolute[nSolute];
+ allSolute = new SoluteGrid[nSolute];
+ allReac = new SoluteGrid[nSolute];
+ allDiffReac = new SoluteGrid[nSolute];
+
+ /* TODO: here both bLayer and diffusivity initiate from the same grid like in iDyno 1
+ * but both construct a new conc-grid. */
+ _bLayer = new MultigridSolute(_soluteList.get(0), "boundary layer", manager);
+ _diffusivity =
+ new MultigridSolute(_soluteList.get(0), "relative diffusivity", manager);
+
+ Double sBulk;
+ for (int i = 0; i < nSolute; i++)
+ {
+ /* FIXME taking initial as fixed boundary concentration bulk */
+ sBulk = environment.getAverageConcentration(_soluteList.get(i).gridName); // this is what the conc grid is set when first solved
+ _solute[i] = new MultigridSolute(_soluteList.get(i),
+ _diffusivity, _bLayer, sBulk, manager);
+ _soluteIndex.add(i); //TODO figure out how solute index was used, adding it here to help program run
+ }
+
+ for (int iSolute : _soluteIndex)
+ {
+ this._relaxationMap.put(_solute[iSolute].soluteName, false);
+ }
+
+ /* 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;
+ for (RecordKeeper r : this._recordKeepers)
+ {
+ String soluteName = r.getSoluteName();
+ for (int i = 0; i < _solute.length; i++)
+ {
+ if (_solute[i].soluteName.contentEquals(soluteName))
+ {
+ Integer order = r.getOrder();
+ _solute[i]._conc[order].setRecordKeeper(r);
+ }
+ }
+ }
+ }
+
+ /**
+ * \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 this is the region in which diffusion is solved?
+ _bLayer.setFinest( myDomain.getBoundaryLayer() );
+ _bLayer.restrictToCoarsest();
+
+ // TODO this should be per solute in the future?
+ _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();
+ }
+
+ /**
+ * Solve by iterative relaxation.
+ */
+ 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 ) {
+ */
+
+ // Update bulk concentration.
+ updateBulk();
+
+ // Compute new equilibrium concentrations.
+ stepSolveDiffusionReaction();
+
+ // Manage iterations.
+ internalIteration += 1;
+ timeToSolve -= internTimeStep;
+// }
+
+ // Apply results on solute grids
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].applyComputation();
+
+ /* flash current concentration to iDyno 2 concentration grids */
+ for(int iSolute: _soluteIndex)
+ {
+ double[][][] out = MultigridUtils.removePadding(
+ _solute[iSolute].realGrid.grid );
+ this._environment.getSoluteGrid( this._solute[iSolute].soluteName ).
+ setTo(ArrayType.CONCN, out );
+ }
+ }
+
+ /**
+ * One step of the solver
+ */
+ public void stepSolveDiffusionReaction()
+ {
+ for (int iSolute : _soluteIndex)
+ _solute[iSolute].resetMultigridCopies();
+
+ int smoothingScalar = 1; // before 4
+ boolean breakVCycle = false;
+ int vc =0;
+
+ /*
+ The outer loop is getting finer (starting from coarsest + 1
+ The inner loop is getting coarser and then finer
+
+ /\ / Finest
+ /\ / \ /
+ /\/ \/ \/ Coarsest
+
+
+ order / outer representing finer and coarse grid for
+ */
+
+ int startOrder;
+ if( initialGuess ) {
+ startOrder = maxOrder - 1;
+ } else {
+ startOrder = 1;
+ solveCoarsest( smoothingScalar ); // coarsest order = 0
+ }
+
+ /* the active V-cycle. */
+ for (int outer = startOrder; outer < maxOrder; outer++)
+ {
+ order = outer;
+ /* this interpolates boundary at start of loop, that does not seem logical.
+ interpolate during upward part of the vCycle only. */
+// for (int iSolute : _soluteIndex)
+// _solute[iSolute].initLoop(order);
+
+ // V-cycle loop.
+ for (int v = 0; v < _vCycles; v++)
+ {
+ vc++;
+ // Downward stroke of V.
+ while ( order > 0 )
+ {
+ // Pre-smoothing.
+ if( this.autoVcycleAdjust )
+ relax( smoothingScalar * (order+1));
+// relax( Math.min( 5*(stage+1), nPreSteps) );
+ else
+ 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.
+ if( this.autoVcycleAdjust )
+ solveCoarsest( smoothingScalar );
+ else
+ 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.
+ if( this.autoVcycleAdjust ) // smooth more if Vcycle becomes stagnant
+ relax( smoothingScalar * (order+1) );
+// relax( Math.min( 5*(stage+1), nPostSteps) );
+ else
+ relax(nPostSteps);
+ }
+
+ /* Break the V-cycles if remaining error is dominated
+ * by local truncation error (see p. 884 of Numerical Recipes)
+ */
+ breakVCycle = true;
+
+ for (int iSolute : _soluteIndex)
+ breakVCycle &= _solute[iSolute].breakVCycle(order);
+
+ /* don't cycle initial coarse cycles */
+ if (breakVCycle || outer < maxOrder-1)
+ {
+ breakVCycle = true;
+ break;
+ }
+
+ /* if the solver struggles to reach stop conditions smooth more */
+ smoothingScalar += 3;
+ }
+ if( ! breakVCycle && Log.shouldWrite( Log.Tier.CRITICAL ) )
+ Log.out(Log.Tier.CRITICAL,
+ "Warning: Multigrid VCycle stopped at maximum number of cycles.");
+ }
+ initialGuess = true;
+
+ for (int iSolute : _soluteIndex)
+ {
+ for (int i = 0; i < maxOrder; i++)
+ {
+ if (!_solute[iSolute]._conc[i]._recordKeeper.isEmpty())
+ for (RecordKeeper r : _solute[iSolute]._conc[i]._recordKeeper)
+ r.flush();
+ }
+ }
+ if( Log.shouldWrite( Log.Tier.EXPRESSIVE ) )
+ Log.out(Log.Tier.EXPRESSIVE, "Vcycles: " + vc );
+
+ }
+
+ /**
+ * \brief Update concentration in the reactor.
+ */
+ public void updateBulk()
+ {
+ /* Update reaction rates.
+ * This yields solute change rates in fg.L-1.hr-1
+ */
+ //FIXME is this next line required?
+// updateReacRateAndDiffRate(maxOrder-1);
+
+ /* 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(int steps)
+ {
+ // NOTE disabled reset to bulk, previous solution should be better
+ order = 0;
+ // Reset coarsest grid to bulk concentration.
+// for (int iSolute : _soluteIndex)
+// _solute[iSolute].setWellmixed(order);
+
+ // Relax NSOLVE times.
+ relax(steps);
+ }
+
+ public void solveCoarsest() {
+ solveCoarsest(nCoarseStep);
+ }
+
+ /**
+ * Apply nIter relaxations to the grid at the current resolution.
+ * Check here whether to continue with further post-steps?
+ *
+ * @param nIter
+ */
+ public void relax(int nIter)
+ {
+ for (int j = 0; j < nIter; j++)
+ {
+ updateReacRateAndDiffRate(order);
+ for (int iSolute : _soluteIndex) {
+ _solute[iSolute].relax(order);
+ }
+//
+// if (this._relaxationMap.values().contains(false))
+// {
+// updateReacRateAndDiffRate(order);
+// for (int iSolute : _soluteIndex)
+// {
+// if (!this._relaxationMap.get(_solute[iSolute].soluteName))
+// {
+// double[][][] difference = _solute[iSolute].relax(order);
+//
+// double highestConc = Array.max(_solute[iSolute]._conc[order].grid);
+//
+// if (Array.max(difference) < ((PDEWrapper)this._manager).absTol
+// || Array.max(difference) < highestConc *
+// ((PDEWrapper)this._manager).relTol)
+// this._relaxationMap.put(_solute[iSolute].soluteName, true);
+// }
+// }
+// }
+// }
+// for (String s : this._relaxationMap.keySet())
+// {
+// this._relaxationMap.put(s, false);
+ }
+ }
+
+ /**
+ * 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);
+ Array.restrictMinimum(_solute[iSolute]._conc[resOrder].grid, 0.0);
+ allSolute[iSolute] = _solute[iSolute]._conc[resOrder];
+ // TODO environment reactions
+ allReac[iSolute] = _solute[iSolute]._reac[resOrder];
+ allDiffReac[iSolute] = _solute[iSolute]._diffReac[resOrder];
+ }
+ applyReaction(resOrder);
+ }
+
+ /**
+ * method original comming from reaction
+ * @param concGrid
+ * @param reacGrid
+ * @param diffReacGrid
+ * @param biomassGrid
+ */
+ public void applyReaction(SolverGrid[] concGrid, SolverGrid[] reacGrid,
+ SolverGrid[] diffReacGrid, SolverGrid biomassGrid)
+ {
+ nSolute = concGrid.length;
+ double[] s = Vector.zerosDbl(nSolute);
+ int _nI, _nJ, _nK;
+ _nI = biomassGrid.getGridSizeI();
+ _nJ = biomassGrid.getGridSizeJ();
+ _nK = biomassGrid.getGridSizeK();
+ //globalReactionRate = 0;
+ for (int i = 1; i<_nI+1; i++)
+ for (int j = 1; j<_nJ+1; j++)
+ for (int k = 1; k<_nK+1; k++)
+ {
+ // If there is no biomass, go to the next grid element
+// if (biomassGrid.grid[i][j][k].equals(0.0) )
+// continue;
+ // Read local solute concentration
+ for (int iGrid : this._soluteIndex)
+ s[iGrid] = concGrid[iGrid].grid[i][j][k];
+ // First compute local uptake-rates in g.h-1
+// computeUptakeRate(s, biomassGrid.grid[i][j][k], 0.0);
+
+ // Now add them on the received grids
+ for (int iGrid : this._soluteIndex)
+ {
+// reacGrid[iGrid].grid[i][j][k] += _uptakeRate[iGrid];
+ // appears to always be 0.0 for typical monod or first order reactions
+// diffReacGrid[iGrid].grid[i][j][k] += _diffUptakeRate[iGrid];
+ if (Double.isNaN(reacGrid[iGrid].grid[i][j][k]))
+ Log.out("Warning: NaN generated in Reaction");
+ }
+ }
+ }
+
+ /**
+ * apply reactions to grid at specified resOrder
+ */
+ public void applyReaction(int resorder)
+ {
+ double[] temp = new double[(allSolute[0]._is3D ? 3 : 2)];
+ Vector.addEquals(temp, this._solute[0]._conc[resorder]._reso );
+ ((PDEWrapper) this._manager).applyReactions(this._solute, resorder, allReac, temp,
+ Math.pow( this._solute[0]._conc[resorder]._reso, (allSolute[0]._is3D ? 3.0 : 2.0) ));
+
+ /* synchronise cyclic reaction nodes */
+ for( SolverGrid s : allReac )
+ {
+ s.syncBoundary(myDomain);
+ }
+ }
+
+}
diff --git a/src/solver/mgFas/MultigridSolute.java b/src/solver/mgFas/MultigridSolute.java
new file mode 100644
index 000000000..f0fc2766c
--- /dev/null
+++ b/src/solver/mgFas/MultigridSolute.java
@@ -0,0 +1,852 @@
+/**
+ * \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 dataIO.Log;
+import idynomics.Global;
+import processManager.library.PDEWrapper;
+import utility.ExtraMath;
+import debugTools.QuickCSV;
+import linearAlgebra.Array;
+
+import java.util.LinkedList;
+import java.util.List;
+
+
+/**
+ * \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.
+ *
+ * Grids stored from finest [0] to coarsest [length]
+ */
+ public SoluteGrid[] _conc;
+
+ /**
+ *
+ */
+ public SoluteGrid[] _reac;
+
+ /**
+ *
+ */
+ public SoluteGrid[] _diffReac;
+
+ /**
+ *
+ */
+ protected SoluteGrid[] _rhs, _itemp;
+
+ /**
+ *
+ */
+ protected SoluteGrid[] _itau;
+
+ /**
+ * where _tempres[order].grid[i][j][k] = ( lop - _rhs ) / dlop
+ */
+ private SoluteGrid[] _tempRes;
+
+ /**
+ *
+ */
+ public double truncationError;
+
+ /**
+ * storing previous residual for analysis.
+ */
+ private double _res[];
+
+ /**
+ * As more smoothing may be required stage is increased
+ */
+ private int _stage = 0;
+
+ private int _tempOrder = 0;
+
+ private List _tempNums = new LinkedList();
+
+ /**
+ * \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;
+
+ private PDEWrapper manager;
+
+ /**
+ * \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, PDEWrapper wrap)
+ {
+ realGrid = aSolute;
+ soluteName = realGrid.gridName;
+
+ _nI = realGrid.getGridSizeI();
+ _nJ = realGrid.getGridSizeJ();
+ _nK = realGrid.getGridSizeK();
+
+ setReferenceSide();
+
+ this.manager = wrap;
+
+ 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];
+ _tempRes = new SoluteGrid[maxOrder];
+
+ _res = new double[maxOrder];
+
+ for (int iGrid = 0; iGrid();
+ }
+
+ /* We obtain data on mgFas concentrations and
+ residuals to decide when to stop the cycle */
+ double[][][] ratio = Array.copy( this._conc[order].grid );
+ Array.restrictMinimum( ratio, NEGLIGIBLE / RELATIVE );
+ Array.elemRatioTo( ratio, _tempRes[order].grid, ratio);
+ double maxRatio = MultigridUtils.largestRealNonZero( ratio , NEGLIGIBLE);
+ double locResidual = MultigridUtils.largestRealNonZero( _tempRes[order].grid ,
+ NEGLIGIBLE * NEGLIGIBLE );
+ double smallestConc = MultigridUtils.smallestNonZero( this._conc[order].grid ,
+ NEGLIGIBLE * NEGLIGIBLE ); // only for reporting
+
+ if ( Log.shouldWrite( Log.Tier.EXPRESSIVE ) )
+ System.out.println( this.soluteName + " order: " + order +
+ ", ratio: " + maxRatio + ", smallest concentration: " +
+ smallestConc + ", max local residual: " + locResidual );
+
+ if ( Log.shouldWrite(Log.Tier.DEBUG) ) {
+ Log.out(Log.Tier.DEBUG,
+ this.getClass().getSimpleName() + " vCycle stagnated:\n "
+ + "\torder: " + order + ", ratio: " + maxRatio
+ + ", \n\tsmallest concentration: " + smallestConc
+ + ", \n\tmax local residual: " + locResidual);
+ }
+
+ /* Stopping because of converged outcome */
+
+ /* The local residuals are small in relation to the local concentration. */
+ if( ( maxRatio <= RELATIVE ) ) {
+ return true;
+ }
+
+ /* Debugging stagnating solver scenarios */
+
+ /* Diminishing change in residual, the solver seems to have stopped converging. */
+ if ( Log.shouldWrite(Log.Tier.DEBUG) ||
+ almostEqual( _res[order], locResidual,locResidual * 1e-6 ) ) {
+ Log.out( Log.Tier.CRITICAL, this.soluteName + " stagnant Vcycle in "
+ + this.getClass().getSimpleName() + " residual res: " + locResidual );
+ }
+ this._res[order] = locResidual;
+
+ /* The solver loops in the same patern, the solver seems to have stopped converging. */
+ if( Log.shouldWrite( Log.Tier.DEBUG ) ) {
+ for (Double d : _tempNums)
+ if ( almostEqual( d, maxRatio, maxRatio * 1e-6 ) ) {
+ Log.out(Log.Tier.CRITICAL, this.soluteName + " repeated number patern in "
+ + this.getClass().getSimpleName() + ": " + maxRatio);
+ return true;
+ }
+ _tempNums.add(maxRatio);
+ }
+
+// computeResidual(_itemp, order); //assigns lop to _itemp.
+// MultigridUtils.subtractTo(_itemp[order].grid, _rhs[order].grid);
+// Double res = MultigridUtils.computeNorm(_itemp[order].grid);
+// if( Log.shouldWrite(Log.Tier.DEBUG))
+// Log.out( Log.Tier.DEBUG, "mgFasTruncation: " + truncationError);
+// if( res <= truncationError )
+// {
+// System.out.println("mgFas stop condi: truncation error passed residual.");
+// return true;
+// }
+ return false;
+ }
+
+ public static boolean almostEqual(double a, double b, double eps){
+ return Math.abs(a-b)= 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;
+
+ double absRes = Math.abs(res);
+ totalRes += absRes;
+ difference[_i - 1][_j - 1][_k - 1] = absRes;
+ // 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]);
+
+ _tempRes[order].grid[_i][_j][_k] = res;
+
+ 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]);
+ }
+ }
+ }
+ }
+ _conc[order].refreshBoundary();
+ // refresh the padding elements to enforce
+ // boundary conditions for all solutes
+// this.setWellmixed(order);
+ }
+
+ if (!_conc[order]._recordKeeper.isEmpty())
+ for (RecordKeeper r : _conc[order]._recordKeeper)
+ r.step(u, order, this.soluteName);
+
+ return difference;
+ }
+
+ /**
+ *
+ */
+ 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();
+
+ // h = gridsize
+ 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();
+ }
+
+ /**
+ *
+ * @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()
+ {
+ this._stage = 0;
+
+ for (int order = 0; order < maxOrder; order++)
+ {
+ // TODO Test whether changes lead to issues
+ // NOTE: the solution of the previous timestep should be a better starting point than
+ // the bulk concentrations!
+ // NOTE: removing this breaks the solver
+ setWellmixed(order);
+ _itau[order].resetToZero();
+ _itemp[order].resetToZero();
+ _reac[order].resetToZero();
+ _diffReac[order].resetToZero();
+ _rhs[order].resetToZero();
+ _res[order] = Double.MAX_VALUE;
+ }
+ }
+
+ /**
+ *
+ */
+ public int getStage()
+ {
+ return this._stage;
+ }
+
+ /**
+ *
+ * @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;
+ }
+ }
+ }
+
+ public void setWellmixed(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;
+ }
+ }
+ }
+
+ /**
+ *
+ * @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();
+
+ /*
+ * Switch from node system to voxel system (subtract 1)
+ */
+ _referenceSystemSide -= 1;
+ _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 applyComputation()
+ {
+ Array.copyTo(realGrid.grid, _conc[maxOrder-1].grid);
+ }
+
+ /**
+ *
+ */
+ public void readSoluteGrid()
+ {
+ Array.copyTo(_conc[maxOrder-1].grid, realGrid.grid);
+ }
+
+ /**
+ * Update bulk concentration.
+ */
+ public void readBulk()
+ {
+ this.sBulk = manager.fetchBulk(this.soluteName);
+ for( SoluteGrid s : this._conc) {
+ s.updateBulk( sBulk );
+ }
+ }
+}
\ 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..7c01accec
--- /dev/null
+++ b/src/solver/mgFas/MultigridUtils.java
@@ -0,0 +1,686 @@
+/**
+ * \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 grid.ArrayType;
+import linearAlgebra.Array;
+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; i absolute)
+ min = (a[i][j][k] < min ? a[i][j][k] : min);
+ }
+ }
+ if( min < absolute )
+ return absolute;
+ return min;
+ }
+
+ public static double largestRealNonZero(double a[][][], double absolute) {
+ double max = a[0][0][0];
+ double t = 0.0;
+ for (int i = 0; i absolute && Double.isFinite(a[i][j][k]) )
+ {
+ max = (a[i][j][k] > max ? a[i][j][k] : max);
+ }
+ }
+ }
+ if( max < absolute )
+ return absolute;
+ return max;
+ }
+
+ /**
+ * Find maximum value in a 3D matrix
+ *
+ * @param a
+ * @return the maximum value in the matrix
+ */
+ public static float max(float a[][][]) {
+ float max = a[0][0][0];
+ 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 ?
+ // 3D
+ temp[l][m][n] + temp[l+1][m][n] +
+ temp[l][m+1][n] + temp[l][m][n+1] +
+ temp[l+1][m+1][n] + temp[l+1][m][n+1] +
+ temp[l][m+1][n+1] + temp[l+1][m+1][n+1] :
+ // 2D
+ temp[l][m][n] + temp[l+1][m][n] +
+ temp[l][m+1][n] + temp[l+1][m+1][n] );
+ }
+ return out;
+ }
+
+ /**
+ * Return values in a matrix (excluding boundaries) as a formatted string
+ *
+ * @param matrix to output as string
+ * @return string output
+ */
+ public static String coreMatrixToString(float[][][] 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]);
+ // 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 _series = new LinkedList();
+
+ public RecordType readRecordType (String recordType)
+ {
+ if (recordType.contentEquals("concentration"))
+ return RecordType.CONCENTRATION;
+ else if (recordType.contentEquals("differenceNorm"))
+ return RecordType.DIFFERENCENORM;
+ else if (recordType.contentEquals("differenceMax"))
+ return RecordType.DIFFERENCEMAX;
+ else if (recordType.contentEquals("difference"))
+ return RecordType.DIFFERENCE;
+ else
+ Idynomics.simulator.interupt("No record type set. "
+ + "Returning concentration.");
+ return RecordType.CONCENTRATION;
+ }
+
+ @Override
+ public void instantiate(Element xmlElement, Settable parent)
+ {
+ if (xmlElement != null)
+ this.loadAspects(xmlElement);
+ this._name = (String) xmlElement.getAttribute(XmlRef.nameAttribute);
+ this._soluteName = (String) this.getValue(AspectRef.solute);
+ this._order = (Integer) this.getValue(AspectRef.order);
+ this._recordType = readRecordType((String) this.getValue(AspectRef.recordType));
+ this._interval = (Integer) this.getValue(AspectRef.interval);
+ this._absoluteValue = (Boolean) this.getOr(AspectRef.absoluteValue, false);
+ this._counter = 0;
+ }
+
+ public void step(double[][][] grid, Integer order, String soluteName)
+ {
+ double[][][] trimmedGrid = MultigridUtils.removePadding(grid);
+ if (this._order == order && this._soluteName.contentEquals(soluteName))
+ {
+ if (this._savedGrid == null)
+ this._savedGrid = new double[trimmedGrid.length]
+ [trimmedGrid[0].length][trimmedGrid[0][0].length];
+
+ this._counter++;
+
+ if (this._counter == this._interval)
+ {
+ if (this._recordType == RecordType.CONCENTRATION)
+ {
+ QuickCSV.write( "solute_" + this._soluteName + "_concentration_order_" +
+ this._order, Array.slice( trimmedGrid, 2, 0 ));
+ }
+
+ else if (this._recordType == RecordType.DIFFERENCE)
+ {
+ double[][][] difference = new double[trimmedGrid.length]
+ [trimmedGrid[0].length][trimmedGrid[0][0].length];
+ for (int i = 0; i < trimmedGrid.length; i++)
+ {
+ for (int j = 0; j < trimmedGrid[0].length; j++)
+ {
+ for (int k = 0; k < trimmedGrid[0][0].length; k++)
+ {
+ if (this._absoluteValue)
+ {
+ difference[i][j][k] =
+ Math.abs(trimmedGrid[i][j][k] - this._savedGrid[i][j][k]);
+ }
+ else
+ {
+ difference[i][j][k] =
+ trimmedGrid[i][j][k] - this._savedGrid[i][j][k];
+ }
+ }
+ }
+ }
+ QuickCSV.write( "solute_" + this._soluteName + "_difference_order_" +
+ this._order, Array.slice( difference, 2, 0 ));
+ }
+
+ else if (this._recordType == RecordType.DIFFERENCENORM)
+ {
+ double[][][] difference = new double[trimmedGrid.length]
+ [trimmedGrid[0].length][trimmedGrid[0][0].length];
+ for (int i = 0; i < trimmedGrid.length; i++)
+ {
+ for (int j = 0; j < trimmedGrid[0].length; j++)
+ {
+ for (int k = 0; k < trimmedGrid[0][0].length; k++)
+ {
+ if (this._absoluteValue)
+ {
+ difference[i][j][k] =
+ Math.abs(trimmedGrid[i][j][k] - this._savedGrid[i][j][k]);
+ }
+ else
+ {
+ difference[i][j][k] =
+ trimmedGrid[i][j][k] - this._savedGrid[i][j][k];
+ }
+ }
+ }
+ }
+ double norm = MultigridUtils.computeNormUnpaddedMatrix(difference);
+ this._series.add(norm);
+ this._savedGrid = Vector.copy(trimmedGrid);
+ }
+
+ else if (this._recordType == RecordType.DIFFERENCEMAX)
+ {
+ float[][][] difference = new float[trimmedGrid.length]
+ [trimmedGrid[0].length][trimmedGrid[0][0].length];
+ for (int i = 0; i < trimmedGrid.length; i++)
+ {
+ for (int j = 0; j < trimmedGrid[0].length; j++)
+ {
+ for (int k = 0; k < trimmedGrid[0][0].length; k++)
+ {
+ if (this._absoluteValue)
+ {
+ difference[i][j][k] =
+ (float) Math.abs(trimmedGrid[i][j][k] - this._savedGrid[i][j][k]);
+ }
+ else
+ {
+ difference[i][j][k] =
+ (float) (trimmedGrid[i][j][k] - this._savedGrid[i][j][k]);
+ }
+ }
+ }
+ }
+ float max = MultigridUtils.max(difference);
+ this._series.add((double) max);
+ this._savedGrid = Vector.copy(trimmedGrid);
+ }
+
+ this._counter = 0;
+ }
+ }
+ }
+
+ public void flush()
+ {
+ if (this._recordType == RecordType.DIFFERENCENORM)
+ {
+ double[][] series = new double[this._series.size()][1];
+ for (int i = 0; i < this._series.size(); i++)
+ {
+ series[i][0] = this._series.get(i);
+ }
+ QuickCSV.write( "solute_" + this._soluteName + "_differenceNorm_order_" +
+ this._order, series);
+ }
+
+ else if (this._recordType == RecordType.DIFFERENCEMAX)
+ {
+ double[][] series = new double[this._series.size()][1];
+ for (int i = 0; i < this._series.size(); i++)
+ {
+ series[i][0] = this._series.get(i);
+ }
+ QuickCSV.write( "solute_" + this._soluteName + "_differenceMax_order_" +
+ this._order, series);
+ }
+ }
+
+ @Override
+ public AspectReg reg()
+ {
+ return _aspectRegistry;
+ }
+
+ public String getSoluteName()
+ {
+ return this._soluteName;
+ }
+
+ public Integer getOrder()
+ {
+ return this._order;
+ }
+
+ public String defaultXmlTag()
+ {
+ return XmlRef.record;
+ }
+
+ @Override
+ 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 ));
+
+ for ( String key : this.reg().getLocalAspectNames() )
+ modelNode.add(reg().getAspectNode(key));
+
+ return modelNode;
+ }
+
+ @Override
+ public void setParent(Settable parent)
+ {
+ this._parentNode = parent;
+ }
+
+ @Override
+ public Settable getParent()
+ {
+ return this._parentNode;
+ }
+
+}
diff --git a/src/solver/mgFas/SoluteGrid.java b/src/solver/mgFas/SoluteGrid.java
new file mode 100644
index 000000000..db4d75ea4
--- /dev/null
+++ b/src/solver/mgFas/SoluteGrid.java
@@ -0,0 +1,413 @@
+/**
+ * \package simulator
+ * \brief Package of classes that create a simulator object and capture
+ * simulation time.
+ *
+ * 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.LinkedList;
+
+import boundary.WellMixedBoundary;
+import grid.ArrayType;
+import grid.SpatialGrid;
+import linearAlgebra.Array;
+import linearAlgebra.Vector;
+import settable.Settable;
+import shape.Dimension;
+import shape.Shape;
+import solver.mgFas.boundaries.CartesianPadding;
+
+/**
+ * \brief Class for containing chemical solutes, that are represented by a
+ * grid.
+ *
+ * The grid is a padded 2D or 3D grid as specified in the protocol file,
+ * unless the simulation is being run in chemostat conditions. Solute
+ * diffusivity is expressed in the local time unit.
+ *
+ * @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)
+ */
+public class SoluteGrid extends SolverGrid
+{
+ /**
+ * Serial version used for the serialisation of the class
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * All solute names are stored in a simulation dictionary. This holds the
+ * position of this solute in this list.
+ */
+ public int soluteIndex;
+
+ /**
+ * Diffusivity of this solute in water, if specified in the protocol file.
+ */
+ public double diffusivity;
+
+ /**
+ * Computation domain this solute is associated with. Provides description
+ * of diffusion, carrier, and bulk domains for this solute.
+ */
+ private Domain _domain;
+
+ protected LinkedList _recordKeeper = new LinkedList();
+
+
+
+ public double bulk = 0.0;
+ /*************************************************************************
+ * CLASS METHODS
+ ************************************************************************/
+
+ /**
+ * \brief Creates a solute grid for a solute specified in the simulation
+ * protocol file.
+ *
+ * Each of the solutes specified in the XML protocol file exists in
+ * iDynoMiCS within its own solute grid. This constructor is used by
+ * 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.
+ */
+ public SoluteGrid(Domain domain, String name, SpatialGrid grid, Settable parent)
+ {
+ /*
+ * 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();
+ /*
+ * Now initialise the grid - setting the grid to the required size
+ */
+ initGrids();
+ /*
+ * Set the diffusivity - if specified in the XML file
+ */
+
+// ///////////////////////////
+// // TODO set diffusivity
+// grid.getArray(ArrayType.DIFFUSIVITY);
+
+ // Note seems to be taken from chemostat???
+ diffusivity = grid.getDiffusivity();
+ /*
+ * Set the initial concentration.
+ */
+
+// ///////////////////////////
+// // TODO set concentration
+//
+ double[][][] in = grid.getArray(ArrayType.CONCN);
+// Array.setAll(this.grid, in[0][0][0]);
+ Array.setAll(new double[in.length-1][in[0].length-1][in[0][0].length-1], in[0][0][0]);
+ }
+
+ 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
+ */
+
+ /*
+ * Now initialise the grid - setting the grid to the required size
+ */
+ initGrids();
+ }
+
+ /**
+ * \brief Constructor used to establish a solute grid when creating
+ * multigrids.
+ *
+ * Simply calls the SpatialGrid constructor.
+ *
+ * @param nI Number of grid elements in X direction of grid.
+ * @param nJ Number of grid elements in Y direction of grid.
+ * @param nK Number of grid elements in Z direction of grid.
+ * @param res The width of each grid element (in micrometres).
+ */
+ public SoluteGrid(Domain domain, int nI, int nJ, int nK, double res)
+ {
+ super(nI, nJ, nK, res);
+ this._domain = domain;
+ }
+
+ /**
+ * \brief Creates a solute grid of a specified size and resolution, and
+ * with a given name. Example - Used to define computation domain.
+ *
+ * Creates a solute grid of a specified size and resolution, as calculated
+ * by the Domain class, and with the name specified in the protocol file.
+ *
+ * @param nI Number of grid elements in X direction of grid.
+ * @param nJ Number of grid elements in Y direction of grid.
+ * @param nK Number of grid elements in Z direction of grid.
+ * @param res The width of each grid element (in micrometres).
+ * @param aName The type of grid being created (e.g. domainGrid).
+ * @param aDomain The computation domain to which this grid is part of.
+ */
+ public SoluteGrid(int nI, int nJ, int nK, double res, String aName,
+ Domain aDomain)
+ {
+ super(nI, nJ, nK, res);
+ gridName = aName;
+ _domain = aDomain;
+ }
+
+ /**
+ * \brief Class for creating a new solute grid using a previous solute
+ * grid.
+ *
+ * @param nI Number of grid elements in X direction of grid.
+ * @param nJ Number of grid elements in Y direction of grid.
+ * @param nK Number of grid elements in Z direction of grid.
+ * @param res The width of each grid element (in micrometres).
+ * @param aSolG The solute grid to use to create this grid.
+ */
+ public SoluteGrid(int nI, int nJ, int nK, double res, SoluteGrid aSolG)
+ {
+ super(nI, nJ, nK, res);
+ useExternalSoluteGrid(aSolG);
+ }
+
+ public SoluteGrid(int nI, int nJ, int nK, double res, SoluteGrid aSolG, double initial)
+ {
+ super(nI, nJ, nK, res);
+ useExternalSoluteGrid(aSolG);
+
+ this.setAllValueAt(initial);
+
+ }
+
+ /**
+ * \brief Initialise a solute grid based on the properties of another
+ * provided grid.
+ *
+ * @param aSolG Solute grid on which to base a new solute grid.
+ */
+ public SoluteGrid(SoluteGrid aSolG)
+ {
+ gridName = aSolG.gridName;
+ diffusivity = aSolG.diffusivity;
+ _domain = aSolG._domain;
+ /*
+ *
+ */
+ _reso = aSolG.getResolution();
+ _nI = aSolG.getGridSizeI();
+ _nJ = aSolG.getGridSizeJ();
+ _nK = aSolG.getGridSizeK();
+ /*
+ *
+ */
+ initGrids();
+ }
+
+ public SoluteGrid(SoluteGrid aSolG, double initial)
+ {
+ gridName = aSolG.gridName;
+ diffusivity = aSolG.diffusivity;
+ _domain = aSolG._domain;
+ /*
+ *
+ */
+ _reso = aSolG.getResolution();
+ _nI = aSolG.getGridSizeI();
+ _nJ = aSolG.getGridSizeJ();
+ _nK = aSolG.getGridSizeK();
+ /*
+ *
+ */
+ initGrids();
+ }
+
+ /**
+ * \brief Initialise a new solute grid, cloning the properties of a
+ * provided solute grid.
+ *
+ * @param aSolG Solute grid for which the properties are being copied for
+ * this new grid.
+ */
+ public void useExternalSoluteGrid(SoluteGrid aSolG)
+ {
+ gridName = aSolG.gridName;
+ soluteIndex = aSolG.soluteIndex;
+ diffusivity = aSolG.diffusivity;
+ _domain = aSolG._domain;
+ }
+
+ /**
+ * \brief Use the size and the resolution used to define the computation
+ * domain to define the solute grid.
+ *
+ * Use the size and the resolution used to define the computation domain
+ * to define the solute grid. This is in cases where the protocol file
+ * does not specifically specify a resolution to use for this solute.
+ */
+ public void useDomaingrid()
+ {
+ _reso = _domain.getGrid().getResolution();
+ _nI = _domain.getGrid().getGridSizeI();
+ _nJ = _domain.getGrid().getGridSizeJ();
+ _nK = _domain.getGrid().getGridSizeK();
+ }
+
+ public double getRes()
+ {
+ /* TODO now taking the smallest, but actually we should check wether they match together. */
+ return
+ Math.min( Math.min(_domain.getShape().getResolutionCalculator(null, 0).getResolution(),
+ _domain.getShape().getResolutionCalculator(null, 1).getResolution() ),
+ _domain.getShape().getResolutionCalculator(null, 2).getResolution() );
+ }
+
+ /*************************************************************************
+ * MAIN METHODS
+ ************************************************************************/
+
+ /**
+ * \brief Examines all objects at the boundary of the grid, and adjusts
+ * them as specified by the boundary condition rules.
+ */
+ public void refreshBoundary()
+ {
+ /*
+ * Three possibilities: periodic, constant concentration, zero flux
+ */
+ CartesianPadding pad = new CartesianPadding(_nI, _nJ, _nK );
+
+ /* TODO accessing dimensions is overly complex, simplify */
+ for( Dimension.DimName d : this._domain.getShape().getDimensionNames() )
+ {
+ Dimension dim = this._domain.getShape().getDimension( d );
+ if ( dim.isCyclic() )
+ {
+ pad.cyclic(this, d.dimNum(), true);
+ pad.cyclic(this, d.dimNum(), false);
+ }
+ else {
+ if ( dim.isBoundaryDefined(0) && dim.getBoundary(0) instanceof WellMixedBoundary) {
+ pad.constantConcentration(this, d.dimNum(), false, bulk);
+
+ } else {
+ pad.zeroFlux(this, d.dimNum(), false);
+ }
+
+ if (dim.isBoundaryDefined(1) && dim.getBoundary(1) instanceof WellMixedBoundary) {
+ pad.constantConcentration(this, d.dimNum(), true, bulk);
+ } else {
+ pad.zeroFlux(this, d.dimNum(), true);
+ }
+ }
+ }
+//
+// /* solid bound */
+// pad.zeroFlux( this, 1, false);
+//
+// /* bulk boundary */
+// pad.constantConcentration( this, 1, true, bulk);
+//
+// /* cyclic bound 1 */
+// pad.cyclic( this, 0, false);
+//
+// /* cyclic bound 2 */
+// pad.cyclic( this, 0, true);
+//
+// /* virtual z dimension (Thanks Tim!) */
+// pad.zeroFlux( this, 2, false);
+// pad.zeroFlux( this, 2, true);
+
+ }
+
+ /**
+ * \brief Returns the name of this solute grid.
+ *
+ * Name was specified in the protocol file.
+ *
+ * @return String value representing the name of this grid.
+ */
+ public String getName()
+ {
+ return gridName;
+ }
+
+ /**
+ * \brief Returns the diffusivity of the solute in this grid.
+ *
+ * Diffusivity was specified in the protocol file.
+ *
+ * @return Double value representing the diffusivity in water of this
+ * solute.
+ */
+ public double getDiffusivity()
+ {
+ return diffusivity;
+ }
+
+ /**
+ * \brief Returns the computation domain that this solute is associated
+ * with.
+ *
+ * @return Computation domain associated with the solute in this grid.
+ */
+ public Domain getDomain()
+ {
+ return _domain;
+ }
+
+ public void updateBulk(double bulk)
+ {
+ this.bulk = bulk;
+ }
+
+ public void setRecordKeeper(RecordKeeper r)
+ {
+ this._recordKeeper.add(r);
+ }
+}
diff --git a/src/solver/mgFas/SolverGrid.java b/src/solver/mgFas/SolverGrid.java
new file mode 100644
index 000000000..495a32fb7
--- /dev/null
+++ b/src/solver/mgFas/SolverGrid.java
@@ -0,0 +1,990 @@
+/**
+ * \package simulator
+ * \brief Package of classes that create a simulator object and capture
+ * simulation time.
+ *
+ * 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.Serializable;
+
+import shape.Dimension;
+import solver.mgFas.boundaries.CartesianPadding;
+import solver.mgFas.utils.ContinuousVector;
+import solver.mgFas.utils.DiscreteVector;
+import utility.ExtraMath;
+import linearAlgebra.Array;
+import linearAlgebra.Vector;
+
+/**
+ * \brief Class defining a spatial grid, i.e. a matrix of double.
+ *
+ * The grid is padded, 3D grid.
+ *
+ * @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 Sónia Martins (SCM808@bham.ac.uk), Centre for Systems Biology,
+ * University of Birmingham (UK)
+ */
+public class SolverGrid implements Serializable
+{
+ /**
+ * Serial version used for the serialisation of the class
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Name assigned to this spatial grid. Taken from an XML tag in the
+ * protocol file.
+ */
+ public String gridName;
+
+ /**
+ * The unit for all values stored on this grid.
+ */
+ public String gridUnit = "g.L-1";
+
+ /**
+ * The solute grid - a three dimensional array of Double values.
+ */
+ public double[][][] grid;
+
+ /**
+ * Number of grid voxels in I direction
+ */
+ protected int _nI;
+
+ /**
+ * Number of grid voxels in J direction
+ */
+ protected int _nJ;
+
+ /**
+ * Number of grid voxels in K direction
+ */
+ protected int _nK;
+
+ /**
+ * Grid resolution = side length of a voxel
+ */
+ protected double _reso;
+
+ /**
+ * Boolean noting whether this grid is 3D (true) or 2D (false)
+ */
+ protected Boolean _is3D;
+
+
+
+ /**
+ * \brief Blank constructor.
+ */
+ public SolverGrid()
+ {
+
+ }
+
+ /**
+ * \brief Default constructor for an empty spatial grid
+ *
+ * Sets the grid resolution and dimensions as provided in the simulation
+ * protocol file.
+ *
+ * @param nI The number of grid locations in the I direction.
+ * @param nJ The number of grid locations in the J direction.
+ * @param nK The number of grid locations in the K direction.
+ * @param resolution The grid resolution.
+ */
+ public SolverGrid(int nI, int nJ, int nK, double resolution)
+ {
+ _nI = nI;
+ _nJ = nJ;
+ _nK = nK;
+ _reso = resolution;
+ // Create a padded grid.
+ initGrids();
+ }
+
+ /**
+ * \brief Default constructor for an empty 2D spatial grid
+ *
+ * Sets the grid resolution and dimensions as provided in the simulation
+ * protocol file.
+ *
+ * @param nI The number of grid locations in the I direction
+ * @param nJ The number of grid locations in the J direction
+ * @param resolution the grid resolution
+ */
+ public SolverGrid(int nI, int nJ, double resolution)
+ {
+
+ _nI = nI;
+ _nJ = nJ;
+ _nK = 1;
+ _reso = resolution;
+ // Create a padded grid.
+ initGrids();
+ }
+
+ /**
+ * \brief Creates the solute grid at the required size
+ *
+ * If this is a chemostat, this will simple be a 1x1x1; if not there are
+ * further checks to determine whether we are simulating 3D or not.
+ */
+ protected void initGrids()
+ {
+ _is3D = ! ( _nK == 1 );
+ grid = Array.array(_nI+2, _nJ+2, _nK+2, 0.0);
+ }
+
+ /**
+ * \brief Determine if a given discrete position is valid or outside the
+ * grid (Padding excluded).
+ *
+ * TODO Rob 13Mar2015: Surely this should be > 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);
+ }
+
+ public Boolean isPadding(int i, int j, int k)
+ {
+ return (i > 0) && (i < _nI) &&
+ (j > 0) && (j < _nJ) &&
+ (k > 0) && (k < _nK);
+ }
+
+// public Boolean shouldSolve(int i, int j, int k, double threshold)
+// {
+// if ( isPadding(i, j, k) )
+// return false;
+// if( grid[i][j][k] > threshold)
+// return true;
+// if( grid[i-1][j][k] > threshold &! isPadding(i-1, j, k) )
+// return true;
+// if( grid[i+1][j][k] > threshold &! isPadding(i+1, j, k) )
+// return true;
+// if( grid[i][j-1][k] > threshold &! isPadding(i, j-1, k) )
+// return true;
+// if( grid[i][j+1][k] > threshold &! isPadding(i, j+1, k) )
+// return true;
+// if( grid[i][j][k-1] > threshold &! isPadding(i, j, k-1) )
+// return true;
+// if( grid[i][j][k+1] > threshold &! isPadding(i, j, k+1) )
+// return true;
+// return false;
+// }
+
+ /**
+ * \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);
+ int j = (int) Math.floor(cC[1]/_reso);
+ int k = (int) Math.floor(cC[2]/_reso);
+ 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 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 ContinuousVector getContinuousCoordinates(DiscreteVector coord)
+ {
+ ContinuousVector out = new ContinuousVector();
+ out.setToVoxelCenter(coord, _reso);
+ return out;
+ }
+
+
+ /**
+ * \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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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),
+ (int) Math.ceil(cC[0]/_reso),
+ (int) Math.ceil(cC[0]/_reso)};
+ 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),
+ (int) Math.ceil(cC[0]/_reso),
+ (int) Math.ceil(cC[0]/_reso)};
+ 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 dc 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];
+ }
+
+ public Double getValueAt(int[] dc, boolean padded)
+ {
+ if( padded )
+ return getValueAt(dc);
+ else
+ return grid[dc[0]][dc[1]][dc[2]];
+ }
+
+ /**
+ * \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;
+ }
+
+ public void setValueAt(Double value, int[] dC, boolean padded)
+ {
+ if( padded )
+ setValueAt(value, dC );
+ else
+ grid[dC[0]][dC[1]][dC[2]] = 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;
+ }
+
+ public void addValueAt(Double value, int[] dC, boolean padded)
+ {
+ if( padded )
+ addValueAt(value, dC);
+ else
+ grid[dC[0]][dC[1]][dC[2]] += 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;
+ case 2:
+ return _nJ*_reso;
+ case 3:
+ return _nK*_reso;
+ 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 Math.pow(_reso,3.0);
+ }
+
+ /**
+ * \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");
+// }
+
+ public void syncBoundary(Domain domain) {
+ /*
+ * Three possibilities: periodic, constant concentration, zero flux
+ */
+
+ CartesianPadding pad = new CartesianPadding(_nI, _nJ, _nK);
+
+ /* TODO accessing dimensions is overly complex, simplify */
+ for (Dimension.DimName d : domain.getShape().getDimensionNames()) {
+ Dimension dim = domain.getShape().getDimension(d);
+ if (dim.isCyclic()) {
+ pad.synchroniseCyclic(this, d.dimNum());
+ }
+ }
+ }
+}
diff --git a/src/solver/mgFas/boundaries/AllBC.java b/src/solver/mgFas/boundaries/AllBC.java
new file mode 100644
index 000000000..329e19aeb
--- /dev/null
+++ b/src/solver/mgFas/boundaries/AllBC.java
@@ -0,0 +1,304 @@
+/**
+ * \package simulator.geometry.boundaryConditions
+ * \brief Package of boundary conditions that can be used to capture agent
+ * behaviour at the boundary of the computation domain.
+ *
+ * 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.boundaries;
+
+import java.util.LinkedList;
+
+import shape.Shape;
+import solver.mgFas.SoluteGrid;
+import solver.mgFas.SolverGrid;
+import solver.mgFas.utils.ContinuousVector;
+import solver.mgFas.utils.DiscreteVector;
+
+/**
+ * \brief Group all methods expected by the interface but common to most of
+ * the boundary classes.
+ *
+ * @author Laurent Lardon (lardonl@supagro.inra.fr), INRA, France
+ */
+public abstract class AllBC
+{
+ /* _____________________________ FIELDS _______________________________ */
+ /**
+ * The name of the boundary describing its side (xOy,...).
+ */
+ protected String _mySide;
+
+ /**
+ * The shape of the boundary.
+ */
+ protected Shape _myShape;
+
+ /**
+ * Boolean noting whether this boundary is the supporting structure
+ * (substratum).
+ */
+ protected boolean _isSupport = false;
+
+ /**
+ * Boolean noting whether this boundary can contain active solute.
+ */
+ protected boolean activeForSolute = true;
+
+ /* _________________ INTERNAL TEMPRARY VARIABLES ______________________ */
+ /**
+ * Discrete coordinates of a voxel inside the computation domain but along
+ * the boundary.
+ */
+ protected static DiscreteVector dcIn = new DiscreteVector();
+
+ /**
+ * Discrete coordinates of the voxel in front of the one outside the boundary
+ */
+ protected static DiscreteVector dcOut = new DiscreteVector();
+
+ /* ________________________ CONSTRUCTION METHODS ________________________ */
+
+ /**
+ * \brief Generic constructor called to dynamically instantiate a child
+ * class object.
+ *
+ * @param root Set of XML tags relating to one boundary condition
+ * @param aSim The current simulation object used to simulate the
+ * conditions specified in this protocol file.
+ * @param aDomain The computation domain to which this boundary
+ * condition is assigned.
+ */
+// public static AllBC staticBuilder(XMLParser root, Simulator aSim,Domain aDomain)
+// {
+// // Create the object
+// AllBC out = (AllBC) root.instanceCreator("simulator.geometry.boundaryConditions");
+//
+// // Initialise & declare the boundary
+// out.init(aSim, aDomain, root);
+//
+// return out;
+// }
+
+ /**
+ * \brief Initialises the boundary condition.
+ *
+ * This method should be overridden by each boundary condition class file.
+ *
+ * @param aSim The current simulation object used to simulate the
+ * conditions specified in this protocol file.
+ * @param aDomain The computation domain to which this boundary
+ * condition is assigned.
+ * @param root Set of XML tags relating to one boundary condition.
+ */
+// public abstract void init(Simulator aSim, Domain aDomain, XMLParser root);
+
+ /**
+ * \brief Used during the initialisation, load the class describing the
+ * shape of the boundary defined in the parent class.
+ *
+ * @param geometryRoot Usually an XML set of elements that describe the
+ * boundary to be created.
+ * @param aDomain The computational domain which this boundary is
+ * associated with.
+ */
+// public void readGeometry(XMLParser geometryRoot, Domain aDomain)
+// {
+// // Set the name of the boundary.
+// _mySide = geometryRoot.getName();
+// // Set the class to use to define the shape.
+// String className = "simulator.geometry.shape.";
+// className += geometryRoot.getChildParser("shape").getAttribute("class");
+// // Build the instance used to describe the shape.
+// try
+// {
+// _myShape = (IsShape) Class.forName(className).newInstance();
+// _myShape.readShape(new
+// XMLParser(geometryRoot.getChildElement("shape")), aDomain);
+// }
+// catch (Exception e)
+// {
+//
+// }
+// }
+
+ /**
+ * \brief Determines if a point is outside the boundary.
+ *
+ * @param position ContinuousVector to check.
+ * @return Boolean value noting whether this coordinate is outside the
+ * boundary (true) or not (false).
+ */
+ public Boolean isOutside(ContinuousVector position)
+ {
+ return !_myShape.isInside(new double[] { position.x,
+ position.y,
+ position.z } );
+ }
+
+ /**
+ * \brief Determine whether this boundary is the supporting structure
+ * (substratum).
+ *
+ * @return Boolean noting whether this boundary is the supporting
+ * structure (true) or not (false).
+ */
+ public boolean isSupport()
+ {
+ return _isSupport;
+ }
+
+ /**
+ * \brief Return the name of the side of the domain which this boundary is
+ * on.
+ *
+ * TODO this is a duplicate of getSide()!
+ *
+ * @return String containing the name of the side of the domain
+ * (e.g. x0z, xNz, etc).
+ */
+ public String getSideName()
+ {
+ return this._mySide;
+ }
+
+ /**
+ * \brief Solver for the variable concentration boundary condition.
+ *
+ * Initialises the course along the shape of the boundary during multigrid
+ * computation.
+ *
+ * @param aSoluteGrid Grid of solute information which is to be
+ * refreshed by the solver.
+ * @see ComputationDomain.refreshBoundaries()
+ */
+ public abstract void refreshBoundary(SoluteGrid aSoluteGrid);
+
+ /**
+ * \brief Method used if a boundary modifies the local diffusivity
+ * constant. Most of boundaries do not modify it.
+ *
+ * @param relDiff Relative difference grid
+ * @param aSolutegrid Grid of solute information which is to be
+ * refreshed by the solver.
+ *
+ * @see BoundaryGasMembrane
+ */
+ public void refreshDiffBoundary(SoluteGrid relDiff, SoluteGrid aSolutegrid)
+ {
+
+ };
+
+ /* ______________INTERACTION WITH THE PARTICLES _____________________ */
+
+ /**
+ * \brief Method used by another which gets the indexed grid position of a
+ * continuous vector.
+ *
+ * Some boundary conditions (e.g. BoundaryCyclic) need the input corrected
+ * due to the condition, some don't and just return the input. Maybe we'll
+ * change this at some point as to just return the input looks a bit daft
+ * - but we'll leave it here for the moment.
+ *
+ * @param position ContinuousVector that gives the current location of an
+ * agent to check on the grid.
+ */
+ public ContinuousVector lookAt(ContinuousVector position)
+ {
+ return position;
+ }
+
+
+
+ /* ___________________ INTERACTION WITH THE DOMAIN _________________________ */
+
+
+ /**
+ * \brief Determine if this boundary is active for solute.
+ *
+ * @return Boolean noting whether this boundary is active for solute
+ * (true) or not (false).
+ */
+ public boolean isActive()
+ {
+ return activeForSolute;
+ }
+
+ /**
+ * \brief Determines if a discrete vector location is outside the boundary.
+ *
+ * @param dc DiscreteVector to check.
+ * @param aSpatialGrid The grid to check whether a point is outside.
+ * @return Boolean value noting whether this coordinate is outside the
+ * boundary (true) or not (false).
+ */
+ public boolean isOutside(DiscreteVector dc, SolverGrid aSpatialGrid)
+ {
+ ContinuousVector temp = new ContinuousVector();
+ temp.setToVoxelCenter(dc, aSpatialGrid.getResolution());
+ return isOutside(temp);
+ }
+
+ /* ____________________ TOOLBOX ______________________________ */
+
+ /**
+ * \brief Calculate the orthogonal projection of a location on the
+ * boundary.
+ *
+ * @param position A continuous vector stating the point to be used in
+ * the calculation.
+ * @return ContinuousVector stating the point on the boundary after the
+ * orthogonal projection.
+ */
+ public ContinuousVector getOrthoProj(ContinuousVector position)
+ {
+ return getOrthoProj(position);
+ }
+
+ /**
+ * \brief Return the name of the side of the domain which this boundary is
+ * on.
+ *
+ * @return String containing the name of the side of the domain (e.g.
+ * x0z, xNz, etc).
+ */
+ public String getSide()
+ {
+ return _mySide;
+ }
+
+ /**
+ * \brief Returns the distance from a point to the boundary.
+ *
+ * @param position The continuous vector of points to calculate how far
+ * the point is from the boundary.
+ * @return Double value stating the distance from the point to the
+ * boundary.
+ */
+ public Double getDistance(ContinuousVector position)
+ {
+ return getDistanceShape(position);
+ }
+
+ /**
+ * NOTE Comming from isShape, correct behavior?
+ *
+ * \brief Gets the distance from a point on the other side
+ * (ContinuousVector).
+ *
+ * Used in cyclic boundaries.
+ *
+ * @return Double stating distance to that shape.
+ */
+ public Double getDistanceShape(ContinuousVector point)
+ {
+ ContinuousVector diff = getOrthoProj(point);
+ diff.subtract(point);
+ return diff.norm();
+ }
+
+}
diff --git a/src/solver/mgFas/boundaries/CartesianPadding.java b/src/solver/mgFas/boundaries/CartesianPadding.java
new file mode 100644
index 000000000..82ce8a6d0
--- /dev/null
+++ b/src/solver/mgFas/boundaries/CartesianPadding.java
@@ -0,0 +1,203 @@
+package solver.mgFas.boundaries;
+
+import linearAlgebra.Vector;
+import solver.mgFas.SoluteGrid;
+import solver.mgFas.SolverGrid;
+
+/**
+ * FIXME Should we include padding corners fx (-1, -1) ?
+ */
+public class CartesianPadding {
+
+ int nI, nJ, nK;
+ int[] extremes;
+
+ public CartesianPadding(int nI, int nJ, int nK)
+ {
+ this.nI = nI;
+ this.nJ = nJ;
+ this.nK = nK;
+ this.extremes = new int[] { nI, nJ, nK };
+ }
+
+ /**
+ * Solid boundary
+ * @param sol
+ * @param dim
+ * @param extreme
+ */
+ public void zeroFlux(SoluteGrid sol, int dim, boolean extreme)
+ {
+ int[] in = {0, 0, 0};
+ int[] out = {0, 0, 0};
+ if( extreme )
+ {
+ in[dim] = extremes[dim];
+ out[dim] = extremes[dim]+1;
+ }
+ else
+ in[dim] = 1;
+
+ int[] step = new int[] {-1, -1, -1};
+
+ while( step.length > 1 )
+ {
+ sol.setValueAt( sol.getValueAt(
+ Vector.add( in, step ) ),
+ Vector.add( out, step ) );
+
+ step = step(step, dim);
+ }
+
+// int[] iterate = other(dim);
+// int[] inTemp = Vector.copy(in);
+// int[] ouTemp = Vector.copy(out);
+// for( int a = -1; a < extremes[iterate[0]]; a++)
+// {
+// for( int b = -1; (b < extremes[iterate[1]] || extremes[iterate[1]] == 0) ; b++)
+// {
+// sol.setValueAt(sol.getValueAt(inTemp), ouTemp);
+// }
+// }
+
+ }
+
+ /**
+ * Cyclic boundary
+ * @param sol
+ * @param dim
+ * @param extreme
+ */
+ public void cyclic(SoluteGrid sol, int dim, boolean extreme)
+ {
+ int[] in = {0, 0, 0};
+ int[] out = {0, 0, 0};
+ if( extreme )
+ {
+ in[dim] = extremes[dim];
+ }
+ else
+ {
+ in[dim] = 1;
+ out[dim] = extremes[dim]+1;
+ }
+
+ int[] step = new int[] {-1, -1, -1};
+
+ while( step.length > 1 )
+ {
+ sol.setValueAt( sol.getValueAt(
+ Vector.add( in, step ) ),
+ Vector.add( out, step ) );
+
+ step = step(step, dim);
+ }
+ }
+
+ /**
+ * points on either side of the domain on the cyclic boundary represent the same point in
+ .space
+ */
+ public void synchroniseCyclic(SolverGrid sol, int dim)
+ {
+ int[] in = {0, 0, 0};
+ int[] out = {0, 0, 0};
+
+ {
+ in[dim] = 1;
+ out[dim] = extremes[dim];
+ }
+
+ int[] step = new int[] {-1, -1, -1};
+
+ while( step.length > 1 )
+ {
+ double value = sol.getValueAt(
+ Vector.add( in, step ) ) +
+ sol.getValueAt( Vector.add( out, step ) );
+
+ sol.setValueAt(value, Vector.add( in, step ));
+ sol.setValueAt(value, Vector.add( out, step ));
+
+ step = step(step, dim);
+ }
+ }
+
+ /**
+ * Constant concentration and bulk boundary
+ * @param sol
+ * @param dim
+ * @param extreme
+ * @param value
+ */
+ public void constantConcentration(SoluteGrid sol, int dim, boolean extreme, double value)
+ {
+ int[] out = {0, 0, 0};
+ if( extreme )
+ out[dim] = extremes[dim]+1;
+ else
+ out[dim] = 0;
+
+ int[] step = new int[] {-1, -1, -1};
+
+ while( step.length > 1 )
+ {
+ int[] temp = Vector.add( out, step );
+ sol.setValueAt( value, Vector.add( out, step ) );
+ step = step(step, dim);
+ }
+ }
+
+ /**
+ * step trough the padding, start + step = current
+ * @param step
+ * @param dim
+ * @return
+ */
+ public int[] step( int[] step, int dim )
+ {
+ int a = -1;
+ int b = -1;
+ int[] iterate = other(dim);
+
+ if ( step != null )
+ {
+ a = step[iterate[0]];
+ b = step[iterate[1]];
+ }
+
+ if ( a <= extremes[iterate[0]] )
+ {
+ if ( b < extremes[iterate[1]])
+ {
+ step[iterate[1]]++;
+ }
+ else if ( a == extremes[iterate[0]] )
+ {
+ return new int[1];
+ }
+ else
+ {
+ step[iterate[0]]++;
+ step[iterate[1]] = b = -1;
+ }
+ return step;
+ }
+ return new int[1];
+ }
+
+ /**
+ * return the perpendicular dimensions
+ * @param dim
+ * @return
+ */
+ public int[] other(int dim)
+ {
+ if( dim == 0 )
+ return new int[] { 1, 2 };
+ if( dim == 1 )
+ return new int[] { 0, 2 };
+ else
+ return new int[] { 0, 1 };
+ }
+}
diff --git a/src/solver/mgFas/mgFAS.md b/src/solver/mgFas/mgFAS.md
new file mode 100644
index 000000000..f67fe8420
--- /dev/null
+++ b/src/solver/mgFas/mgFAS.md
@@ -0,0 +1,3 @@
+MG (Multigrid) FAS (Brandt’s Full Approximation Storage Algorithm) see also numerical recipes in C pp. 882.
+
+FMG-FAS -> Full MultiGrid (FMG) - Full Approximation Scheme (FAS)
\ No newline at end of file
diff --git a/src/solver/mgFas/utils/ContinuousVector.java b/src/solver/mgFas/utils/ContinuousVector.java
new file mode 100644
index 000000000..3f37ed814
--- /dev/null
+++ b/src/solver/mgFas/utils/ContinuousVector.java
@@ -0,0 +1,436 @@
+/**
+ * \package simulator.geometry
+ * \brief 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.utils;
+
+import utility.ExtraMath;
+
+/**
+ * \brief Implements 3D vector of continuous spatial coordinates.
+ *
+ * Cartesian (x, y, z) coordinates obligatory.
+ * Can be used to store Continuous coordinates or Movement vectors.
+ *
+ * @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 João Xavier (xavierj@mskcc.org), Memorial Sloan-Kettering Cancer
+ * Center (NY, USA).
+ *
+ */
+public class ContinuousVector implements Cloneable
+{
+ /**
+ * X coordinate of the point contained in this vector
+ */
+ public Double x;
+
+ /**
+ * Y coordinate of the point contained in this vector
+ */
+ public Double y;
+
+ /**
+ * Z coordinate of the point contained in this vector
+ */
+ public Double z;
+
+ /**
+ * \brief Constructs a ContinuousVector at origin.
+ */
+ public ContinuousVector()
+ {
+ reset();
+ }
+
+ /**
+ * \brief Constructs a continuous vector with points specified by a
+ * provided continuous vector.
+ *
+ * @param aCC ContinuousVector which to initialise the points from.
+ */
+ public ContinuousVector(ContinuousVector aCC)
+ {
+ set(aCC);
+ }
+
+ /**
+ * \brief Constructs a continuous vector with points specified from an
+ * XMLParser.
+ *
+ * @param coordinatesRoot An XMLParser containing x, y and z coordinates.
+ */
+// public ContinuousVector(XMLParser coordinatesRoot)
+// {
+// x = coordinatesRoot.getAttributeDbl("x");
+// y = coordinatesRoot.getAttributeDbl("y");
+// z = coordinatesRoot.getAttributeDbl("z");
+// }
+
+ /**
+ * \brief Create a continuous vector from three provided points.
+ *
+ * @param x X coordinate.
+ * @param y Y coordinate.
+ * @param z Z coordinate.
+ */
+ public ContinuousVector(Double x, Double y, Double z)
+ {
+ set(x, y, z);
+ }
+
+ /**
+ * \brief Set this vector to the points contained in a supplied continuous
+ * vector.
+ *
+ * @param cc Continuous vector of points to set this vector to.
+ */
+ public void set(ContinuousVector cc)
+ {
+ set(cc.x, cc.y, cc.z);
+ }
+
+ /**
+ * \brief Set this vector to the supplied X,Y,Z points.
+ *
+ * @param x X coordinate.
+ * @param y Y coordinate.
+ * @param z Z coordinate.
+ */
+ public void set(Double x, Double y, Double z)
+ {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ /**
+ *
+ * TODO Rob 13Mar2015: Check padding.
+ * Compare Agentcontainer.getGridLocation(int index)
+ *
+ * @param dC
+ * @param res
+ */
+ public void setToVoxelCenter(DiscreteVector dC, Double res)
+ {
+ set(dC.i + 0.5, dC.j + 0.5, dC.k + 0.5);
+ times(res);
+ }
+
+ /**
+ *
+ * @param dC
+ */
+ public void set(DiscreteVector dC)
+ {
+ set(dC.i + 0.0, dC.j + 0.0, dC.k + 0.0);
+ }
+
+ /**
+ *
+ * @param dC
+ * @param res
+ */
+ public void set(DiscreteVector dC, Double res)
+ {
+ set(dC);
+ times(res);
+ }
+
+ /**
+ * \brief Set all points in the vector to zero.
+ */
+ public void reset()
+ {
+ set(0.0, 0.0, 0.0);
+ }
+
+ /**
+ * \brief Determine whether the numeric points in this vector are valid.
+ *
+ * @return Boolean stating whether this vector is valid (true) or not (false)
+ */
+ public Boolean isValid()
+ {
+ return ! ( x.isInfinite() || x.isNaN() ||
+ y.isInfinite() || y.isNaN() ||
+ z.isInfinite() || z.isNaN() );
+ }
+
+ /**
+ * \brief Changes the sign of the vector.
+ *
+ * Used for movement vectors.
+ */
+ public void turnAround()
+ {
+ times(-1.0);
+ }
+
+ /**
+ * \brief Determine if this vector is in the given location.
+ *
+ * @param x X coordinate.
+ * @param y Y coordinate.
+ * @param z Z coordinate.
+ * @return Boolean stating whether the vector position and coordinate
+ * (x,y,z) is identical.
+ */
+ public Boolean equals(Double x, Double y, Double z)
+ {
+ return (this.x.equals(x) && this.y.equals(y) && this.z.equals(z));
+ }
+
+ /**
+ * \brief Check if this vector is the same as another.
+ *
+ * @param other
+ * @return
+ */
+ public Boolean equals(ContinuousVector other)
+ {
+ if ( other == null )
+ return false;
+ return equals(other.x, other.y, other.z);
+ }
+
+ /**
+ * \brief Determine if all points in the vector are zero.
+ *
+ * @return Boolean stating whether all points in the vector are zero.
+ */
+ public Boolean isZero()
+ {
+ return equals(0.0, 0.0, 0.0);
+ }
+
+ /**
+ * \brief Print coordinates to string.
+ *
+ * @return String containing the points in this vector.
+ */
+ @Override
+ public String toString()
+ {
+ return "("+x
+ +", "+y
+ +", "+z+")";
+ }
+
+ /**
+ * \brief Add vector v to this continuous vector.
+ *
+ * @param v ContinuousVector to add to this vector.
+ */
+ public void add(ContinuousVector v)
+ {
+ add(v.x, v.y, v.z);
+ }
+
+ /**
+ * \brief Add points X,Y,Z to their respective point in this vector.
+ *
+ * @param x X coordinate.
+ * @param y Y coordinate.
+ * @param z Z coordinate.
+ */
+ public void add(Double x, Double y, Double z)
+ {
+ this.x += x;
+ this.y += y;
+ this.z += z;
+ }
+
+ /**
+ * \brief Store in this vector the sum of two other continuous vectors.
+ *
+ * @param a First continuous vector.
+ * @param b Continuous vector to add to first.
+ */
+ public void sendSum(ContinuousVector a, ContinuousVector b)
+ {
+ set(a);
+ add(b);
+ }
+
+ /**
+ * \brief Subtract vector v from this continuous vector.
+ *
+ * @param cV ContinuousVector to subtract from this vector.
+ */
+ public void subtract(ContinuousVector cV)
+ {
+ add(-cV.x, -cV.y, -cV.z);
+ }
+
+ /**
+ * \brief Store in this vector the difference of two other continuous
+ * vectors.
+ *
+ * @param a First continuous vector.
+ * @param b Continuous vector to subtract from the first.
+ */
+ public void sendDiff(ContinuousVector a, ContinuousVector b)
+ {
+ set(a);
+ subtract(b);
+ }
+
+ /**
+ * \brief Calculate scalar product (dot product) of this vector with vector
+ * cc supplied.
+ *
+ * @param cc Continuous vector to multiply (dot product) with this vector.
+ * @return Double value of scalar product of two vectors.
+ */
+ public Double prodScalar(ContinuousVector cc)
+ {
+ return (this.x * cc.x) + (this.y * cc.y) + (this.z * cc.z);
+ }
+
+ /**
+ * \brief Multiply (stretch) this vector by supplied multiplier.
+ *
+ * @param multiplier Amount to stretch this vector by.
+ */
+ public void times(Double multiplier)
+ {
+ this.x *= multiplier;
+ this.y *= multiplier;
+ this.z *= multiplier;
+ }
+
+ /**
+ * \brief Set this vector to a random coordinate (x,y,z).
+ *
+ * Coordinates are chosen from a uniform distribution in (-1, 1).
+ *
+ * @param is3D Boolean noting if a Z coordinate needs to be calculated.
+ */
+// public void alea(Boolean is3D)
+// {
+// this.x = ExtraMath.getUniRand(-1.0, 1.0);
+// this.y = ExtraMath.getUniRand(-1.0, 1.0);
+// this.z = (is3D ? ExtraMath.getUniRand(-1.0, 1.0) : 0.0);
+// }
+
+ /**
+ * \brief Normalize this Vector to unit length.
+ */
+ public void normalizeVector()
+ {
+ normalizeVector(1.0);
+ }
+
+ /**
+ * \brief Normalize this Vector to a given length.
+ *
+ * @param newLength Length used to normalise vector.
+ */
+ public void normalizeVector(Double newLength)
+ {
+ Double norm = this.norm();
+ if ( ! norm.equals(0.0) )
+ this.times(newLength/norm);
+ }
+
+ /**
+ * \brief Calculate and return the absolute distance to a vector expressed in cc.
+ *
+ * Does not take cyclic boundaries into account.
+ *
+ * @param cc ContinuousVector to calculate distance to.
+ */
+ public Double distance(ContinuousVector cc)
+ {
+ return ExtraMath.hypotenuse(this.x - cc.x, this.y - cc.y, this.z - cc.z);
+ }
+
+ /**
+ * \brief Return absolute length.
+ *
+ * @return Double value stating absolute length of this vector.
+ */
+ public Double norm()
+ {
+ return ExtraMath.hypotenuse(x, y, z);
+ }
+
+ /**
+ * \brief Calculate cosine of the angle to a given vector.
+ *
+ * @param v ContinuousVector for which cosine of the angle to this one
+ * should be calculated.
+ * @return Cosine of the angle to vector given.
+ */
+ public Double cosAngle(ContinuousVector v)
+ {
+ /*
+ * Returning 0.0 if the dot product is 0.0 removes the danger of
+ * dividing 0.0/0.0 and also speeds things up slightly if the vectors
+ * are orthogonal.
+ */
+ Double dotProd = prodScalar(v);
+ return ( dotProd == 0.0 ) ? 0.0 : dotProd/(this.norm() * v.norm());
+ }
+
+ /**
+ * \brief Calculate the angle to another vector.
+ *
+ * @param v Another vector
+ * @return Angle between this vector and that given.
+ */
+ public Double angle(ContinuousVector v)
+ {
+ return Math.acos(cosAngle(v));
+ }
+
+ /**
+ * \brief Clone this vector, if supported.
+ *
+ * @throws CloneNotSupportedException Thrown if the object cannot be cloned.
+ */
+ @Override
+ public Object clone() throws CloneNotSupportedException
+ {
+ return super.clone();
+ }
+
+ public Boolean isOrthogonal(ContinuousVector other)
+ {
+ return ( prodScalar(other) == 0.0 );
+ }
+
+ public Boolean isParallel(ContinuousVector other)
+ {
+ return ( Math.abs(cosAngle(other)) == 1.0 );
+ }
+
+
+ /**
+ * \brief Returns the cross product of this vector with another.
+ *
+ * Note that the resulting vector is orthogonal to both this vector and
+ * the one given.
+ *
+ * @param other
+ * @return
+ */
+ public ContinuousVector crossProduct(ContinuousVector other)
+ {
+ ContinuousVector out = new ContinuousVector();
+ out.x = this.y*other.z - this.z*other.y;
+ out.y = this.z*other.x - this.x*other.z;
+ out.z = this.x*other.y - this.y*other.x;
+ return out;
+ }
+}
\ No newline at end of file
diff --git a/src/solver/mgFas/utils/DiscreteVector.java b/src/solver/mgFas/utils/DiscreteVector.java
new file mode 100644
index 000000000..dc6bdaf4a
--- /dev/null
+++ b/src/solver/mgFas/utils/DiscreteVector.java
@@ -0,0 +1,238 @@
+/**
+ * \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.utils;
+
+import java.io.Serializable;
+
+
+/**
+ * \brief Implements 3D vector of discrete spatial coordinates.
+ *
+ * @author João Xavier (xavierj@mskcc.org), Memorial Sloan-Kettering Cancer
+ * Center (NY, USA).
+ */
+public class DiscreteVector implements Cloneable, Serializable
+{
+ /**
+ * Serial version used for the serialisation of the class.
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * I Location on a grid.
+ */
+ public int i;
+
+ /**
+ * J Location on a grid.
+ */
+ public int j;
+
+ /**
+ * K Location on a grid.
+ */
+ public int k;
+
+ /**
+ * \brief Creates a discrete vector initialised at the origin.
+ */
+ public DiscreteVector()
+ {
+ reset();
+ }
+
+ /**
+ * \brief Creates a clone of this discrete vector.
+ *
+ * @return Clone of this discrete vector object.
+ */
+ @Override
+ public DiscreteVector clone()
+ {
+ DiscreteVector out = new DiscreteVector(i, j, k);
+ return out;
+ }
+
+ /**
+ * \brief Constructs a continuous vector with points specified by a
+ * provided discrete vector.
+ *
+ * @param dV DiscreteVector from which to initialise the points.
+ */
+ public void set(DiscreteVector dV)
+ {
+ set(dV.i, dV.j, dV.k);
+ }
+
+ /**
+ * \brief Translate a continuous coordinate expressed on a spatial grid
+ * with the resolution res to form a discrete vector.
+ *
+ * @param cV Continuous vector containing points on a grid.
+ * @param res The resolution of this grid, to use to transform these points.
+ */
+ public DiscreteVector(ContinuousVector cV, Double res)
+ {
+ set(cV, res);
+ }
+
+ /**
+ * \brief Translate a continuous coordinate expressed on a spatial grid
+ * with the resolution res to form a discrete vector.
+ *
+ * @param cV Continuous vector containing points on a grid.
+ * @param res The resolution of this grid, to use to transform these points.
+ */
+ public void set(ContinuousVector cV, Double res)
+ {
+ set( (int) Math.ceil(cV.x/res),
+ (int) Math.ceil(cV.y/res),
+ (int) Math.ceil(cV.z/res));
+ }
+
+ /**
+ * \brief Set this vector to the supplied i, j, k points.
+ *
+ * @param i i-coordinate
+ * @param j j-coordinate
+ * @param k k-coordinate
+ */
+ public void set(int i, int j, int k)
+ {
+ this.i = i;
+ this.j = j;
+ this.k = k;
+ }
+
+ /**
+ * \brief Set all points in the vector to zero.
+ */
+ public void reset()
+ {
+ set(0, 0, 0);
+ }
+
+ /**
+ * \brief Create a discrete vector from the supplied i, j, k points.
+ *
+ * @param i i-coordinate
+ * @param j j-coordinate
+ * @param k k-coordinate
+ */
+ public DiscreteVector(int i, int j, int k)
+ {
+ set(i, j, k);
+ }
+
+ /**
+ * \brief Add points I,J,K to their respective point in this vector.
+ *
+ * @param i I coordinate.
+ * @param j J coordinate.
+ * @param k K coordinate.
+ */
+ public void add(int i, int j, int k)
+ {
+ this.i += i;
+ this.j += j;
+ this.k += k;
+ }
+
+ /**
+ * \brief Add vector v to this discrete vector.
+ *
+ * @param dV DiscreteVector to add to this vector.
+ */
+ public void add(DiscreteVector dV)
+ {
+ add(dV.i, dV.j, dV.k);
+ }
+
+ /**
+ * \brief Store in this vector the sum of two other discrete vectors.
+ *
+ * @param a First discrete vector.
+ * @param b Discrete vector to add to first.
+ */
+ public void sendSum(DiscreteVector a, DiscreteVector b)
+ {
+ set(a);
+ add(b);
+ }
+
+ /**
+ * \brief Subtract vector v from this discrete vector.
+ *
+ * @param dV DiscreteVector to subtract from this vector.
+ */
+ public void subtract(DiscreteVector dV)
+ {
+ add( -dV.i, -dV.j, -dV.k );
+ }
+
+ /**
+ * \brief Store in this vector the difference of two other discrete
+ * vectors.
+ *
+ * @param a First discrete vector.
+ * @param b Discrete vector to subtract from the first.
+ */
+ public void sendDiff(DiscreteVector a, DiscreteVector b)
+ {
+ set(a);
+ subtract(b);
+ }
+
+ /**
+ * \brief Multiply (stretch) this vector by supplied multiplier.
+ *
+ * @param n Amount to stretch this vector by.
+ */
+ public void times(int n)
+ {
+ i *= n;
+ j *= n;
+ k *= n;
+ }
+
+ /**
+ * \brief Determine if this vector equals the points given in the provided
+ * vector.
+ *
+ * @param dc Discrete vector to compare to this vector
+ * @return Boolean stating whether the two vectors are equal
+ */
+ public Boolean equals(DiscreteVector dc)
+ {
+ return equals(dc.i, dc.j, dc.k);
+ }
+
+ /**
+ *
+ * @param i
+ * @param j
+ * @param k
+ * @return
+ */
+ public Boolean equals(int i, int j, int k) {
+ return ((i == this.i) && (j == this.j) && (k == this.k));
+ }
+
+ /**
+ * \brief Print coordinates to string.
+ *
+ * @return String containing the points in this vector.
+ */
+ @Override
+ public String toString()
+ {
+ return "("+i+","+j+","+k+")";
+ }
+}
diff --git a/src/solver/mgFas/utils/IsShape.java b/src/solver/mgFas/utils/IsShape.java
new file mode 100644
index 000000000..ee41c41d8
--- /dev/null
+++ b/src/solver/mgFas/utils/IsShape.java
@@ -0,0 +1,4 @@
+package solver.mgFas.utils;
+
+public class IsShape {
+}
diff --git a/src/spatialRegistry/Area.java b/src/spatialRegistry/Area.java
index 87a1ba38f..ecb0f0e36 100644
--- a/src/spatialRegistry/Area.java
+++ b/src/spatialRegistry/Area.java
@@ -1,5 +1,7 @@
package spatialRegistry;
+import linearAlgebra.Vector;
+
import java.util.function.Predicate;
/**
@@ -49,6 +51,11 @@ public void set(double[] low, double[] high, boolean[] periodic)
this.periodic = periodic;
}
+ public Area copy()
+ {
+ return new Area(Vector.copy(low),Vector.copy(high),Vector.copy(periodic));
+ }
+
/**
* test whether this area is NOT hitting the input area
*/
diff --git a/src/spatialRegistry/splitTree/SplitTree.java b/src/spatialRegistry/splitTree/SplitTree.java
index 392de0e8e..8bedd0be7 100644
--- a/src/spatialRegistry/splitTree/SplitTree.java
+++ b/src/spatialRegistry/splitTree/SplitTree.java
@@ -170,6 +170,21 @@ public List search(Area area)
{
if ( this._periodic[i] )
{
+ /*
+ * If the bounding box is bigger than the compartment in periodic
+ * dimension i, simply set the bounds to equal the extremes of
+ * the dimension. This avoids the bounding box wrapping around
+ * at both ends, causing the middle of the bounding box to be
+ * effectively cancelled out.
+ */
+ if ((area.getHigh()[i] - area.getLow()[i]) > this._lengths[i])
+ {
+ double[] low = area.getLow();
+ double[] high = area.getHigh();
+ low[i] = this.node.getLow()[i];
+ high[i] = this.node.getHigh()[i];
+ area.set(low, high);
+ }
if ( area.getHigh()[i] > this.node.getHigh()[i] )
{
area.getHigh()[i] -= this._lengths[i];
diff --git a/src/surface/BoundingBox.java b/src/surface/BoundingBox.java
index ce8bbb25f..545bf7fe3 100644
--- a/src/surface/BoundingBox.java
+++ b/src/surface/BoundingBox.java
@@ -1,6 +1,7 @@
package surface;
import linearAlgebra.Vector;
+import settable.Module;
import spatialRegistry.Area;
/**
@@ -21,6 +22,13 @@ public BoundingBox()
{
}
+
+ public BoundingBox copy()
+ {
+ BoundingBox out = new BoundingBox();
+ out.set(Vector.copy(low),Vector.copy(high),Vector.copy(periodic));
+ return out;
+ }
/**
* construct from a matrix of locations, a sphere radius for the sphere-
diff --git a/src/surface/Point.java b/src/surface/Point.java
index e864b02a7..e4936b408 100644
--- a/src/surface/Point.java
+++ b/src/surface/Point.java
@@ -257,38 +257,23 @@ public double[] dxdt( double radius )
* @param dt Time step to use (in units of second).
* @param radius Radius of a sphere (in units of micrometer).
*/
- public void shove(double dt, double radius)
+ public void shove(double shovingLimit, double shoveFactor, double radius)
{
/*
* No point shoving if there's no force.
*/
- if ( Vector.isZero( this.getForce() ))
+ if ( Vector.isZero( this.dxdt(radius) ))
return;
- /*
- * Scale the force.
- */
- double scalar = 0.2;
+
/* the following dynamic scaling is a slight deviation from the original
- * iDynoMiCS where instead of dynamic scaling the overlap was simply
- * considered resolved at small when the difference vector (and thus
- * the force was sufficiently small)
- * TODO, make these things settable from xml.
+ * iDynoMiCS as the iDynoMiCS 2 collision detection cumulative displacement
+ * vector is used to calculate delta rather than stepping through every individually.
*/
- if ( Vector.normEuclid( this.getForce()) < 0.2 )
- {
- /* Anti deadlock. */
- scalar *= 2.0;
- }
- else
- {
- /* Anti catapult */
- scalar *= 0.2;
- }
- Vector.timesEquals(this._f, scalar);
+ double delta = 2 * ( radius * ( shoveFactor - 1.0 ) ) + shovingLimit;
/*
* Apply the force and reset it.
*/
- Vector.addEquals(this._p, this._f);
+ Vector.addEquals( this._p, Vector.normaliseEuclid( this.getForce() , delta * 0.5 ) );
this.resetForce();
}
diff --git a/src/surface/collision/Collision.java b/src/surface/collision/Collision.java
index f2de25b0a..efe0d69c0 100644
--- a/src/surface/collision/Collision.java
+++ b/src/surface/collision/Collision.java
@@ -165,9 +165,16 @@ public void setAttractionFunction(String functionClass)
+ " instead .\n" + e.getMessage());
}
}
-
}
-
+
+ public void resetOverlap() {
+ this._variables.resetOverlap();
+ }
+
+ public double maxOverlap() {
+ return this._variables.maxOverlap();
+ }
+
/* ***********************************************************************
* FORCE METHODS
* **********************************************************************/
@@ -200,15 +207,17 @@ public void collision(Surface a, AspectInterface first,
this.distance(a, b, var);
if ( Double.isNaN(var.interactionVector[0]))
- System.out.println(var.interactionVector[0] + "f0");
+ Log.out( Tier.CRITICAL, this.getClass().getSimpleName() +
+ " detected unidentified number (NaN) " + var.interactionVector[0]);
/*
* If the two surfaces overlap, then they should push each other away.
*/
- if ( var.distance < 0.0 )
+ if ( var.getDistance() < 0.0 )
{
this._collisionFun.interactionForce( var, first, second );
if ( Double.isNaN(var.interactionVector[0]))
- System.out.println(var.interactionVector[0] + "f");
+ Log.out( Tier.CRITICAL, this.getClass().getSimpleName() +
+ " detected unidentified number (NaN) " + var.interactionVector[0]);
if( var.flip )
{
this.applyForce(b, var.interactionVector, var.s);
@@ -296,7 +305,8 @@ public void collision(Surface a, AspectInterface first,
private void applyForce(Surface surf, double[] force, double intersect)
{
if ( Double.isNaN(force[0]))
- System.out.println(force[0] + "h");
+ Log.out( Tier.CRITICAL, this.getClass().getSimpleName() +
+ " detected unidentified number (NaN) ");
switch ( surf.type() )
{
case SPHERE:
@@ -344,7 +354,7 @@ public double distance(Surface a, Surface b)
{
_variables.setMargin( 0.0 );
CollisionVariables var = this.distance( a, b, _variables );
- return var.distance;
+ return var.getDistance();
}
/**
@@ -406,13 +416,13 @@ public double distance(Surface a, double[] p)
{
case SPHERE :
this.spherePoint( (Ball) a, p, this._variables );
- return this._variables.distance;
+ return this._variables.getDistance();
case ROD :
this.rodPoint( (Rod) a, p, this._variables );
- return this._variables.distance;
+ return this._variables.getDistance();
case PLANE:
this.planePoint( (Plane) a, p, this._variables );
- return this._variables.distance;
+ return this._variables.getDistance();
default:
Log.out( Tier.CRITICAL, this.getClass().getSimpleName() +
" encountered undefined surface assessment, returning 0.");
@@ -571,14 +581,14 @@ public boolean intersect(Surface a, Surface b, double margin)
case SPHERE:
_variables.flip = false;
this.assessSphere((Ball) a, b, _variables);
- return _variables.distance < margin;
+ return _variables.getDistance() < margin;
case ROD:
_variables.flip = false;
return this.intersectRod((Rod) a, b, _variables);
case PLANE:
_variables.flip = false;
this.assessPlane((Plane) a, b, _variables);
- return _variables.distance < margin;
+ return _variables.getDistance() < margin;
case VOXEL:
_variables.flip = false;
return this.intersectVoxel((Voxel) a, b, _variables);
@@ -603,13 +613,13 @@ private boolean intersectRod(Rod rod, Surface otherSurface,
{
case SPHERE:
this.rodSphere(rod, (Ball) otherSurface, var);
- return var.distance < var.margin;
+ return var.getDistance() < var.margin;
case ROD:
this.rodRod(rod, (Rod) otherSurface, var);
- return var.distance < var.margin;
+ return var.getDistance() < var.margin;
case PLANE:
this.planeRod((Plane) otherSurface, rod, var);
- return var.distance < var.margin;
+ return var.getDistance() < var.margin;
case VOXEL:
return this.voxelRodIntersection(rod, (Voxel) otherSurface, var);
default:
@@ -634,7 +644,7 @@ private boolean intersectVoxel(Voxel vox, Surface otherSurface,
{
case SPHERE:
this.voxelSphere(vox, (Ball) otherSurface, var);
- return var.distance < var.margin;
+ return var.getDistance() < var.margin;
case ROD:
return this.voxelRodIntersection((Rod) otherSurface, vox, var);
default:
@@ -662,7 +672,7 @@ private CollisionVariables pointPoint(double[] p, double[] q,
CollisionVariables var)
{
this.setPeriodicDistanceVector(p, q, var);
- var.distance = Vector.normEuclidTo(var.distance, var.interactionVector);
+ var.setDistance(Vector.normEuclidTo(var.getDistance(), var.interactionVector));
return var;
}
@@ -688,7 +698,7 @@ private CollisionVariables spherePoint(Ball a, double[] p,
* Subtract the sphere's radius to find the distance between the point
* and the surface of the sphere.
*/
- var.distance -= a.getRadius();
+ var.setDistance(var.getDistance() - a.getRadius());
return var;
}
@@ -721,7 +731,7 @@ private CollisionVariables sphereSphere(Ball a, Ball b,
*/
/* Normal collision. */
- var.distance -= a.getRadius() + b.getRadius();
+ var.setDistance(var.getDistance() - (a.getRadius() + b.getRadius()));
/* additional collision variables */
if (extend)
{
@@ -753,19 +763,19 @@ private CollisionVariables planeLineSeg(double[] normal, double d,
i=0;
}
this.planePoint(normal, d, p0, var);
- double a = Double.valueOf(var.distance);
+ double a = Double.valueOf(var.getDistance());
this.planePoint(normal, d, p1, var);
- double b = Double.valueOf(var.distance);
+ double b = Double.valueOf(var.getDistance());
if ( a < b )
{
var.t = 0.0;
- var.distance = a;
+ var.setDistance(a);
return var;
}
if ( a > b )
{
var.t = 1.0;
- var.distance = b;
+ var.setDistance(b);
return var;
}
/* a = b */
@@ -794,7 +804,7 @@ private CollisionVariables planeRod(Plane plane, Rod rod,
var);
/* Subtract the rod's radius to find the distance between the plane and
* the rod's surface. */
- var.distance -= rod.getRadius();
+ var.setDistance(var.getDistance() - rod.getRadius());
/* additional collision variables */
if (extend)
{
@@ -831,7 +841,7 @@ public CollisionVariables linesegPoint(double[] p0, double[] p1,
Vector.timesEquals(var.interactionVector, var.s);
Vector.addEquals(var.interactionVector, sp0);
Vector.minusEquals(var.interactionVector, q0);
- var.distance = Vector.normEuclid(var.interactionVector);
+ var.setDistance(Vector.normEuclid(var.interactionVector));
return var;
}
@@ -856,7 +866,7 @@ public CollisionVariables rodPoint(Rod aRod, double[] p,
aRod._points[1].getPosition(), p, var);
/* Subtract the rod's radius to find the distance between the point and
* the rod's surface. */
- var.distance -= aRod.getRadius();
+ var.setDistance(var.getDistance() - aRod.getRadius());
return var;
}
@@ -887,7 +897,7 @@ public CollisionVariables rodSphere(Rod aRod, Ball aBall,
* Subtract the radii of both to find the distance between their
* surfaces.
*/
- var.distance -= aRod.getRadius() + aBall.getRadius();
+ var.setDistance(var.getDistance() - (aRod.getRadius() + aBall.getRadius()));
/*
* additional collision variables
*/
@@ -971,7 +981,7 @@ else if ( var.t > 1.0 )
Vector.addEquals(d2, q0);
/* finally calculate the distance between the two points */
this.setPeriodicDistanceVector(d1, d2, var);
- var.distance = Vector.normEuclid(var.interactionVector);
+ var.setDistance(Vector.normEuclid(var.interactionVector));
return var;
}
@@ -995,7 +1005,7 @@ private CollisionVariables rodRod(Rod a, Rod b, CollisionVariables var)
b._points[1].getPosition(), var);
/* Subtract the radii of both rods to find the distance between their
* surfaces. */
- var.distance -= a.getRadius() + b.getRadius();
+ var.setDistance(var.getDistance() - (a.getRadius() + b.getRadius()));
/* additional collision variables */
if (extend)
{
@@ -1019,7 +1029,7 @@ public CollisionVariables planePoint(Plane plane, double[] point,
CollisionVariables var)
{
Vector.reverseTo(var.interactionVector, plane.getNormal());
- var.distance = Vector.dotProduct(plane.getNormal(), point)-plane.getD();
+ var.setDistance(Vector.dotProduct(plane.getNormal(), point)-plane.getD());
return var;
}
@@ -1042,7 +1052,7 @@ public double[] closestPointOnPlane(double[] normal, double d,
* distance between the point and the plane in the direction of the
* planes normal.
*/
- return Vector.minus(point, Vector.times(normal, - var.distance));
+ return Vector.minus(point, Vector.times(normal, -var.getDistance()));
}
/**
@@ -1069,7 +1079,7 @@ public CollisionVariables planeSphere(Plane plane, Ball sphere,
* Subtract the rod's radius to find the distance between the plane and
* the rod's surface.
*/
- var.distance -= sphere.getRadius();
+ var.setDistance(var.getDistance() - sphere.getRadius());
/*
* additional collision variables
*/
@@ -1099,7 +1109,7 @@ private CollisionVariables planePoint(double[] normal, double d,
/* store the direction vector */
Vector.reverseTo(var.interactionVector, normal);
/* calculate the distance between a point and a normalized plane */
- var.distance = Vector.dotProduct(normal, point) - d;
+ var.setDistance(Vector.dotProduct(normal, point) - d);
return var;
}
@@ -1116,14 +1126,14 @@ private CollisionVariables voxelSphere(Voxel voxel, Ball sphere,
CollisionVariables var)
{
var = voxelPoint(voxel, sphere._point.getPosition(), var);
- var.distance -= sphere.getRadius();
+ var.setDistance(var.getDistance() - sphere.getRadius());
return var;
}
private CollisionVariables voxelPoint(Voxel voxel, double[] point,
CollisionVariables var)
{
- var.distance = 0.0; double t,v = 0.0;
+ var.setDistance(0.0); double t,v = 0.0;
for(int i=0; i < voxel.getLower().length ; i++)
{
double[] p = this._shape.getNearestShadowPoint( point,
@@ -1131,12 +1141,12 @@ private CollisionVariables voxelPoint(Voxel voxel, double[] point,
t = voxel.getLower()[i];
v = p[i];
if (v < t)
- var.distance += ( t - v ) * ( t - v );
+ var.setDistance(var.getDistance() + ( t - v ) * ( t - v ));
t = voxel.getHigher()[i];
if (v > t)
- var.distance += ( v - t ) * ( v - t );
+ var.setDistance(var.getDistance() + ( v - t ) * ( v - t ));
}
- var.distance = Math.sqrt(var.distance);
+ var.setDistance(Math.sqrt(var.getDistance()));
return var;
}
@@ -1165,7 +1175,7 @@ private boolean voxelRodIntersection(Rod rod, Voxel voxel, CollisionVariables va
var = intersectRayAABB(periodicShadow._points[0].getPosition(),
periodicShadow._points[1].getPosition(), e, var);
- if (var.distance == Double.MAX_VALUE || var.t > 1.0 )
+ if (var.getDistance() == Double.MAX_VALUE || var.t > 1.0 )
return false;
/* Compute which min and max faces of b the intersection point p lies
* outside of. Note, u and v cannot have the same bits set and
@@ -1254,7 +1264,7 @@ private boolean voxelRodIntersection(Rod rod, Voxel voxel, CollisionVariables va
private CollisionVariables intersectRayAABB( double[] p, double[] o,
Voxel a, CollisionVariables var)
{
- var.distance = 0.0;
+ var.setDistance(0.0);
double[] d = Vector.minus(o, p);
/* set to max distance ray can travel (for segment) */
double tmax = Vector.distanceEuclid(p, o);
@@ -1269,7 +1279,7 @@ private CollisionVariables intersectRayAABB( double[] p, double[] o,
/* Ray is parallel to slab. No hit if origin not within slab */
if (p[i] < a.getLower()[i] || p[i] > a.getHigher()[i])
{
- var.distance = Double.MAX_VALUE;
+ var.setDistance(Double.MAX_VALUE);
return var;
}
}
@@ -1292,7 +1302,7 @@ private CollisionVariables intersectRayAABB( double[] p, double[] o,
* empty. */
if (var.t > tmax)
{
- var.distance = Double.MAX_VALUE;
+ var.setDistance(Double.MAX_VALUE);
return var;
}
}
@@ -1311,10 +1321,10 @@ private boolean intersectSegmentCapsule(double[] sa, double[] sb,
{
/* checking caps */
var = linesegPoint( sa, sb, p, var );
- if(var.distance < r + var.margin)
+ if(var.getDistance() < r + var.margin)
return true;
var = linesegPoint( sa, sb, q, var );
- if(var.distance < r + var.margin)
+ if(var.getDistance() < r + var.margin)
return true;
/* checking cylinder */
return intersectSegmentCylinder( sa, sb, p, q, r, var );
diff --git a/src/surface/collision/CollisionVariables.java b/src/surface/collision/CollisionVariables.java
index e6fc6093f..da3eef242 100644
--- a/src/surface/collision/CollisionVariables.java
+++ b/src/surface/collision/CollisionVariables.java
@@ -71,10 +71,33 @@ public void setMargin(double margin )
/*
* calculated distance between two objects.
*/
- public double distance;
+ private double distance;
+
+ /*
+ * used to track max overlap
+ */
+ private double maxOverlap = 0;
/*
* Effective radius (required for Herz model).
*/
public double radiusEffective;
+
+ public double getDistance() {
+ return distance;
+ }
+
+ public void setDistance(double distance) {
+ this.distance = distance;
+ if( distance < maxOverlap )
+ maxOverlap = distance;
+ }
+
+ public void resetOverlap() {
+ this.maxOverlap = 0.0;
+ }
+
+ public double maxOverlap() {
+ return this.maxOverlap;
+ }
}
\ No newline at end of file
diff --git a/src/surface/collision/model/DefaultPullFunction.java b/src/surface/collision/model/DefaultPullFunction.java
index 2f350ba91..19e42a836 100644
--- a/src/surface/collision/model/DefaultPullFunction.java
+++ b/src/surface/collision/model/DefaultPullFunction.java
@@ -62,10 +62,10 @@ public CollisionVariables interactionForce(CollisionVariables var,
*
* TODO magic number, set in defaults or avoid
*/
- if ( var.distance > 0.001 && var.distance < var.margin )
+ if ( var.getDistance() > 0.001 && var.getDistance() < var.margin )
{
/* Linear. */
- double c = Math.abs(this._forceScalar * var.distance);
+ double c = Math.abs(this._forceScalar * var.getDistance());
/* dP is overwritten here. */
Vector.normaliseEuclidEquals(var.interactionVector, c);
return var;
diff --git a/src/surface/collision/model/DefaultPushFunction.java b/src/surface/collision/model/DefaultPushFunction.java
index 9fba13a8f..43653403a 100644
--- a/src/surface/collision/model/DefaultPushFunction.java
+++ b/src/surface/collision/model/DefaultPushFunction.java
@@ -61,10 +61,10 @@ public CollisionVariables interactionForce(CollisionVariables var,
* Otherwise, return a zero vector. A small overlap is allowed to
* prevent objects bouncing in equilibrium
*/
- if ( var.distance < -0.001 )
+ if ( var.getDistance() < -0.001 )
{
/* Linear. */
- double c = Math.abs( this._forceScalar * var.distance );
+ double c = Math.abs( this._forceScalar * var.getDistance() );
/* two component, better force scaling for low vs high overlap */
/* dP is overwritten here. */
Vector.normaliseEuclidEquals( var.interactionVector, c );
diff --git a/src/surface/collision/model/HerzSoftSphere.java b/src/surface/collision/model/HerzSoftSphere.java
index 39c2206a1..19eb67e6a 100644
--- a/src/surface/collision/model/HerzSoftSphere.java
+++ b/src/surface/collision/model/HerzSoftSphere.java
@@ -66,11 +66,11 @@ public CollisionVariables interactionForce(CollisionVariables var,
* Otherwise, return a zero vector. A small overlap is allowed to
* prevent objects bouncing in equilibrium
*/
- if ( var.distance < -0.001 )
+ if ( var.getDistance() < -0.001 )
{
double kn = 1.33333333 * Math.sqrt( var.radiusEffective ) * forceScalar();
- double c = kn * Math.pow(-var.distance, 1.5 );
+ double c = kn * Math.pow(-var.getDistance(), 1.5 );
/* dP is overwritten here. */
Vector.normaliseEuclidEqualsUnchecked( var.interactionVector, c );
return var;
diff --git a/src/test/junit/newTests/MassBalance.java b/src/test/junit/newTests/MassBalance.java
index 9934b5050..2a2aaf623 100644
--- a/src/test/junit/newTests/MassBalance.java
+++ b/src/test/junit/newTests/MassBalance.java
@@ -83,6 +83,8 @@ public void test(TestMode mode)
"accu\t" +
"solver", mode);
+ Idynomics.simulator.initialRun();
+
/* run the simulator manually and gather relevant system properties
* in the mean while. */
while ( Idynomics.simulator.timer.isRunning() )
diff --git a/src/test/junit/newTests/ReactionDiffusion.java b/src/test/junit/newTests/ReactionDiffusion.java
index eb1d9b44b..439d1bbf5 100644
--- a/src/test/junit/newTests/ReactionDiffusion.java
+++ b/src/test/junit/newTests/ReactionDiffusion.java
@@ -75,6 +75,9 @@ public void test(TestMode mode)
double mre1 = 0, mre2 = 0;
int e5 = 0, e10 = 0, e20 = 0;
int i=0;
+
+ Idynomics.simulator.initialRun();
+
while ( Idynomics.simulator.timer.isRunning() )
{
i++;
diff --git a/src/test/junit/newTests/ReactionDiffusionMgFas.java b/src/test/junit/newTests/ReactionDiffusionMgFas.java
new file mode 100644
index 000000000..63807d107
--- /dev/null
+++ b/src/test/junit/newTests/ReactionDiffusionMgFas.java
@@ -0,0 +1,193 @@
+package test.junit.newTests;
+
+import boundary.Boundary;
+import boundary.WellMixedBoundary;
+import compartment.Compartment;
+import dataIO.Log;
+import dataIO.Log.Tier;
+import debugTools.Testable;
+import debugTools.Tester;
+import grid.ArrayType;
+import idynomics.Idynomics;
+import org.junit.Test;
+
+public class ReactionDiffusionMgFas implements Testable {
+
+ String sol = "glucose";
+ Compartment chemostat = null;
+ Compartment biofilm = null;
+
+ @Test
+ public void test()
+ {
+ test(TestMode.UNIT);
+ }
+
+ public void test(TestMode mode)
+ {
+ String file = "protocol/unit-tests/reaction_diffusion_mgFas.xml";
+// String file = "protocol/unit-tests/reaction_diffusion_Large.xml";
+
+ /* basic simulator initiation */
+ Log.set(Tier.CRITICAL);
+ Idynomics.setupSimulator(file);
+ Log.set(Tier.CRITICAL);
+
+ Tester.println("reaction diffusion test", mode);
+ chemostat = Idynomics.simulator.getCompartment("chemostat");
+ biofilm = Idynomics.simulator.getCompartment("biofilm");
+
+// /* set height of the biofilm and the diffusion boundary layer */
+// int hBiofilm = 16, hDBL = hBiofilm+20, x=0;
+// /* max accepted Mean absolute relative error. As it is quite difficult
+// * to get to precisely line-out the biofilm height with the grid and to
+// * get a precise packing density typically 15% would be a good result */
+// double acceptedMRE = 0.15;
+// /* polling frequency, set equal to the grid resolution (or a multitude),
+// * does not go below 1 */
+// int polling = 2;
+
+ /* collect some values from the compartment to make life a bit easier
+ * when testing different settings */
+ double bLayer= 0.0;
+ for(Boundary b : biofilm.getShape().getAllBoundaries())
+ if(b instanceof WellMixedBoundary)
+ bLayer = ((WellMixedBoundary) b).getLayerThickness();
+
+ double[] vLength = new double[3];
+ biofilm.getShape().getVoxelSideLengthsTo(vLength, new int[3]);
+
+ /* set height of the biofilm and the diffusion boundary layer */
+ int hBiofilm = 10, hDBL = (int) (hBiofilm+bLayer), x=0;
+ /* packing density of catalyst *cylinders* */
+ double pakcing = 0.75;
+ /* max accepted Mean absolute relative error. As it is quite difficult
+ * to get to precisely line-out the biofilm height with the grid and to
+ * get a precise packing density typically 15% would be a good result */
+ double acceptedMRE = 0.15;
+ /* polling frequency, set equal to the grid resolution (or a multitude),
+ * does not go below 1 */
+ int polling = Math.max((int)vLength[0], 1);
+
+ /* setting up internally used variables */
+ double solver, model, error;
+ double mre1 = 0, mre2 = 0;
+ int e5 = 0, e10 = 0, e20 = 0;
+ int i=0;
+
+ Idynomics.simulator.initialRun();
+
+ while ( Idynomics.simulator.timer.isRunning() )
+ {
+ i++;
+ Idynomics.simulator.step();
+ if(i > 1)
+ {
+ Tester.println( "Solver \t\t\t Symbolic model "
+ + "\t Relative error \t Location", mode);
+ for (int y = 0; y < hDBL+1; y++)
+ {
+ boolean poll = ( y%polling == 0);
+ solver = concn(x ,y);
+ if(y <= hBiofilm && poll)
+ {
+ /* catalyst part */
+ model = concnFirstOrder( y, (100000.0*0.15*pakcing) /
+ 36000.0, hBiofilm, concn(x, hBiofilm) );
+ error = (1-solver/model);
+ Tester.println( solver + "\t " + model + "\t " +
+ error + "\t film", mode);
+ mre1 += Math.abs(error);
+ if(Math.abs(error) > 0.05)
+ e5++;
+ if(Math.abs(error) > 0.10)
+ e10++;
+ if(Math.abs(error) > 0.20)
+ e20++;
+ }
+ else if(y > hBiofilm && y <= hDBL && poll)
+ {
+ /* diffusion boundary layer */
+ model = concnDiff(y, hBiofilm, concn(x, hBiofilm),
+ hDBL, concn(x, hDBL));
+ error = (1-solver/model);
+ Tester.println( solver + "\t " + model + "\t " +
+ error + "\t DBL", mode);
+ mre2 += Math.abs(error);
+ if(Math.abs(error) > 0.05)
+ e5++;
+ if(Math.abs(error) > 0.10)
+ e10++;
+ if(Math.abs(error) > 0.20)
+ e20++;
+ }
+ }
+ }
+ }
+ mre1 /= hBiofilm/polling;
+ mre2 /= (hDBL-hBiofilm)/polling;
+
+ System.out.println(
+ "max accepted Mean absolute relative error. As it is quite difficult\n" +
+ "to get to precisely line-out the biofilm height with the grid and to\n" +
+ "get a precise packing density typically 15% would be a good result."
+ );
+
+ /* amount of times the relative error exceeds .05, .10 and .20 */
+ Tester.println("\n", mode);
+ Tester.println("#n |Relative error| > .05 = " + e5 , mode);
+ Tester.println("#n |Relative error| > .10 = " + e10 , mode);
+ Tester.println("#n |Relative error| > .20 = " + e20 , mode);
+
+ /* Unit test: are the MREs close to 0? */
+ Tester.println("\n", mode);
+ Tester.assess(0.0, mre1, acceptedMRE , mode,
+ "Mean Relative error biofilm < " + acceptedMRE);
+ Tester.assess(0.0, mre2, acceptedMRE , mode,
+ "Mean Relative error diffusion boundary layer < " +acceptedMRE);
+ Tester.assess(0.0, (mre1+mre2)/2, acceptedMRE , mode,
+ "Mean Relative error overall < " + acceptedMRE);
+ }
+ /**
+ * Poll concentration in biofilm compartment.
+ *
+ * @param x location
+ * @param y location
+ * @return conentration at location (x,y,z=0)
+ */
+ private double concn(int x, int y)
+ {
+ return biofilm.environment.getSoluteGrid(sol).
+ getValueAt(ArrayType.CONCN, new double[] {x,y,0});
+ }
+ /**
+ * calculate concentration profile based on symbolic solution 1D first order
+ * reaction diffusion.
+ *
+ * @param y location
+ * @param k reaction constant
+ * @param b height of upper boundary
+ * @param bc concentration at upper boundary
+ * @return concentration at location y
+ */
+ private double concnFirstOrder(double y, double k, double b, double bc)
+ {
+ return ( bc * Math.exp( -Math.sqrt(k) * ( y - b ) ) *
+ ( Math.exp( 2 * Math.sqrt(k) * y ) + 1 ) ) /
+ ( 1 + Math.exp( 2 * b * Math.sqrt( k ) ) );
+ }
+ /**
+ * Calculate concentration profile based on simple 1D diffusion model.
+ *
+ * @param y location
+ * @param b starting height
+ * @param bc concentration at starting height
+ * @param t top height
+ * @param tc concentration at top height
+ * @return concentration at location y
+ */
+ private double concnDiff(double y, double b, double bc, double t, double tc)
+ {
+ return ( (tc-bc)*y + (bc*t - tc*b) ) / ( t-b );
+ }
+}
diff --git a/src/test/junit/newTests/ReactionDiffusionMgFasDistributed.java b/src/test/junit/newTests/ReactionDiffusionMgFasDistributed.java
new file mode 100644
index 000000000..fc00c7b66
--- /dev/null
+++ b/src/test/junit/newTests/ReactionDiffusionMgFasDistributed.java
@@ -0,0 +1,192 @@
+package test.junit.newTests;
+
+import boundary.Boundary;
+import boundary.WellMixedBoundary;
+import compartment.Compartment;
+import dataIO.Log;
+import dataIO.Log.Tier;
+import debugTools.Testable;
+import debugTools.Tester;
+import grid.ArrayType;
+import idynomics.Idynomics;
+import org.junit.Test;
+
+public class ReactionDiffusionMgFasDistributed implements Testable {
+
+ String sol = "glucose";
+ Compartment chemostat = null;
+ Compartment biofilm = null;
+
+ @Test
+ public void test()
+ {
+ test(TestMode.UNIT);
+ }
+
+ public void test(TestMode mode)
+ {
+ String file = "protocol/unit-tests/reaction_diffusion_smooth_distribution.xml";
+// String file = "protocol/unit-tests/reaction_diffusion_Large.xml";
+
+ /* basic simulator initiation */
+ Log.set(Tier.CRITICAL);
+ Idynomics.setupSimulator(file);
+ Log.set(Tier.CRITICAL);
+
+ Tester.println("reaction diffusion test", mode);
+ chemostat = Idynomics.simulator.getCompartment("chemostat");
+ biofilm = Idynomics.simulator.getCompartment("biofilm");
+
+// /* set height of the biofilm and the diffusion boundary layer */
+// int hBiofilm = 16, hDBL = hBiofilm+20, x=0;
+// /* max accepted Mean absolute relative error. As it is quite difficult
+// * to get to precisely line-out the biofilm height with the grid and to
+// * get a precise packing density typically 15% would be a good result */
+// double acceptedMRE = 0.15;
+// /* polling frequency, set equal to the grid resolution (or a multitude),
+// * does not go below 1 */
+// int polling = 2;
+
+ /* collect some values from the compartment to make life a bit easier
+ * when testing different settings */
+ double bLayer= 0.0;
+ for(Boundary b : biofilm.getShape().getAllBoundaries())
+ if(b instanceof WellMixedBoundary)
+ bLayer = ((WellMixedBoundary) b).getLayerThickness();
+
+ double[] vLength = new double[3];
+ biofilm.getShape().getVoxelSideLengthsTo(vLength, new int[3]);
+
+ /* set height of the biofilm and the diffusion boundary layer */
+ int hBiofilm = 31, hDBL = (int) (hBiofilm+bLayer), x=0;
+ /* packing density of catalyst *cylinders* */
+ double pakcing = 0.5/(2.0*2.0);
+ /* max accepted Mean absolute relative error. As it is quite difficult
+ * to get to precisely line-out the biofilm height with the grid and to
+ * get a precise packing density typically 15% would be a good result */
+ double acceptedMRE = 0.025;
+ /* polling frequency, set equal to the grid resolution (or a multitude),
+ * does not go below 1 */
+ int polling = Math.max((int)vLength[0], 1);
+
+ /* setting up internally used variables */
+ double solver, model, error;
+ double mre1 = 0, mre2 = 0;
+ int e5 = 0, e10 = 0, e20 = 0;
+ int i=0;
+ boolean nodesystem = true;
+
+ Idynomics.simulator.initialRun();
+
+ while ( Idynomics.simulator.timer.isRunning() )
+ {
+ i++;
+ Idynomics.simulator.step();
+ if(i > 1)
+ {
+ Tester.println( "Solver \t\t\t Symbolic model "
+ + "\t Relative error \t Location", mode);
+ for (int y = 0; y < hDBL+1; y++)
+ {
+ boolean poll;
+ if( nodesystem )
+ poll = ( (y%polling)-1 == 0);
+ else
+ poll = (y%polling == 0);
+ solver = concn(x ,y);
+ if(y <= hBiofilm && poll)
+ {
+ /* catalyst part */
+ model = concnFirstOrder( y, ((2.0E-02/35.0E-06)*2.63*pakcing) /
+ 36000.0, hBiofilm, concn(x, hBiofilm) );
+ error = (1-solver/model);
+ Tester.println( solver + "\t " + model + "\t " +
+ error + "\t film", mode);
+ mre1 += Math.abs(error);
+ if(Math.abs(error) > 0.05)
+ e5++;
+ if(Math.abs(error) > 0.10)
+ e10++;
+ if(Math.abs(error) > 0.20)
+ e20++;
+ }
+ else if(y > hBiofilm && y <= hDBL && poll)
+ {
+ /* diffusion boundary layer */
+ model = concnDiff(y, hBiofilm, concn(x, hBiofilm),
+ hDBL, concn(x, hDBL));
+ error = (1-solver/model);
+ Tester.println( solver + "\t " + model + "\t " +
+ error + "\t DBL", mode);
+ mre2 += Math.abs(error);
+ if(Math.abs(error) > 0.05)
+ e5++;
+ if(Math.abs(error) > 0.10)
+ e10++;
+ if(Math.abs(error) > 0.20)
+ e20++;
+ }
+ }
+ }
+ }
+ mre1 /= hBiofilm/polling;
+ mre2 /= (hDBL-hBiofilm)/polling;
+
+ /* amount of times the relative error exceeds .05, .10 and .20 */
+ Tester.println("\n", mode);
+ Tester.println("#n |Relative error| > .05 = " + e5 , mode);
+ Tester.println("#n |Relative error| > .10 = " + e10 , mode);
+ Tester.println("#n |Relative error| > .20 = " + e20 , mode);
+
+ /* Unit test: are the MREs close to 0? */
+ Tester.println("\n", mode);
+ Tester.assess(0.0, mre1, acceptedMRE , mode,
+ "Mean Relative error biofilm " + (float)mre1 + " < " + acceptedMRE);
+ Tester.assess(0.0, mre2, acceptedMRE , mode,
+ "Mean Relative error diffusion boundary layer " + (float)mre2 + " < " +acceptedMRE);
+ Tester.assess(0.0, (mre1+mre2)/2, acceptedMRE , mode,
+ "Mean Relative error overall " + (float)(mre1+mre2)/2 + " < " + acceptedMRE);
+ }
+ /**
+ * Poll concentration in biofilm compartment.
+ *
+ * @param x location
+ * @param y location
+ * @return conentration at location (x,y,z=0)
+ */
+ private double concn(int x, int y)
+ {
+ return biofilm.environment.getSoluteGrid(sol).
+ getValueAt(ArrayType.CONCN, new double[] {x,y,0});
+ }
+ /**
+ * calculate concentration profile based on symbolic solution 1D first order
+ * reaction diffusion.
+ *
+ * @param y location
+ * @param k reaction constant
+ * @param b height of upper boundary
+ * @param bc concentration at upper boundary
+ * @return concentration at location y
+ */
+ private double concnFirstOrder(double y, double k, double b, double bc)
+ {
+ return ( bc * Math.exp( -Math.sqrt(k) * ( y - b ) ) *
+ ( Math.exp( 2 * Math.sqrt(k) * y ) + 1 ) ) /
+ ( 1 + Math.exp( 2 * b * Math.sqrt( k ) ) );
+ }
+ /**
+ * Calculate concentration profile based on simple 1D diffusion model.
+ *
+ * @param y location
+ * @param b starting height
+ * @param bc concentration at starting height
+ * @param t top height
+ * @param tc concentration at top height
+ * @return concentration at location y
+ */
+ private double concnDiff(double y, double b, double bc, double t, double tc)
+ {
+ return ( (tc-bc)*y + (bc*t - tc*b) ) / ( t-b );
+ }
+}
diff --git a/src/test/junit/newTests/ReactionDiffusionMgFasDistributedZeroBoundry.java b/src/test/junit/newTests/ReactionDiffusionMgFasDistributedZeroBoundry.java
new file mode 100644
index 000000000..9c86a595f
--- /dev/null
+++ b/src/test/junit/newTests/ReactionDiffusionMgFasDistributedZeroBoundry.java
@@ -0,0 +1,171 @@
+package test.junit.newTests;
+
+import boundary.Boundary;
+import boundary.WellMixedBoundary;
+import compartment.Compartment;
+import dataIO.Log;
+import dataIO.Log.Tier;
+import debugTools.Testable;
+import debugTools.Tester;
+import grid.ArrayType;
+import idynomics.Idynomics;
+import org.junit.Test;
+
+public class ReactionDiffusionMgFasDistributedZeroBoundry implements Testable {
+
+ String sol = "glucose";
+ Compartment chemostat = null;
+ Compartment biofilm = null;
+
+ @Test
+ public void test()
+ {
+ test(TestMode.UNIT);
+ }
+
+ public void test(TestMode mode)
+ {
+ String file = "protocol/unit-tests/reaction_diffusion_smooth_distribution_0_boundry.xml";
+
+ /* basic simulator initiation */
+ Log.set(Tier.CRITICAL);
+ Idynomics.setupSimulator(file);
+ Log.set(Tier.CRITICAL);
+
+ Tester.println("reaction diffusion test", mode);
+ chemostat = Idynomics.simulator.getCompartment("chemostat");
+ biofilm = Idynomics.simulator.getCompartment("biofilm");
+
+// /* set height of the biofilm and the diffusion boundary layer */
+// int hBiofilm = 16, hDBL = hBiofilm+20, x=0;
+// /* max accepted Mean absolute relative error. As it is quite difficult
+// * to get to precisely line-out the biofilm height with the grid and to
+// * get a precise packing density typically 15% would be a good result */
+// double acceptedMRE = 0.15;
+// /* polling frequency, set equal to the grid resolution (or a multitude),
+// * does not go below 1 */
+// int polling = 2;
+
+ /* collect some values from the compartment to make life a bit easier
+ * when testing different settings */
+ double bLayer= 0.0;
+ for(Boundary b : biofilm.getShape().getAllBoundaries())
+ if(b instanceof WellMixedBoundary)
+ bLayer = ((WellMixedBoundary) b).getLayerThickness();
+
+ double[] vLength = new double[3];
+ biofilm.getShape().getVoxelSideLengthsTo(vLength, new int[3]);
+
+ /* set height of the biofilm and the diffusion boundary layer */
+ int hBiofilm = 31, hDBL = (int) (hBiofilm+bLayer), x=0;
+ /* packing density of catalyst *cylinders* */
+ double pakcing = 0.5/(2.0*2.0);
+ /* max accepted Mean absolute relative error. As it is quite difficult
+ * to get to precisely line-out the biofilm height with the grid and to
+ * get a precise packing density typically 15% would be a good result */
+ double acceptedMRE = 0.025;
+ /* polling frequency, set equal to the grid resolution (or a multitude),
+ * does not go below 1 */
+ int polling = Math.max((int)vLength[0], 1);
+
+ /* setting up internally used variables */
+ double solver, model, error;
+ double mre1 = 0, mre2 = 0;
+ int e5 = 0, e10 = 0, e20 = 0;
+ int i=0;
+ boolean nodesystem = true;
+
+ Idynomics.simulator.initialRun();
+
+ while ( Idynomics.simulator.timer.isRunning() )
+ {
+ i++;
+ Idynomics.simulator.step();
+ if(i > 1)
+ {
+ Tester.println( "Solver \t\t\t Symbolic model "
+ + "\t Relative error \t Location", mode);
+ for (int y = 0; y < hDBL+1; y++)
+ {
+ boolean poll;
+ if( nodesystem )
+ poll = ( (y%polling)-1 == 0);
+ else
+ poll = (y%polling == 0);
+ solver = concn(x ,y);
+ if(y <= hBiofilm && poll)
+ {
+ /* catalyst part */
+ model = concnFirstOrder( y, ((2.0E-02/35.0E-06)*2.63*pakcing) /
+ 36000.0, hBiofilm, 2e-6 ); // since we dont use bl here we can just write bulk 2e-6 instead of concn(x, hBiofilm)
+ error = (1-solver/model);
+ Tester.println( solver + "\t " + model + "\t " +
+ error + "\t film", mode);
+ mre1 += Math.abs(error);
+ if(Math.abs(error) > 0.05)
+ e5++;
+ if(Math.abs(error) > 0.10)
+ e10++;
+ if(Math.abs(error) > 0.20)
+ e20++;
+ }
+ }
+ }
+ }
+ mre1 /= hBiofilm/polling;
+ mre2 /= (hDBL-hBiofilm)/polling;
+
+ /* amount of times the relative error exceeds .05, .10 and .20 */
+ Tester.println("\n", mode);
+ Tester.println("#n |Relative error| > .05 = " + e5 , mode);
+ Tester.println("#n |Relative error| > .10 = " + e10 , mode);
+ Tester.println("#n |Relative error| > .20 = " + e20 , mode);
+
+ /* Unit test: are the MREs close to 0? */
+ Tester.println("\n", mode);
+ Tester.assess(0.0, mre1, acceptedMRE , mode,
+ "Mean Relative error biofilm " + (float)mre1 + " < " + acceptedMRE);
+ }
+ /**
+ * Poll concentration in biofilm compartment.
+ *
+ * @param x location
+ * @param y location
+ * @return conentration at location (x,y,z=0)
+ */
+ private double concn(int x, int y)
+ {
+ return biofilm.environment.getSoluteGrid(sol).
+ getValueAt(ArrayType.CONCN, new double[] {x,y,0});
+ }
+ /**
+ * calculate concentration profile based on symbolic solution 1D first order
+ * reaction diffusion.
+ *
+ * @param y location
+ * @param k reaction constant
+ * @param b height of upper boundary
+ * @param bc concentration at upper boundary
+ * @return concentration at location y
+ */
+ private double concnFirstOrder(double y, double k, double b, double bc)
+ {
+ return ( bc * Math.exp( -Math.sqrt(k) * ( y - b ) ) *
+ ( Math.exp( 2 * Math.sqrt(k) * y ) + 1 ) ) /
+ ( 1 + Math.exp( 2 * b * Math.sqrt( k ) ) );
+ }
+ /**
+ * Calculate concentration profile based on simple 1D diffusion model.
+ *
+ * @param y location
+ * @param b starting height
+ * @param bc concentration at starting height
+ * @param t top height
+ * @param tc concentration at top height
+ * @return concentration at location y
+ */
+ private double concnDiff(double y, double b, double bc, double t, double tc)
+ {
+ return ( (tc-bc)*y + (bc*t - tc*b) ) / ( t-b );
+ }
+}
diff --git a/src/test/junit/newTests/ReactionDiffusionMgFasEcoli.java b/src/test/junit/newTests/ReactionDiffusionMgFasEcoli.java
new file mode 100644
index 000000000..6f1110308
--- /dev/null
+++ b/src/test/junit/newTests/ReactionDiffusionMgFasEcoli.java
@@ -0,0 +1,193 @@
+package test.junit.newTests;
+
+import boundary.Boundary;
+import boundary.WellMixedBoundary;
+import compartment.Compartment;
+import dataIO.Log;
+import dataIO.Log.Tier;
+import debugTools.Testable;
+import debugTools.Tester;
+import grid.ArrayType;
+import idynomics.Idynomics;
+import org.junit.Test;
+
+public class ReactionDiffusionMgFasEcoli implements Testable {
+
+ String sol = "glucose";
+ Compartment chemostat = null;
+ Compartment biofilm = null;
+
+ @Test
+ public void test()
+ {
+ test(TestMode.UNIT);
+ }
+
+ public void test(TestMode mode)
+ {
+ String file = "protocol/unit-tests/reaction_diffusion_mgFas_ecoli.xml";
+// String file = "protocol/unit-tests/reaction_diffusion_Large.xml";
+
+ /* basic simulator initiation */
+ Log.set(Tier.CRITICAL);
+ Idynomics.setupSimulator(file);
+ Log.set(Tier.CRITICAL);
+
+ Tester.println("reaction diffusion test", mode);
+ chemostat = Idynomics.simulator.getCompartment("chemostat");
+ biofilm = Idynomics.simulator.getCompartment("biofilm");
+
+// /* set height of the biofilm and the diffusion boundary layer */
+// int hBiofilm = 16, hDBL = hBiofilm+20, x=0;
+// /* max accepted Mean absolute relative error. As it is quite difficult
+// * to get to precisely line-out the biofilm height with the grid and to
+// * get a precise packing density typically 15% would be a good result */
+// double acceptedMRE = 0.15;
+// /* polling frequency, set equal to the grid resolution (or a multitude),
+// * does not go below 1 */
+// int polling = 2;
+
+ /* collect some values from the compartment to make life a bit easier
+ * when testing different settings */
+ double bLayer= 0.0;
+ for(Boundary b : biofilm.getShape().getAllBoundaries())
+ if(b instanceof WellMixedBoundary)
+ bLayer = ((WellMixedBoundary) b).getLayerThickness();
+
+ double[] vLength = new double[3];
+ biofilm.getShape().getVoxelSideLengthsTo(vLength, new int[3]);
+
+ /* set height of the biofilm and the diffusion boundary layer */
+ int hBiofilm = 10, hDBL = (int) (hBiofilm+bLayer), x=0;
+ /* packing density of catalyst *cylinders* */
+ double pakcing = 0.75;
+ /* max accepted Mean absolute relative error. As it is quite difficult
+ * to get to precisely line-out the biofilm height with the grid and to
+ * get a precise packing density typically 15% would be a good result */
+ double acceptedMRE = 0.15;
+ /* polling frequency, set equal to the grid resolution (or a multitude),
+ * does not go below 1 */
+ int polling = Math.max((int)vLength[0], 1);
+
+ /* setting up internally used variables */
+ double solver, model, error;
+ double mre1 = 0, mre2 = 0;
+ int e5 = 0, e10 = 0, e20 = 0;
+ int i=0;
+
+ Idynomics.simulator.initialRun();
+
+ while ( Idynomics.simulator.timer.isRunning() )
+ {
+ i++;
+ Idynomics.simulator.step();
+ if(i > 1)
+ {
+ Tester.println( "Solver \t\t\t Symbolic model "
+ + "\t Relative error \t Location", mode);
+ for (int y = 0; y < hDBL+1; y++)
+ {
+ boolean poll = ( y%polling == 0);
+ solver = concn(x ,y);
+ if(y <= hBiofilm && poll)
+ {
+ /* catalyst part */
+ model = concnFirstOrder( y, ((2.0E-02/35.0E-06)*2.63*0.15*pakcing) /
+ 36000.0, hBiofilm, concn(x, hBiofilm) );
+ error = (1-solver/model);
+ Tester.println( solver + "\t " + model + "\t " +
+ error + "\t film", mode);
+ mre1 += Math.abs(error);
+ if(Math.abs(error) > 0.05)
+ e5++;
+ if(Math.abs(error) > 0.10)
+ e10++;
+ if(Math.abs(error) > 0.20)
+ e20++;
+ }
+ else if(y > hBiofilm && y <= hDBL && poll)
+ {
+ /* diffusion boundary layer */
+ model = concnDiff(y, hBiofilm, concn(x, hBiofilm),
+ hDBL, concn(x, hDBL));
+ error = (1-solver/model);
+ Tester.println( solver + "\t " + model + "\t " +
+ error + "\t DBL", mode);
+ mre2 += Math.abs(error);
+ if(Math.abs(error) > 0.05)
+ e5++;
+ if(Math.abs(error) > 0.10)
+ e10++;
+ if(Math.abs(error) > 0.20)
+ e20++;
+ }
+ }
+ }
+ }
+ mre1 /= hBiofilm/polling;
+ mre2 /= (hDBL-hBiofilm)/polling;
+
+ System.out.println(
+ "max accepted Mean absolute relative error. As it is quite difficult\n" +
+ "to get to precisely line-out the biofilm height with the grid and to\n" +
+ "get a precise packing density typically 15% would be a good result."
+ );
+
+ /* amount of times the relative error exceeds .05, .10 and .20 */
+ Tester.println("\n", mode);
+ Tester.println("#n |Relative error| > .05 = " + e5 , mode);
+ Tester.println("#n |Relative error| > .10 = " + e10 , mode);
+ Tester.println("#n |Relative error| > .20 = " + e20 , mode);
+
+ /* Unit test: are the MREs close to 0? */
+ Tester.println("\n", mode);
+ Tester.assess(0.0, mre1, acceptedMRE , mode,
+ "Mean Relative error biofilm < " + acceptedMRE);
+ Tester.assess(0.0, mre2, acceptedMRE , mode,
+ "Mean Relative error diffusion boundary layer < " +acceptedMRE);
+ Tester.assess(0.0, (mre1+mre2)/2, acceptedMRE , mode,
+ "Mean Relative error overall < " + acceptedMRE);
+ }
+ /**
+ * Poll concentration in biofilm compartment.
+ *
+ * @param x location
+ * @param y location
+ * @return conentration at location (x,y,z=0)
+ */
+ private double concn(int x, int y)
+ {
+ return biofilm.environment.getSoluteGrid(sol).
+ getValueAt(ArrayType.CONCN, new double[] {x,y,0});
+ }
+ /**
+ * calculate concentration profile based on symbolic solution 1D first order
+ * reaction diffusion.
+ *
+ * @param y location
+ * @param k reaction constant
+ * @param b height of upper boundary
+ * @param bc concentration at upper boundary
+ * @return concentration at location y
+ */
+ private double concnFirstOrder(double y, double k, double b, double bc)
+ {
+ return ( bc * Math.exp( -Math.sqrt(k) * ( y - b ) ) *
+ ( Math.exp( 2 * Math.sqrt(k) * y ) + 1 ) ) /
+ ( 1 + Math.exp( 2 * b * Math.sqrt( k ) ) );
+ }
+ /**
+ * Calculate concentration profile based on simple 1D diffusion model.
+ *
+ * @param y location
+ * @param b starting height
+ * @param bc concentration at starting height
+ * @param t top height
+ * @param tc concentration at top height
+ * @return concentration at location y
+ */
+ private double concnDiff(double y, double b, double bc, double t, double tc)
+ {
+ return ( (tc-bc)*y + (bc*t - tc*b) ) / ( t-b );
+ }
+}
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);
}
diff --git a/src/utility/Helper.java b/src/utility/Helper.java
index e855cff11..d8b62675c 100644
--- a/src/utility/Helper.java
+++ b/src/utility/Helper.java
@@ -736,6 +736,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)