arrow-left

All pages
gitbookPowered by GitBook
1 of 6

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Work with Process/Step Outputs

When working with process and step outputs, you can do the following:

  • Update UDF/Custom Field Values for a Derived Sample Output

  • Rename Derived Samples Using the API

  • Find the Container Location of a Derived Sample

Traverse a Pooled and Demultiplexed Sample History/Genealogy
View the Inputs and Outputs of a Process/Step

Update UDF/Custom Field Values for a Derived Sample Output

As processing occurs in the lab, associated processes and steps are run in Clarity LIMS. Often, key data must be recorded for the derived samples (referred to as analytes in the API) generated by these steps.

The following example explains how to change the value of an analyte UDF/global custom field.

If you would like to update a batch of output derived samples (analytes), you can increase the script execution speed by using batch operations. For more information, see Working with Batch Resources.

hashtag
Prerequisites

In Clarity LIMS v5 or later, the key data fields are configured as global custom fields on derived samples. If you are using Clarity LIMS v5 or later, make sure you have the following items:

  • A defined global custom field named Library Size on the Derived Sample object.

  • A configured Library Prep step to apply Library Size to generated derived samples.

  • A Library Prep process that has been run and has generated derived samples.

hashtag
Terminology

As of Clarity LIMS v5, the term user-defined field (UDF) has been replaced with custom field in the user interface. However, the API resource is still called UDF.

There are two types of custom fields:

  • Master step fields—Configured on master steps. Master step fields only apply to the following:

    • The master step on which the fields are configured.

    • The steps derived from those master steps.

hashtag
Code example

In Clarity LIMS v5 and later, the Record Details screen displays the information about the derived samples generated by a step. You can view the global fields associated with the derived samples in the Sample Table.

The following screenshot shows the Library Size values for the derived samples.

circle-info

Derived sample information is stored in the API in the analyte resource. Step information is stored in the process resource. Each global field value is stored as an udf.

An analyte resource contains specific derived sample details that are recorded in lab steps. Those details are typically stored in global custom fields (configured in Clarity LIMS on the Derived Sample object) and then associated with the step.

When you update the information for a derived sample by updating the analyte API resource, only the global fields that are associated with the step can be updated.

hashtag
Step 1. Request the Process Resource

To update the derived samples generated by a step, you must first request the process resource through a GET method.

The following GET method provides the full XML structure for the step:

The process variable now holds the complete XML structure returned from the GET request.

The XML returned from a GET on the process resource contains the URIs of the process output artifacts (the derived samples generated by the step). You can use these URIs to query for each individual artifact resource.

The process resource contains many input-output-map elements, where each element represents an artifact. The following snippet of the XML shows the process:

circle-info

Because processes with multiple inputs and outputs tend to be large, many of the input-output-map nodes have been omitted from this example.

hashtag
Step 2. Request the Artifact Resource and Update the Analyte UDF/Custom Field

After you have retrieved each individual artifact resource, you can use this information to update the UDFs/custom fields for each output analyte after you request its resource.

Request the analyte output resource and update the UDF/custom field as follows.

  1. If the output-type is analyte, then run through each input-output-map and request the output artifact resource.

  2. Use a GET to return the XML for each artifact and store it in a variable.

  3. When you have the analytes stored, change the analyte UDF/custom field through the following methods:

The UDF/custom field change can be achieved with the Library Size UDF/custom field XML element defined in the following code. In this example, the Library Size value is updated to 25.

The PUT method updates the artifact resource at the specified URI using the complete XML representation, including the UDF/custom field. The setUdfValue method of the util library is used to perform this in a safe manner.

The output-type attribute is the user-defined name for each of the output types generated by a process/step. This is not equivalent to the type element of an artifact whose value is one of several hard-coded artifact types.

If you must filter inputs or outputs from the input-output-map based on the artifact type, you will must GET each artifact in question to discover its type.

circle-info

It is important that you remove the state from each of the analyteURIs before you GET them, to make sure that you are working with the most recent state.

Otherwise, when you PUT the analyteURI back with your UDF/custom field changes, you can inadvertently revert information, such as QC, volume, and concentration, to previous values.

hashtag
Expected Output and Results

The results can be reviewed in a web browser through the following URI:

In Clarity LIMS v5 or later, in the Record Details screen, the Sample table now shows the updated Library Size.

hashtag
Attachments

UpdateProcessUDFInfo.groovy:

UpdateUDFAnalyteOutput.groovy:

Global fields—Configured on entities (eg, submitted sample, derived sample, measurement, etc.). Global fields apply to the entire Clarity LIMS system.
The UDF/custom field change in the XML.
  • The http PUT call to update the artifact resource.

  • file-download
    2KB
    UpdateProcessUDFInfo.groovy
    arrow-up-right-from-squareOpen
    file-download
    1KB
    UpdateUDFAnalyteOutput.groovy
    arrow-up-right-from-squareOpen
    // Retrieve Process processURI = "http://${hostname}/api/v2/processes/${processLIMSID}" process = GLSRestApiUtils.httpGET(processURI, username, password)
    <prc:process uri="http://yourIPaddress/api/v2/processes/A14-BMJ-100830-24-1472" limsid="A14-BMJ-100830-24-1472"> <type>API Cookbook Example 1.4</type> <date-run>2010-08-30</date-run> <technician uri="http://yourIPaddress/api/v2/researchers/305"> <first-name>Brandon</first-name> <last-name>Johnson</last-name> </technician> <input-output-map> <input uri="http://yourIPaddress/api/v2/artifacts/HAM754A4PA1?state=15633" post-process-uri="http://yourIPaddress/api/v2/artifacts/HAM754A4PA1?state=15641" limsid="HAM754A4PA1"/> <output uri="http://yourIPaddress/api/v2/artifacts/HAM754A4AP8?state=15644" output-type="Analyte" limsid="HAM754A4AP8"/> </input-output-map> <input-output-map> <input uri="http://yourIPaddress/api/v2/artifacts/HAM754A1PA1?state=15622" post-process-uri="http://yourIPaddress/api/v2/artifacts/HAM754A1PA1?state=15646" limsid="HAM754A1PA1"/> <output uri="http://yourIPaddress/api/v2/artifacts/HAM754A1AP8?state=15642" output-type="Analyte" limsid="HAM754A1AP8"/> </input-output-map> <input-output-map> <input uri="http://yourIPaddress/api/v2/artifacts/HAM754A3PA1?state=15626" post-process-uri="http://yourIPaddress/api/v2/artifacts/HAM754A3PA1?state=15637" limsid="HAM754A3PA1"/> <output uri="http://yourIPaddress/api/v2/artifacts/HAM754A3AP8?state=15639" output-type="Analyte" limsid="HAM754A3AP8"/> </input-output-map></prc:process>
    // For each input-output-map, if its output is an Analyte, set its Library Size UDF process.'input-output-map'.each { if (it.output.@'output-type'[0] == "Analyte") { analyteURI = it.output.@uri[0] analyte = GLSRestApiUtils.httpGET(analyteURI, username, password) analyte = GLSRestApiUtils.setUdfValue(analyte, 'Library Size', '25') GLSRestApiUtils.httpPUT(analyte, analyte.@uri, username, password) } }
    http://yourIPaddress/api/v2/artifacts/HAM754A4AP8\
    
    <art:artifact uri="http://yourIPaddress/api/v2/artifacts/HAM754A4AP8?state=15644" limsid="HAM754A4AP8"> <name>Colon-4</name> <type>Analyte</type> <output-type>Analyte</output-type> <parent-process uri="http://yourIPaddress/api/v2/processes/A14-BMJ-100830-24-1472" limsid="A14-BMJ-100830-24-1472"/> <volume unit="uL">0.0</volume> <concentration unit="ug/mL">10.0</concentration> <qc-flag>UNKNOWN</qc-flag> <location> <container uri="http://yourIPaddress/api/v2/containers/27-2320" limsid="27-2320"/> <value>1:1</value> </location> <working-flag>true</working-flag> <sample uri="http://yourIPaddress/api/v2/samples/HAM754A4" limsid="HAM754A4"/> <udf:field type="Numeric" name="Library Size">25</udf:field></art:artifact>

    Find the Container Location of a Derived Sample

    As samples are processed in the lab, substances are moved from one container to another. Because container locations are sometimes used to reference the sample in data files, tracking the location of these substances within containers is one of the key values that Clarity LIMS provides to the lab.

    Within the REST API (v2 r21 or later), analytes represent the substances on which processes/steps are run. These analytes are the substances that are chemically altered and transferred between containers as samples are processed in the lab.

    Each individual sample resource has an analyte artifact that describes its container location and is used to run processes.

    In Clarity LIMS, steps are not run on the original submitted samples, but are instead run on (and can also generate) derived samples. In the API, derived samples are known as analytes. Each sample resource, which is the original submitted sample in Clarity LIMS, has a corresponding analyte that is used for running processes/steps and describing placement in a container.

    For more information on analyte artifacts and other REST resources, see Structure of REST Resources.

    hashtag
    Prerequisites

    For all Clarity LIMS users, make sure you have done the following actions:

    • Added a sample to Clarity LIMS.

    • Run a process/step on the sample, with the same process/step generating a derived sample output.

    • Added the generated derived sample to a multi-well container (eg, a 96-well plate).

    hashtag
    Code Example

    The container location information for an individual derived sample/analyte is located within the XML for the individual artifact resource. Because artifacts are generated by running steps in the LIMS, this is a logical place to keep track of the location.

    Within a script, you can use a GET method to request the artifact. The resulting XML structure contains all the information related to the artifact, including its container and well location.

    In this example, a derived sample named Brain-600 is placed in well A:1 of a container with LIMS ID 27-1259. This information is found in the location element.

    The location elements has two child data elements:

    • One linking to the container URI, which specifies which container the analyte is in.

    • One for the well location, which has the name 'value' in the XML structure.

    Valid values for a well location can be either numeric or alphabetic, and are determined by the configuration of the container in Clarity LIMS.

    Well locations are always represented in the row:column format. For example, a 96-well plate can have locations A:1 and C:12, and a tube can have a single well called 1:1.

    hashtag
    Step 1. Retrieve the Artifact

    Use the following XML example to retrieve the artifact:

    hashtag
    Step 2. Access, Store, and Print the Container Location

    Because the container position is structured in the row:column format, you can store the row and column in separate variables by splitting the container position on the colon character. You can access the string value of the location value node using the text() method, as shown in the following code:

    hashtag
    Expected Output and Results

    Running the script in a console produces the following output:

    hashtag
    Attachments

    GetContainerAnalyteLocation.groovy:

    file-download
    1KB
    GetContainerAnalyteLocation.groovy
    arrow-up-right-from-squareOpen
    <art:artifact uri="http://yourIPaddress/api/v2/artifacts/HAM751A481PA1?state=9995" limsid="HAM751A481PA1">
        <name>Brain-600</name>
        <type>Analyte</type>
        <output-type>Analyte</output-type>
        <volume unit="uL">645.0</volume>
        <concentration unit="ug/mL">0.5478</concentration>
        <qc-flag>UNKNOWN</qc-flag>
        <location>
            <container uri="http://yourIPaddress/api/v2/containers/27-1259" limsid="27-1259"/>
            <value>A:1</value>
        </location>
        <working-flag>true</working-flag>
        <sample uri="http://yourIPaddress/api/v2/samples/HAM751A481" limsid="HAM751A481"/>
    </art:artifact> 
    // Retrieve the artifact
    artifactURI = "http://${hostname}/api/v2/artifacts/${artifactLIMSID}"
    artifact = GLSRestApiUtils.httpGET(artifactURI, username, password)
    // Separate the artifact's position inside of its container
    containerPosition = artifact.location.value.text()
    positionList = containerPosition.tokenize(':')
     
    // Output its position
    row = positionList[0]
    column = positionList[1]
    println "This sample is located at row: $row, column: $column"
    This sample is located at row: A, column: 1

    Traverse a Pooled and Demultiplexed Sample History/Genealogy

    The large capacity of current Next Generation Sequencing (NGS) instruments means that labs are able to perform multiplexed experiments with multiple samples pooled into a single lane or region of the container. Before being pooled, samples are assigned a unique tag or index. After sequencing and initial analysis are complete, the sequencing results must be demultiplexed to separate data and relate the results back to each individual sample.

    Clarity LIMS allows you to track a multiplexing workflow by adding reagents and reagent labels to artifacts, and then using the reagent labels to demultiplex the resulting files.

    There are several ways to apply reagent labels. However, all methods involve creating placeholders that link the final sequences back to the original submitted samples. Either the lab scientist or an automated process must determine which file actually belongs with which placeholder. For more information on applying reagent labels, refer to Work with Multiplexing.

    This example walks through assigning user-defined field (UDF)/custom field values to the demultiplexed output files based on upstream derived sample (analyte) UDF/custom field values. This includes upwards traversal of a sample history / genealogy, based on assigned reagent labels. This differs from upstream traversal based strictly upon process input-output mappings.

    As of Clarity LIMS v5, the term user-defined field (UDF) has been replaced with custom field in the user interface. However, the API resource is still called UDF.

    There are two types of custom fields:

    • Master step fields—Configured on master steps. Master step fields only apply to the following:

      • The master step on which the fields are configured.

      • The steps derived from those master steps.

    hashtag
    Prerequisites

    If you are using Clarity LIMS v5 or later, make sure you have completed the following actions:

    • Created a project and have added multiple samples to it.

    • Run the samples through a sequence of steps that perform the following:

      • Reagent addition / reagent label assignment

    You also must make sure that API v2 r21 or later is installed.

    hashtag
    Code Example

    Due to the complexity of NGS workflows, beginning at the top level submitted sample resource and working down to the result file is not the most efficient way to traverse the sample history/genealogy. It is easier to start with the result file artifact, and then trace upward to find the process with the UDFs/custom fields that you are looking for.

    Starting from the per-reagent-label result file, you can traverse upward in the sample history using the parent process URI in the XML returned for each artifact. At each level of the sample history, the number of artifacts returned may increase due to processes that pooled individual artifacts.

    In this example:

    • The upstreamArtifactLUIDs list represents the current set of relevant artifacts.

    • The foundUpstreamArtifactNodes list stores the target upstream artifact nodes found.

    • The sample history traversal stops at the inputs to the process that performed the reagent addition/reagent label assignment.

    The traversal is executed using a while loop over the contents of the upstreamArtifactLUIDs list.

    The list serves as a stack of artifacts. With each iteration of the loop, an artifact is removed from the end of the list and the relevant input artifacts to its parent process are pushed back onto the end of the list.

    After the loop has executed, the foundUpstreamArtifactNodes list will contain all of the artifacts that are assigned the reagent label of interest upon execution of the next process in the sample history.

    The final step in the script assigns a value to a Numeric UDF / custom field on the per-reagent-label output result file, Mean DNA Prep 260:280 Ratio, by computing the mean value of a Numeric UDF / custom field on each of the foundUpstreamArtifactNodes, DNA prep 260:280 ratio.

    First, compute the mean using the following example:

    Then, set the UDF/custom field on the per-reagent-label output result file using the following example:

    hashtag
    Attachments

    TraversingPooledDemuxGenealogy.groovy:

    View the Inputs and Outputs of a Process/Step

    When samples are processed in the lab, they generally produce child samples that are altered in some way. Eventually, the samples are analyzed on an instrument, with the result being a data file. Often these data are analyzed further, which produces additional data files.

    The sample processing that occurs in the lab is modeled as steps in the Clarity LIMS web interface. In the REST API (v2 r21 or later), this processing is modeled as processes, and the samples and files that are processed are represented as artifacts. Understanding the representation of inputs and outputs within the XML for an individual process is critical to being able to use the REST API effectively.

    hashtag
    Prerequisites

    If you are using Clarity LIMS v5 or later, make sure that you have done the following actions:

    Global fields—Configured on entities (eg, submitted sample, derived sample, measurement, etc.). Global fields apply to the entire Clarity LIMS system.
    Pooling
  • Demultiplexing (to produce a set of per-reagent-label result file outputs).

  • Set a Numeric custom field value on each derived sample input to the reagent addition process.

  • A Numeric custom field with no assigned value exists on each of the per-reagent-label result file outputs. The value of this field will be computed from the set of upstream derived sample custom field values corresponding to the reagent label of the result file.

  • file-download
    5KB
    TraversingPooledDemuxGenealogy.groovy
    arrow-up-right-from-squareOpen
    • Added samples to the LIMS.

    • Configured a step that generates derived samples in the Lab Work tab.

    • Configured a file placeholder for a sample measurement file to be generated and attached by an automation script at run time. This configuration is done in the Master Step Settings of the step on the Record Details milestone.

    • Configured an automation that generates the sample measurement file and have enabled it on the step. This configuration is done in the Automation tab.

    • Configured the automation triggers. This configuration is done in the Step Settings screen, under the Record Details milestone.

    • Run the step on some samples.

    hashtag
    Code Example

    As of Clarity LIMS v5, the Operations Interface Java client has been deprecated. In LIMS v5 and later, there is no equivalent screen to the Input/Output Explorer where you can select step inputs/outputs and generated files and view their corresponding inputs/outputs and files.

    However, the following API code example is still relevant and will produce the same results.

    hashtag
    Step 1. Request Individual Process Resource

    The first step in this example is to request the individual process resource through a GET method. The full XML representation returned includes the input-output-map.

    To illustrate the relationships between the inputs and outputs, you can save them using a Groovy Map data structure. This maps the output LIMS IDs to a list of input LIMS IDs associated with each output, as shown in the following example:

    The process variable now holds the complete XMLstructure returned from the processURI.

    In the following example XML snippet, elements of the input-output-map are labeled with <input-output-map>:

    All of the input and output URIs include a ?state= some number. State allows Clarity LIMS to track historical values for QC, volume, and concentration, so you can compare the state of an analyte before and after a process was run. However, when you make changes to an artifact you should always work with the most current state.

    To make sure that you are getting the current state when you do a GET request, simply remove the state from the artifact URI.

    hashtag
    Step 2. Map Output LIMS IDs to Input LIMS IDs

    You can examine each input-output-map to find details about the relationship represented between inputs and outputs. The following code puts the output and input LIMS IDs into an array named outputToInputMap.

    As the output type is also important for further processing, outputToInputMap is formatted as follows:

    If the output is shared for all inputs (eg, the sample measurement file with LIMS ID 92-13007), the inputs to the process are listed. If the output relates to an individual input, only the LIMS ID for that particular input will be listed.

    Outputs are listed in multiple input-output-map elements when they have multiple input files generating them. The first time any particular output LIMS ID is seen, the output type and input LIMS ID in the input-output-map are added to the list, stored in outputToInputMap.

    If the output LIMS ID already has a list in outputToInputMap, then the code adds input LIMS ID to the list.

    hashtag
    Step 3. Print the List

    One way to access the information is to print it out. You can run through each key-value pair and print the information it contains, as shown in the following example:

    hashtag
    Expected Output and Results

    After running the script on the command line, an output similar to the following will be generated, whereby the inputs used to generate each output are listed.

    hashtag
    Attachments

    GetProcessInputOutput.groovy:

    file-download
    2KB
    GetProcessInputOutput.groovy
    arrow-up-right-from-squareOpen
    targetDownstreamArtifactNode = GLSRestApiUtils.httpGET(artifactsListURI + artifactLUID, username, password)
        targetReagentLabel = targetDownstreamArtifactNode.'reagent-label'[0]?.'@name'
        if (!targetReagentLabel) {
            println "Specified artifact should contain at least one reagent-label.  Skipping ${artifactLUID}..."
            continue
        }
        // At each upstream level of the workflow the number of searched artifacts may increase due to Pooling processes
        upstreamArtifactLUIDs = [ artifactLUID ]
        /*
         * This 'stack' will store all upstream artifacts that serve as input to an 'Add Multiple Reagents' process
         * which are subsequently assigned the 'target' Reagent Label by this process.
         */
        foundUpstreamArtifactNodes = []
    while (!upstreamArtifactLUIDs.isEmpty()) {
            currentArtifactLUID = upstreamArtifactLUIDs.pop()
            currentArtifactNode = GLSRestApiUtils.httpGET(artifactsListURI + currentArtifactLUID, username, password)
            /*
             * Upstream traversal will stop when either an artifact is found that does not have reagent label(s) assigned
             * (i.e. the artifact is the input to a process that adds reagents and reagent labels), or a root artifact is found.
             * At this point, the current artifact is added to the list of 'found' upstream artifact nodes.
             */
            if (currentArtifactNode.'reagent-label'.isEmpty() || currentArtifactNode.'parent-process'.isEmpty()) {
                foundUpstreamArtifactNodes += [currentArtifactNode]
            } else if (currentArtifactNode.'reagent-label'.collect { it.'@name' }.contains(targetReagentLabel)) {
                /*
                 * If the current artifact contains the 'target' reagent label, continue traversing upstream.
                 * Get the artifact's parent process
                 */
                parentProcessURI = currentArtifactNode.'parent-process'[0].@uri
                parentProcessNode = GLSRestApiUtils.httpGET(parentProcessURI, username, password)
                // Find all input-output maps for the parent process
                parentProcessNode.'input-output-map'.each {
                    ioMapInputLUID = it.'input'[0].@limsid
                    ioMapOutputLUID = it.'output'[0].@limsid
                    // Push all process input artifacts that have the current artifact as the mapped process output onto the 'stack'
                    if( ioMapOutputLUID == currentArtifactLUID && !upstreamArtifactLUIDs.contains(ioMapInputLUID) ) {
                        upstreamArtifactLUIDs.push(ioMapInputLUID)
                    }
                }
            }
        }
    /*
     * Compute the 'Mean DNA Prep 260:280 Ratio' for all upstream analyte artifacts that have the
     * target Reagent Label applied.  The assumption here is that the 'DNA prep 260:280 ratio' UDF
     * is set on analytes that serve as input to an 'Add Multiple Reagents' process that assigns Reagent Labels.
     */
    avgAcrossUpstreamArtifacts = foundUpstreamArtifactNodes.collect {
        foundUdf = it.'udf:field'.find{ it.'@name' == upstreamArtifactUdfToMine }
        return foundUdf ? foundUdf.value()[0] as double : 0.0
    }.sum()/foundUpstreamArtifactNodes.size()
    // Set the computed mean on the 'Mean DNA Prep 260:280 Ratio' UDF on the target downstream ResultFile
    targetDownstreamAritfactUDF = targetDownstreamArtifactNode.'udf:field'.find{ it.'@name' == downstreamArtifactUdfToUpdate }
    if (targetDownstreamAritfactUDF) {
        targetDownstreamAritfactUDF.setValue(avgAcrossUpstreamArtifacts)
    } else {
        targetDownstreamArtifactNode.appendNode('udf:field',
                        ['name':downstreamArtifactUdfToUpdate,
                         'xmlns:udf':'http://genologics.com/ri/userdefined'],
                         avgAcrossUpstreamArtifacts)
    }
    outputToInputMap = [:]
    processURI = "http://${hostname}/api/v2/processes/${processLIMSID}"
    p+cess = GLSRestApiUtils.httpGET(processURI, username, password) 
    <prc:process uri="http://IPAddress/api/v2/processes/TES-SA1-130107-24-5259" limsid="TES-SA1-130107-24-5259">
        <type uri="http://IPAddress/api/v2/processtypes/355">Cookbook Example Process</type>
        <date-run>2013-01-07</date-run>
        <technician uri="http://IPAddress/api/v2/researchers/1">
            <first-name>System</first-name>
            <last-name>Administrator</last-name>
        </technician>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A3PA1?state=8055" uri="http://IPAddress/api/v2/artifacts/ADM224A3PA1?state=8040" limsid="ADM224A3PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/92-13007?state=8065" output-generation-type="PerAllInputs" output-type="ResultFile" limsid="92-13007" />
        </input-output-map>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A3PA1?state=8055" uri="http://IPAddress/api/v2/artifacts/ADM224A3PA1?state=8040" limsid="ADM224A3PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/ADM224A3TE3?state=8054" output-generation-type="PerInput" output-type="Analyte" limsid="ADM224A3TE3" />
        </input-output-map>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A5PA1?state=8053" uri="http://IPAddress/api/v2/artifacts/ADM224A5PA1?state=8047" limsid="ADM224A5PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/92-13007?state=8065" output-generation-type="PerAllInputs" output-type="ResultFile" limsid="92-13007" />
        </input-output-map>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A5PA1?state=8053" uri="http://IPAddress/api/v2/artifacts/ADM224A5PA1?state=8047" limsid="ADM224A5PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/ADM224A5TE3?state=8060" output-generation-type="PerInput" output-type="Analyte" limsid="ADM224A5TE3" />
        </input-output-map>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A2PA1?state=8056" uri="http://IPAddress/api/v2/artifacts/ADM224A2PA1?state=8042" limsid="ADM224A2PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/92-13007?state=8065" output-generation-type="PerAllInputs" output-type="ResultFile" limsid="92-13007" />
        </input-output-map>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A2PA1?state=8056" uri="http://IPAddress/api/v2/artifacts/ADM224A2PA1?state=8042" limsid="ADM224A2PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/ADM224A2TE3?state=8059" output-generation-type="PerInput" output-type="Analyte" limsid="ADM224A2TE3" />
        </input-output-map>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A4PA1?state=8063" uri="http://IPAddress/api/v2/artifacts/ADM224A4PA1?state=8048" limsid="ADM224A4PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/92-13007?state=8065" output-generation-type="PerAllInputs" output-type="ResultFile" limsid="92-13007" />
        </input-output-map>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A4PA1?state=8063" uri="http://IPAddress/api/v2/artifacts/ADM224A4PA1?state=8048" limsid="ADM224A4PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/ADM224A4TE3?state=8057" output-generation-type="PerInput" output-type="Analyte" limsid="ADM224A4TE3" />
        </input-output-map>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A1PA1?state=8061" uri="http://IPAddress/api/v2/artifacts/ADM224A1PA1?state=8046" limsid="ADM224A1PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/92-13007?state=8065" output-generation-type="PerAllInputs" output-type="ResultFile" limsid="92-13007" />
        </input-output-map>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A1PA1?state=8061" uri="http://IPAddress/api/v2/artifacts/ADM224A1PA1?state=8046" limsid="ADM224A1PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/ADM224A1TE3?state=8058" output-generation-type="PerInput" output-type="Analyte" limsid="ADM224A1TE3" />
        </input-output-map>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A6PA1?state=8064" uri="http://IPAddress/api/v2/artifacts/ADM224A6PA1?state=8045" limsid="ADM224A6PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/92-13007?state=8065" output-generation-type="PerAllInputs" output-type="ResultFile" limsid="92-13007" />
        </input-output-map>
        <input-output-map>
            <input post-process-uri="http://IPAddress/api/v2/artifacts/ADM224A6PA1?state=8064" uri="http://IPAddress/api/v2/artifacts/ADM224A6PA1?state=8045" limsid="ADM224A6PA1" />
            <output uri="http://IPAddress/api/v2/artifacts/ADM224A6TE3?state=8062" output-generation-type="PerInput" output-type="Analyte" limsid="ADM224A6TE3" />
        </input-output-map>
    </prc:process> 
    outputLIMSID -> [output-type, inputLIMSID-1, inputLIMSID-2, inputLIMSID-3, ...|output-type, inputLIMSID-1, inputLIMSID-2, inputLIMSID-3, ...]
    // For each io-map in the process, add its information to outputToInputMap
    process.'input-output-map'.each {
        outputType = it.'output'[0].'@output-type'
        outputLIMSID = it.'output'[0].@limsid
        inputLIMSID = it.'input'[0].@limsid
        // outputToInputMap stores all the output type and LIMS IDs of all the inputs to the output
        if (!outputToInputMap[outputLIMSID]) {
            outputToInputMap[outputLIMSID] = [outputType, inputLIMSID]
        } else {
            // If entry already exists, add another input to the list
            outputToInputMap[outputLIMSID] << inputLIMSID
        }
    }
    // Print the contents of the map, which stores the inputs LIMSIDs under the output's LIMSID
    o+tputToInputMap.each { key, value ->    println "$key is a(n) ${value[0]} with input:"
        for (int i = 1; i < value.size(); i++) {
            println '\t' + value[i]
        }
    }
    92-13007 is a(n) ResultFile with input:
            27-2028
            27-2029
            27-2030
            27-2031
            27-2032
            27-2033
    27-2034 is a(n) Analyte with input:
            27-2028
    27-2035 is a(n) Analyte with input:
            27-2029
    27-2036 is a(n) Analyte with input:
            27-2030
    27-2037 is a(n) Analyte with input:
            27-2031
    27-2038 is a(n) Analyte with input:
            27-2032
    27-2039 is a(n) Analyte with input:
            27-2033

    Rename Derived Samples Using the API

    Lab scientists must understand the priority of the samples they are working with. To help them prioritize their work, you can rename the derived samples generated by a step so that they include the priority assigned to the original submitted sample.

    If you would like to rename a batch of derived samples, you can increase the script execution speed by using batch operations. You can also use a script to rename a derived sample after a step completes.

    hashtag
    Prerequisites

    If you are using Clarity LIMS v5 and later, make sure that you have done the following actions:

    • Added samples to the system.

    • Defined a global custom field named Priority on the Submitted Sample object. The field should have default values sp1, sp2, and sp3, and it should be enabled on a step.

    • Run samples through the step with the Priority of each sample set to sp1, sp2, or sp3.

    hashtag
    Code example

    In this example, six samples have been added to a project in Clarity LIMS. The submitted samples names are Heart-1 through Heart-6. The samples are run through a step that generates derived samples, and the priority of each sample is set.

    By default, the name of the derived samples generated by the step would follow the name of the original submitted samples as shown in the Assign Next Steps screen of the step.

    This example appends the priority of the submitted sample to the name of the derived sample output. The priority is defined by the Priority sample UDF (in Clarity LIMS v4.2 or earlier) or the Priority submitted sample custom field (in Clarity LIMS v5 or later).

    Renaming the derived sample consists of the following steps:

    • Request the step information (process resource) for the step that generated the derived sample (analyte resource).

    • Request the individual analyte resource for the derived sample to be renamed.

    • Request the sample resource linked from the analyte resource to get the submitted sample UDF/custom field value to use for the update.

    hashtag
    Step 1. Request the Step Information (Process Resource) for the Step that Generated the Derived Sample (Analyte Resource)

    When using the REST API, you will often start with the LIMS ID for the step that generated a derived sample. The key API concepts are as follows.

    • Information about a step is stored in the process resource.

    • In general, automation scripts access information about a step using the processURI, which links to the individual process resource. The input-output-map in the XML returned by the individual process resource gives the script access to the artifacts that were inputs and outputs to the process.

    • Information about a derived sample is stored in the analyte resource. This is used as the input and output of a step.

    The following GET method returns the full XML structure for the step.

    The process variable now holds the complete XML structure returned from the process GET request, as shown in the following example. The URI for each analyte generated is given in the output node in each input-output-map element. For more information on the input-output-map, see .

    hashtag
    Step 2. Request the Individual Resource for the Derived Sample to be Renamed (Analyte Resource)

    Each output node has an output-type attribute that is the user-defined type name of the output. You can iterate through each input-output-map and request the output artifact resource for each output of a particular output-type.

    In the code example shown below, we filter on output-type = Analyte

    The output-type attribute is the user-defined name for each of the output types generated by a process. This is not equivalent to the type element of an artifact whose value is one of several hard-coded artifact types.

    If you must filter inputs or outputs from the input-output-map based on the artifact type, you need to GET each artifact in question to discover its type.

    circle-info

    It is important that you remove the state from each of the analyteURIs before you GET them to make sure that you are working with the most recent state. Otherwise, when you PUT the analyteURI back with your UDF changes, you can inadvertently revert information (eg, QC, volume, and concentration) to their previous values.

    hashtag
    Step 3. Request the Sample Resource to Get the Field Value to Use for the Update

    From the analyte XML, you can use the submitted sample URI to return the sample that maps to that analyte.

    shows how to set a sample UDF/global field. To get the value of a sample UDF/global field, use the same method to find the field, and then use the .text() method to get the field value.

    The value of the UDF is stored in the variable samplePriority so that it is then available for the renaming step described below.

    The variable analyte holds the complete XML structure returned from a GET on the URI in the output node. The variable nameNode references the XML element in that structure that contains the artifact's name. The XML for the analyte named Heart-1.

    hashtag
    Step 4. Update the Analyte Resource with the Name Change

    Renaming the derived sample consists of two steps:

    1. The name change in the XML.

    2. The PUT call to update the analyte resource.

    The name change can be performed with the nameNode XML element node defined. The following example shows this element defined.

    The http PUT command updates the artifact resource using the complete XML representation, including the new name.

    hashtag
    Expected Output and Results

    After a successful PUT, the results can be reviewed in a web browser at http://yourIPaddress/api/v2/artifacts/TST110A291AP45.

    The following XML resource is returned from the PUT command and is stored in returnNode.

    In Clarity LIMS, the Assign Next Steps screen shows the new names for the generated derived samples.

    This example shows simple renaming of derived samples based on a submitted sample UDF/global field. However, you can use step names, step UDFs (known as master step fields in Clarity LIMS v5 or later), project information, and so on, to rename derived samples and provide critical information to scientists working in the lab.

    hashtag
    Attachments

    UpdateAnalyteName.groovy:

    Update the individual analyte output resource with the new name.

    Analytes are also used to record specific details from lab processing.

  • The XML representation for an individual analyte contains a link to the URI of its submitted sample, and to the URI of the process that generated it (parent process).

  • View the Inputs and Outputs of a Process/Step
    Updating Sample Information
    file-download
    2KB
    UpdateAnalyteName.groovy
    arrow-up-right-from-squareOpen
    // Retrieve the process
    processURI = "http://${hostname}/api/v2/processes/${processLIMSID}"
    process = GLSRestApiUtils.httpGET(processURI, username, password)
    <prc:process uri="http://yourIPaddress/api/v2/processes/A13-BMJ-100830-24-1475" limsid="A13-BMJ-100830-24-1475">
        <type>API Cookbook Example 1.3</type>
        <date-run>2010-08-30</date-run>
        <technician uri="http://yourIPaddress/api/v2/researchers/305">
            <first-name>Brandon</first-name>
            <last-name>Johnson</last-name>
        </technician>
        <input-output-map>
            <input uri="http://yourIPaddress/api/v2/artifacts/HAM754A3PA1?state=15657" post-process-uri="http://yourIPaddress/api/v2/artifacts/HAM754A3PA1?state=15678" limsid="HAM754A3PA1"/>
            <output uri="http://yourIPaddress/api/v2/artifacts/HAM754A3AP10?state=15683" output-type="Analyte" limsid="HAM754A3AP10"/>
        </input-output-map>
        <input-output-map>
            <input uri="http://yourIPaddress/api/v2/artifacts/HAM754A1PA1?state=15651" post-process-uri="http://yourIPaddress/api/v2/artifacts/HAM754A1PA1?state=15685" limsid="HAM754A1PA1"/>
            <output uri="http://yourIPaddress/api/v2/artifacts/HAM754A1AP10?state=15680" output-type="Analyte" limsid="HAM754A1AP10"/>
        </input-output-map>
        <input-output-map>
            <input uri="http://yourIPaddress/api/v2/artifacts/HAM754A2PA1?state=15656" post-process-uri="http://yourIPaddress/api/v2/artifacts/HAM754A2PA1?state=15686" limsid="HAM754A2PA1"/>
            <output uri="http://yourIPaddress/api/v2/artifacts/HAM754A2AP10?state=15681" output-type="Analyte" limsid="HAM754A2AP10"/>
        </input-output-map>
        <input-output-map>
            <input uri="http://yourIPaddress/api/v2/artifacts/HAM754A6PA1?state=15659" post-process-uri="http://yourIPaddress/api/v2/artifacts/HAM754A6PA1?state=15679" limsid="HAM754A6PA1"/>
            <output uri="http://yourIPaddress/api/v2/artifacts/HAM754A6AP10?state=15677" output-type="Analyte" limsid="HAM754A6AP10"/>
        </input-output-map>
        <input-output-map>
            <input uri="http://yourIPaddress/api/v2/artifacts/HAM754A4PA1?state=15655" post-process-uri="http://yourIPaddress/api/v2/artifacts/HAM754A4PA1?state=15682" limsid="HAM754A4PA1"/>
            <output uri="http://yourIPaddress/api/v2/artifacts/HAM754A4AP10?state=15687" output-type="Analyte" limsid="HAM754A4AP10"/>
        </input-output-map>
        <input-output-map>
            <input uri="http://yourIPaddress/api/v2/artifacts/HAM754A5PA1?state=15652" post-process-uri="http://yourIPaddress/api/v2/artifacts/HAM754A5PA1?state=15684" limsid="HAM754A5PA1"/>
            <output uri="http://yourIPaddress/api/v2/artifacts/HAM754A5AP10?state=15688" output-type="Analyte" limsid="HAM754A5AP10"/>
        </input-output-map>
    </prc:process>
    // For each input-output-map process.'input-output-map'.each { if (it.output.@'output-type'[0] == "Analyte") { // Retrieve the analyte analyteURI = it.output.@uri[0] analyte = GLSRestApiUtils.httpGET(analyteURI, username, password) // Retrieve the analyte's sample and get its Priority UDF's value sampleURI = analyte.sample.@uri[0] sample = GLSRestApiUtils.httpGET(sampleURI, username, password) samplePriority = sample.'udf:field'.find { it.@name== 'Priority' }?.text() // Rename the analyte nameNode = analyte.name[0]
    // For each input-output-map
    process.'input-output-map'.each {
        if (it.output.@'output-type'[0] == "Analyte") {
            // Retrieve the analyte
            analyteURI = it.output.@uri[0]
            analyte = GLSRestApiUtils.httpGET(analyteURI, username, password)
     
            // Retrieve the analyte's sample and get its Priority UDF's value
            sampleURI = analyte.sample.@uri[0]
            sample = GLSRestApiUtils.httpGET(sampleURI, username, password)
            samplePriority = sample.'udf:field'.find { it.@name== 'Priority' }?.text()
     
            // Rename the analyte
            nameNode = analyte.name[0]
    <art:artifact uri="http://yourIPaddress/api/v2/artifacts/AFF853A43AP2?state=20985" limsid="AFF853A43AP2">
        <name>Heart-1</name>
        <type>Analyte</type>
        <output-type>Analyte</output-type>
        <parent-process uri="http://yourIPaddress/api/v2/processes/A13-BMJ-100923-24-2182" limsid="A13-BMJ-100923-24-2182"/>
        <qc-flag>UNKNOWN</qc-flag>
        <location>
            <container uri="http://yourIPaddress/api/v2/containers/27-303" limsid="27-303"/>
            <value>1:1</value>
        </location>
        <working-flag>true</working-flag>
        <sample uri="http://yourIPaddress/api/v2/samples/AFF853A43" limsid="AFF853A43"/>
    </art:artifact>
    newName = nameNode.text() + " " + samplePriority
            nameNode.setValue(newName)
            returnNode = GLSRestApiUtils.httpPUT(analyte, analyte.@uri, username, password)
        }
    } 
    <art:artifact uri="http://yourIPaddress/api/v2/artifacts/AFF853A43AP2?state=20985" limsid="AFF853A43AP2">
        <name>Heart-1 sp1</name>
        <type>Analyte</type>
        <output-type>Analyte</output-type>
        <parent-process uri="http://yourIPaddress/api/v2/processes/A13-BMJ-100923-24-2182" limsid="A13-BMJ-100923-24-2182"/>
        <qc-flag>UNKNOWN</qc-flag>
        <location>
            <container uri="http://yourIPaddress:/api/v2/containers/27-303" limsid="27-303"/>
            <value>1:1</value>
        </location>
        <working-flag>true</working-flag>
        <sample uri="http://yourIPaddress/api/v2/samples/AFF853A43" limsid="AFF853A43"/>
    </art:artifact>Â