.. _PhysiCell_java_CancerImmune_ImmuneCellRule_java: ImmuneCellRule.java =================== .. role:: raw-html(raw) :format: html .. raw:: html .. code-block:: console import ru.biosoft.physicell.biofvm.VectorUtil; import ru.biosoft.physicell.core.Cell; import ru.biosoft.physicell.core.CellFunctions.CustomCellRule; import ru.biosoft.physicell.core.Model; import ru.biosoft.physicell.core.Phenotype; import ru.biosoft.physicell.core.RandomGenerator; public class ImmuneCellRule extends CustomCellRule { private RandomGenerator rng; public ImmuneCellRule(Model model) { rng = model.getRNG(); } public void execute(Cell pCell, Phenotype phenotype, double dt) { int attach_lifetime_i = pCell.customData.findVariableIndex( "attachment_lifetime" ); if( phenotype.death.dead == true ) { // the cell death functions don't automatically turn off custom functions, since those are part of mechanics. // Let's just fully disable now. pCell.functions.customCellRule = null; return; } // if I'm docked if( pCell.state.numberAttachedCells() > 0 ) { // attempt to kill my attached cell Cell attached = pCell.state.attachedCells.iterator().next();///[0]; boolean detachMe = false; if( attemptApoptosis( pCell, attached, dt ) ) { triggerApoptosis( pCell, attached ); detachMe = true; } // decide whether to detach if( rng.checkRandom( dt / ( pCell.customData.get( attach_lifetime_i ) + 1e-15 ) ) ) detachMe = true; // if I dettach, resume motile behavior if( detachMe ) { Cell.detachCells( pCell, attached ); phenotype.motility.isMotile = true; } return; } // I'm not docked, look for cells nearby and try to docked if this returns non-NULL, we're now attached to a cell if( checkNeighborsForAttachment( pCell, dt ) != null ) { phenotype.motility.isMotile = false; return; } phenotype.motility.isMotile = true; } static boolean triggerApoptosis(Cell pAttacker, Cell pTarget) { if( pTarget.phenotype.death.dead ) return false; pTarget.startDeath( pTarget.phenotype.death.findDeathModelIndex( "apoptosis" ) ); return true; } boolean attemptApoptosis(Cell pAttacker, Cell pTarget, double dt) { int oncoproteinIndex = pTarget.customData.findVariableIndex( "oncoprotein" ); int killRateIndex = pAttacker.customData.findVariableIndex( "kill_rate" ); double oncoproteinSaturation = pAttacker.customData.get( "oncoprotein_saturation" ); // 2.0; double oncoproteinThreshold = pAttacker.customData.get( "oncoprotein_threshold" ); // 0.5; // 0.1; double oncoproteinDifference = oncoproteinSaturation - oncoproteinThreshold; double targetOconoprotein = pTarget.customData.get( oncoproteinIndex ); if( targetOconoprotein < oncoproteinThreshold ) return false; double scale = ( targetOconoprotein - oncoproteinThreshold ) / oncoproteinDifference; scale = Math.min( scale, 1.0 ); if( rng.checkRandom( pAttacker.customData.get( killRateIndex ) * scale * dt ) ) return true; return false; } public Cell checkNeighborsForAttachment(Cell pAttacker, double dt) { for( Cell nearbyCell : pAttacker.cells_in_my_container() ) { if( nearbyCell != pAttacker )// don't try to kill yourself { if( attemptAttachment( pAttacker, nearbyCell, dt ) ) return nearbyCell; } } return null; } boolean attemptAttachment(Cell pAttacker, Cell pTarget, double dt) { double oncoprotein_saturation = pAttacker.customData.get( "oncoprotein_saturation" ); double oncoprotein_threshold = pAttacker.customData.get( "oncoprotein_threshold" ); double maxAttachmentDistance = pAttacker.customData.get( "max_attachment_distance" ); double minAttachmentDistance = pAttacker.customData.get( "min_attachment_distance" ); double targetOncoprotein = pTarget.customData.get( "oncoprotein" ); if( targetOncoprotein > oncoprotein_threshold && !pTarget.phenotype.death.dead ) { double distance = VectorUtil.dist( pTarget.position, pAttacker.position ); if( distance > maxAttachmentDistance ) return false; double attachRate = pAttacker.customData.get( "attachment_rate" ); double scale = ( targetOncoprotein - oncoprotein_threshold ) / ( oncoprotein_saturation - oncoprotein_threshold ); double distanceScale = ( maxAttachmentDistance - distance ) / ( maxAttachmentDistance - minAttachmentDistance ); attachRate *= Math.min( scale, 1.0 ) * Math.min( distanceScale, 1.0 ); if( rng.checkRandom( attachRate * dt ) ) Cell.attachcCells( pAttacker, pTarget ); return true;//TODO: should we return true only if attached successfully? } return false; } }