Class BioAssaySet

All Implemented Interfaces:
AccessControlled, Annotatable, FileStoreEnabled, Identifiable, Nameable, Removable

public class BioAssaySet extends ChildItem implements Nameable, Removable, Annotatable, FileStoreEnabled
A bioassayset represents the current intensities of the raw data after some Transformation has been applied to it. The first transformation is called a root transformation. A bioassayset created by a root transformation is called a root bioassayset.

A bioassayset is created by the Transformation.newProduct(String, String, boolean) method. Bioassaysets can only be created if the transformation hasn't been committed to the database.

Version:
2.0
Author:
Nicklas
See Also:
Last modified
$Date: 2017-05-22 14:35:27 +0200 (må, 22 maj 2017) $
  • Field Details

  • Constructor Details

    • BioAssaySet

      BioAssaySet(BioAssaySetData data)
      Creates a new experiment item from the given data.
      Parameters:
      data - the data
  • Method Details

    • getNew

      Create a new BioAssaySet item.
      Parameters:
      dc - The DbControl which will be used for permission checking and database access.
      transformation - The transformation that created the bioassayset
      layer - The data cube layer where the bioassayset should store it's data
      Returns:
      The new BioAssaySet item
      Throws:
      PermissionDeniedException - If the logged in user doesn't have write permission for the experiment the transformation belongs to
      InvalidDataException - If the transformation is null
      BaseException - If there is an error
      See Also:
    • getById

      Get a BioAssaySet item when you know the id.
      Parameters:
      dc - The DbControl which will be used for permission checking and database access.
      id - The id of the item to load
      Returns:
      The BioAssaySet item
      Throws:
      ItemNotFoundException - If an item with the specified id is not found
      PermissionDeniedException - If the logged in user doesn't have Permission.READ permission to the item
      BaseException - If there is another error
    • getQuery

      public static ItemQuery<BioAssaySet> getQuery(Experiment experiment) throws InvalidDataException
      Get a query configured to retrieve bioassaysets for a given experiment.
      Parameters:
      experiment - The experiment to retreive bioassaysets for, null is not allowed
      Returns:
      An ItemQuery object
      Throws:
      InvalidDataException - If the parameter is null.
    • getQuery

      public static ItemQuery<BioAssaySet> getQuery(Transformation transformation) throws InvalidDataException
      Get a query configured to retrieve bioassaysets created by a given transformation.
      Parameters:
      transformation - The transformation to retreive bioassaysets for, null is not allowed
      Returns:
      An ItemQuery object
      Throws:
      InvalidDataException - If the transformation parameter is null.
    • getData

      BioAssaySetData getData()
      Description copied from class: BasicItem
      Get the BasicData object that holds all data for this item.
      Specified by:
      getData in class BasicItem
    • getType

      public Item getType()
      Description copied from interface: Identifiable
      Get the type of item represented by the object. The returned value is one of the values defined in the Item enumeration.
      Specified by:
      getType in interface Identifiable
      Returns:
      A value indicating the type of item
    • getName

      public String getName()
      Description copied from interface: Nameable
      Get the name of the item.
      Specified by:
      getName in interface Nameable
      Returns:
      A String with the name of the item
    • setName

      public void setName(String name) throws PermissionDeniedException, InvalidDataException
      Description copied from interface: Nameable
      Set the name of the item. The name cannot be null and mustn't be longer than the value specified by the Nameable.MAX_NAME_LENGTH constant.
      Specified by:
      setName in interface Nameable
      Parameters:
      name - The new name for the item
      Throws:
      PermissionDeniedException - If the logged in user doesn't have write permission
      InvalidDataException - If the name is null or longer than specified by the Nameable.MAX_NAME_LENGTH constant
    • getDescription

      public String getDescription()
      Description copied from interface: Nameable
      Get the description for the item.
      Specified by:
      getDescription in interface Nameable
      Returns:
      A String with a description of the item
    • setDescription

      public void setDescription(String description) throws PermissionDeniedException, InvalidDataException
      Description copied from interface: Nameable
      Set the description for the item. The description can be null but mustn't be longer than the value specified by the Nameable.MAX_DESCRIPTION_LENGTH constant.
      Specified by:
      setDescription in interface Nameable
      Parameters:
      description - The new description for the item
      Throws:
      PermissionDeniedException - If the logged in user doesn't have write permission
      InvalidDataException - If the description longer than specified by the Nameable.MAX_DESCRIPTION_LENGTH constant
    • isRemoved

      public boolean isRemoved()
      Description copied from interface: Removable
      Check if the removed flag is set for this item.
      Specified by:
      isRemoved in interface Removable
      Returns:
      TRUE if the item is flagged as removed, FALSE otherwise
    • setRemoved

      public void setRemoved(boolean removed) throws PermissionDeniedException
      Description copied from interface: Removable
      Set the removed flag for this item.
      Specified by:
      setRemoved in interface Removable
      Parameters:
      removed - TRUE if the item should be flagged as removed, FALSE otherwise
      Throws:
      PermissionDeniedException - If the logged in user doesn't have Permission.DELETE permission for setting the flag to TRUE or Permission.WRITE permission for setting the flag to FALSE
    • getRemovedBy

      public User getRemovedBy() throws PermissionDeniedException, ItemNotFoundException
      Description copied from interface: Removable
      Get the user that flagged this item for removal.
      Specified by:
      getRemovedBy in interface Removable
      Returns:
      A User object, or null if this item has not been flagged
      Throws:
      PermissionDeniedException - If the logged in user doesn't have Permission.READ permission for the user
      ItemNotFoundException - If the user that removed this item can't be found
    • getAnnotationSet

      public AnnotationSet getAnnotationSet() throws PermissionDeniedException, BaseException
      Description copied from interface: Annotatable
      Get the annotation set containing the annotations for this item. If the item doesn't have any annotations a new annotation set is created and automatically saved to the database when DbControl.commit() is called. To check if an item has annotations without creating a new annotation set use the Annotatable.isAnnotated() method.
      Specified by:
      getAnnotationSet in interface Annotatable
      Returns:
      An AnnotationSet
      Throws:
      PermissionDeniedException - If the logged in user doesn't have enough permissions
      BaseException - If there is another error
      Since:
      2.2
    • isAnnotated

      public boolean isAnnotated()
      Description copied from interface: Annotatable
      Check if this item has an annotation set. The annotation set may be empty.
      Specified by:
      isAnnotated in interface Annotatable
      Returns:
      TRUE if an annotation set exists, FALSE otherwise
      Since:
      2.2
    • removeAnnotations

      public void removeAnnotations() throws PermissionDeniedException, BaseException
      Description copied from interface: Annotatable
      Remove all annotations from this item, by deleting the annotation set.
      Specified by:
      removeAnnotations in interface Annotatable
      Throws:
      PermissionDeniedException - If the logged in user doesn't have write permission
      BaseException - If there is another error
      Since:
      2.2
    • getProtocol

      public Protocol getProtocol()
      Default implementation returns null. Should be overriden by subclasses that has protocols.
      Specified by:
      getProtocol in interface Annotatable
      Returns:
      Always null
      Since:
      2.2
    • getAnnotatableParents

      public Set<Annotatable> getAnnotatableParents() throws BaseException
      Get the parent bioassay set (if any) and the experiment.
      Specified by:
      getAnnotatableParents in interface Annotatable
      Returns:
      A set containing annotatable items, or null
      Throws:
      BaseException - If there is an error
      Since:
      2.2
    • getFileSet

      public FileSet getFileSet()
      Description copied from interface: FileStoreEnabled
      Get the file set that collects all files that holds data for this item. If no file set exists a new one is created and automatically saved to the database when DbControl.commit() is called. To check if an item has files without creating a new file set use the FileStoreEnabled.hasFileSet() method.
      Specified by:
      getFileSet in interface FileStoreEnabled
      Returns:
      A file set
      Since:
      2.8
    • hasFileSet

      public boolean hasFileSet()
      Description copied from interface: FileStoreEnabled
      Check if this item has a file set. Always call this method before FileStoreEnabled.getFileSet() to avoid creating a new file set when there is no need for it.
      Specified by:
      hasFileSet in interface FileStoreEnabled
      Returns:
      TRUE if a file set exists, FALSE if not
      Since:
      2.8
    • getPlatform

      public Platform getPlatform()
      Description copied from interface: FileStoreEnabled
      Get the platform the item is related to. The platform is used to limit the DataFileType:s that can be added to the file set.
      Specified by:
      getPlatform in interface FileStoreEnabled
      Returns:
      Always null
      Since:
      2.8
    • getVariant

      public PlatformVariant getVariant()
      Description copied from interface: FileStoreEnabled
      Get the platform variant the item is related to. The platform is used to limit the DataFileType:s that can be added to the file set.
      Specified by:
      getVariant in interface FileStoreEnabled
      Returns:
      Always null
      Since:
      2.8
    • getParentFileSets

      public Collection<FileSet> getParentFileSets()
      Get the file set from the parent bioassay set if it exists.
      Specified by:
      getParentFileSets in interface FileStoreEnabled
      Returns:
      A collection of FileSet or null
      Since:
      2.8
    • onBeforeCommit

      void onBeforeCommit(Transactional.Action action) throws BaseException
      On creation, count the number of spots and reporters in the bioassays attached to this bioassayset. On deletion, delete all analysed data in this bioassayset and all child bioassaysets.
      Overrides:
      onBeforeCommit in class BasicItem
      Throws:
      BaseException - If there is an error
      See Also:
    • getSharedParent

      SharedData getSharedParent()
      Get the experiment.
      Specified by:
      getSharedParent in class ChildItem
      Returns:
      The parent item
    • getPermissionForWriteDeleteAndCreate

      Permission getPermissionForWriteDeleteAndCreate()
      USE permission is enough to be able to manage bioassay sets.
      Overrides:
      getPermissionForWriteDeleteAndCreate in class ChildItem
    • getExperiment

      public Experiment getExperiment() throws PermissionDeniedException, BaseException
      Get the experiment this bioassayset belongs to.
      Returns:
      An Experiment object
      Throws:
      PermissionDeniedException - If the logged in user doesn't have read permission to the experiment
      BaseException - If there is another error
    • setExperiment

      private void setExperiment(Experiment experiment) throws PermissionDeniedException, InvalidDataException
      Set the experiment. This cannot be changed after the bioassayset has been created.
      Throws:
      PermissionDeniedException
      InvalidDataException
    • getTransformation

      public Transformation getTransformation() throws PermissionDeniedException, BaseException
      Get the transformation that created this bioassayset.
      Returns:
      A Transformation object
      Throws:
      PermissionDeniedException - If the logged in user doesn't have read permission to the experiment
      BaseException - If there is another error
    • setTransformation

      private void setTransformation(Transformation transformation) throws PermissionDeniedException, InvalidDataException
      Set the transformation that created this bioassayset. This cannot be changed after the bioassayset has been created.
      Throws:
      PermissionDeniedException
      InvalidDataException
    • getRawDataType

      public RawDataType getRawDataType()
      Get the raw data type this experiment uses for the raw data. The raw data type cannot be changed once the experiment has been created.
      Returns:
      A RawDataType object
    • getNumReporters

      public int getNumReporters()
      Get the number of unique reporters among all bioassays in this bioassayset.
    • getNumSpots

      public int getNumSpots()
      Get the number of spots in all bioassays in this bioassayset.
    • getNumFileReporters

      public int getNumFileReporters()
      Get the number of unique reporters for data that is stored in files.
      Since:
      2.8
    • setNumFileReporters

      public void setNumFileReporters(int numReporters)
      Set the number of unique reporters for data that is stored in files.
      Parameters:
      numReporters - The number of reporters
      Since:
      2.8
    • getNumFileSpots

      public int getNumFileSpots()
      Get the number of spots that are stored in files.
      Since:
      2.8
    • setNumFileSpots

      public void setNumFileSpots(int numSpots)
      Set the number of spots that are stored in files.
      Parameters:
      numSpots - The number of spots
      Since:
      2.8
    • getMaxRawMappingsForSpot

      public int getMaxRawMappingsForSpot()
      Get the number of mappings to raw data spots for the spot with the most number of mappings. For most bioassay sets this value is probably 1. After a merge, the count can be higher which may require some plugins to behave differently when using values from the raw data table.
      Since:
      2.2
    • getIntensityTransform

      public IntensityTransform getIntensityTransform()
      Get information about in what way the spot intensities has been transformed before they were stored in the database.
      Since:
      2.12
    • setIntensityTransform

      public void setIntensityTransform(IntensityTransform transform)
      Sets the transform used on the spot intensities before they were stored in the database. NOTE! Calling this method doesn't change the data in the database!
      Parameters:
      transform - The transform that was used to store the data
      Since:
      2.12
    • getDataCubeNo

      public short getDataCubeNo()
      Get the number of the data cube this bioassayset stores it's data in.
      See Also:
    • getDataCubeLayerNo

      public short getDataCubeLayerNo()
      Get the layer coordinate in the data cube that this bioassayset stores it's data in.
      See Also:
    • getDataCubeFilterNo

      public short getDataCubeFilterNo()
      Get the number of the filter that this bioassayset is using, or 0 if no filter is used.
      Returns:
      The number of the filter or 0 if no filter is used
      See Also:
    • getVirtualDb

      VirtualDb getVirtualDb()
      Get the virtual database this bioassayset stores it's data in.
    • getDataCube

      Get the data cube this biossayset stores it's data in.
      Throws:
      PermissionDeniedException
      BaseException
    • getDataCubeLayer

      DataCubeLayer getDataCubeLayer()
      Get the data cube layer this biossayset stores it's data in.
    • setDataCubeLayer

      private void setDataCubeLayer(DataCubeLayer layer)
    • getDataCubeFilter

      DataCubeFilter getDataCubeFilter()
      Get the data cube filter this biossayset uses to filter spot data.
    • setDataCubeFilter

      private void setDataCubeFilter(DataCubeFilter filter)
    • newTransformation

      public Transformation newTransformation(Job job) throws PermissionDeniedException, BaseException
      Create a new transformation using this bioassayset as it's source bioassayset.
      Parameters:
      job - The job that executed the transformation
      Throws:
      PermissionDeniedException - If the logged in user doesn't have write permission for the experiment this bioassayset belongs to
      BaseException - If there is another error
    • getTransformations

      public ItemQuery<Transformation> getTransformations()
      Get a query that return all transformations using this bioassayset as a source.
      Returns:
      An ItemQuery object
      See Also:
    • newRootBioAssay

      Create a new BioAssay with links to raw bioassays. This type of bioassay can only be created if the transformation that created it is a root transformation. New bioassays can only be created if the bioassayset hasn't been committed to the database.

      The raw bioassay collection should contain only those raw bioassays whose spots have been used to calculate the intensities stored in this bioassay.

      Parameters:
      rawParents - A collection containing the raw bioassays that are the parents of this bioassay
      Returns:
      The new BioAssay item
      Throws:
      PermissionDeniedException - If the logged in user doesn't have write permission for the experiment of if the bioassayset has been committed to the database
      InvalidDataException - If this bioassayset is not a product of a root transformation or if any of the raw bioassay parents isn't a member of the transformation
      BaseException - If something else goes wrong.
      See Also:
    • newBioAssay

      public BioAssay newBioAssay(BioAssay parent) throws InvalidDataException, PermissionDeniedException
      Create a new BioAssay in this bioassayset using a single parent. The data cube column coordinate of the new bioassay is set to the same as that of the parent. The bioassayset of the parent bioassay must match the bioassayset set of the source of the transformation and this bioassayset must use the same data cube as the source bioassayset. The new bioassay is automatically linked to the same raw bioassays as the parent bioassay.

      New bioassays can only be created if the bioassayset hasn't been committed to the database.

      Parameters:
      parent - The parent bioassay
      Returns:
      The new bioassay
      Throws:
      InvalidDataException - If the parent is null or it's bioassayset is not the same as the source bioassayset of the transformation or if the data cube of the source is not the same as the data cube for this bioassayset
      PermissionDeniedException - If the bioassayset has already been committed to the database
      See Also:
    • newBioAssay

      public BioAssay newBioAssay(Collection<BioAssay> parents)
      Create a new BioAssay with links to multiple parent bioassays. This type of bioassay can only be created if the transformation that created it isn't a root transformation, since a root transformation can't have a parent bioassayset. This type of bioassay must be created if this bioassayset uses a different data cube than the bioassayset that is the source of the transformation. The new bioassay is automatically linked to the same raw bioassays as the parent bioassay.

      New bioassays can only be created if the bioassayset hasn't been committed to the database.

      Parameters:
      parents - A collection containing the bioassays that are the parents of this bioassay
      Returns:
      The new BioAssay item
      Throws:
      PermissionDeniedException - If the logged in user doesn't have write permission for the experiment of if the bioassayset has been committed to the database
      InvalidDataException - If this bioassayset is the product of a root transformation or if any of the bioassay parents isn't a member source bioassayset of the transformation
      See Also:
    • newBioAssay

      private BioAssay newBioAssay(DataCubeColumn column, Collection<BioAssay> parents)
      Create a new bioassay and link to the parents. Assume that all neccessary checks has been made by calling code. If the collections contains only a single parent, the name will be copied to the child.
    • getBioAssays

      public ItemQuery<BioAssay> getBioAssays()
      Get a query returning the bioassays that are part of this bioassayset.
      Returns:
      An ItemQuery object
    • getExtraValues

      public ItemQuery<ExtraValue> getExtraValues()
      Get a query returning the extra values that are part of this bioassayset. To add extra values use one of the methods that returns a batcher.
      Returns:
      An ItemQuery object
      See Also:
    • getExtraValueTypes

      public ItemQuery<ExtraValueType> getExtraValueTypes()
      Get a query returning all extra values types that are used in this bioassay set.
      Returns:
      An ItemQuery object
      Since:
      2.15
      See Also:
    • getExtraValue

      public ExtraValue getExtraValue(ExtraValueType extraValueType) throws BaseException
      Get the extra value of the specified type in this bioassayset. To add extra values use one of the methods that returns a batcher.
      Parameters:
      extraValueType - For which extra value should be returned.
      Returns:
      An ExtraValue item, or null if no extra value of the specified type has been created for this bioassayset
      Throws:
      BaseException - If something fails when getting the extra value.
      See Also:
    • getPositionBatcher

      public PositionBatcher getPositionBatcher() throws PermissionDeniedException
      Get a batcher that links position coordinates to reporters for the data cube this bioassayset uses. The links must be created before the data cube is committed to the database. This means that only the first bioassayset in a data cube can create the links to reporters. To insert extra values (which can be done at any time) based on the position use the getPositionExtraValueBatcher(Class, ExtraValueType, Job) method to get a batcher for that.
      Returns:
      A PositionBatcher object
      Throws:
      PermissionDeniedException - If the logged in user doesn't have write permission or if the data cube has already been committed to the database
      See Also:
    • getMappingBatcher

      public MappingBatcher getMappingBatcher() throws PermissionDeniedException
      Get a batcher used to insert mappings to raw data. The links must be created before the data cube is committed to the database. This means that only the first bioassayset in a data cube can create the links to raw data.
      Returns:
      A MappingBatcher object
      Throws:
      PermissionDeniedException - If the logged in user doesn't have write permission or if the data cube has already been committed to the database
    • getSpotBatcher

      public SpotBatcher getSpotBatcher() throws PermissionDeniedException
      Get a batcher used to insert spot data for this bioassayset. If this bioassayset uses the same layer as another bioassayset or if this bioassayset has already been committed to the database no more intensities can be inserted. To insert extra values (which can be done at any time) based on the position use the getSpotExtraValueBatcher(Class, ExtraValueType, Job) method to get a batcher for that.
      Returns:
      A SpotBatcher object
      Throws:
      PermissionDeniedException - If the logged in user doesn't have write permission or if the data cube layer has already been committed to the database
      See Also:
    • getFilterBatcher

      public FilterBatcher getFilterBatcher() throws PermissionDeniedException
      Get a batcher used to insert the position/column coordinates that remain after some filter has been applied to the spot data of a bioassayset. Filter information cannot be inserted after the bioassayset has been committed to the database. Calling this method and not inserting any position/column coordinates will result in a bioassayset with no data.
      Returns:
      A FilterBatcher object
      Throws:
      PermissionDeniedException - If the bioassayset has already been committed to the database or if the logged in user doesn't have write permission
      See Also:
    • getSpotExtraValueBatcher

      public <I> SpotExtraValueBatcher<I> getSpotExtraValueBatcher(Class<I> clazz, ExtraValueType extraValueType, Job job) throws PermissionDeniedException, InvalidDataException
      Get a batcher that is used to insert extra values per spot of the specified type. A bioassay set can only have one set of extra values for each type. If this method is called more than once in the same transaction with the same extra value type parameter, the same batcher is returned.
      Parameters:
      clazz - The class object for the values, ie. Integer.class, Float.class or String.class
      extraValueType - The definition of the extra value type
      job - The job that is doing the extra value calculations or null
      Returns:
      A SpotExtraValueBatcher object
      Throws:
      PermissionDeniedException - If the loggged in user doesn't have write permission for the bioassay set
      InvalidDataException - If the extra value type is null or has a value type that doesn't match the specified class
      See Also:
    • getPositionExtraValueBatcher

      public <I> PositionExtraValueBatcher<I> getPositionExtraValueBatcher(Class<I> clazz, ExtraValueType extraValueType, Job job) throws PermissionDeniedException, InvalidDataException
      Get a batcher that is used to insert extra values per position of the specified type. A bioassay set can only have one set of extra values for each type. If this method is called more than once in the same transaction with the same extra value type parameter, the same batcher is returned.
      Parameters:
      clazz - The class object for the values, ie. Integer.class, Float.class or String.class
      extraValueType - The definition of the extra value type
      job - The job that is doing the extra value calculations or null
      Returns:
      A PositionExtraValueBatcher object
      Throws:
      PermissionDeniedException - If the loggged in user doesn't have write permission for the bioassay set
      InvalidDataException - If the extra value type is null or has a value type that doesn't match the specified class
    • getSpotData

      public DynamicSpotQuery getSpotData()
      Get a query that returns spot data for this bioassayset. The query will select column, position and spot intensities by default. Ie.
      // Default query -- filter is only joined if the bioassayset is filtered
      SELECT spt.column, spt.position, spt.ch1, spt.ch2, ...
      FROM Dynamic#PerSpot spt
      [ JOIN Dynamic#Filter flt 
         ON flt.cube = spt.cube AND flt.column = spt.column 
         AND flt.position = spt.position ]
      WHERE spt.cube = <cube_no> AND spt.layer = <layer_no> 
         [ AND flt.filter = <filter_no> ]
      

      Note! If the bioassay set contains transformed intensities, the default selection will un-transform the values.

      Returns:
      A DynamicSpotQuery object
    • getPositionData

      public DynamicPositionQuery getPositionData()
      Get a query that returns position data for the data cube where this bioassayset is located. The query will only select the position by default. The returned result doesn't depend on what spots are located in this bioassayset. Ie. the query will return the same result for all bioassaysets in the same data cube. If you need position data that depends on the spots in the bioassayset, use the getSpotData() method and then join reporters using the DynamicSpotQuery.joinReporters(JoinType) method.
      // Default query
      SELECT pos.position
      FROM Dynamic#PerPosition AS pos
      WHERE pos.cube = <cube_no>
      
      Returns:
      A DynamicPositionQuery object
    • countSpotsAndReporters

      private void countSpotsAndReporters()
      Count the number of unique reporters and spots in all bioassays in this bioassayset. This method in called by the onBeforeCommit method to calculate the numbers (which cannot be changed later) before the bioassayset is committed to the database.
    • getSpotCount

      int getSpotCount(int column)
      Get the number of spots in a single bioassay. This method in called by the BioAssay.onBeforeCommit method to calculate the numbers (which cannot be changed later) before the bioassay is saved to the database. The reason it is located here is that a single query can calculate the spots for all bioassays in a one go.
    • countBioAssaySpots

      private void countBioAssaySpots()
      See Also:
    • checkAndCreateTables

      private void checkAndCreateTables()
    • deleteAnalysedData

      private void deleteAnalysedData() throws BaseException
      Called when a bioassayset is about to be deleted. Finds which data cubes, layers, filters and extra values that are exclusively used by this bioassayset or one of the child bioassaysets (which are deleted by Hibernate cascade). Then, it deletes all those items. A bug in this method may cause stale data to be left in the database (bad) or data used by other bioassaysets to be deleted (even worse). For each type of item it is a three-step process:
      1. Find the items used by at least one of the bioassaysets that are going to be deleted
      2. Among the items found, find out if any of them are also used by other bioassaysets that are not going to be deleted
      3. Delete only those items that are left
      Throws:
      BaseException
    • addChildBioAssaySets

      private void addChildBioAssaySets(BioAssaySetData parent, Set<BioAssaySetData> all)
      Find all bioassaysets that are children to the specified parent (ie. the product of a transformation using the parent as a source) and add those the all set. The method is then called recursively to add the grandchildren and so on.