/** * \brief Select random coordinates for the new agent within a restricted birth area * * <p>Select random coordinates for the new agent within a restricted birth area. This restricted * area is set within the protocol file, and defined as a ContinuousVector by the method * defineSquareArea * * @param cc ContinuousVector that will hold the coordinates of this agent * @param area Area within which these coordinates should be restricted */ public void shuffleCoordinates(ContinuousVector cc, ContinuousVector[] area) { do { cc.x = ExtraMath.getUniRandDbl(area[0].x, area[1].x); cc.y = ExtraMath.getUniRandDbl(area[0].y, area[1].y); cc.z = ExtraMath.getUniRandDbl(area[0].z, area[1].z); } while (domain.testCrossedBoundary(cc) != null); }
/** * \brief For self-attach scenarios, corrects 3D coordinates that have crossed the front or back * boundary (x0y and xNy) * * <p>For self-attach scenarios, corrects 3D coordinates that have crossed the front or back * boundary (x0y and xNy). The coordinate is either placed on the opposite side for cyclic * boundaries, or bounces off the boundary at the required angle * * @param boundaryCrossed The boundary that has been detected to have been crossed * @param distanceMoving The distance that the cell is moving in this step of its repositioning */ public void correctCrossedFrontBackBoundaries(AllBC boundaryCrossed) { // Cell has passed through the boundary on the front or back of the grid // If is cyclic, the point is deemed to reappear at the opposite side if (boundaryCrossed instanceof BoundaryCyclic) { // This will be inside the grid at the amount that the move would // have taken the point outside of the grid. swimmingAgentPosition.z = swimmingAgentPosition.z % domain.length_Z; } else { // Can simply take the correct value of the new Z coordinate and // reflect it the correct side of the boundary. swimmingAgentPosition.z = -swimmingAgentPosition.z % domain.length_Z; // Now we need to change the angle to note the change of direction angleOfMovingAgentXZ = 2 * Math.PI - angleOfMovingAgentXZ; } }
/** * \brief Determine if a swimming agent has left the boundary layer and returned to the bulk * * <p>For self attachment, an agent starts at the top of the boundary layer and swims in a random * direction until it attaches somewhere. If however it returns to the bulk, we assume this cell * does not return. This method checks the move to determine if the cell is moving in a trajectory * that has returned it to the bulk * * @return Boolean stating whether the cell has returned to the bulk */ public boolean isNewCoordAboveBoundaryLayer() { // Get the top of the bulk - note we may need to correct here. The // method that calls this calculates new positions. However this is run // before it is determined whether any boundaries have been crossed (as // it would be silly to check all boundaries when there is a high // chance, especially at the start, that the cell may return into the // bulk. Thus, a high Y or Z value may be sent in here, which when // referenced to the boundary layer array, will cause an error. So if // the Y or Z values are higher than the size of the grid, we will use // the size of the grid as the array reference if (swimmingAgentPosition.y > domain.length_Y) swimmingAgentPosition.y = domain.length_Y - 1; if (swimmingAgentPosition.z > domain.length_Z) swimmingAgentPosition.z = domain.length_Z - 1; // System.out.println("Checking if "+swimmingAgentPosition.toString()+" above boundary layer"); // Now calculate the top of the boundary layer at the y, z coordinate. int j = (int) (swimmingAgentPosition.y / domain._resolution); int k = (int) (swimmingAgentPosition.z / domain._resolution); double boundaryAtThisPoint = domain._topOfBoundaryLayer[j + 1][k + 1]; boundaryAtThisPoint *= domain._resolution; // System.out.println("..."+(swimmingAgentPosition.x > boundaryAtThisPoint)); // Check if we are above it return (swimmingAgentPosition.x > boundaryAtThisPoint); }
/** * \brief For self-attachment scenarios, initialises agents on the boundary layer rather than * substrarum, and models their swim to the surface or biofilm * * <p>For self-attachment scenarios, the agents are initialised at the top of the boundary layer * rather than on the substratum. These agents then perform a 'run and tumble' motion until they * either attach to the substratum or forming biofilm. This method captures this behaviour for * cells that are created for a time step. Once this swimming action has been performed, the agent * is created at its final position. Note that input of agents onto the boundary layer is decided * by a parameter set in the protocol file, cellAttachmentFrequency, measured in hours. The number * of cells is adjusted to suit the global time step that is being used. Also note that this * injection of cells can be for a set period (specified in the protocol file as parameter * cellInjectionPeriod), or can be stopped and started (modelling a 'settling' period) using * parameters cellInjectionOffPeriod and cellInjectionStopHour. This is explained in detail in the * tutorial for version 1.2 of iDynoMiCS. * * @param spRoot The Species markup from the protocol file for one particular species being * initialised * @param numberAttachedInjectedAgents The number of agents of this type that need to be created * in this global timestep */ public void createBoundaryLayerPop(XMLParser spRoot, int numberAttachedInjectedAgents) { LogFile.writeLog( "\t\tAttempting to create " + numberAttachedInjectedAgents + " agents of " + speciesName + " in the boundary layer"); // Create all the required agents // Note that this continues UNTIL THE DESIRED NUMBER OF CELLS HAVE ATTACHED SOMEWHERE // Just out of interest, I've decided to keep a count of how many cells are required for this to // happen int totalNumberOfInjectedAgents = 0; int agentsReturnedToBulk = 0; int requiredNumAttachedAgents = numberAttachedInjectedAgents; // Temporary DiscreteVector to make finding the boundary layer tidier. DiscreteVector dV = new DiscreteVector(); while (numberAttachedInjectedAgents > 0) { totalNumberOfInjectedAgents++; if (_progenitor instanceof LocatedAgent) { swimmingAgentPosition.reset(); // Now to choose coordinates for this particular agent while (true) { // This cell needs to take a random location in the Z and Y // directions. The X will come from the position of the // boundary layer on those axes. Generate these randomly. swimmingAgentPosition.y = ExtraMath.getUniRandDbl() * domain.length_Y; if (domain.is3D) { swimmingAgentPosition.z = ExtraMath.getUniRandDbl() * domain.length_Z; } // Now to work out the X coordinate. This is based on where // the top of the boundary layer is when this agent is // created. The top of the boundary layer is calculated in // Domain at each step. Now the resolution differs (this is // in nI x nJ x nK rather than microns - so this will need // to be converted accordingly. Method to calculate this: // - get the value from the top of the boundary layer // - reduce by 1 (such that the micron value will be the // top of the layer) // - multiply by resolution of this domain. dV.set(swimmingAgentPosition, domain._resolution); if (!domain.is3D) dV.k = 1; swimmingAgentPosition.x = domain._topOfBoundaryLayer[dV.j][dV.k] - 1.0; swimmingAgentPosition.x *= domain._resolution; // Check this is ok. // System.out.println("Trying starting position "+dV.toString()+" => // "+this.swimmingAgentPosition.toString()); if (domain.testCrossedBoundary(swimmingAgentPosition) == null) break; } // Now we can do the run and tumble motion of these cells int cellRunResult = performRunAndTumble(spRoot); // If increment the relevant counters, as these may be useful switch (cellRunResult) { case 1: // Successfully Attached numberAttachedInjectedAgents--; // Create the agent at these coordinates ((LocatedAgent) _progenitor).createNewAgent(this.swimmingAgentPosition); // System.out.println("Cell "+swimmingAgentPosition.toString()+" attached"); break; case 2: // System.out.println("Cell at "+swimmingAgentPosition.toString()+" returned to bulk"); agentsReturnedToBulk++; break; } } else { // If this isn't a located species, just create a new agent. _progenitor.createNewAgent(); } } // Write the stats to the log file incase of interest LogFile.writeLog( requiredNumAttachedAgents + " agents of species " + speciesName + " for self-attachment successfully created"); LogFile.writeLog( totalNumberOfInjectedAgents + " agents of species " + speciesName + " attempted to attach"); LogFile.writeLog( agentsReturnedToBulk + " agents of species " + speciesName + " returned to the bulk"); }