arrow-left

All pages
gitbookPowered by GitBook
1 of 2

Loading...

Loading...

Comparing Stop/Start Dates and Times with LLTK

Lab scientists need to record both a start and stop date/time for an incubation. As a second evaluation of how many hours the incubation lasted, the scientists want BaseSpace Clarity LIMS to calculate the elapsed time.

The Lab Logic Toolkit evaluateDynamicExpression script can compare date/time entries and calculate elapsed hours. As Date fields in the LIMS do not display the required time component for this calculation, Text fields are needed.

The bash command uses a 'Date' function to convert the Text date/time entries into dates, and also uses a 'getTime' method to convert those dates into milliseconds since 1 January 1970 00:00:00 UTC. The difference between the two converted entries is then changed from milliseconds to hours.

hashtag
Example

  1. Create a step level Text field for the Start Date/Time.

    • In this example, the field is named Incubation Start yyyy-mm-dd hh24:mi. The format is included in the name to assist the scientist entering the date/time.

  2. Create a step level Text field for the Stop Date/Time.

If you want to use a button to populate a Text field with the current date/time, then use:

  • In this example, the field is named Incubation Stop yyyy-mm-dd hh24:mi.

  • Create a step level Numeric field for the Incubation Hours. Set your preferred decimal place limit.

  • Create an automation and enter the following command line (if you have used different field names, edit the example command line to match):

  • Set the automation to be triggered by a button on the step. This allows the scientist to enter/edit the Start and Stop Date/Time before the elapsed hours are calculated.

    ℹ Adjustment for the Start/Stop events taking place over the 'daylight savings change events' is not included in this example.

  • bash -l -c "/opt/gls/clarity/bin/java -jar /opt/gls/clarity/extensions/ngs-common/v5/EPP/ngs-extensions.jar -i {stepURI:v2} -u {username} -p {password} script:evaluateDynamicExpression 
    -exp 'step.::Incubation Hours:: = (Date.parse(::yyyy-mm-dd H:m::, step.::Incubation Stop yyyy-mm-dd hh24:mi::).getTime() - Date.parse(::yyyy-mm-dd H:m::, step.::Incubation Start yyyy-mm-dd hh24:mi::).getTime()) / (1000*60*60)' -log {compoundOutputFileLuid0}"
    bash -l -c "/opt/gls/clarity/bin/java -jar /opt/gls/clarity/extensions/ngs-common/v5/EPP/ngs-extensions.jar -i {stepURI:v2} -u {username} -p {password} script:evaluateDynamicExpression -exp 'step.::Formulation:: = new Date().getDateTimeString()' -log {compoundOutputFileLuid0}"

    Lab Logic Toolkit Script Examples

    BaseSpace Clarity LIMS Lab Logic Toolkit (LLTK) provides the evaluateDynamicExpression script, which allows for the evaluation of simple dynamic expressions.

    This article provides examples that you can modify to suit the needs of your lab.

    For details on script parameters and usage, and additional examples, see the Working with Lab Logic Toolkit article.

    hashtag
    Setting QC flags

    See the article.

    hashtag
    Setting next actions

    See the article.

    hashtag
    Create string from multiple UDFs and add additional characters

    hashtag
    Determine total number of samples

    This example assumes that the step UDF / custom field Total samples has a default numeric value of 0:

    Without a default value, the expression must set the initial value before continuing to sum:

    hashtag
    Calculate concentration from a dilution factor

    hashtag
    Calculate volume of buffer and source sample to dilute

    hashtag
    Calculate the remaining amount of submitted sample left after the step

    hashtag
    Calculate volumes of all components to add to master mix (e.g., PCR reaction)

    hashtag
    Calculate nM from concentration and size

    hashtag
    Determine dilution to populate robot file

    hashtag
    Calculate average concentration

    This example demonstrates the use of step UDFs / custom fields to store temporary values in order to enable calculations between iteration.

    hashtag
    Check container name changed from default value

    This example checks that the container name has been changed from the default value (container LIMSID)

    hashtag
    Calculate yield of sequenced samples using the submittedSamples entity

    This example includes , using both implicit variables (it) and explicit variable names (for example, currentSample).

    hashtag
    Concatenate strings

    hashtag
    Regex example: Validate output container barcode mask

    hashtag
    Regex example: Verify format of flow cell / reagent cartridge barcode

    Check the flow cell/reagent cartridge format (Illumina’s flow cell check) as follows:

    hashtag
    Regex example: Validate a scanned / manually entered container barcode

    hashtag
    Populate a Timestamp (Single-line Text and Text) UDF / custom field

    The following expression results in the format: Wed Apr 03 21:28:38 EDT 2015

    hashtag
    Populate a Timestamp (Date) UDF / custom field

    The following expression results in the format: 2015-04-03

    hashtag
    Add values within a pool

    This example assumes that the analyte / derived sample UDF Pool Volume (uL) has a default numeric value of 0.

    This can also be done without setting a default value for the UDF:

    hashtag
    Convert placement information to a numeric position

    The example below assumes the following:

    • The placement is alphanumeric (e.g., A:1)

    • The offset for the alphabetical row is 0, and the offset for the numeric column is 1

    • The placement order desired is horizontal: A:1 maps to 1, A:2 maps to 2, etc.

    Note the following:

    • The call to split() here will return a list of row:column, so we use [0] and [1] to access these values, respectively.

    • :: : ::.trim() is used to obtain the result ':' - because :: is used as a reserved character, and thus ::::: directly results in '': and errors.

    hashtag
    Set the error status bar message

    See the article.

    hashtag
    Check for special characters

    In some cases, special characters are not permitted in a field in the LIMS. To prevent users from entering special characters, the best practice is to include validation to check that the field contains only letters and/or numbers. Wherever possible, we recommend that you use this 'positive checking' method as it is much less error-prone. However, if this preferred method is not possible, you can use the Lab Logic Toolkit to check for the presence of special characters, and display an error message if one is found.

    The following example use the Groovy matches command to check step output container names for the characters ? ( ) [ ] / \ and quotes or spaces.

    The matches command

    The matches command takes a regular expression (regex) as its input. Call this command on the field you want to check.

    In our example, the matches command is:

    If we isolate the regex, we have:

    Here, we're checking for any text that contains any one of the special characters listed. It's important to note that the way regex is supported in Java (and therefore Groovy) leads to some quirks, noted in the following table.

    Escaping characters Normally, in regex we would need to escape the following characters using a single backslash:

    However, because of how matches works, not all of these characters need to be escaped - for example the '?' character. Characters that do still need to be escaped, need to be escaped with an additional backslash (e.g., \\).

    Checking for quotes Because the command is run via Automated Informatics / Automation Worker, we also need to use a different approach for checking for quotes.

    We cannot use them as we typically would when writing a regex expression (e.g., "), or escape them as we would in a call to matches (e.g., \"). Instead, we need to provide them as their unicode number, shown in our example as \u0022 and \u00.

    hashtag
    Resources

    The placement of interest is the output placement
  • Placement is configured for a specific, known container type, and the dimensions of this container type are also known. This example uses a 96 well container configuration (12 columns are available and this value is used directly in the expression below). This value can be replaced for other container types.

  • \/

    Forward slash

    \

    \\

    Backslash

    (space)

    \s

    Spaces

    Regex testerarrow-up-right
  • Groovy dates and timesarrow-up-right

  • Entry

    Standard regex representation

    Character being checked for

    \u0022 and \u0027

    ' and "

    Single and double quotes

    ?

    \?

    Question mark

    ( and )

    \( and \)

    Brackets

    [ and ]

    \[ and \]

    Square brackets

    Setting QC Flags
    Setting Next Actions
    Groovy Closuresarrow-up-right
    Failing a Script
    Unicode character tablearrow-up-right
    Java Pattern documentationarrow-up-right
    Regex visual toolarrow-up-right

    /

    -exp 'submittedSample.::Run Name:: = step.::Source:: + ::_:: + step.::Numeric ID::'
    -exp '(step.::Total samples:: = step.::Total samples:: + 1)'
    -exp 'if(step.hasValue(::Total samples::)) { step.::Total samples:: = step.::Total samples:: + 1 } 
    else { step.::Total samples:: = 1 }'
    -exp 'output.::Concentration (nM):: = (input.::Concentration:: * step.::Dilution Factor::)'
    -exp 'output.::Diluent Needed:: = step.::Desired Volume:: - output.::Sample Volume::'
    -exp 'submittedSample.::Sample Volume:: = submittedSample.::Sample Volume:: - output.::VolumeUsed::'
    -exp ‘(step.::Component1:: = step.::NumberofSamples:: * 1.5) ; 
    (step.::Component2:: = step.::NumberofSamples:: * 0.5) ; 
    (step.::Component3:: = step.::NumberofSamples:: * 5)’ -log {compoundOutputFileLuid0}"
    -exp 'output.::Concentration (nM):: = (input.::Concentration:: / input.::Average length (bp)::)
    * 1540.832'
    -exp 'output.::Sample Needed (uL):: = step.::Input Amount (ng):: / input.::Library Concentration:: ;
     if ( output.::Sample Needed (uL):: > step.::Final Volume (uL):: ) { output.::Sample Needed (uL):: =
     step.::Final Volume (uL):: } ; if (output.::Sample Needed (uL):: < 1.0 ) 
    { output.::Sample Needed (uL):: == 1.0 } ; output.::Diluent Volume (uL):: = 
    step.::Final Volume (uL):: - output.::Sample Needed (uL):: ; output.::Final Amount (ng):: =
     output.::Sample Needed (uL):: * input.::Library Concentration::'
    -exp 'output.::Concentration::=input.Concentration ;
    if(!step.hasValue(::No. of samples::)) { step.::No. of samples:: = 0 } else { step.::No. of samples:: += 1 }; 
    if(!step.hasValue(::Total Conc.::)) { step.::Total Conc.:: = 0 } else { step.::Total Conc.:: += output.Concentration };
    if(!step.hasValue(::Average Conc.::)) { step.::Average Conc.:: = 0 } 
    else { step.::Average Conc.:: = step.::Total Conc.:: / step.::No. of samples:: };' 
    -exp 'if (output.container.name == output.container.node.@limsid) { fail(::Invalid Barcode. 
    Please verify and try again.::) }'
    submittedSamples.each { it.::Workflow Progress:: = ::Sequencing Finished:: }; 
    if (!input.hasValue(::Lane Failed?::) || !input.::Lane Failed?::) { def acquiredYield = 0; 
    if (input.hasValue(::Yield PF (Gb) R1::)) { acquiredYield += input.::Yield PF (Gb) R1:: }; 
    if (input.hasValue(::Yield PF (Gb) R2::)) { acquiredYield += input.::Yield PF (Gb) R2:: }; 
    acquiredYield = acquiredYield / submittedSamples.size(); submittedSamples.each { currentSample -> 
    def currentSampleAcquiredYield = acquiredYield; 
    if (currentSample.hasValue(::Acquired Yield (Gb)::)) { currentSampleAcquiredYield += 
    currentSample.::Acquired Yield (Gb):: }; currentSample.::Acquired Yield (Gb):: =
    currentSampleAcquiredYield; currentSample.::Missing Yield (Gb):: = 
    currentSample.::Required Yield (Gb):: - currentSampleAcquiredYield }
    submittedSample.::Lab Comments:: = output.::Sample Comment::.toString() + ::; :: 
    + submittedSample.::Lab Comments::.toString()
    -exp 'if ( !output.container.name.matches( ::LP[0-9]{7}-QSTD:: )) 
    {fail ( ::Invalid QSTD Plate Barcode. Please verify and try again.:: ) }'
    -exp 'if(!output.container.name.matches(::^[Hh][0-9A-Za-z]{4}([Bb][Bb]|[Cc][Cc]|[Aa][Ll])[Xx][Xx]$::)) 
    { fail(::Invalid Patterned Flowcell Barcode. Please verify and try again.::) }'
    -exp 'if ( !output.container.name.matches( ::LP[0-9]{7}-QNT:: ) &&
     !output.container.name.matches( ::LP[0-9]{7}-SQNT:: ) ) 
    {fail ( ::Invalid QNT & SQNT Plate Barcodes. Please verify and try again.:: ) }'
    -exp 'step.::Timestamp:: = new Date().toString()'
    -exp 'step.::Timestamp:: = new Date().format(::yyyy-MM-dd::)'
    -exp 'output.::Pool Volume (uL):: = output.::Pool Volume (uL):: + input.::Volume (uL)::'
    -exp 'if(output.hasValue(::Pool Volume (uL)::)) { output.::Pool Volume (uL):: = output.::Pool Volume (uL):: 
    + input.::Volume (uL):: } else { output.::Pool Volume (uL):: = input.::Volume (uL):: }'
    -exp 'output.::Position:: = (((output.well.split(:: : ::.trim())[0].toString().toUpperCase() as char) 
    - (::A:: as char)) * (int) Math.pow(26, 0)*12) + output.well.split(:: : ::.trim())[1].toInteger()'
    -exp 'if (output.container.name.matches(::.*[\u0022\u0027?()\\[\\]/\\\\ ].*::)) 
    { fail(::The following characters are not allowed in the Container Name: ? ( ) [ ] / \ and quotes or spaces.::) }'
    output.container.name.matches(::.*[\u0022\u0027?()\\[\\]/\\\\ ].*::)
    .*[\u0022\u0027?()\\[\\]/\\\\ ].*
    .^$*+?()[{|-]\