Пример #1
0
    def get_gel_extraction_steps(self):
        p = stepwise.Protocol()
        names = self._cluster_names_by_molecule()

        desired = oxford_comma(x) if (x := self.desired_bands) else 'desired'
        n = plural(max(len(self.desired_bands), len(self.samples)))
        f = "Based on Fitzy's DNA PAGE purification protocol, [Nilson2013], and [Petrov2013]."

        p += pl(f"Cut the {desired} {n:band/s} out of the gel{p.add_footnotes(f)}.", ul(
            "Place the gel over a TLC plate.",
            "Use a UV light to visualize the RNA (dark spot).",
            "Consider visualizing remaining gel to ensure that all desired RNA was excised.",
        ))
        p += pl(f"Crush the gel {n:slice/s}.", ul(
            "Poke a hole in the bottom of a 0.65 mL tube with a 27 g needle.",
            "Place gel slice inside the 0.65 mL tube.",
            "Place the 0.65 mL tube inside a 1.5 mL tube.",
            "Spin at max speed for 5 min.",
        ))

        eb = elution_buffer()
        eb.hold_ratios.volume = 500 * len(self.samples), 'µL'
        p += pl(
                "Resuspend gel in 400 µL PAGE elution buffer:",
                eb,
        )

        if names['RNA']:
            p += f"Incubate {join_if(names['RNA'], names['DNA'])}at 4°C overnight with end-over-end mixing."

        if names['DNA']:
            p += f"Incubate {join_if(names['DNA'], names['RNA'])}at 55°C overnight with 800 rpm mixing."

        return p
Пример #2
0
    def _format_stage(self, prefix):

        class SkipStage(Exception):
            pass

        def has(attr):
            return hasattr(self, f'{prefix}_{attr}')

        def get(attr, *args):
            return getattr(self, f'{prefix}_{attr}', *args)


        def have_repeats():
            n = get('repeats')
            return n > 1 if isinstance(n, int) else bool(n)

        def format_repeats():
            n = get('repeats')
            if isinstance(n, int):
                n = f'{n}x'
            return f"Repeat {n}:"

        def format_submerge():
            if not has('buffer'): raise SkipStage
            return f"Submerge gel in ≈{get('volume_mL', 30)} mL {get('buffer')}."

        def format_microwave():
            if get('microwave', False):
                return f"Microwave until almost boiling (≈{format_sec(get('microwave_time_s', 45))})."

        def format_incubate():
            return f"Shake gently for {format_min(get('time_min'))}."

        step_templates = get('steps', ['submerge', 'microwave', 'incubate'])
        step_formatters = {
                'submerge': format_submerge,
                'microwave': format_microwave,
                'incubate': format_incubate,
        }

        out = steps = ul()
        for template in step_templates:
            formatter = step_formatters.get(template, lambda: template)
            try:
                steps += formatter()
            except SkipStage:
                return

        if have_repeats():
            out = ul(pl(format_repeats(), steps, br='\n'))

        if n := get('rinse_repeats', False):
            out += f"Rinse {plural(n)://#x }with water."
Пример #3
0
    def get_prep_step(self):
        def both_or_neither(key1, key2):
            has_key1 = has_key2 = True

            try:
                value1 = getattr(self, key1)
            except AttributeError:
                has_key1 = False

            try:
                value2 = getattr(self, key2)
            except AttributeError:
                has_key2 = False

            if has_key1 and not has_key2:
                raise ConfigError(f"specified {key1!r} but not {key2!r}")
            if has_key2 and not has_key1:
                raise ConfigError(f"specified {key2!r} but not {key1!r}")

            if has_key1 and has_key2:
                return value1, value2
            else:
                return False

        s = pl(
            f"Prepare {plural(self.num_samples):# sample/s} for {self.title}:",
            self.sample_mix,
        )
        if x := both_or_neither('incubate_temp_C', 'incubate_time_min'):
            temp_C, time_min = x
            s += ul(f"Incubate at {temp_C:g}°C for {time_min:g} min.")
    def get_protocol(self):
        p = stepwise.Protocol()
        s = ul()

        if self.names:
            p += pl(
                f"Purify {','.join(self.names)} by ethanol precipitation [1,2]:",
                s)
        else:
            p += pl("Perform an ethanol precipitation [1,2]:", s)

        s += f"""\
                Add {self.cation_name} to {self.cation_conc}."""
        s += f"""\
                Add {self.carrier_name} to {self.carrier_conc}."""
        s += f"""\
                Add {plural(self.solvent_volume):# volume/s} 
                {self.solvent_name} and mix well."""
        s += f"""\
                If necessary, divide the sample between microfuge tubes
                such that none holds more than 400 µL."""

        if self.incubation and (t := self.incubation_time):
            incubation_time = "overnight" if t == 'overnight' else f"for {t}"
            s += f"""\
    def get_protocol(self):
        transfer = self.volume * (f := self.inv_factor) / (1 - f)
        initial_volume = self.volume + transfer

        conc_high_str = format_quantity(self.conc_high, self.conc_unit, 'g')
        material_str = f'{conc_high_str} {self.material}'.lstrip()
        conc_table = [[i, format_quantity(conc, self.conc_unit, 'e')]
                      for i, conc in enumerate(self.concentrations, 1)]

        num_tubes = self.steps if self.include_zero else self.steps - 1
        each_tube = 'each tube *except the last*' if self.include_zero else 'each tube'

        protocol = stepwise.Protocol()
        protocol += pl(
            "Perform a serial dilution [1]:",
            ul(
                f"Put {initial_volume:.2f} μL {material_str} in a tube.",
                f"Put {self.volume:.2f} μL {self.diluent} in {plural(num_tubes):# adjacent tube/s}.",
                f"Transfer {transfer:.2f} μL between {each_tube} to make {self.steps} {self.factor:.2g}-fold dilutions.",
            ),
        )

        protocol.footnotes[1] = pl(
            "The final concentrations will be:",
            pre(stepwise.tabulate(conc_table, align='>>')),
            br='\n',
        )
        return protocol
Пример #6
0
    def get_protocol(self):
        # Maybe this should be the getter function for the assembly param...

        p = stepwise.Protocol()
        rxn = self.reaction
        n = rxn.num_reactions
        n_frags = self.num_fragments

        f = 'https://tinyurl.com/yaa5mqz5'
        p += pl(
            f"Setup {plural(n):# Golden Gate assembl/y/ies}{p.add_footnotes(f)}:",
            rxn,
        )
        if n_frags <= 2:
            p += pl(
                "Run the following thermocycler protocol:",
                ul("37°C for 5 min", ),
                "Or, to maximize the number of transformants:",
                ul(
                    "37°C for 60 min",
                    "60°C for 5 min",
                ),
            )

        elif n_frags <= 4:
            p += pl(
                "Run the following thermocycler protocol:",
                ul(
                    "37°C for 60 min",
                    "60°C for 5 min",
                ),
            )

        elif n_frags <= 10:
            p += pl(
                "Run the following thermocycler protocol:",
                ul(
                    "Repeat 30 times:",
                    ul(
                        "37°C for 1 min",
                        "16°C for 1 min",
                    ),
                    "60°C for 5 min",
                ),
            )

        else:
            p += pl(
                "Run the following thermocycler protocol:",
                ul(
                    "Repeat 30 times:",
                    ul(
                        "37°C for 5 min",
                        "16°C for 5 min",
                    ),
                    "60°C for 5 min",
                ),
            )

        return p
Пример #7
0
    def get_protocol(self):
        p = stepwise.Protocol()
        rxn = self.reaction

        p += pl(
                f"Setup {plural(self.num_reactions):# {self.title} reaction/s}{p.add_footnotes(self.setup_footnote)}:",
                rxn,
                ul(*self.setup_instructions),
        )
        if self.incubation_time != '0':
            p += f"Incubate at {self.incubation_temp_C:g}°C for {self.incubation_time}{p.add_footnotes(self.incubation_footnote)}."

        return p
Пример #8
0
 def get_protocol(self):
     p = stepwise.Protocol()
     p += pl(
             "Remove unligated linker by ultrafiltration:",
             s := ul(
                 "Bring reaction to 500 µL with 8M urea.",
                 f"Load onto a {self.mwco_kDa} kDa MWCO spin-filter [1].",
                 "Spin 14000g, 15 min.",
                 "Wash with 500 µL 8M urea.",
                 "Wash with 500 µL nuclease-free water.",
                 "Wash with water again.",
                 "Wash with water again, but spin for 30 min.",
                 "Invert the filter into a clean tube and spin 1000g, 2 min to collect ligated product in a volume of ≈15 µL.",
             ),
     )
Пример #9
0
    def get_protocol(self):
        p = stepwise.Protocol()
        rxn = self.reaction

        p += pl(
            f"Setup {plural(rxn.num_reactions):# ligation reaction/s}{p.add_footnotes('https://tinyurl.com/y7gxfv5m')}:",
            rxn,
        )
        p += pl(
            "Incubate at the following temperatures:",
            ul(
                "25°C for 15 min",
                "65°C for 10 min",
            ),
        )
        return p
Пример #10
0
    def get_protocol(self):
        p = stepwise.Protocol()
        rxn = self.reaction
        rxn_name = 'ligation' if self.use_ligase else 'negative control'
        n = rxn.num_reactions

        p += stepwise.pl(
                f"Setup {plural(n):# {rxn_name} reaction/s}:",
                rxn,
        )
        if self.incubate:
            p += pl(
                    f"Incubate the {plural(n):ligation reaction/s} as follows:",
                    s := ul(
                        f"{self.incubate_temp} for {self.incubate_time}."
                    ),
            )
            if self.quench:
Пример #11
0
    def get_product_recovery_steps(self):
        p = stepwise.Protocol()
        names = self._cluster_names_by_molecule()

        # Filter material:
        # - Corning has a good guide on which material to select:
        #   https://www.corning.com/catalog/cls/documents/selection-guides/t_filterselectionguide.pdf
        #
        # - I want 0.22 µm, because that's the standard size for filter 
        #   sterilizing biological buffers (that's not my application here, but 
        #   I can see myself wanting to do that).
        #
        # - I want cellulose acetate filters.  Nylon and cellulose nitrate have 
        #   high DNA binding, which will cause me to lose material.  The 
        #   downside to cellulose acetate is that it has a wetting agent that 
        #   will end up in the sample.  However, this will be removed by the 
        #   Zymo column in the subsequent step.
        #
        # - Product number: 8161 (non sterile)
        #
        # Centrifugation speed:
        # - Fitzy's DNA PAGE purification protocol calls for 4 min at 7000 rpm
        # - The Corning guide (see above) includes an agarose gel purification 
        #   protocol, which calls for 13,000g for 5-20 min.  But this protocol 
        #   has no incubation step, so I gather that the spin is supposed to 
        #   pull the solvent out of the gel.  I probably don't need to go so 
        #   fast, but why not go as fast as the columns can tolerate?
        f = "Nylon and cellulose nitrate have high DNA-binding: https://tinyurl.com/3pkyc8dr"
        p += pl(
                "Remove gel debris by spin filtration:",
                ul(
                    f"Load samples onto a 0.22 µm cellose-acetate Spin-X column{p.add_footnotes(f)}.",
                    "Spin at 13,000g for 5 min."
                ),
        )

        if self.cleanup:
            if names['RNA']:
                p += cleanup(self.rna_cleanup_preset, names['RNA'], names['DNA'])

            if names['DNA']:
                p += cleanup(self.dna_cleanup_preset, names['DNA'], names['RNA'])

        return p
Пример #12
0
    def get_protocol(self):
        p = stepwise.Protocol()

        footnotes = [x] if (x := self.protocol_link) else []
        footnotes += self.footnotes

        s = pl(f"Stain gel with {self.title}{p.add_footnotes(*footnotes)}:")

        if self.light_sensitive:
            #s += "Keep gel in the dark in all following steps."
            s += ul("Keep the stain protected from light.")
            #s += ul("In all following steps, protect the stain from light.")

        s += self._format_stage('prep')
        s += self._format_stage('stain')
        s += self._format_stage('destain')

        p += s

        if self.imaging_cmd:
            p += stepwise.load(self.imaging_cmd)

        return p
Пример #13
0
    def get_protocol(self):
        p = stepwise.Protocol()
        rxn = self.reaction
        n = rxn.num_reactions

        p += pl(
            f"Setup {plural(n):# annealing reaction/s} [1]:",
            rxn,
        )

        p.footnotes[1] = """\
                Using 0.6x linker reduces the amount of unligated 
                linker, see expt #1."""

        p += pl(
            f"Perform the {plural(n):annealing reaction/s}:",
            ul(
                "Incubate at 95°C for 2 min.",
                "Cool at room temperature.",
            ),
        )

        return p
Пример #14
0
    def get_protocol(self):
        p = stepwise.Protocol()

        if self.dnase_treatment == 'pre':
            mm = stepwise.MasterMix("""\
                    Reagent                   Stock    Volume  MM?
                    ======================  =======  ========  ===
                    nuclease-free water              to 50 µL   +
                    DNA digestion buffer        10x      5 µL   +
                    DNase I [1]              1 U/µL      5 µL   +
                    RNA sample               <10 µg     40 µL   -
            """)

            step = "Setup a DNase I reaction for each sample:"
            if self.num_samples:
                step = f"Setup {plural(self.num_samples):# DNase I reaction/s}:"
                mm.num_reactions = self.num_samples

            if self.sample_volume_uL:
                mm['RNA sample'].volume = self.sample_volume_uL, 'µL'

            p += pl(step, mm)
            p += "Incubate at room temperature for 15 min."

            p.footnotes[
                1] = "Reconstitute lyophilized DNase I (#E1009-A; 250U) with 275 µL nuclease-free water and mix by gentle inversion.  Store frozen aliquots."

        if self.dnase_treatment == 'post':
            mm = stepwise.MasterMix("""\
                    Reagent                   Stock    Volume  MM?
                    ======================  =======  ========  ===
                    DNA digestion buffer        10x     75 µL   +
                    DNase I [1]              1 U/µL      5 µL   +
            """)
            if self.num_samples:
                mm.num_reactions = self.num_samples

            p += pl("Prepare 80 µL DNase I reaction mix for each sample:", mm)

        s = ul()
        p += pl("Purify RNA using Zymo Clean & Concentrator spin columns:", s)

        if self.sample_volume_uL:
            if self.sample_volume_uL < 50:
                s += f"Add {50 - self.sample_volume_uL:g} nuclease-free water to each sample"

            v = max(50, self.sample_volume_uL)
            s += f"Add {2*v:g} µL RNA binding buffer; mix."
            s += f"Add {3*v:g} µL >95% ethanol; mix."

        else:
            s += "If necessary, bring each sample to 50 µL."
            s += "Add 2 volumes RNA binding buffer; mix."
            s += "Add 3 volumes >95% ethanol; mix."

        s += f"Load sample on spin column."
        s += f"Spin 1 min, 16000g; discard flow-through."

        if self.dnase_treatment == 'post':
            s += f"Add 400 µL RNA wash buffer."
            s += f"Spin 30s, 16000g; discard flow-through."
            s += f"Add 80 µL DNase I reaction mix."
            s += f"Incubate at room temperature for 15 min."

        s += f"Add 400 µL RNA prep buffer."
        s += f"Spin 30s, 16000g; discard flow-through."
        s += f"Add 700 µL RNA wash buffer."
        s += f"Spin 30s, 16000g; discard flow-through."
        s += f"Add 400 µL RNA wash buffer."
        s += f"Spin 60s, 16000g; discard flow-through."
        s += f"Add {self.elute_volume_uL:g} µL nuclease-free water."
        s += f"Spin 30s, 16000g."

        return p
Пример #15
0
        if x := self.gel_percent:
            gel.gel_percent = x
        if x := self.gel_run_volts:
            gel.run_volts = x
        if x := self.gel_run_time_min:
            gel.run_time_min = x

        try:
            gel.load_volume_uL = unanimous(
                    x.load_volume_per_lane_uL
                    for x in self.samples
            )
        except ValueError:
            gel.load_volume_uL = 0

            p += pl(f"Load the {n:sample/s} in the gel as follows:", u := ul())
            for sample in self.samples:
                num_lanes = f" in each of {m} lanes" if (m := sample.num_lanes) != 1 else ""
                u += f"{sample.load_volume_per_lane_uL:.2g} µL {sample.name}{num_lanes}"

        p += gel.run_step

        return p

    def get_gel_extraction_steps(self):
        p = stepwise.Protocol()
        names = self._cluster_names_by_molecule()

        desired = oxford_comma(x) if (x := self.desired_bands) else 'desired'
        n = plural(max(len(self.desired_bands), len(self.samples)))
        f = "Based on Fitzy's DNA PAGE purification protocol, [Nilson2013], and [Petrov2013]."
Пример #16
0
    def get_protocol(self):
        from itertools import groupby
        from operator import itemgetter

        protocol = stepwise.Protocol()
        rxn = self.reaction
        rxn_type = (self.enzymes[0]['name']
                    if len(self.enzymes) == 1 else 'restriction')

        def incubate(temp_getter,
                     time_getter,
                     time_formatter=lambda x: f'{x} min'):
            incubate_params = [
                (k, max(time_getter(x) for x in group))
                for k, group in groupby(self.enzymes, temp_getter)
            ]
            return [
                f"{temp}°C for {time_formatter(time)}"
                for temp, time in sorted(incubate_params)
            ]

        if self.time:
            digest_steps = incubate(
                itemgetter('incubateTemp'),
                lambda x: self.time,
                lambda x: x,
            )
        else:
            digest_steps = incubate(
                itemgetter('incubateTemp'),
                lambda x: 15 if x['timeSaver'] else 60,
                lambda x: '5–15 min' if x == 15 else '1 hour',
            )

        inactivate_steps = incubate(
            itemgetter('heatInactivationTemp'),
            itemgetter('heatInactivationTime'),
        )

        protocol += pl(
            f"Setup {plural(rxn.num_reactions):# {rxn_type} digestion/s} [1,2]:",
            rxn,
        )
        protocol += pl(
            f"Incubate at the following temperatures [3]:",
            ul(*digest_steps, *inactivate_steps),
        )

        urls = [x['url'] for x in self.enzymes if x.get('url')]
        protocol.footnotes[1] = pl(*urls, br='\n')
        protocol.footnotes[2] = """\
NEB recommends 5–10 units of enzyme per µg DNA 
(10–20 units for genomic DNA).  Enzyme volume 
should not exceed 10% of the total reaction 
volume to prevent star activity due to excess 
glycerol.
"""
        protocol.footnotes[3] = """\
The heat inactivation step is not necessary if 
the DNA will be purified before use.
"""
        return protocol
Пример #17
0
""")
rxn.num_reactions = 2
rxn.extra_percent = 0
rxn.hold_ratios.volume = '3 µL'

p += pl(
    f"Setup {rxn.num_reactions} click reactions:",
    rxn,
)
p += "Divide each reaction in three."

p += pl(
    "Incubate the reactions as follows:",
    ul(
        "−20°C overnight",
        "25°C for 4h, −20°C overnight",
        "25°C overnight",
    ),
)

p += "Label the product: o236"

p += stepwise.load(f"gel urea {3 * rxn.num_reactions + 2} -c 1730 -S")
p.insert_footnotes(
    pl(
        "The product (o236) has MW = 17285 g/mol, so:",
        "100 µM = 1730 ng/µL",
        br='\n',
    ), )
p += stepwise.load("stain sybr-green-ii/page -I")
p += stepwise.load("laser blue red")
Пример #18
0
        # PCR reaction setup:

        if self.footnote:
            # Before the footnote on resuspending the primers, if it hasn't 
            # been added to the protocol already.
            footnotes.insert(0, self.footnote)

        if x := pcr['template DNA'].stock_conc:
            footnotes.append(pl(
                    f"For diluting template DNA to {x}:",
                    f"Dilute 1 µL twice into {sqrt(1000/x.value):.1g}*sqrt([DNA]) µL",
                    br='\n',
            ))

        title = 'qPCR' if self.qpcr else 'PCR'
        instructions = ul()
        protocol += pl(
                f"Setup {plural(pcr.num_reactions):# {title} reaction/s}{protocol.add_footnotes(*footnotes)}:",
                pcr,
                instructions,
        )

        if pcr.volume > '50 µL':
            instructions += f"Split each reaction into {ceil(pcr.volume.value / 50)} tubes."
        if pcr.num_reactions > 1:
            instructions += "Use any extra master mix as a negative control."

        # Thermocycler protocol:

        protocol += pl(
                "Run the following thermocycler protocol:",