arrow-left

All pages
gitbookPowered by GitBook
1 of 4

Loading...

Loading...

Loading...

Loading...

Remove Samples from Workflows

In Clarity LIMS, derived sample automations are automations that users can run on derived samples directly from the Projects Dashboard.

The following example uses an automation to initiate a script that removes multiple derived samples from workflows. The example also describes the main functions included in the script, and shows how to configure the automation in Clarity LIMS and run it from the Projects Dashboard.

hashtag
Prerequisites

Before removing samples from the workflows, make sure you have the following items:

  • A project containing at least one sample assigned to a workflow.

  • A step has been run on a sample, resulting in a derived sample.

  • The derived sample is associated with one or more workflows.

hashtag
Code example

The attached UnassignSamplesFromWorkflows.groovy script uses the derived sample automations feature to remove selected derived samples from their associated workflows. The following actions must be done when removing samples from these workflows.

hashtag
Step 1. Create Sample Node List

This getSampleNodes function is passed a list of derived sample LIMS IDs (as a command-line argument) to build a list containing the XML representations of the samples. A for-each loop on the derived sample list makes a GET call for each sample and creates the sample node list. The following command-line example shows how the getSampleNodes function works:

This list is used to retrieve the sample URIs and the workflow-stage URIs. These URIs are required to build the unassignment XML.

hashtag
Step 2. Retrieve Workflow URIs

A sample can be associated with one or many workflows, and each derived sample has a list of the workflow-stages to which it is assigned. Making a GET call on each workflow-stage URI retrieves its XML representation, from which the workflow URI can be acquired and added to a list. The getWorkflowURIs function calls for each sample node included in the list (eg, sampleURIList, username, and password from ).

The for loop does the following actions:

  1. Makes a GET call for each workflow-stage to which the passed sample is assigned.

  2. Retrieves the associated workflow URIs.

  3. Returns a list containing all URIs for the workflows with which the sample is associated.

hashtag
Step 3. Build and POST the Unassignment XML

Now that the functions used to retrieve both the derived sample URIs and the workflow URIs have been built, you can use StreamingMarkupBuilder to create the XML and then POST to the unassignment URI. This process can be done with the unassignSamplesFromWorkflows and unassignSamplesXML functions.

To unassign the derived samples, you can POST to the artifacts URI at ${hostname}v2/route/artifacts. Nested loops create the declaration for each sample and their associated workflows. The following example shows the declaration built in the format of the workflow URI, with the unassign flag followed by the URI of the sample being unassigned.

Now that the XML is built, convert the XML to a node and post it as follows.

  1. Use GLSRestApiUtils to convert the XML to a node

  2. POST the node using the following command:

hashtag
Configuring and Running the Automation

Automations can be configured and run using Clarity LIMS

  1. In Clarity LIMS, under Configuration, select the Automation tab.

  2. Select the Derived Sample Automation tab.

  3. Select New Automation and enter the following information:

Run the automation as follows.

  1. Open the Projects Dashboard.

  2. Select a project containing in-progress samples. Select In-progress samples.

    In the sample list, you see the submitted and derived samples that are currently in progress for this project.

hashtag
Expected Output and Results

The API of the selected samples now shows an additional workflow stage with a status of REMOVED.

hashtag
Attachments

UnassignSamplesFromWorkflows.groovy:

Automation Name—This is the name that displays to the user running the automation from the Projects Dashboard. Choose a descriptive name that reflects the functionality/purpose (eg, Remove from Workflows).

  • Channel Name—Enter the channel name.

  • Command Line—Enter the command line required to invoke the script.\

  • Select Save.

  • Select one or more derived samples.

    Selecting samples activates the Action button and drop-down list.

  • In the Action drop-down list, select the Remove From Workflows automation created in the previous step.

  • file-download
    4KB
    UnassignSamplesFromWorkflows.groovy
    arrow-up-right-from-squareOpen
    Step 1. Create Sample Node List
    def getSampleNodes(sampleList, hostname, username, password){
        sampleURIList = sampleList.collect{"${hostname}v2/artifacts/${it}"}
        return sampleNodeList = GLSRestApiUtils.batchGET(sampleURIList, username, password)
    } 
    def getWorkflowURIs(sampleNode, username, password){
        return sampleNode.'workflow-stages'?.'workflow-stage'.collect\
              {GLSRestApiUtils.httpGET(it.@uri, username, password).workflow.@uri}
    } 
    def unassignSamplesFromWorkflows(sampleNodeList, username, password){
        def builder = new StreamingMarkupBuilder()
        builder.encoding = "UTF-8"
        def unassignSamplesXML = builder.bind{
            mkp.xmlDeclaration()
            mkp.declareNamespace(rt: 'http://genologics.com/ri/routing')
             'rt:routing' {
                 //Dynamically build XML using a for loop for each sampleNode
                 sampleNodeList.each{ sampleNode ->
                     //Generates the URI list for each sample
                     workflowUriList = getWorkflowURIs(sampleNode, username, password)
                     workflowUriList?.each{
                         'unassign'('workflow-uri': it){
                             'artifact'(uri: sampleNode.@uri)
                         }
                     }
                 }
             }
         }
         return GLSRestApiUtils.xmlStringToNode(unassignSamplesXML.toString())
    }
    unassignSampleNode = unassignSamplesFromWorkflows(sampleNodeList, username, password)
    //Try the post
    try{
        unassignSampleNode = GLSRestApiUtils.httpPOST(unassignSampleNode, unassignmentURI, username, password)
    } 

    Work with Derived Sample Automations

    When working with containers, you can do the following:

    • Remove Samples from Workflows

    • Requeue Samples

    • Rearray Samples

    Requeue Samples

    Derived sample automations are automations that users can run on derived samples directly from the Projects Dashboard in Clarity LIMS.

    The following example uses an automation to initiate a script that requeues samples to an earlier step in the workflow. The example also describes the main functions included in the script and demonstrates the configuration options that prompt the user for input. These options allow for greater flexibility during script runs. Before you follow the example, make sure that you have the following items:

    • A project containing samples assigned to a multi-stage workflow.

    • Samples that must be requeued. These samples must have completed at least one step in the workflow and must be available for requeue.

    hashtag
    Code Example

    The purpose of the attached RequeueSamples.groovy script is to requeue selected derived samples to a previous step in the workflow with the derived sample automations feature.

    hashtag
    Step 1. Get Sample Nodes

    The getSampleNodes function is passed a list of derived sample LIMS IDs (as a command-line argument) to build a list containing the XML representations of the samples. The resulting sample URI list can then be used with a batchGET to return the sample nodes:

    hashtag
    Step 2. Retrieve Workflow and Stage URIs

    To retrieve the workflow name, you can URL encode the workflow name and use the result to query and retrieve the workflow URI:

    The stage names are guaranteed to be unique for each workflow. However, they may not be unique in the Clarity LIMS system. As a result, the stage URI cannot be queried for in the same way as the workflow URI.

    Instead, you can navigate through the workflow node to find the stage that matches the stage name specified using the getStageURI function. If a match is found, return the stage URI.

    hashtag
    Step 3. Verify Each Sample Meets the Requeue Criteria

    Next, you must make sure that each sample meets the criteria to be requeued using the canRequeue function. The following method checks all workflow stages for the samples:

    • If a match is found between a workflow stage URI and the stage URI specified, the sample node is added to a list of samples that can be requeued using the requeueList function.

    • If all the samples have this match and a status that allows for requeue, the list is returned. Otherwise, the script exits with an error message that states the first sample to cause failure.

    hashtag
    Step 4. Check and Retrieve Workflow Stage for Sample Node

    In this example, both unassignment from and assignment to a workflow stage must occur to complete the requeue. As the samples are requeuing to a previous stage in the workflow and can currently be queued for another stage, you must remove them from these queues.

    The getCurrentStageURI and lastStageRun functions check the sample node for its most recent workflow stage. If the node is in a queued status, it returns that stage URI to be unassigned.

    hashtag
    Step 5. Build the XML Assignment

    Using the previous methods and their results, the following code uses Streaming Markup Builder and the assignmentXML function to build the XML to be posted:

    The returned XML node is then posted using httpPOST.

    hashtag
    Configuring and Running the Automation

    Add and configure the automation

    1. In Clarity LIMS, under Configuration, select the Automation tab.

    2. Select the Derived Sample Automation tab.

    3. Select New Automation and enter the following information:

    Run the automation as follows.

    1. Open the Projects Dashboard.

    2. Select a project containing in-progress samples. Select In-progress samples.

      In the sample list, you will see all of the submitted and derived samples that are currently in progress for this project.

    In this example, the –w and -t {userinput} options invoke a dialog box on automation trigger. The user is required to enter two parameters: the full name of the stage and the workflow for which selected samples are to be requeued. The names must be enclosed in quotation marks.

    hashtag
    Expected Output and Results

    If the requeue is successful, each requeued sample is marked with a complete tag. Hovering over a sample shows a more detailed message.

    hashtag
    Attachments

    RequeueSamples.groovy:

    Automation Name—This is the name that displays to the user running the automation from the Projects Dashboard. Choose a descriptive name that reflects the functionality/purpose (eg, Requeue Samples).

  • Channel Name—Enter the channel name.

  • Command Line—Enter the command line required to invoke the script.

  • Select Save.

  • Select one or more derived samples. Selecting samples activates the Action button and drop-down list.
  • In the Action drop-down list, select the Requeue Samples automation.

  • file-download
    1KB
    RenamingSample.groovy
    arrow-up-right-from-squareOpen
    def getSampleNodes(sampleList, hostname, username, password){
        sampleURIList = sampleList.collect{"${hostname}v2/artifacts/${it}"}
        return GLSRestApiUtils.batchGET(sampleURIList, username, password)
    }
    encodedWorkflowName = java.net.URLEncoder.encode(workflowName, "UTF-8")
    try {
        workflowURI = GLSRestApiUtils.httpGET\
            ("${hostname}v2/configuration/workflows?name=${encodedWorkflowName}", username, password).workflow.@uri[0]
    if (!workflowURI) {
            throw new Exception()
        }
    } catch (Exception e) {
        println "Unable to find workflow: " + workflowName
        System.exit(-1)
    }
    def getStageURI (workflowURI, stageName, username, password) {
        def stageURI
        GLSRestApiUtils.httpGET(workflowURI, username, password).stages.stage.find {
            if ([email protected]().equals(stageName)) {
                stageURI = it.@uri
                return true
            }
        }
        if (stageURI) {
            return stageURI
        } 
    def canRequeue(nodeList, stageURI){
        def Set conditions = ["REMOVED", "FAILED", "COMPLETE", "SKIPPED"]
        def requeueList = []
        def lastStageRun
        nodeList.each{ sampleNode ->
            sampleNode.'workflow-stages'?.'workflow-stage'.each {
                if ([email protected]().equals(stageURI)) {
                    lastStageRun = it
                }
            }
            if (conditions.contains([email protected]())) {
                requeueList.add(sampleNode)
            } else {
                println "Sample: " + [email protected]() + " cannot be queued to stage " +  stageName
                System.exit(-1)
            }
        }
        return requeueList
    }
    def getCurrentStageURI(sampleNode, workflowURI) {
        def lastStageRun
        sampleNode.'workflow-stages'?.'workflow-stage'.each {
            stageWorkflowURI = GLSRestApiUtils.httpGET(it.@uri, username, password).'workflow'.@uri[0]
            if (stageWorkflowURI.toString().equals(workflowURI.toString())) {
                lastStageRun = it
            }
        }
        return ([email protected]().equals('QUEUED')) ? [email protected]() : null
    } 
    def assignmentXML =  builder.bind {
            mkp.xmlDeclaration()
            mkp.declareNamespace(rt: 'http://genologics.com/ri/routing')
            'rt:routing' {
                requeueList.each { sampleNode ->
                    currentURI = getCurrentStageURI(sampleNode, workflowURI)
                    if (currentURI) {
                        'unassign'('stage-uri': currentURI) {
                            'artifact'(uri: sampleNode.@uri)
                        }
                    }
                    'assign'('stage-uri': stageURI) {
                        'artifact'(uri: sampleNode.@uri)
                    }
                }
            }
        }
        return GLSRestApiUtils.xmlStringToNode(assignmentXML.toString())
    }

    Rearray Samples

    In high throughput labs, samples are worked on in batches and some work is executed by a robot. Sometimes, a set of plates must be rearrayed to one larger plate before the robot can begin the lab step.

    This example accomplishes this using two scripts. One script is configured on a derived sample automation, while the second script is included in a command line configured on a step automation.

    hashtag
    Prerequisites

    Before you follow the example, make sure that you have the following items:

    • A project containing samples assigned to a workflow in Clarity LIMS.

    • The workflow name.

    • Given samples are assigned to the same workflow stage.

    hashtag
    Code Example

    This example demonstrates the following scripts:

    • AssignToRearrayWf.groovy—Executed as a derived sample automation, this script assigns selected samples to the rearray step.

    • AssignToLastRemoved.groovy—Executed after the rearray step, this script assigns the samples to the stage to which they were originally assigned. The script is included in a command line configured on a step automation.

    hashtag
    Configure the Assign To Rearray Automation

    1. In Clarity LIMS, under Configuration, select the Automation tab.

    2. Select the Derived Sample Automation tab.

    3. Select New Automation and create an automation that prompts the user for the workflow stage name to be used.

    In the example, note the following:

    • The {groovy_bin_location} and {script_location} parameters must be customized to reflect the locations on your computer.

    • The –w option allows for user input to be passed to the script as a command-line variable.

    hashtag
    AssignToRearrayWf Script Methods

    hashtag
    Step 1. Retrieve the Artifact Nodes Using the Artifact LIMS IDs

    The AssignToRearrayWf script has a list of artifact (sample) LIMS IDs given on the command line. To begin, use this script to build a list of artifact nodes.

    The following code example builds a list of artifact URIs using the artifact LIMS ID list and the getArtifactNodes function. The resulting artifact URI list can then be used for a batchGET call to return the artifact nodes.

    hashtag
    Step 2. Retrieve Workflow Name and URI

    In this example, you can assume that the workflow name is known by the user and is passed to the script by user input when the automation is initiated.

    The workflow can then be queried for using the passed workflow name. The workflow name is first encoded, and from this, you can retrieve the workflow URI.

    hashtag
    Step 3. Make Sure that the Samples Belong to the Same Workflow Stage

    For the samples to be placed in the same container, they must all belong to the same workflow and be currently queued to the same stage in that workflow.

    Using the workflow name passed in by the user, do the following:

    1. Search the workflow stage list of the first artifact and store the URI of the most recent stage that is part of the workflow, if it is queued. Otherwise, the script exits with an error message.

    2. After storing the workflow stage URI of the first artifact, use the checkMatch function check against the remaining artifacts in the list to verify they are all currently queued to the same stage.

    If all artifacts are queued for the stage, they are removed from the queue of the stage under the lastWfStageURI function.

    hashtag
    Step 4. Build the XML for stage assignment using Streaming Markup Builder

    In this example, all the artifacts are unassigned from the previous workflow stage returned and assigned to the rearray stage using the queuePlacementStep function. The previous methods have verified that the artifacts in the list can be rearrayed together.

    The returned XML node is then posted using httpPOST.

    hashtag
    Step 2. Configuring Placement Workflow, Protocol, and Step

    1. In Clarity LIMS, under Configuration, select the Lab Work tab.

    2. Create a master step of Standard step type.

    3. From Configuration, select the Automation tab.

    hashtag
    AssignToLastRemovedStage Script Methods

    hashtag
    Step 1. Build List of Artifact Nodes from the Step Input-Output Map

    The first step of AssignToLastRemovedStage script is the same as for the AssignToRearrayWf script: return the artifact node list.

    However, in this script, you are not directly given the artifact LIMS IDs. Instead, because you receive the step URI from the process parameter command line, you can collect the artifact URIs from the inputs of the step details input-output map using the getArtifactNodes function.

    An example step details URI might be {hostname}/api/v2/steps/{stepLIMSID}/details.

    hashtag
    Step 2. Assign Artifacts Back to the Original Stage

    Each artifact in the list was removed from this stage before going through the rearray step.

    With this in mind, and because the Clarity LIMS API stores artifact history by time (including stage history), the stage to which you now want to assign the samples to be the second-to-last stage in the workflow-stage list.

    The following method finds the stage from which the artifacts were removed using the getLastRemoved function:

    hashtag
    Step 3. Make Sure that Artifacts are Assigned to the Same Stage

    You can then check to make sure all artifacts originated in this stage. This helps you avoid the scenario where the AssignToRearrayStage.groovy script was run on two groups of artifacts queried while in different workflow stages.

    hashtag
    Step 4. Build the XML to Assign the Samples Back to the Returned Stage

    Function: assignStage

    This returned stage URI is then used to build the assignment XML to assign all the samples back to this stage with the assignStage function.

    After posting this XML node, the samples are assigned back to the stage in which they began.

    hashtag
    Step 3. Running the Assign to Rearray Automation

    1. In the Projects Dashboard, select the samples to be rearrayed and run the 'Assign to Rearray' automation.

      On automation trigger, the {userinput} phrase will invoke a dialog that prompts for the full name of the workflow.

    hashtag
    Step 4. Placing the Samples and Running the Rearray Step

    1. In Clarity LIMS, under Lab View, select the protocol you created in .

      The samples assigned by the Assign to Rearray automation is available to assign to a new container.

    2. Add the samples to the Ice Bucket and begin work.

    hashtag
    Attachments

    AssignToRearrayWf.groovy:

    AssignToLastRemoved.groovy:

    Select the Step Automation tab.
  • Create an automation for the AssignToLastRemoved.groovy script.

    The {groovy_bin_location} and {script_location} parameters must be customized to reflect the locations on your computer.

  • Enable the automation on the master step you created in step 2.

  • Configure a new protocol and step as follows.

    • On the Lab Work tab, create a non-QC protocol.

    • In the Protocols list, select the new protocol and then add a new step to it. Base the new step on the master step you created in step 2.

    • On the Step Settings form, in the Automation section, you see the step automation you configured. Configure the automation triggers as follows.

      • Trigger Location—Step

      • Trigger Style—Automatic upon exit

    • On the Placement milestone, Add 96 well plate and 384 well plate as the permitted destination container types for the step.

    • Remove the default Tube container type.

    • Save the step.

  • Configure a new workflow as follows:

    • On the Lab Work tab, create a workflow.

    • Add the protocol you created to the workflow.

  • The placement screen opens, allowing you to place the samples into the new container, in your desired placement pattern.
  • Proceed to the Record Details screen, then on to Next Steps. Do not perform any actions on these screens.

  • In the next step drop-down list, select Mark Protocol as Complete and select Apply.

  • Selec Next. This initiates the 'Assign to last removed' trigger, which assigns the samples back to the step from which they were removed.

  • file-download
    6KB
    AssignToRearrayWf.groovy
    arrow-up-right-from-squareOpen
    file-download
    4KB
    AssignToLastRemoved.groovy
    arrow-up-right-from-squareOpen
    Step 2. Configuring Placement Workflow, Protocol, and Step
    def getArtifactNodes(artifactList, hostname, username, password) {
        artifactURIList = artifactList.collect{"${hostname}v2/artifacts/${it}"}
        return GLSRestApiUtils.batchGET(artifactURIList, username, password)
    } 
    encodedWorkflowName = URLEncoder.encode(workflowName, "UTF-8")
    workflowURI = GLSRestApiUtils.httpGET("${hostname}v2/configuration/workflows?name=${encodedWorkflowName}", username, password)?.workflow?.getAt(0)?.@uri
    def checkMatch (artifactNodeList, workflowURI, username, password) {
        def lastWfStageURI
        def valid = false
        firstArtifactStageList = artifactNodeList[0].'workflow-stages'.'workflow-stage'
        for (i = 0; i < firstArtifactStageList.size(); i++) {
            if (firstArtifactStageList[i][email protected]().equals('QUEUED')) {
                stageWfURI = GLSRestApiUtils.httpGET(firstArtifactStageList[i].@uri, username, password)?.workflow?.@uri[0].toString()
                if (stageWfURI.equals(workflowURI.toString())) {
                    valid = true
                    lastWfStageURI = firstArtifactStageList[i].@uri
                    if (firstArtifactStageList[i+1][email protected]().equals('REMOVED')) {
                        valid = false
                    }
                }
            }
        }
        if (!valid) {
            println "artifact " + artifactNodeList[0].name.text() + " is not currently queued to this workflow"
            System.exit(-1)
        }
        for (i = 1; i < artifactNodeList.size(); i++) {
            valid = false
            artifactNodeList[i].'workflow-stages'.'workflow-stage'.each {
                if ([email protected]().equals(lastWfStageURI.toString())) {
                    if ([email protected]().equals('QUEUED')) {
                        valid = true
                    } else {
                        valid = false
                    }
                }
            }
            if (!valid) {
                println "Artifact " + artifactNodeList[i].name.text() + " is not currently queued to this workflow"
                System.exit(-1)
            }
        }  
    def queuePlacementStep (artifactNodeList, unassignStageURI, workflowToAssign) {
        def builder = new StreamingMarkupBuilder()
        builder.encoding = "UTF-8"
        def placementStepAssignment = builder.bind {
            mkp.xmlDeclaration()
            mkp.declareNamespace(rt: 'http://genologics.com/ri/routing')
            'rt:routing' {
                'unassign'('stage-uri': unassignStageURI) {
                    artifactNodeList.each { artifactNode ->
                        'artifact'(uri: artifactNode.@uri)
                    }
                }
                'assign'('workflow-uri': workflowToAssign) {
                    artifactNodeList.each { artifactNode ->
                        'artifact'(uri: artifactNode.@uri)
                    }
                }
            }
        }
        return GLSRestApiUtils.xmlStringToNode(placementStepAssignment.toString())
    }
    def getArtifactNodes (stepDetails, username, password) {
        artifactURIList = GLSRestApiUtils.httpGET(stepDetails, username, password)\
            .'input-output-maps'.'input-output-map'.collect{it.input.@uri[0]}.toSet()
        return GLSRestApiUtils.batchGET(artifactURIList, username, password)
    } 
    def getLastRemoved (artifactNodeList) {
        def stageList = artifactNodeList[0].'workflow-stages'.'workflow-stage'
        stageToQueue = (stageList[(stageList.size()) - 2][email protected]().equals('REMOVED')) ? stageList[(stageList.size()) - 2].@uri : null 
    if (!stageToQueue) {
            println "Failed to requeue, ${artifactNodeList[0].name.text()} may have been assigned to a new workflow"
            System.exit(-1)
        } else {
            artifactNodeList.each {
                nodeStageList = it.'workflow-stages'.'workflow-stage'
                lastRemoved = nodeStageList[(nodeStageList.size() -2)][email protected]().equals('REMOVED') ? nodeStageList[(nodeStageList.size()) -2].@uri : null
                if (!lastRemoved.toString().equals(stageToQueue.toString())) {
                    println "Sample ${it.name.text()} started in a separate stage, verify all samples are being arrayed for the same workflow"
                    System.exit(-1)
                }
            }
        } 
    def assignStage (artifactNodeList, assignStageURI) {
        def builder = new StreamingMarkupBuilder()
        builder.encoding = "UTF-8"
        def assignmentXML = builder.bind {
            mkp.xmlDeclaration()
            mkp.declareNamespace(rt: 'http://genologics.com/ri/routing')
            'rt:routing' {
                'assign'('stage-uri': assignStageURI) {
                    artifactNodeList.each { artifactNode ->
                        'artifact'(uri: artifactNode.@uri)
                    }
                }
            }
        }
        return GLSRestApiUtils.xmlStringToNode(assignmentXML.toString())