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
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
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): protocol = stepwise.Protocol() pcr, primer_mix = self.reaction thermocycler = self.thermocycler_protocol footnotes = [] # Primer mix (if applicable): example_uM = min(x.stock_uM for x in flatten(self.primer_pairs)) footnotes.append(pl( f"For resuspending lyophilized primers:", f"{example_uM} µM = {1e3 / example_uM:g} µL/nmol", br='\n', )) if primer_mix: protocol += pl( f"Prepare 10x primer mix{protocol.add_footnotes(*footnotes)}:", primer_mix, ) footnotes = [] # 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', ))
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
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() 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
def get_protocol(self): p = stepwise.Protocol() p += pl( f"Setup {plural(self.num_reactions):# ligation reaction/s}:", self.reaction, ) p += "Incubate at room temperature for 1h." return p
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."
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
def get_protocol(self): optics = [self.parse_optics(x) for x in self.optics] lasers = [f"{plural(optics):laser/s}:" ] + [f"{x['laser']} nm" for x in optics] filters = [f"{plural(optics):filter/s}:" ] + [x['filter'] for x in optics] p = stepwise.Protocol() p += pl( "Image with a laser scanner:", table([lasers, filters], align='<>>'), ) return p
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
def get_protocol(self): p = stepwise.Protocol() rxn = self.reaction n = rxn.num_reactions f = "https://tinyurl.com/ychbvkra" p += pl( f"Setup {plural(n):# Gibson assembl/y/ies}{p.add_footnotes(f)}:", rxn, ) incubation_time = '15 min' if self.num_fragments <= 3 else '1h' p += f"Incubate at 50°C for {incubation_time}." return p
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:
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
def get_run_step(self): p = stepwise.Protocol() additive = f" with {x}" if (x := self.gel_additive) else "" percent = x.replace('-', '–') if isinstance(x := self.gel_percent, str) else x p += pl( f"Run a gel{p.add_footnotes(self.protocol_link)}:", dl( ("gel", f"{percent}% {self.gel_type}{additive}"), ("buffer", f"{self.gel_buffer}"), ("ladder", self.ladder_name and f"{self.ladder_volume_uL:g} µL {self.ladder_name}"), ("samples", self.load_volume_uL and f"{self.load_volume_uL:.3g} µL/lane"), ("prerun", self.prerun_time_min and f"{self.prerun_volts:g}V for {self.prerun_time_min:g} min"), ("run", f"{self.run_volts:g}V for {self.run_time_min:g} min"), )) return p
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
class MergeParams(Params): args = 'inputs, output' params_empty = [ #################################### ([ Protocol(), ], Protocol(), ), #################################### ([ Protocol(), Protocol(), ], Protocol(), ), #################################### ] params_dates = [ #################################### ([ Protocol( date=arrow.get(1988, 11, 8), ), ], Protocol( date=arrow.get(1988, 11, 8), ), ), #################################### ([ Protocol( date=arrow.get(1988, 11, 8), ), Protocol( date=arrow.get(1989, 9, 19), ), ], Protocol( date=arrow.get(1989, 9, 19), ), ), #################################### ([ Protocol(), Protocol( date=arrow.get(1988, 11, 8), ), ], Protocol( date=arrow.get(1988, 11, 8), ), ), ] params_commands = [ #################################### ([ Protocol( commands=['command-1'] ), ], Protocol( commands=['command-1'] ), ), #################################### ([ Protocol(), Protocol( commands=['command-1'] ), ], Protocol( commands=['command-1'] ), ), #################################### ([ Protocol( commands=['command-1'] ), Protocol( commands=['command-2'] ), ], Protocol( commands=['command-1', 'command-2'] ), ), #################################### ([ Protocol( commands=['command-1', 'command-2'] ), Protocol( commands=['command-3', 'command-4'] ), ], Protocol( commands=['command-1', 'command-2', 'command-3', 'command-4'] ), ), ] params_steps = [ #################################### ([ Protocol( steps=['Step 1'], ), ], Protocol( steps=['Step 1'], ), ), #################################### ([ 'Step 1' ], Protocol( steps=['Step 1'], ), ), #################################### ([ pl('Step 1') ], Protocol( steps=[pl('Step 1')], ), ), #################################### ([ Protocol(), Protocol( steps=['Step 1'], ), ], Protocol( steps=['Step 1'], ), ), #################################### ([ Protocol(), 'Step 1', ], Protocol( steps=['Step 1'], ), ), #################################### ([ Protocol( steps=['Step 1'], ), Protocol( steps=['Step 2'], ), ], Protocol( steps=['Step 1', 'Step 2'], ), ), #################################### ([ 'Step 1', 'Step 2', ], Protocol( steps=['Step 1', 'Step 2'], ), ), #################################### ([ Protocol( steps=['Step 1', 'Step 2'], ), Protocol( steps=['Step 3', 'Step 4'], ), ], Protocol( steps=['Step 1', 'Step 2', 'Step 3', 'Step 4'], ), ), #################################### ([ ['Step 1', 'Step 2'], ['Step 3', 'Step 4'], ], Protocol( steps=['Step 1', 'Step 2', 'Step 3', 'Step 4'], ), ), ] params_footnotes = [ #################################### ([ Protocol( steps=['Step A [1]'], footnotes={1: 'Footnote A'}, ), ], Protocol( steps=['Step A [1]'], footnotes={1: 'Footnote A'}, ), ), #################################### ([ Protocol(), Protocol( steps=['Step A [1]'], footnotes={1: 'Footnote A'}, ), ], Protocol( steps=['Step A [1]'], footnotes={1: 'Footnote A'}, ), ), #################################### ([ Protocol( steps=['Step A [1]'], footnotes={1: 'Footnote A'}, ), Protocol( steps=['Step B'], ), ], Protocol( steps=['Step A [1]', 'Step B'], footnotes={1: 'Footnote A'}, ), ), #################################### ([ Protocol( steps=['Step A'], ), Protocol( steps=['Step B [1]'], footnotes={1: 'Footnote B'}, ), ], Protocol( steps=['Step A', 'Step B [1]'], footnotes={1: 'Footnote B'}, ), ), #################################### ([ Protocol( steps=['Step A [1]'], footnotes={1: 'Footnote A'}, ), Protocol( steps=['Step B [1]'], footnotes={1: 'Footnote B'}, ), ], Protocol( steps=['Step A [1]', 'Step B [2]'], footnotes={1: 'Footnote A', 2: 'Footnote B'}, ), ), #################################### ([ Protocol( steps=['Step A [2]'], footnotes={2: 'Footnote A'}, ), Protocol( steps=['Step B [1]'], footnotes={1: 'Footnote B'}, ), ], Protocol( steps=['Step A [1]', 'Step B [2]'], footnotes={1: 'Footnote A', 2: 'Footnote B'}, ), ), #################################### ([ Protocol( steps=['Step A [1]', 'Step B [2]'], footnotes={1: 'Footnote A', 2: 'Footnote B'}, ), Protocol( steps=['Step C [1]', 'Step D [2]'], footnotes={1: 'Footnote C', 2: 'Footnote D'}, ), ], Protocol( steps=['Step A [1]', 'Step B [2]', 'Step C [3]', 'Step D [4]'], footnotes={1: 'Footnote A', 2: 'Footnote B', 3: 'Footnote C', 4: 'Footnote D'}, ), ), #################################### ([ Protocol(), Protocol( steps=['Step A [1]'], footnotes={1: pre('Footnote A')}, ), ], Protocol( steps=['Step A [1]'], footnotes={1: pre('Footnote A')}, ), ), ] params_footnotes_shared = [ #################################### ([ Protocol( steps=['Step A [1]'], footnotes={1: 'Same footnote'}, ), Protocol( steps=['Step B [1]'], footnotes={1: 'Same footnote'}, ), ], Protocol( steps=['Step A [1]', 'Step B [1]'], footnotes={1: 'Same footnote'} ), ), #################################### ([ Protocol( steps=['Step A [2]'], footnotes={2: 'Same footnote'}, ), Protocol( steps=['Step B [1]'], footnotes={1: 'Same footnote'}, ), ], Protocol( steps=['Step A [1]', 'Step B [1]'], footnotes={1: 'Same footnote'} ), ), #################################### ([ Protocol( steps=['Step A [1]'], footnotes={1: 'Same footnote'}, ), Protocol( steps=['Step B [2]'], footnotes={2: 'Same footnote'}, ), ], Protocol( steps=['Step A [1]', 'Step B [1]'], footnotes={1: 'Same footnote'} ), ), #################################### ([ Protocol( steps=['Step A [2]'], footnotes={2: 'Same footnote'}, ), Protocol( steps=['Step B [2]'], footnotes={2: 'Same footnote'}, ), ], Protocol( steps=['Step A [1]', 'Step B [1]'], footnotes={1: 'Same footnote'} ), ), #################################### ([ Protocol( steps=['Step A [1] [2]',], footnotes={1: 'Footnote 1', 2: 'Same footnote'}, ), Protocol( steps=['Step B [1]'], footnotes={1: 'Same footnote'}, ), ], Protocol( steps=['Step A [1] [2]', 'Step B [2]'], footnotes={1: 'Footnote 1', 2: 'Same footnote'} ), ), #################################### ([ Protocol( steps=['Step A [1] [2]',], footnotes={1: 'Footnote 1', 2: 'Same footnote'}, ), Protocol( steps=['Step B [2]'], footnotes={2: 'Same footnote'}, ), ], Protocol( steps=['Step A [1] [2]', 'Step B [2]'], footnotes={1: 'Footnote 1', 2: 'Same footnote'} ), ), #################################### ([ Protocol( steps=['Step A [1] [2]',], footnotes={1: 'Same footnote', 2: 'Footnote 2'}, ), Protocol( steps=['Step B [1]'], footnotes={1: 'Same footnote'}, ), ], Protocol( steps=['Step A [1] [2]', 'Step B [1]'], footnotes={1: 'Same footnote', 2: 'Footnote 2'}, ), ), #################################### ([ Protocol( steps=['Step A [1] [2]',], footnotes={1: 'Same footnote', 2: 'Footnote 2'}, ), Protocol( steps=['Step B [2]'], footnotes={2: 'Same footnote'}, ), ], Protocol( steps=['Step A [1] [2]', 'Step B [1]'], footnotes={1: 'Same footnote', 2: 'Footnote 2'}, ), ), #################################### ([ Protocol( steps=['Step A [1] [2]',], footnotes={1: 'Same footnote', 2: 'Footnote 2'}, ), Protocol( steps=['Step B [1] [2]'], footnotes={1: 'Footnote 1', 2: 'Same footnote'}, ), ], Protocol( steps=['Step A [1] [2]', 'Step B [3] [1]'], footnotes={1: 'Same footnote', 2: 'Footnote 2', 3: 'Footnote 1'} ), ), #################################### ([ Protocol( steps=['Step A [1] [2]',], footnotes={1: 'Same footnote X', 2: 'Same footnote Y'}, ), Protocol( steps=['Step B [1] [2]'], footnotes={1: 'Same footnote Y', 2: 'Same footnote Z'}, ), Protocol( steps=['Step C [1] [2]'], footnotes={1: 'Same footnote Z', 2: 'Same footnote X'}, ), ], Protocol( steps=['Step A [1] [2]', 'Step B [2] [3]', 'Step C [3] [1]'], footnotes={1: 'Same footnote X', 2: 'Same footnote Y', 3: 'Same footnote Z'} ), ), #################################### ([ Protocol( steps=['Step A [1]'], footnotes={1: pre('Same footnote')}, ), Protocol( steps=['Step B [1]'], footnotes={1: pre('Same footnote')}, ), ], Protocol( steps=['Step A [1]', 'Step B [1]'], footnotes={1: pre('Same footnote')} ), ), #################################### ] params_typecasts = [ #################################### ([ Protocol(steps=['Step 1']), 'Step 2', ], Protocol(steps=['Step 1', 'Step 2']), ), #################################### ([ Protocol(steps=['Step 1']), ['Step 2', 'Step 3'], ], Protocol(steps=['Step 1', 'Step 2', 'Step 3']), ), #################################### ([ Protocol(steps=['Step 1']), ProtocolIO( protocol=Protocol(steps=['Step 2']), errors=0, ) ], Protocol( steps=['Step 1', 'Step 2'], ), ), #################################### ([ Protocol(steps=['Step 1']), ProtocolIO( protocol='Error', errors=1, ) ], Protocol( steps=['Step 1'], ), ), #################################### ]
def test_protocol_iadd(): # The core functionality is tested by `test_protocol_merge()`; this just # needs to make sure the `+=` syntax works. p = Protocol() assert p.steps == [] p += "A" assert p.steps == ["A"] assert p[-1] == "A" # Do it again just to make sure the first addition didn't put the protocol # into some kind of broken state. p += "B" assert p.steps == ["A", "B"] assert p[-1] == "B" p += ["C", "D"] assert p.steps == ["A", "B", "C", "D"] assert p[-1] == "D" p += pl("E") assert p.steps == ["A", "B", "C", "D", pl("E")] assert p[-1] == pl("E") p += [pl("F"), pl("G")] assert p.steps == ["A", "B", "C", "D", pl("E"), pl("F"), pl("G")] assert p[-1] == pl("G") p += Protocol(steps=["H"], footnotes={1: "h"}) assert p.steps == ["A", "B", "C", "D", pl("E"), pl("F"), pl("G"), "H"] assert p.footnotes == {1: "h"} assert p[-1] == "H"
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
def get_full_protocol(self): df = self.dilutions uL = lambda x: x if isinstance(x, str) else f'{x:.2f} µL' ## Main table: main_header = [ "Name", "Stock Vol", "Diluent Vol", ] main_row = lambda x: [ x['tag'], uL(x['stock_uL']), uL(x['diluent_uL']), ] main_align = '<>>' to_conc = "" in_diluent = "" try: target_conc = unanimous(df['target_conc']) except ValueError: show_conc = True else: show_conc = False to_conc = f"to {target_conc} " if self.diluent: in_diluent = f"in {self.diluent} " if show_conc or df['too_dilute'].any(): main_header.append("Final Conc") main_row_3 = main_row main_row = lambda x: [ *main_row_3(x), str(x['final_conc']), ] main_align += '>' main_table = stepwise.table( rows=[main_row(x) for _, x in df.iterrows()], header=main_header, align=main_align, ) ## Supplementary table: def stock_str(row): c0, c1 = row['stock_conc'], row['stock_conc_converted'] return f'{c0} = {c1}' if c0.unit != c1.unit else f'{c1}' def mw_str(row): mw = row['mw'] return f'{mw:.1f}' if mw else '?' supp_table = stepwise.table( rows=[[x['tag'], mw_str(x), stock_str(x), x['target_conc']] for _, x in df.iterrows()], header=['Name', 'MW', 'Stock Conc', 'Target Conc'], align='<>>>', ) ## Protocol: p = stepwise.Protocol() p += pl( f"Dilute the following {plural(df):stock solution/s} {to_conc}{in_diluent}[1]:", main_table, ) p.footnotes[1] = pl( "Concentrations:", supp_table, ) return p
# 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:", thermocycler, )
M = np.array([ [mg_mM, -mg_stock_mM, 0, 0], [ k_mM, 0, -k_stock_mM, 0], [ 1, -1, -1, rxn_uL], ]) salt_uL = np.linalg.solve(M[:,:3], M[:,3]) rxn = stepwise.MasterMix() rxn.num_reactions = int(args['--num-reactions']) rxn.extra_min_volume = 5, 'µL' rxn.solvent = None rxn['translation reaction'].volume = rxn_uL, 'µL' rxn['translation reaction'].name = args['<reagent>'] rxn['translation reaction'].stock_conc = args['--ivtt-stock'] rxn['MgOAc'].stock_conc = mg_stock_mM, 'mM' rxn['MgOAc'].volume = salt_uL[1], 'µL' rxn['MgOAc'].master_mix = True rxn['KCl'].stock_conc = k_stock_mM, 'mM' rxn['KCl'].volume = salt_uL[2], 'µL' rxn['KCl'].master_mix = True p = stepwise.Protocol() p += pl( f"Setup the coupling reaction:", rxn, ) p += f"Incubate at {args['--incubate-temp']}°C for {args['--incubate-time']}." p.print()
def get_protocol(self): p = stepwise.Protocol() anneal, mmlv = self.reactions if self.nrt_control: mmlv_nrt = deepcopy(mmlv) mmlv_nrt.num_reactions = 1 anneal.num_reactions += 1 del mmlv_nrt['SMART MMLV RT'] p += pl( f"Anneal the {plural(self.primers):RT primer/s} to the {plural(self.templates):RNA template/s} [1]:", anneal, ) p.footnotes[1] = pre("""\ This protocol is based on the official Takara SMART MMLV reverse transcription protocol: https://tinyurl.com/y4ash7dl However, I made three modifications: - I reduced the volume of the annealing step as much as possible, the increase the concentrations of the oligos. - I added buffer to the annealing step, because annealing works much better with some salt to shield the backbone charge. I don't actually know how much salt is in the buffer, but some is better than none. - I included the MMLV in the transcription master mix, because excluding it seemed too inaccurate. The changes to the annealing step also mean that the master mix has a 1x buffer concentration, so I don't need to worry about the enzyme being unhappy. """) p += "Incubate at 70°C for 3 min, then immediately cool on ice." p += pl( "Setup {plural(mmlv.num_reactions):# reverse transcription reaction/s}:", mmlv, ) if self.nrt_control: p += pl( f"Setup a −reverse transcriptase (NRT) control:", mmlv_nrt, ) p += "Incubate at 42°C for 60 min [2]." p.footnotes[2] = "Samples can be incubated for 50-90 min if necessary." if self.quench == 'none': pass elif self.quench == 'heat': p += "Incubate at 70°C for 15 min." elif self.quench == 'edta': p += "Add 4 µL 60 mM EDTA." else: raise ConfigError( f"unexpected value for quench parameter: {self.quench}") return p
p += stepwise.load('cond optimize_click_freeze_cond.xlsx') rxn = stepwise.MasterMix("""\ Reagent Stock Volume MM? ======= ====== ====== === PBS 2x 2 µL - o126 400 µM 1 µL + o233 400 µM 1 µL + """) 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")
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