Module: Utility::CommonDilutionCalculations

Extended by:
ActiveSupport::Concern
Included in:
ConcentrationBinningCalculator, ConcentrationNormalisationCalculator, FixedNormalisationCalculator, NormalisedBinningCalculator, PcrCyclesBinningCalculator
Defined in:
app/models/utility/common_dilution_calculations.rb

Overview

This module holds common functions used by other utility calculators.

Defined Under Namespace

Classes: Binner, Compressor

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



16
17
18
# File 'app/models/utility/common_dilution_calculations.rb', line 16

def config
  @config
end

Instance Method Details

#compute_vol_source_reqd(sample_conc) ⇒ float

Computes the volume of source material required for normalisation based on the sample concentration and attributes from the purpose configuration (target amount and volume, minimum source volume). Includes checks for minimum source volume and rounding for low diluent volumes due to liquid handler robot restrictions.

Parameters:

  • sample_conc (float)

    The concentration of the source sample in ng/ul

Returns:

  • (float)

    The volume of the source required in ul.



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'app/models/utility/common_dilution_calculations.rb', line 88

def compute_vol_source_reqd(sample_conc)
  calculated_raw_volume = config.target_amount / sample_conc

  # adjust the calculated volume to the maximum permissible for samples with very weak concentrations
  max_adj_volume = [calculated_raw_volume, config.minimum_source_volume].max

  # the robot cannot accept a diluent volume of less than 1ul, so this section adjusts the transfer
  # volume to prevent that when required
  transfer_volume =
    if ((config.target_volume - 1.0)...config.target_volume).cover?(max_adj_volume)
      max_adj_volume.round(half: :down)
    else
      max_adj_volume
    end

  # adjust the transfer volume to the minimum permissible for samples with very strong concentrations
  [transfer_volume, config.target_volume].min
end

#construct_dest_qc_assay_attributes(child_uuid, transfer_hash) ⇒ array

Constructs the qc_assays collection details for use when writing calculated concentrations for the newly created child plate.

Parameters:

  • child_uuid (string)

    The uuid of the child plate being transferred into.

  • transfer_hash (hash)

    The transfers hash from which we extract the destination concentrations.

Returns:

  • (array)

    An array of qc assay details for the child plate, ready to send via Api to sequencescape.



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'app/models/utility/common_dilution_calculations.rb', line 116

def construct_dest_qc_assay_attributes(child_uuid, transfer_hash)
  dest_concs = extract_destination_concentrations(transfer_hash)
  dest_concs.map do |dest_locn, dest_conc|
    {
      'uuid' => child_uuid,
      'well_location' => dest_locn,
      'key' => 'concentration',
      'value' => dest_conc,
      'units' => 'ng/ul',
      'cv' => 0,
      'assay_type' => self.class.name.demodulize,
      'assay_version' => version
    }
  end
end

#extract_destination_concentrations(transfer_hash) ⇒ hash

Refactor the transfers hash to give destination concentrations

Parameters:

  • transfer_hash (hash)

    The transfer details.

Returns:

  • (hash)

    A refactored hash of well concentrations.



139
140
141
142
143
144
145
# File 'app/models/utility/common_dilution_calculations.rb', line 139

def extract_destination_concentrations(transfer_hash)
  transfer_hash
    .values
    .each_with_object({}) do |dest_details, dest_hash|
      dest_hash[dest_details['dest_locn']] = dest_details['dest_conc']
    end
end

#initialize(config) ⇒ Object

The calculators all use a common configuration structure stored on the plate purpose.

Parameters:

  • config (hash)

    The relevant section from the plate purpose configuration.



24
25
26
# File 'app/models/utility/common_dilution_calculations.rb', line 24

def initialize(config)
  @config = Utility::DilutionsConfig.new(config)
end

#normalisation_details(wells) ⇒ hash

Creates a hash of well normalisation details for a plate used when generating the well transfers and qc assays.

Parameters:

  • wells (Wells)

    The source wells being normalised.

Returns:

  • (hash)

    The well details hash containing calculated normalisation values.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'app/models/utility/common_dilution_calculations.rb', line 45

def normalisation_details(wells) # rubocop:todo Metrics/AbcSize
  # sort on well coordinate to ensure wells are in plate column order
  wells
    .sort_by(&:coordinate)
    .each_with_object({}) do |well, details|
      # skip empty wells
      next if well.aliquots.blank?

      # check for well concentration value present
      if well.latest_concentration.blank?
        errors.add(:base, "Well #{well.location} does not have a concentration, cannot calculate amount in well")
        next
      end

      sample_conc = well.latest_concentration.value.to_f
      vol_source_reqd = compute_vol_source_reqd(sample_conc)
      vol_diluent_reqd = (config.target_volume - vol_source_reqd)
      amount = (vol_source_reqd * sample_conc)
      dest_conc = (amount / config.target_volume)

      # NB. we do not round the destination concentration so the full number is written
      # in the qc_results to avoid rounding errors causing the presenter to display some
      # wells as being in different bins.
      details[well.location] = {
        'vol_source_reqd' => vol_source_reqd.round(number_decimal_places),
        'vol_diluent_reqd' => vol_diluent_reqd.round(number_decimal_places),
        'amount_in_target' => amount.round(number_decimal_places),
        'dest_conc' => dest_conc
      }
    end
end