Class: CherrypickTask::ControlLocator
- Inherits:
-
Object
- Object
- CherrypickTask::ControlLocator
- Defined in:
- app/models/cherrypick_task/control_locator.rb
Overview
A cherrypick Batch can source one or more controls from a ControlPlate For the initial destination plate in a batch these controls are distributed (pseudo)randomly across available wells. (Two controls can’t occupy the same wells) Subsequent destination plates within the same batch will offset the controls by a fixed amount to ensure destination plates in a batch have different control locations. This is especially important for negative controls, as it allows plate swaps to be identified (the negative control location can be thought of as a fingerprint).
Once all well locations have been used, an new set of random locations will be generated, and the cycle will begin again.
We need to be particularly careful with the offset value, as otherwise we risk reusing wells before the full cycle has been completed. For this reason we select prime numbers that are NOT a factor of the number of available wells.
Constant Summary collapse
- BETWEEN_PLATE_OFFSETS =
A cherrypick batch may contain multiple destination plates. In this case the control wells should be located at different locations on each destination. The positions on the first plate in a batch are determined randomly, and then the locations are advanced by BETWEEN_PLATE_OFFSET for each subsequent plate. This is done to avoid the risk of subsequent plates having the same negative control location, which would reduce the ability to detect plate swaps. WARNING! These needs to be a prime number (which isn’t also a factor of the available well size) to avoid re-using wells prematurely. These offsets are prioritised in order. Technically any number that only shares 1 as a common factor with the available well size would work, but we limit ourself to primes to simplify validation.
[53, 59].freeze
Instance Attribute Summary collapse
-
#available_positions ⇒ Object
readonly
Returns the value of attribute available_positions.
-
#batch_id ⇒ Object
readonly
Returns the value of attribute batch_id.
-
#control_source_plate ⇒ Object
readonly
Returns the value of attribute control_source_plate.
-
#num_control_wells ⇒ Object
readonly
Returns the value of attribute num_control_wells.
-
#total_wells ⇒ Object
readonly
Returns the value of attribute total_wells.
-
#wells_to_leave_free ⇒ Object
readonly
Returns the value of attribute wells_to_leave_free.
Instance Method Summary collapse
-
#control_positions(num_plate) ⇒ Array<Integer>
Returns a list with the destination positions for the control wells distributed randomly using batch_id as seed and num_plate to increase position with plates in same batch.
- #handle_incompatible_plates ⇒ Object
-
#initialize(params) ⇒ ControlLocator
constructor
control wells being missed in cDNA quant QC.
Constructor Details
#initialize(params) ⇒ ControlLocator
wells_to_leave_free was originally hardcoded for 96 well plates at 24, in order to avoid
control wells being missed in cDNA quant QC. This requirement was removed in github.com/sanger/sequencescape/issues/2967 however I’ve avoided stripping out the behaviour completely in case controls are used in other pipelines.
52 53 54 55 56 57 58 59 60 |
# File 'app/models/cherrypick_task/control_locator.rb', line 52 def initialize(params) @batch_id = params[:batch_id] @total_wells = params[:total_wells] @num_control_wells = params[:num_control_wells] @wells_to_leave_free = params[:wells_to_leave_free].to_a || [] @available_positions = (0...@total_wells).to_a - @wells_to_leave_free @control_source_plate = params[:control_source_plate] @plate_template = params[:template] end |
Instance Attribute Details
#available_positions ⇒ Object (readonly)
Returns the value of attribute available_positions.
32 33 34 |
# File 'app/models/cherrypick_task/control_locator.rb', line 32 def available_positions @available_positions end |
#batch_id ⇒ Object (readonly)
Returns the value of attribute batch_id.
32 33 34 |
# File 'app/models/cherrypick_task/control_locator.rb', line 32 def batch_id @batch_id end |
#control_source_plate ⇒ Object (readonly)
Returns the value of attribute control_source_plate.
32 33 34 |
# File 'app/models/cherrypick_task/control_locator.rb', line 32 def control_source_plate @control_source_plate end |
#num_control_wells ⇒ Object (readonly)
Returns the value of attribute num_control_wells.
32 33 34 |
# File 'app/models/cherrypick_task/control_locator.rb', line 32 def num_control_wells @num_control_wells end |
#total_wells ⇒ Object (readonly)
Returns the value of attribute total_wells.
32 33 34 |
# File 'app/models/cherrypick_task/control_locator.rb', line 32 def total_wells @total_wells end |
#wells_to_leave_free ⇒ Object (readonly)
Returns the value of attribute wells_to_leave_free.
32 33 34 |
# File 'app/models/cherrypick_task/control_locator.rb', line 32 def wells_to_leave_free @wells_to_leave_free end |
Instance Method Details
#control_positions(num_plate) ⇒ Array<Integer>
Returns a list with the destination positions for the control wells distributed randomly using batch_id as seed and num_plate to increase position with plates in same batch.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'app/models/cherrypick_task/control_locator.rb', line 70 def control_positions(num_plate) raise StandardError, 'More controls than free wells' if num_control_wells > total_available_positions # Check that all elements in wells_to_leave_free fall within the acceptable range raise StandardError, 'More wells left free than available' unless wells_to_leave_free.all?(0...total_wells) return [] if num_control_wells.zero? # If num plate is equal to the available positions, the cycle is going to be repeated. # To avoid it, every num_plate=available_positions we start a new cycle with a new seed. placement_type = control_placement_type if placement_type.nil? || %w[fixed random].exclude?(placement_type) raise StandardError, 'Control placement type is not set or is invalid' end handle_control_placement_type(placement_type, num_plate) end |
#handle_incompatible_plates ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 |
# File 'app/models/cherrypick_task/control_locator.rb', line 88 def handle_incompatible_plates return false if control_placement_type == 'random' return false if @plate_template.wells.empty? control_assets = control_source_plate.wells.joins(:samples) converted_control_assets = convert_assets(control_assets.map(&:map_id)) converted_template_assets = convert_assets(@plate_template.wells.map(&:map_id)) converted_control_assets.intersect?(converted_template_assets) end |