iGene is able to assign sample storage locations and track the movements of samples and storage containers within the application. The storage area is very configurable and this document should assist in setting up a basic sample storage process to expand on.
Key items in the sample storage process are:
One of the key features of the sample storage area is the ability to run groovy scripts at certain stages of the storage process. These stages are:
At each of these points, the custom scripts allow endless possibilities. The groovy scripts in this document are examples only, most things are possible with a little imagination.
The main idea behind the changes to the sample storage area is to allow multiple dimensions of storage and facilitate the simple moving of samples en masse. A typical scenario is to move a container of samples from one fridge to another. Previously, iGene was limited to a single storage location with minimal history. The enhancements include allowing multiple dimensions of storage, whats inside a container as well of a history of where a sample is and was.
To explore the sample storage area in more detail, it is useful to consider a few scenario which might occur in a lab environment.
Container templates as the name implies are used to create new containers. For example, DNA storage containers are very much differently from your liquid nitrogen tanks. The container templates allow you to define such things as what should happen to a sample when it’s added. In the example of a liquid nitrogen tank, it would probably set the sample status to “Frozen in liquid nitrogen.”
Another example might be a -80 freezer used to migrate sample into the liquid nitrogen freezer. On adding as a sample, it might start a timer, via a workflow, to ensure the sample is moved in time avoiding sample deterioration.
Locate the Container Template Preference preference by:
In order to access the preferences area, a user must be a member of a role that has the Administration: Preferences and Administration menu permissions assigned.
To add a new container template preference, click the + button on the table. The user will then see the following screen:
The following is a description of the fields:
Samples are assigned to locations automatically if the option is selected under the sample type preferences. If this is selected then iGene will search through the available sample storage policies until it finds one that matches. The application will used the first one found, the user must be careful not to overlap sample storage policies. e.g. Don’t have 2 policies with DNA only as the sample type, as the application will pick the first one. Ordering of these policies is performed using the weight option in the preferences, where the lower the weight, the earlier it is checked. This allows the ordering of policies.
It is a good rule to order policies from specific (with a lower weight so run first), to more generic (higher weight so run last), to avoid issues of items in the wrong location.
Locate the Sample Storage Policies preference by:
In order to access the preferences area, a user must be a member of a role that has the Administration: Preferences and Administration menu permissions assigned.
To add a new sample storage policy, click the ‘+’ button on the table. The user will then see the following screen:
The following is a description of the fields:
New containers can either be manually named, or auto generated based on what has been defined within the Container # Nomenclature. The Container # nomenclature is located under the Administration > Preferences area of iGene.
In order to access the preferences area, a user must be a member of a role that has the Administration: Preferences and Administration menu permissions assigned.
Scroll to the Nomenclature preference of Container # and click View. The user will then see the following screen where the nomenclature can be defined by adding new Compositions. Either click the + button at the bottom of the table of select New Composition from the Actions menu.
The following is a description of the fields:
As compositions are added, examples of the output can be seen. Click Save to apply the changes.
Once the storage policy and the container template have been setup, it is now possible to create a container to hold the samples or other containers. To create a container:
The user is presented with a popup window.
Enter:
Once the form has been completed, click the ‘Create’ button to see the details for the container. Below is an example of a fridge with 4 shelves.
Once the user has created items to keep samples in within the sample container by following the above process, the locations are now listed with the details. Below is an example of a sample container with a box located in position 1 of the fridge.
By clicking ‘View’ on each of the rows, it’s possible to see the details of the containers and it’s previous locations in a popup window.
On each of the items, it is possible to click the ‘Log’ button. This will show any errors when items were moved or items were placed into that storage location.
Adding samples to a container is performed in 3 locations:
Sample Management > Samples
Laboratory > Cultures
Moving a sample from a container to another container, or even completely out of storage is performed in 2 main areas:
The sample details screen can be accessed from either the lab referral screen (Laboratory > Lab Referral), the setup screen (Laboratory > Setup) or from the Sample screen (Sample Management > Samples). Once in either of these locations, the process is the same to move a sample.
The sample has now been moved to a new location.
When viewing a container within the sample storage screen, the storage location can be changed.
The sample is now moved to a different location.
Moving a container follows the same method as moving a sample. Since a container is just a location within another container, the process to move them are the same. However, final screen where the container is moved differs from the sample movement screen.
The container and all it’s contents are now moved. This has also updated all the samples to reflect the movement.
Samples and containers can also be assigned to locations manually rather than automatically. This is particularly useful when the user is ‘back filling’ storage locations. There are 2 main ways to manually assign samples and only a single way to manually assign a container to a location.
The item is now located in the location specified.
Sample Details Screen From a sample details screen the user can set a location for a sample. The sample details screen can be accessed from:
Lab Referral - Laboratory > Lab Referral > View Referral > View on Sample
Setup - Laboratory > Setup > View Referral > View on Sample
Samples - Sample Management > Samples > Click Details
To manually assign a sample to a location:
If the ‘Manually Assign Location’ button is not available, the sample must already have a location assigned. To manually assign it, move the sample to a new location from the Storage Location screens.
The sample has now been moved to a new location.
It is possible to delete a container provided that it does not have any samples or other containers stored within it. If the container does, it is a manual task to remove the containers contents. To delete a container:
It is possible to rename a container. To do this:
This option has a permission assigned to it. Do not use it unless the user knows the consequences.
This option has a permission assigned to it. Do not use it unless the user knows the consequences.
It is possible to mark a container and all the boxes in it as destroyed. This will also mark the samples within those boxes as destroyed as well. A scenario for this might be if a fridge breaks and the user wishes to mark all items destroyed in one go.
All scripts used in this scenario are the standard ones placed when items are first created.
A laboratory has the requirement to take samples which have been extracted and store those in boxes within a fridge. Once the box is full, the entire box needs to be moved from a fridge to a freezer and all the samples within that need to be updated to let the users know where they are located.
Create a new Sample Storage Policy. The example below has been set to only apply to DNA samples.
Ensure the Weight is lower than any generic policy that may already be set up, so that this more specific policy is run first when samples are auto-assigned a location.
Create container templates for a box, a fridge and a freezer. Ensure the box is setup to accept samples, and the fridge and freezer accept containers.
Navigate to Sample Management > Sample Storage and create 3 new storage containers by clicking the ‘+’ or selecting ‘New Storage Container’ from the ‘Actions’ tab:
Container Template: Fridge. ‘Name’ can either be entered or left as “Auto Generated”. Leave the fields ‘Create in Container’ and ‘Create in Location’ blank as this is a top level container.
Container Template: Freezer. ‘Name’ can either be entered or left as “Auto Generated”. Leave the fields ‘Create in Container’ and ‘Create in Location’ blank as this is a top level container.
Container Template: Box. Select the Fridge that has just been created in the “Create in Container” field as this Box is going to be stored within the Fridge. Choose a location and leave the Name to Auto-Generate .
Return to the Sample Storage screen and click ‘View’ next to the new Fridge container. Below, the name of the fridge was auto-generated as FR-0002 and the new Box, B-0001 has been assigned to Position 1 of the fridge. Positions 2 and 3 are currently free.
Return to the Sample Storage screen and click ‘View’ on the Box container. Under the ‘Locations’ section, all records will currently be displayed as “Not set”. To manually assign a sample to one of the free locations, click the ‘View’ icon. This will display details of that current location.
Click the ‘Assign’ icon to bring up the Assign Sample window where the specific sample which is to be assigned to that location can be searched for. Once located, click ‘Assign’ and a notification should display that the assignment was successful.
Alternatively, storage locations for B-001 can be automatically assigned via the Storage Policy. Navigate to the Sample Details window for another sample which is to be stored in a box within the fridge and click the ‘Auto-Allocate’ icon to allocate it to the next free location.
The storage policy set up in this example is for DNA samples only. If a sample other than a DNA is selected, the DNA storage policy will not be triggered and the next weighted storage policy will be checked.
The remaining container locations of B-001 can then be filled up with samples, and once there aren’t any free locations left, the status of the container changes from ‘Free’ to ‘Not Free’.
Now that the box is full, it needs to be moved to the freezer. Click ‘View’ against the highlighted container and in the subsequent Container details screen, click ‘Change Location’.
In the Change Location window, select the Freezer container created earlier in the “Create in Container” field, and an available location within that container in the “Create in Location” field. Click “Change” to complete the relocation
All previous locations of the container are tracked under the “Past Locations” section of the particular container.
Within the Sample Details screen an up-to-date storage location is displayed, including any parent containers.
// Variables
// index = The index of the label, e.g. 5 of 96. The index starts from 1 and ends at the number of positions
// size = The number of positions.
// Using index and size, return a label for the requested index
// Returns the given index as a number
return index.toString()
Below is an example of a script which could be used to display items within a liquid nitrogen tank. This has the dimensions of Cane (colour), level and location. An example of this would be ‘Green:3A’
//Cane can hold 15 samples (5 x 3), assume 1 based!
//Total samples, 75 (15 * 5 canes)
def caneLevels = 5
def caneLocations = 3
//**** DON"T CHANGE ANYTHING BELOW HERE! ****//
caneSamples = caneLevels * caneLocations
//Which cane?
def caneColour = ""
caneToUse = Integer.valueOf(String.format("%.0f", Math.ceil(index / caneSamples)))
switch (caneToUse) {
case 1:
caneColour = "Green"
break;
case 2:
caneColour = "Red"
break;
case 3:
caneColour = "Blue"
break;
case 4:
caneColour = "Orange"
break;
case 5:
caneColour = "Black"
break;
default:
//Error, it's full!
break;
}
//Which level?
def levelToUse = 0
levelToUse = String.format("%.0f",(Math.ceil(index / caneLocations)) - (caneLevels * caneToUse) + 5)
//Which location
def pos = ""
if ((index % caneLocations) == 0) {
pos = "C"
} else if ((index % caneLocations) == 1) {
pos = "A"
} else if ((index % caneLocations) == 2) {
pos = "B"
}
return "${caneColour}:${levelToUse}${pos}"
Another example is the use of a box with X and Y where the top is A,B,C etc and the side is 1,2,3 etc. Items need to be placed in the the order of A1, B1, C1… A2, B2 etc. The below script will enable that to happen for a 100 well box.
//10 x 10 Grid
xAxis = 10 //A, B, C etc
yAxis = 10
//DO NOT CHANGE BELOW HERE
yValue = Math.floor(index / yAxis) +1
xValue = index % yAxis
if (xValue == 0) {
xValue = 10
yValue --
}
xDisplay = String.valueOf((char)(Integer.valueOf(xValue) + 64))
yDisplay = String.format("%.0f", yValue)
return "${xDisplay}${yDisplay}"
// Variables
// sample = The sample being added
// containerLocation = The location the sample is being added to
// container = The container
import com.genialgenetics.igene.common.server.dao.models.SampleStatus
if (sample) {
def status = SampleStatus.findByCode("inStorage")
if (status) {
sample.setSampleStatus(status)
}
}
// Variables
// sample = The sample being removed
// containerLocation = The location the sample is being removed from
// container = The container the sample was in
import com.genialgenetics.igene.common.server.dao.models.SampleStatus
if (sample){
def status = SampleStatus.findByCode("outStorage")
if (status) {
sample.setSampleStatus(status)
}
}
// Find an return a container that will assign this sample a container
// You are given the variables:
// - sample (The sample to be allocated if this is for a sample)
// - container (The container to be allocated a location if this is for another container)
// - storagePolicy (Reference to this storage policy)
// Return either
// - A string or an exception if something goes wrong. This will be logged into a placement record with no container or location assigne
// - A ContainerLocation that is ready to accept the Sample or Container
import com.genialgenetics.igene.common.server.dao.models.ContainerTemplate
def containerTemplate = ContainerTemplate.findByCode("Rack")
if (!containerTemplate) {
return "Error: Container Template Rack not found"
}
// Search for the first free container
def container = containerTemplate.findFirstFreeContainer()
if (!container) {
// No free container, create a new container
container = containerTemplate.createNewContainer()
if (!container){
return "Error: Failed to create a new container of type Rack"
}
}
// Collect the next free location and return it
def location = container.getNextFreeLocationFor(sample)
if (!location) {
// No free location.
return "Error: no free location in container ${container.name}"
}
// All good, return this location. iGene will then allocate the sample to the location
return location
The below script will create a task for a group of users to complete when the container is 80% full. Once it is 100% full, a new task will be created to move the container to a new location.
// Find an return a container that will assign this sample a container
// You are given the variables:
// - sample (The sample to be allocated if this is for a sample)
// - container (The container to be allocated a location if this is for another container)
// - storagePolicy (Reference to this storage policy)
// Return either
// - A string or an exception if something goes wrong. This will be logged into a placement record with no container or location assigne
// - A ContainerLocation that is ready to accept the Sample or Container
import com.genialgenetics.igene.common.server.dao.models.*
def containerWarnThreshold = 80
def containerManagementGroupCode = 'container_managers'
DistributionList dl = modelHandler.findByCode(DistributionList.class, containerManagementGroupCode)
if (dl == null) {
return "Error: Unable to find the distribution group with the code ${containerManagementGroupCode}"
}
def containerTemplate = ContainerTemplate.findByCode("Rack")
if (!containerTemplate) {
return "Error: Container Template Rack not found"
}
// Search for the first free container
def container = containerTemplate.findFirstFreeContainer()
if (!container) {
// No free container, create a new container
container = containerTemplate.createNewContainer()
if (!container){
return "Error: Failed to create a new container of type Rack"
}
}
// Collect the next free location and return it
def location = container.getNextFreeLocationFor(sample)
if (!location) {
// No free location.
Task createContainer = new Task();
TaskAssignee assignee = new TaskAssignee()
createContainer.getTaskAssignees.add(assignee)
assignee.setTask(createContainer)
assignee.setDistributionList(dl)
createContainer.setName("Create a new container");
createContainer.setDescription("Please create a new container. ${container?.name} is full")
modelHandler.save(assignee)
modelHandler.save(task)
return "Error: no free location in container ${container.name}"
}
if ((location / container?.containerLocations?.size() * 100) > containerWarnThreshold) {
//We are getting close to the max
Task createContainer = new Task();
TaskAssignee assignee = new TaskAssignee()
createContainer.getTaskAssignees.add(assignee)
assignee.setTask(createContainer)
assignee.setDistributionList(dl)
createContainer.setName("Container ${container.name} nearly full.");
createContainer.setDescription("Container ${container.name} is ${containerWarnThreshold}% full. Please create a new container.")
modelHandler.save(assignee)
modelHandler.save(task)
}
// All good, return this location. iGene will then allocate the sample to the location
return location