Repository navigation
Conversation
…degrees in line with experimental data
…division axis is rotating, defaults to apical axis but can be previous division instead
…t to move according to user specification
…oliferationModule and reference it instead of cell-specific critical volume for growth regulation math
…ns with deterministic division always yield a NB and a GMC
kristaphommatha
left a comment
There was a problem hiding this comment.
Look great so far! I looked over all the files except for the proliferation module and proliferation module tests, and had a couple of points of confusion for the files I did review!
I'll plan to come back and review the proliferation module and tests within the next couple of days! 🫡
| import arcade.core.util.MiniBox; | ||
| import arcade.core.util.Parameters; | ||
| import arcade.potts.util.PottsEnums.Phase; | ||
| import arcade.potts.util.PottsEnums.Region; |
There was a problem hiding this comment.
I see right below these lines there is the exact same import, except static. Why were these non-static imports added/ what is the difference between the static/non-static imports?
| case "fly-stem-wt": | ||
| return new PottsCellFlyStem(this, location, parameters, links); | ||
| case "fly-stem-mudmut": | ||
| return new PottsCellFlyStem(this, location, parameters, links); |
There was a problem hiding this comment.
I know that in the PottsCellFlyStem constructor, mudmut and wt cells have a different stemType code that differentiates them. This comment might be nitpicky, but without that context, this implementation could be confusing because it looks like both cases act the exact same way.
Is there a way to specify in the constructor call that you are creating a mudmut or wt cell?
| PottsCellContainer container, Location location, Parameters parameters, GrabBag links) { | ||
| super(container, location, parameters, links); | ||
|
|
||
| if (module != null) { |
There was a problem hiding this comment.
What is the reasoning behind this check?
From the setStateModule method, I assume that the only module that isn't null is proliferation. I'm just curious about why is it important that the state is undefined instead of proliferative?
| PottsCellContainer container = | ||
| new PottsCellContainer( | ||
| randomIntBetween(1, 10), | ||
| randomIntBetween(1, 10), |
There was a problem hiding this comment.
This might be really nitpicky and not even matter, but would there be any unexpected behavior if cellID and the parentID were the same?
|
|
||
| int cellPop = randomIntBetween(1, 10); | ||
| MiniBox parameters = new MiniBox(); | ||
| parameters.put("CLASS", "fly-stem-mudmut"); |
There was a problem hiding this comment.
I feel like because of the way the PottsCellFlyStem constructor is implemented, this test and the one above are virtually the same.
I'm not sure if you need both tests here if the class difference between fly-stem-wt and fly-stem-mudmut is tested already in the constructor_validWTStemType_createsInstance() and constructor_validMUDMUTStemType_createsInstance() tests under PottsCellFlyStemTest. I could be wrong though and would love to talk about this more
| PottsCellContainer container = | ||
| cell.make(cellID, State.PROLIFERATIVE, random, cellPop, cellCriticalVolume); | ||
|
|
||
| assertAll( |
There was a problem hiding this comment.
Would make on fly-stem-mudmut and fly-stem-wt cells create containers with the exact same parameters?
…olumes (instead of each inheriting its own
kristaphommatha
left a comment
There was a problem hiding this comment.
Left some comments on PottsModuleFlyStemProliferation! I still need to look over the tests, though!
| import arcade.potts.util.PottsEnums.Direction; | ||
| import arcade.potts.util.PottsEnums.Phase; | ||
| import arcade.potts.util.PottsEnums.State; | ||
| import static arcade.potts.util.PottsEnums.Direction; |
There was a problem hiding this comment.
Same question as another comment I made, but is there a reason both static arcade.potts.util.PottsEnums.Direction and arcade.potts.util.PottsEnums.Direction are imported? What is the difference between importing static vs. non-static?
| * Ruleset for determining which daughter cell is the GMC. Can be `smaller_gmc`, `basal_gmc`, | ||
| * `random`, or `apical_gmc`. | ||
| */ | ||
| final String differentiationRuleset; |
There was a problem hiding this comment.
Would it be worth making differentiationRuleset,apicalAxisRuleset, apicalAxisRotationDistribution, and divRotationReference enum variables to make it more clear that they can only be specific values?
| } | ||
|
|
||
| /** | ||
| * Chooses the division plane according to the type of stem cell this module is attached to. |
There was a problem hiding this comment.
I think this doc could be a little more specific. When I read "according to the type of stem cell this module is attached to", I didn't know what was meant by "type"-- I thought this meant there were other stem cell types but was confused when the parameter only specified a flyStemCell. Maybe you could write that it chooses the dvisision plane depending on if the fly stem cell is WT or MUDMUT?
| int newID = sim.getID(); | ||
| double daughterCriticalVol; | ||
| if (volumeBasedCriticalVolume) { | ||
| double floor = populationCriticalVolume * .20; |
There was a problem hiding this comment.
Why specifically set the floor at 20% of populationCriticalVolume? Will there ever be a future use case where someone would want to modify this percentage?
|
|
||
| /** | ||
| * Determines whether the daughter cell should be a neuroblast or a GMC according to the | ||
| * orientation. This is deterministic. |
There was a problem hiding this comment.
| * orientation. This is deterministic. | |
| * orientation of the division plane. This is deterministic. |
There was a problem hiding this comment.
Alternatively:
| * orientation. This is deterministic. | |
| * orientation of the apical axis. This is deterministic. |
| /** | ||
| * Updates the neuroblast (NB) contact-dependent growth rate. | ||
| * | ||
| * <p>Growth is repressed as a function of NB contact using a Hill function. The number of |
There was a problem hiding this comment.
I think this would be more straightforward if the function was explicitly written out in the javadoc!
| double offset = sampleDivisionPlaneOffset(); | ||
|
|
||
| if (flyStemCell.getStemType() == StemType.WT | ||
| || (flyStemCell.getStemType() == StemType.MUDMUT |
There was a problem hiding this comment.
Aren't the only StemTypes for a flyStemCell WT and MUDMUT? Is this logic in place for if we add a different StemType in the future? Otherwise this will always be true
| centroid1, centroid2, ((PottsCellFlyStem) cell).getApicalAxis(), range)); | ||
| } | ||
| } | ||
| throw new IllegalArgumentException( |
There was a problem hiding this comment.
Shouldn't this be inside the else if statement? As is, this can run if the cell is neither a WT or MUDMUT, but this is not reflected in the exception message.
| } | ||
|
|
||
| /** | ||
| * Gets the smaller location with fewer voxels and returns it. |
There was a problem hiding this comment.
Maybe add that if the two locations are the same size, then expected behavior is to return the second location?
| } | ||
|
|
||
| /** | ||
| * Gets the location that is lower along the apical axis. |
There was a problem hiding this comment.
I don't quite understand what is meant by "lower" here
| protected HashSet<PottsCellFlyStem> getNBNeighbors(Simulation sim) { | ||
| Potts potts = ((PottsSimulation) sim).getPotts(); | ||
| ArrayList<Voxel> voxels = ((PottsLocation) cell.getLocation()).getVoxels(); | ||
| HashSet<PottsCellFlyStem> stemNeighbors = new HashSet<PottsCellFlyStem>(); |
There was a problem hiding this comment.
HashSets as a data structure should only keep unique objects as a default behavior so I don't think it makes sense to manually keep track of unique IDs (lines 327-332, and the uniqueIDs function) when adding to the set.
Currently nothing overrides the default equals() method in the core Cell class. Unless it is possible reassign cellIDs to the same cell object after initiating the object, cells with different cellIDs should already register as unique objects if you drop it in the HashSet.
If you are worried about cellIDs being reassigned at some point, I think it makes more sense to overwrite the equals() function to compare on cellIDs instead.
As is, I think you can just loop through the neighbors (not counting itself), check if they are the same population ID, and throw it into the hashset. The hashset should take care of the unique cells for you.
| int nbsInContact; | ||
| nbsInContact = getNBNeighbors(sim).size(); | ||
|
|
||
| double neighborSignal = Math.max(0.0, (double) nbsInContact); |
There was a problem hiding this comment.
could nbsInContact be negative?
| * @return whether or not the daughter cell should be a stem cell | ||
| */ | ||
| private boolean daughterStemRuleBasedDifferentiation(PottsLocation loc1, PottsLocation loc2) { | ||
| if (((PottsCellFlyStem) cell).getStemType() == StemType.WT) { |
There was a problem hiding this comment.
Would consider changing this to a switch statement if we anticipate adding more stem types into the model.
Overall the double nested if/else statement is a little difficult to parse through, would consider simplifying with switch statements if we want to be explicit, or just using 'else' if there are only 2 options and we don't anticipate adding more
| * @param range Maximum allowed distance along the apical axis. | ||
| * @return true if the centroids are within the given range along the apical axis. | ||
| */ | ||
| static boolean centroidsWithinRangeAlongApicalAxis( |
There was a problem hiding this comment.
Super nitpicky so feel free to ignore:
At first glance at the method name I thought it was returning a list of centroids rather than a boolean and got a little confused. Maybe 'centroidsAreWithinRange..."?
| Direction.XY_PLANE.vector, | ||
| StemType.MUDMUT.splitDirectionRotation); | ||
| // If TRUE, the daughter should be stem. Otherwise, should be GMC | ||
| return Math.abs(normalVector.getX() - expectedMUDNormalVector.getX()) <= EPSILON |
There was a problem hiding this comment.
It might just be me but I got a little lost in the sauce with this return statement. It might be worth adding a comment explaining why we are comparing each coordinate to a margin of error?
| int newID = sim.getID(); | ||
| double daughterCriticalVol; | ||
| if (volumeBasedCriticalVolume) { | ||
| double floor = populationCriticalVolume * .20; |
There was a problem hiding this comment.
Might be worth making this 20% a global static constant so its explicit what it is
| * @param potts the potts instance for this simulation | ||
| * @param random the random number generator | ||
| */ | ||
| private void scheduleNewCell( |
There was a problem hiding this comment.
In the other proliferation modules (for both potts and patch), I've seen the pattern to be:
addCell( ){
// find available location
// reset current cell
// create new cell through make()
// register + schedule new cell
}
Is there a reason why you chose to make a separate function for schedule, and call schedule inside the make functions instead of putting everything in addCell?
| case "global": | ||
| return ((PottsCellFlyStem) cell).getApicalAxis(); | ||
| case "normal": | ||
| if (!(apicalAxisRotationDistribution instanceof NormalDistribution)) { |
There was a problem hiding this comment.
I think you also check for this in like 702 - can we just check for this once outside of the switch statement?
| protected double calculateGMCDaughterCellCriticalVolume(PottsLocation gmcLoc) { | ||
| double criticalVol; | ||
| if (volumeBasedCriticalVolume) { | ||
| criticalVol = Math.max(gmcLoc.getVolume(), initialSize * .1); |
There was a problem hiding this comment.
Same comment as above with the .2 -> consider making this a global constant to be explicit abt what the .2/.1 represents
| * @param loc2 {@link PottsLocation} to compare to location1. | ||
| * @return the smaller location. | ||
| */ | ||
| public static PottsLocation getSmallerLocation(PottsLocation loc1, PottsLocation loc2) { |
There was a problem hiding this comment.
We should move this to the utils or maybe the grid/location class?
I don't think it makes sense to call this static function on the fly cells class since the purpose seems to be on the grid level, and not specific to flystemcells.
| * @param apicalAxis Unit {@link Vector} defining the apical-basal direction. | ||
| * @return the basal location (lower along the apical axis). | ||
| */ | ||
| public static PottsLocation getBasalLocation( |
There was a problem hiding this comment.
I am confused on why getBasalLocation and getApicalLocation are static methods.
Do all flystemcells share the same apical axis/orientation?
There was a problem hiding this comment.
I think my confusion partly stems from the fact that the actions happening in this method are on the grid level rather than the flystemcell itself. However, the basal/apical axis is specific to the flystemcell class, so Im not sure whats the best way to resolve this.
Estimated time to review: Large (sorry)
Summary of changes:
This code adds the fly neuroblast code into the codebase. The changes include:
How to verify changes:
resolves #137
resolves #109
resolves #91
resolves #58
resolves #50