src/stats/Centroids.js

  1.  
  2.  
  3. import Stat from "./Stat.js"
  4. import PixelsByCell from "./PixelsByCell.js"
  5.  
  6. /** This Stat computes the centroid of a cell. When the cell resides on a torus, the
  7. centroid may be well outside the cell, and other stats may be preferable (e.g.
  8. {@link CentroidsWithTorusCorrection}).
  9. @example
  10. * let CPM = require( "path/to/build" )
  11. *
  12. * // Make a CPM, seed two cells, run a little, and get their centroids
  13. * let C = new CPM.CPM( [100,100], {
  14. * T:20,
  15. * torus:[false,false],
  16. * J:[[0,20],[20,10]],
  17. * V:[0,200],
  18. * LAMBDA_V:[0,2]
  19. * } )
  20. * let gm = new CPM.GridManipulator( C )
  21. * gm.seedCell(1)
  22. * gm.seedCell(1)
  23. * for( let t = 0; t < 100; t++ ){ C.timeStep() }
  24. *
  25. * C.getStat( CPM.Centroids )
  26. */
  27. class Centroids extends Stat {
  28.  
  29. /** The set model method of class CentroidsWithTorusCorrection.
  30. @param {GridBasedModel} M - the model to compute centroids on. */
  31. set model( M ){
  32. /** The model to compute centroids on.
  33. @type {GridBasedModel}*/
  34. this.M = M
  35. /* Check if the grid has a torus; if so, warn that this method may not be
  36. appropriate. */
  37. let torus = false
  38. for( let d = 0; d < this.M.ndim; d++ ){
  39. if( this.M.grid.torus[d] ){
  40. torus = true
  41. break
  42. }
  43. }
  44. if(torus){
  45. // eslint-disable-next-line no-console
  46. console.warn( "Your model grid has a torus, and the 'Centroids' stat is not compatible with torus! Consider using 'CentroidsWithTorusCorrection' instead." )
  47. }
  48. // Half the grid dimensions; if pixels with the same cellid are further apart,
  49. // we assume they are on the border of the grid and that we need to correct
  50. // their positions to compute the centroid.
  51. /** @ignore */
  52. this.halfsize = new Array( this.M.ndim).fill(0)
  53. for( let i = 0 ; i < this.M.ndim ; i ++ ){
  54. this.halfsize[i] = this.M.extents[i]/2
  55. }
  56. }
  57. /** @ignore */
  58. constructor( conf ){
  59. super(conf)
  60. }
  61. /** This method computes the centroid of a specific cell.
  62. @param {CellId} cellid the unique cell id of the cell to get centroid of.
  63. @param {CellArrayObject} cellpixels object produced by {@link PixelsByCell},
  64. with keys for each cellid
  65. and as corresponding value the pixel coordinates of their pixels.
  66. @returns {ArrayCoordinate} coordinate of the centroid.
  67. */
  68. computeCentroidOfCell( cellid, cellpixels ){
  69. //let cellpixels = this.M.getStat( PixelsByCell )
  70. const pixels = cellpixels[ cellid ]
  71. // cvec will contain the x, y, (z) coordinate of the centroid.
  72. // Loop over the dimensions to compute each element separately.
  73. let cvec = new Array(this.M.ndim).fill(0)
  74. for( let dim = 0 ; dim < this.M.ndim ; dim ++ ){
  75. let mi = 0.
  76. // Loop over the pixels;
  77. // compute mean position per dimension with online algorithm
  78. for( let j = 0 ; j < pixels.length ; j ++ ){
  79. // Check distance of current pixel to the accumulated mean in this dim.
  80. // Check if this distance is greater than half the grid size in this
  81. // dimension; if so, this indicates that the cell has moved to the
  82. // other end of the grid because of the torus. Note that this only
  83. // holds AFTER the first pixel (so for j > 0), when we actually have
  84. // an idea of where the cell is.
  85. let dx = pixels[j][dim] - mi
  86. // Update the mean with the appropriate weight.
  87. mi += dx/(j+1)
  88. }
  89. // Set the mean position in the cvec vector.
  90. cvec[dim] = mi
  91. }
  92. return cvec
  93. }
  94. /** Compute centroids for all cells on the grid.
  95. @return {CellObject} with an {@link ArrayCoordinate} of the centroid for each cell
  96. on the grid (see {@link computeCentroidOfCell}). */
  97. compute(){
  98. // Get object with arrays of pixels for each cell on the grid, and get
  99. // the array for the current cell.
  100. let cellpixels = this.M.getStat( PixelsByCell )
  101. // Create an object for the centroids. Add the centroid array for each cell.
  102. let centroids = {}
  103. for( let cid of this.M.cellIDs() ){
  104. centroids[cid] = this.computeCentroidOfCell( cid, cellpixels )
  105. }
  106. return centroids
  107. }
  108. }
  109.  
  110. export default Centroids