Class: LabwareCreators::PlateSplitToTubeRacks

Inherits:
Base
  • Object
show all
Includes:
CustomPage, SupportParent::PlateOnly
Defined in:
app/models/labware_creators/plate_split_to_tube_racks.rb

Overview

Handles the creation of up to 2 child racks of tubes from a single parent 96-well plate. Intended for use in a PBMC cell extraction pipeline.

There will typically be one rack of tubes for ‘contingency’ and one for ‘sequencing’ (this rack is optional).

The parent plate contains multiple copies of material prepared from the same sample. One well instance of each sample will go into a tube in the ‘sequencing’ rack (if present), and any remaining copies will go into tubes in the ‘contingency’ rack.

If after the initial preparation the users feel they need more contingency tubes, then they will go back to prepare more material for that sample from an earlier step in the pipeline and create just ‘contingency’ tubes at this step.

Inputs: 1) The parent plate - This plate contains multiple groups of wells containing the same samples e.g.

there may be 3 wells with sample 1, 3 with sample 2, 3 with sample 3 etc. The number of copies of
each sample is not known in advance.
The first of these parent wells will be transferred into a tube in the 'sequencing' rack if it is
present, and any remaining parent wells for the same sample will be transferred into tubes in the
'contingency' rack.

2) Child tube rack scan CSV files - these are scans of racks of 2D tube barcodes from the ‘contingency’

and 'sequencing' tube racks, to allow us to know the position and barcode of each available tube.
On the upload screen displays counts of how many tubes are needed (e.g. To perform this transfer you
will either need 20 sequencing and 40 contingency tubes, or 60 contingency tubes.)

Validations - Error message to users if any of these are not met: 1) The user must always upload a scan file for the ‘contingency’ rack tube barcodes, whereas the

'sequencing' rack file is optional.

2) The scanned child tube barcodes must be unique and must not already exist in the system i.e. they are

new unused empty tubes. List any that do already exist with rack type and location.

3) The number of tubes available in the racks must be correct for the number of parent wells being

transferred. e.g. if there are 20 distinct samples in the parent and 40 additional copies (60 wells
total), then there must be 20 tubes in the first rack and 40 in the second rack.

rubocop:disable Metrics/ClassLength

Constant Summary collapse

PARENT_PLATE_INCLUDES =
'wells.aliquots,wells.aliquots.sample,wells.downstream_tubes,wells.downstream_tubes.custom_metadatum_collection'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

This class inherits a constructor from LabwareCreators::Base

Instance Attribute Details

#child_contingency_tubesObject (readonly)

Returns the value of attribute child_contingency_tubes.



51
52
53
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 51

def child_contingency_tubes
  @child_contingency_tubes
end

#child_sequencing_tubesObject (readonly)

Returns the value of attribute child_sequencing_tubes.



51
52
53
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 51

def child_sequencing_tubes
  @child_sequencing_tubes
end

#contingency_fileObject

Returns the value of attribute contingency_file.



50
51
52
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 50

def contingency_file
  @contingency_file
end

#sequencing_fileObject

Returns the value of attribute sequencing_file.



50
51
52
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 50

def sequencing_file
  @sequencing_file
end

Instance Method Details

#add_error_if_wrong_number_of_tubes(file, num_tubes, required_tubes) ⇒ Object

Adds an error when there are insufficient or too many tubes in the given file



259
260
261
262
263
264
265
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 259

def add_error_if_wrong_number_of_tubes(file, num_tubes, required_tubes)
  # msg if too many tubes
  errors.add(file, 'contains more tubes than needed') if num_tubes > required_tubes

  # msg if not enough tubes
  errors.add(file, 'contains insufficient tubes') unless num_tubes >= required_tubes
end

#anchorObject

Display the children tab in the plate view so we see the child tubes listed.



139
140
141
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 139

def anchor
  'children_tab'
end

#check_tube_barcodes_differ_between_filesObject

Validation to compare the tube barcodes in the two files to check for duplication

Sets errors if the tube rack barcodes are the same



203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 203

def check_tube_barcodes_differ_between_files
  return unless contingency_file_valid? && sequencing_file_valid?

  seq_barcodes = extract_barcodes(sequencing_csv_file)
  cont_barcodes = extract_barcodes(contingency_csv_file)

  duplicate_barcodes = seq_barcodes & cont_barcodes
  return if duplicate_barcodes.empty?

  errors.add(
    :contingency_csv_file,
    "Tube barcodes are duplicated across contingency and sequencing files (#{duplicate_barcodes.join(', ')})"
  )
end

#check_tube_rack_barcodes_differ_between_filesObject

Validation to compare the tube rack barcodes in the two files to check for duplication

Sets errors if the tube rack barcodes are the same



178
179
180
181
182
183
184
185
186
187
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 178

def check_tube_rack_barcodes_differ_between_files
  return unless contingency_file_valid? && sequencing_file_valid?

  return unless same_tube_rack_barcode?

  errors.add(
    :contingency_csv_file,
    'The tube rack barcodes within the contingency and sequencing files must be different'
  )
end

#check_tube_rack_scan_file(tube_rack_file, msg_prefix) ⇒ void

This method returns an undefined value.

Checks if the tube barcodes in the given tube rack file already exist in the LIMS.

Parameters:

  • tube_rack_file (CsvFile)

    The tube rack file to check.

  • msg_prefix (String)

    The prefix to use for error messages.



282
283
284
285
286
287
288
289
290
291
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 282

def check_tube_rack_scan_file(tube_rack_file, msg_prefix)
  tube_rack_file.position_details.each do |tube_posn, tube_details|
    foreign_barcode = tube_details['tube_barcode']
    tube_in_db = Sequencescape::Api::V2::Tube.find_by(barcode: foreign_barcode)
    next if tube_in_db.blank?

    msg = "#{msg_prefix} tube barcode #{foreign_barcode} (at rack position #{tube_posn}) already exists in the LIMS"
    errors.add(:tube_rack_file, msg)
  end
end

#contingency_csv_fileCsvFile?

Returns a CsvFile object for the contingency tube rack scan CSV file, or nil if the file doesn’t exist.

doesn’t exist.

Returns:

  • (CsvFile, nil)

    A CsvFile object for the contingency tube rack scan CSV file, or nil if the file



156
157
158
159
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 156

def contingency_csv_file
  @contingency_csv_file ||=
    CommonFileHandling::CsvFileForTubeRackWithRackBarcode.new(contingency_file) if contingency_file
end

#contingency_file_valid?Boolean

Returns:

  • (Boolean)


254
255
256
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 254

def contingency_file_valid?
  contingency_file.present? && contingency_csv_file&.valid?
end

#create_child_contingency_tubesArray<Tube>

Creates a child contingency tube for each parent well not already assigned to a sequencing tube.

Returns:

  • (Array<Tube>)

    The child contingency tubes.



122
123
124
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 122

def create_child_contingency_tubes
  create_tubes(contingency_tube_purpose_uuid, parent_wells_for_contingency.length, contingency_tube_attributes)
end

#create_child_sequencing_tubesArray<Tube>

Creates a single child sequencing tube for each parent well containing a unique sample.

Returns:

  • (Array<Tube>)

    The child sequencing tubes.



113
114
115
116
117
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 113

def create_child_sequencing_tubes
  return [] if require_contingency_tubes_only?

  create_tubes(sequencing_tube_purpose_uuid, parent_wells_for_sequencing.length, sequencing_tube_attributes)
end

#create_labware!Boolean

Creates child sequencing and contingency tubes, performs transfers.

Returns:

  • (Boolean)

    true if the child tubes were created successfully.



102
103
104
105
106
107
108
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 102

def create_labware!
  @child_sequencing_tubes = create_child_sequencing_tubes
  @child_contingency_tubes = create_child_contingency_tubes
  
  perform_transfers
  true
end

#extract_barcodes(file) ⇒ Object



218
219
220
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 218

def extract_barcodes(file)
  file.position_details.values.pluck('tube_barcode')
end

#extract_tube_rack_barcode(file) ⇒ Object



196
197
198
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 196

def extract_tube_rack_barcode(file)
  file.position_details.values.first['tube_rack_barcode']
end

#files_valid?Boolean

Checks the files passed their validations

Returns:

  • (Boolean)


244
245
246
247
248
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 244

def files_valid?
  return contingency_file_valid? if require_contingency_tubes_only?

  contingency_file_valid? && sequencing_file_valid?
end

#labware_wellsArray<Well>

Returns the list of wells of the parent labware. In column order (A1, B1, C1 etc.) Used in WellFilter.

Returns:

  • (Array<Well>)

    The wells of the parent labware.



95
96
97
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 95

def labware_wells
  parent.wells_in_columns
end

#must_have_correct_number_of_tubes_in_rack_filesObject

Validation that checks if there are the correct number of tubes in the child tube racks for all the parent wells. This depends on the number of unique samples in the parent plate, and the number of parent wells, as well as whether they are using both sequencing tubes and contingency tubes or just contingency.

Sets errors if there are insufficient or too many tubes.



228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 228

def must_have_correct_number_of_tubes_in_rack_files
  return unless files_valid?

  if require_contingency_tubes_only?
    add_error_if_wrong_number_of_tubes(:contingency_csv_file, num_contingency_tubes, num_parent_wells)
  else
    add_error_if_wrong_number_of_tubes(
      :contingency_csv_file,
      num_contingency_tubes,
      num_parent_wells - num_parent_unique_samples
    )
    add_error_if_wrong_number_of_tubes(:sequencing_csv_file, num_sequencing_tubes, num_parent_unique_samples)
  end
end

#num_parent_unique_samplesInteger

Returns the number of unique sample UUIDs for the parent wells after applying the current well filter.

Returns:

  • (Integer)

    The number of unique sample UUIDs.



164
165
166
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 164

def num_parent_unique_samples
  @num_parent_unique_samples ||= parent_uniq_sample_uuids.length
end

#num_parent_wellsInteger

Returns the number of parent wells after applying the current well filter.

Returns:

  • (Integer)

    The number of filtered parent wells.



171
172
173
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 171

def num_parent_wells
  @num_parent_wells ||= well_filter.filtered.length
end

#parentObject

v2 api is used to select the parent plate



81
82
83
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 81

def parent
  @parent ||= Sequencescape::Api::V2.plate_with_custom_includes(PARENT_PLATE_INCLUDES, uuid: parent_uuid)
end

#parent_v1Object

v1 api is used to upload the tube rack scan files and create the tubes



86
87
88
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 86

def parent_v1
  @parent_v1 ||= api.plate.find(parent_uuid)
end

#perform_transfersvoid

This method returns an undefined value.

Creates transfer requests for the given transfer request attributes and performs the transfers.



129
130
131
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 129

def perform_transfers
  api.transfer_request_collection.create!(user: user_uuid, transfer_requests: transfer_request_attributes)
end

#redirection_targetObject

We will create multiple child tubes, so redirect to the parent plate



134
135
136
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 134

def redirection_target
  parent
end

#same_tube_rack_barcode?Boolean

Returns:

  • (Boolean)


189
190
191
192
193
194
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 189

def same_tube_rack_barcode?
  seq_tube_rack = extract_tube_rack_barcode(sequencing_csv_file)
  cont_tube_rack = extract_tube_rack_barcode(contingency_csv_file)

  seq_tube_rack == cont_tube_rack
end

#saveObject



75
76
77
78
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 75

def save
  # NB. need the && true!!
  super && upload_tube_rack_files && true
end

#sequencing_csv_fileCsvFile?

Returns a CsvFile object for the sequencing tube rack scan CSV file, or nil if the file doesn’t exist.

doesn’t exist.

Returns:

  • (CsvFile, nil)

    A CsvFile object for the sequencing tube rack scan CSV file, or nil if the file



147
148
149
150
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 147

def sequencing_csv_file
  @sequencing_csv_file ||=
    CommonFileHandling::CsvFileForTubeRackWithRackBarcode.new(sequencing_file) if sequencing_file
end

#sequencing_file_valid?Boolean

Returns:

  • (Boolean)


250
251
252
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 250

def sequencing_file_valid?
  sequencing_file.present? && sequencing_csv_file&.valid?
end

#tube_barcodes_are_unique?void

This method returns an undefined value.

Validation that the tube barcodes are unique and do not already exist in the system. NB. this checks all the tube barcodes in the uploaded tube rack scan files, not just the ones that will be used.



272
273
274
275
# File 'app/models/labware_creators/plate_split_to_tube_racks.rb', line 272

def tube_barcodes_are_unique?
  check_tube_rack_scan_file(sequencing_csv_file, 'Sequencing') if sequencing_file
  check_tube_rack_scan_file(contingency_csv_file, 'Contingency') if contingency_file
end