[docs]defassert_indication(self,attr):ind=self.indication(attr)ifindisNone:raiseIndicatorError(f"No configuration indicators found for the {attr}"f" of '{self._cell_type.name}' in '{self._strat.name}'")returnind
[docs]defguess(self,chunk=None,voxels=None):""" Estimate the count of cell to place based on the cell_type's PlacementIndications. Float estimates are converted to int using an acceptance-rejection method. :param chunk: if provided, will estimate the number of cell within the Chunk. :type chunk: bsb.storage._chunks.Chunk :param voxels: if provided, will estimate the number of cell within the VoxelSet. Only for cells with the indication "density_key" set or with the indication "relative_to" set and the target cell has the indication "density_key" set. :type voxels: bsb.voxels.VoxelSet :returns: Cell counts for each chunk or voxel. :rtype: numpy.ndarray[int] """count=self.indication("count")density=self.indication("density")density_key=self.indication("density_key")planar_density=self.indication("planar_density")relative_to=self.indication("relative_to")density_ratio=self.indication("density_ratio")count_ratio=self.indication("count_ratio")local_count_ratio=self.indication("local_count_ratio")ifcountisnotNone:estimate=self._estim_for_chunk(chunk,count)ifdensityisnotNone:estimate=self._density_to_estim(density,chunk)ifplanar_densityisnotNone:estimate=self._pdensity_to_estim(planar_density,chunk)ifrelative_toisnotNone:relation=relative_toifcount_ratioisnotNone:# The total counts of cell of the current strategy is a ratio# of the total number of cell placed by the target strategy.# This number is uniformly distributed across the current# strategy's partition(s).strats=self._strat.scaffold.get_placement_of(relation)estimate=self._estim_for_chunk(chunk,sum(PlacementIndicator(s,relation).guess()forsinstrats)*count_ratio,)eliflocal_count_ratioisnotNone:# This count estimate is the ratio of the number of cell of the# target strategy that were placed in the current chunk.strats=self._strat.scaffold.get_placement_of(relation)estimate=(sum(PlacementIndicator(s,relation).guess(chunk,voxels)forsinstrats)*local_count_ratio)elifdensity_ratioisnotNone:# Create an indicator based on this strategy for the related CT.# This means we'll read only the CT indications, and ignore any# overrides of other strats, but one can set overrides for the# related type in this strat.rel_ind=PlacementIndicator(self._strat,relation)rel_density=rel_ind.indication("density")rel_pl_density=rel_ind.indication("planar_density")rel_pl_density_key=rel_ind.indication("density_key")ifrel_densityisnotNone:estimate=self._density_to_estim(rel_density*density_ratio,chunk)elifrel_pl_densityisnotNone:estimate=self._pdensity_to_estim(rel_pl_density*density_ratio,chunk)elifrel_pl_density_keyisnotNone:# Use the relation's `guess` to guess according to the relation's density keyestimate=rel_ind.guess(chunk,voxels)*density_ratioelse:raisePlacementRelationError(f"{self.cell_type.name} requires relation {relation.name}"+" to specify density information.")else:raisePlacementError(f"Relation specified but no ratio indications provided.")ifdensity_keyisnotNone:ifvoxelsisNone:raiseException("Can't guess voxel density without a voxelset.")elifdensity_keyinvoxels.data_keys:estimate=self._estim_for_voxels(voxels,density_key)else:raiseRuntimeError(f"No voxel density data column '{density_key}' found in any of the"" following partitions:\n"+"\n".join(f"* {p.name}: "+(fstrif(fstr:=", ".join(f"'{col}'"forcolinp.voxelset.data_keys))else"no data")forpinself._strat.partitionsifhasattr(p,"voxelset"))+"\n".join(f"* {p.name} contains no voxelsets"forpinself._strat.partitionsifnothasattr(p,"voxelset")))try:estimate=np.array(estimate)exceptNameError:# If `estimate` is undefined after all this then error out.raiseIndicatorError("No configuration indicators found for the number of"+f"'{self._cell_type.name}' in '{self._strat.name}'")ifnotnp.allclose(estimate,estimate//1):# 1.2 cells == 0.8 probability for 1, 0.2 probability for 2return(np.floor(estimate)+(np.random.rand(estimate.size)<estimate%1)).astype(int)else:returnnp.round(estimate).astype(int)
def_density_to_estim(self,density,chunk=None):returnsum(p.volume(chunk)*densityforpinself._strat.partitions)def_pdensity_to_estim(self,planar_density,chunk=None):returnsum(p.surface(chunk)*planar_densityforpinself._strat.partitions)def_estim_for_chunk(self,chunk,count):ifchunkisNone:returncount# When getting with absolute count for a chunk give back the count# proportional to the volume in this chunk vs total volumechunk_volume=sum(p.volume(chunk)forpinself._strat.partitions)total_volume=sum(p.volume()forpinself._strat.partitions)returncount*chunk_volume/total_volumedef_estim_for_voxels(self,voxels,key):returnvoxels.get_data(key).ravel().astype(float)*np.prod(voxels.get_size_matrix(copy=False),axis=1)