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.

Prerequisites

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

  • 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.

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.

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:

outputToInputMap = [:]
processURI = "http://${hostname}/api/v2/processes/${processLIMSID}"
p+cess = GLSRestApiUtils.httpGET(processURI, username, password) 

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>:

<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> 

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.

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:

outputLIMSID -> [output-type, inputLIMSID-1, inputLIMSID-2, inputLIMSID-3, ...|output-type, inputLIMSID-1, inputLIMSID-2, inputLIMSID-3, ...]

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.

// 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
    }
}

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.

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:

// 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]
    }
}

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.

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

Attachments

GetProcessInputOutput.groovy:

Last updated