qulab-infinite / experiment_protocols.py
workofarttattoo's picture
🚀 QuLab MCP Server: Complete Experiment Taxonomy Deployment
91994bf
"""
Copyright (c) 2025 Joshua Hendricks Cole (DBA: Corporation of Light). All Rights Reserved. PATENT PENDING.
Experiment Protocols - Detailed Step-by-Step Procedures for All Experiment Types
Provides comprehensive protocols for reactions, combinations, reductions, condensations, mixtures, etc.
"""
from dataclasses import dataclass, field
from typing import List, Dict, Any, Optional
from datetime import timedelta
from experiment_taxonomy import ExperimentTemplate, ExperimentCategory
@dataclass
class ProtocolStep:
"""Individual step in an experiment protocol"""
step_number: int
description: str
duration: Optional[timedelta] = None
temperature: Optional[float] = None
conditions: Dict[str, Any] = field(default_factory=dict)
safety_notes: List[str] = field(default_factory=list)
quality_checks: List[str] = field(default_factory=list)
critical_parameters: Dict[str, Any] = field(default_factory=dict)
@dataclass
class ExperimentProtocol:
"""Complete protocol for an experiment"""
experiment_id: str
title: str
overview: str
objective: str
required_equipment: List[str] = field(default_factory=list)
required_materials: List[str] = field(default_factory=list)
safety_precautions: List[str] = field(default_factory=list)
steps: List[ProtocolStep] = field(default_factory=list)
analytical_methods: List[str] = field(default_factory=list)
expected_results: Dict[str, Any] = field(default_factory=dict)
troubleshooting: Dict[str, List[str]] = field(default_factory=dict)
references: List[str] = field(default_factory=list)
estimated_duration: Optional[timedelta] = None
difficulty_level: str = "intermediate" # beginner, intermediate, advanced, expert
class ExperimentProtocols:
"""
Repository of detailed protocols for all experiment types.
Covers every kind of experiment: reactions, combinations, reductions, condensations, mixtures, etc.
"""
def __init__(self):
self.protocols: Dict[str, ExperimentProtocol] = {}
self._initialize_protocols()
def _initialize_protocols(self):
"""Initialize all experiment protocols"""
# Chemical Reaction Protocols
self._add_chemical_reaction_protocols()
# Physical Process Protocols
self._add_physical_process_protocols()
# Analytical Protocols
self._add_analytical_protocols()
# Mixture and Combination Protocols
self._add_mixture_protocols()
# Synthesis Protocols
self._add_synthesis_protocols()
def _add_chemical_reaction_protocols(self):
"""Add detailed protocols for chemical reactions"""
# Aldol Condensation Protocol
aldol_protocol = ExperimentProtocol(
experiment_id='aldol_condensation',
title='Aldol Condensation Reaction',
overview='Carbon-carbon bond forming reaction between carbonyl compounds under basic conditions',
objective='Synthesize β-hydroxy aldehydes/ketones or α,β-unsaturated carbonyl compounds',
required_equipment=[
'Round-bottom flask (50 mL)',
'Magnetic stirrer and stir bar',
'Reflux condenser',
'Ice bath',
'Separatory funnel',
'Rotary evaporator',
'Analytical balance',
'pH meter'
],
required_materials=[
'Aldehyde starting material (1 mmol)',
'Ketone starting material (1 mmol)',
'Base catalyst (NaOH or LDA, 0.1-1 equiv)',
'Organic solvent (ethanol or THF, 10 mL)',
'Acid for quench (dilute HCl)',
'Extraction solvent (ethyl acetate or diethyl ether)',
'Drying agent (anhydrous Na2SO4)'
],
safety_precautions=[
'Wear chemical-resistant gloves and safety goggles',
'Work in fume hood',
'Handle bases with care - can cause burns',
'Organic solvents are flammable',
'Reaction may be exothermic'
],
steps=[
ProtocolStep(
step_number=1,
description='Prepare reaction mixture: Add aldehyde and ketone to solvent in round-bottom flask',
duration=timedelta(minutes=5),
temperature=25.0,
conditions={'atmosphere': 'air', 'stirring': 'magnetic'},
safety_notes=['Ensure proper ventilation'],
quality_checks=['Verify reagent purity by TLC if available']
),
ProtocolStep(
step_number=2,
description='Add base catalyst slowly while stirring',
duration=timedelta(minutes=2),
temperature=0.0,
conditions={'addition_rate': 'dropwise', 'cooling': 'ice bath'},
safety_notes=['Exothermic reaction - control temperature'],
critical_parameters={'base_equivalents': 0.5, 'addition_time': '2 min'}
),
ProtocolStep(
step_number=3,
description='Stir reaction mixture at room temperature',
duration=timedelta(hours=2),
temperature=25.0,
conditions={'stirring_speed': 'moderate'},
quality_checks=['Monitor reaction progress by TLC']
),
ProtocolStep(
step_number=4,
description='Quench reaction with dilute acid',
duration=timedelta(minutes=5),
temperature=0.0,
conditions={'cooling': 'ice bath'},
safety_notes=['Acid addition generates heat'],
critical_parameters={'ph_target': 7.0}
),
ProtocolStep(
step_number=5,
description='Extract product with organic solvent',
duration=timedelta(minutes=10),
conditions={'extraction_cycles': 3},
quality_checks=['Check phases for product distribution']
),
ProtocolStep(
step_number=6,
description='Dry organic layer and concentrate',
duration=timedelta(minutes=15),
temperature=40.0,
conditions={'pressure': 'reduced', 'drying_agent': 'Na2SO4'},
quality_checks=['Verify solvent removal']
),
ProtocolStep(
step_number=7,
description='Purify product by chromatography or crystallization',
duration=timedelta(hours=1),
conditions={'method': 'column_chromatography'},
quality_checks=['Check product purity by TLC/NMR']
)
],
analytical_methods=[
'Thin Layer Chromatography (TLC)',
'Nuclear Magnetic Resonance (NMR)',
'Infrared Spectroscopy (IR)',
'Mass Spectrometry (MS)',
'Melting Point Determination'
],
expected_results={
'yield_range': '40-90%',
'product_characteristics': 'White to yellow solid or oil',
'spectroscopic_data': {
'nmr': 'Characteristic β-proton signals',
'ir': 'Carbonyl stretch, OH stretch'
}
},
troubleshooting={
'low_yield': [
'Check reagent purity',
'Optimize reaction temperature and time',
'Consider alternative bases or conditions'
],
'side_products': [
'Minimize water in reaction',
'Control reaction temperature',
'Use excess of one reagent'
],
'no_reaction': [
'Verify base activity',
'Check for interfering functional groups',
'Consider alternative solvents'
]
},
references=[
'March, J. Advanced Organic Chemistry, 4th ed.',
'Carey, F.A. Organic Chemistry, 8th ed.',
'DOI: 10.1021/cr00002a004 (Aldol Reaction Reviews)'
],
estimated_duration=timedelta(hours=4),
difficulty_level='intermediate'
)
self.protocols['aldol_condensation'] = aldol_protocol
# Catalytic Hydrogenation Protocol
hydrogenation_protocol = ExperimentProtocol(
experiment_id='catalytic_hydrogenation',
title='Catalytic Hydrogenation',
overview='Reduction of unsaturated compounds using molecular hydrogen and metal catalysts',
objective='Convert alkenes, alkynes, or other reducible functional groups to saturated compounds',
required_equipment=[
'Parr hydrogenation apparatus or shaker flask',
'Hydrogen cylinder with regulator',
'Magnetic stirrer',
'Pressure gauge',
'Filtration apparatus',
'Rotary evaporator'
],
required_materials=[
'Substrate (1 mmol)',
'Metal catalyst (Pd/C, Pt/C, or Ni, 5-10% w/w)',
'Organic solvent (methanol, ethanol, or ethyl acetate, 10 mL)',
'Hydrogen gas',
'Celite or filter aid'
],
safety_precautions=[
'Hydrogen gas is flammable and explosive',
'Work in fume hood with proper ventilation',
'Metal catalysts are pyrophoric when dry',
'Handle under inert atmosphere if necessary',
'Pressure vessel safety precautions'
],
steps=[
ProtocolStep(
step_number=1,
description='Prepare catalyst: Add metal catalyst to reaction solvent',
duration=timedelta(minutes=5),
conditions={'atmosphere': 'nitrogen_or_argon'},
safety_notes=['Catalyst may be pyrophoric - keep wet'],
quality_checks=['Verify catalyst loading']
),
ProtocolStep(
step_number=2,
description='Add substrate to catalyst suspension',
duration=timedelta(minutes=2),
conditions={'stirring': 'gentle'},
safety_notes=['Ensure good mixing']
),
ProtocolStep(
step_number=3,
description='Purge system with hydrogen gas',
duration=timedelta(minutes=5),
conditions={'gas_flow': 'gentle_purge'},
safety_notes=['Vent hydrogen properly', 'No ignition sources']
),
ProtocolStep(
step_number=4,
description='Pressurize with hydrogen and start reaction',
duration=timedelta(hours=2),
temperature=25.0,
conditions={'pressure_bar': 1.0, 'stirring': 'vigorous'},
quality_checks=['Monitor pressure drop', 'Check reaction progress by TLC/GC'],
critical_parameters={'hydrogen_pressure': '1-50 bar', 'temperature': '0-100°C'}
),
ProtocolStep(
step_number=5,
description='Vent hydrogen gas carefully',
duration=timedelta(minutes=10),
safety_notes=['Vent slowly to avoid ignition', 'Use fume hood'],
critical_parameters={'venting_rate': 'controlled'}
),
ProtocolStep(
step_number=6,
description='Filter catalyst and concentrate filtrate',
duration=timedelta(minutes=15),
conditions={'filter_aid': 'celite'},
quality_checks=['Verify complete catalyst removal']
),
ProtocolStep(
step_number=7,
description='Purify product by distillation or chromatography',
duration=timedelta(hours=1),
conditions={'method': 'flash_chromatography'},
quality_checks=['Check product purity']
)
],
analytical_methods=[
'Gas Chromatography (GC)',
'Thin Layer Chromatography (TLC)',
'Nuclear Magnetic Resonance (NMR)',
'Infrared Spectroscopy (IR)',
'Hydrogen uptake measurement'
],
expected_results={
'yield_range': '80-99%',
'selectivity': 'Often excellent for alkene reduction',
'catalyst_recovery': 'Possible for precious metal catalysts'
},
troubleshooting={
'slow_reaction': [
'Increase hydrogen pressure',
'Check catalyst activity',
'Add fresh catalyst',
'Increase temperature carefully'
],
'over_reduction': [
'Reduce catalyst loading',
'Lower hydrogen pressure',
'Use poisoned catalyst (Lindlar)',
'Monitor reaction closely'
],
'catalyst_poisoning': [
'Filter out impurities first',
'Use fresh catalyst',
'Consider alternative catalysts'
]
},
references=[
'Rylander, P.N. Hydrogenation Methods, 2nd ed.',
'Freifelder, M. Practical Catalytic Hydrogenation',
'DOI: 10.1002/anie.200902823 (Asymmetric Hydrogenation)'
],
estimated_duration=timedelta(hours=4),
difficulty_level='advanced'
)
self.protocols['catalytic_hydrogenation'] = hydrogenation_protocol
def _add_physical_process_protocols(self):
"""Add detailed protocols for physical processes"""
# Recrystallization Protocol
recrystallization_protocol = ExperimentProtocol(
experiment_id='recrystallization',
title='Recrystallization Purification',
overview='Purification of solid compounds by controlled crystallization from solution',
objective='Obtain pure crystalline material by selective crystallization',
required_equipment=[
'Round-bottom flask or Erlenmeyer flask',
'Hot plate or heating mantle',
'Ice bath',
'Buchner funnel and filter flask',
'Vacuum pump',
'Watch glass or crystallization dish',
'Spatula'
],
required_materials=[
'Impure solid compound (100-500 mg)',
'Solvent system (single solvent or mixture)',
'Seed crystals (optional)',
'Activated charcoal (optional for decolorization)',
'Filter paper'
],
safety_precautions=[
'Handle hot solvents with care',
'Work in fume hood',
'Solvents may be flammable or toxic',
'Glassware may be hot',
'Proper waste disposal'
],
steps=[
ProtocolStep(
step_number=1,
description='Determine suitable solvent system',
duration=timedelta(minutes=15),
conditions={'solubility_testing': 'small_scale'},
quality_checks=['Test solubility at room temperature and hot']
),
ProtocolStep(
step_number=2,
description='Dissolve impure compound in minimal hot solvent',
duration=timedelta(minutes=10),
temperature=80.0,
conditions={'heating': 'gentle', 'stirring': 'magnetic'},
safety_notes=['Use hot plate in fume hood'],
critical_parameters={'solvent_volume': 'minimal_amount'}
),
ProtocolStep(
step_number=3,
description='Add activated charcoal if needed for decolorization',
duration=timedelta(minutes=5),
temperature=80.0,
conditions={'charcoal_amount': 'small_amount'},
quality_checks=['Check solution color']
),
ProtocolStep(
step_number=4,
description='Hot filter solution to remove insolubles',
duration=timedelta(minutes=5),
temperature=80.0,
conditions={'filtration': 'gravity_or_vacuum'},
safety_notes=['Handle hot filtrate carefully']
),
ProtocolStep(
step_number=5,
description='Cool solution slowly to induce crystallization',
duration=timedelta(hours=2),
temperature=0.0,
conditions={'cooling_rate': 'slow', 'seeding': 'optional'},
quality_checks=['Observe crystal formation'],
critical_parameters={'cooling_rate': 'room_temp_to_ice_bath'}
),
ProtocolStep(
step_number=6,
description='Collect crystals by vacuum filtration',
duration=timedelta(minutes=10),
temperature=0.0,
conditions={'washing': 'cold_solvent'},
safety_notes=['Break vacuum slowly']
),
ProtocolStep(
step_number=7,
description='Dry crystals and determine yield and purity',
duration=timedelta(hours=1),
temperature=40.0,
conditions={'drying': 'vacuum_or_air'},
quality_checks=['Weigh product', 'Check melting point', 'Run TLC or spectroscopy']
)
],
analytical_methods=[
'Melting Point Determination',
'Thin Layer Chromatography (TLC)',
'Nuclear Magnetic Resonance (NMR)',
'Infrared Spectroscopy (IR)',
'Elemental Analysis'
],
expected_results={
'yield_range': '50-95%',
'purity_improvement': 'Significant increase',
'crystal_habit': 'Well-formed crystals'
},
troubleshooting={
'oiling_out': [
'Add more solvent',
'Change solvent system',
'Cool more slowly',
'Use seed crystals'
],
'no_crystallization': [
'Concentrate solution',
'Scratch flask walls',
'Add seed crystals',
'Change solvent'
],
'impure_product': [
'Repeat recrystallization',
'Change solvent system',
'Add charcoal treatment',
'Use chromatography instead'
]
},
references=[
'Shriner, R.L. The Systematic Identification of Organic Compounds',
'Armarego, W.L.F. Purification of Laboratory Chemicals',
'DOI: 10.1002/047084289X (Crystallization Techniques)'
],
estimated_duration=timedelta(hours=4),
difficulty_level='intermediate'
)
self.protocols['recrystallization'] = recrystallization_protocol
def _add_analytical_protocols(self):
"""Add detailed protocols for analytical experiments"""
# NMR Spectroscopy Protocol
nmr_protocol = ExperimentProtocol(
experiment_id='nmr_spectroscopy',
title='Nuclear Magnetic Resonance Spectroscopy',
overview='Determination of molecular structure using NMR spectroscopy',
objective='Obtain NMR spectrum and assign peaks to molecular structure',
required_equipment=[
'NMR spectrometer',
'NMR tubes (5 mm diameter)',
'Balance for sample weighing',
'Volumetric pipettes',
'Glove box or inert atmosphere setup (optional)',
'Deuterated solvent'
],
required_materials=[
'Sample compound (10-50 mg)',
'Deuterated solvent (CDCl3, DMSO-d6, etc., 0.5-1 mL)',
'Internal standard (TMS or residual solvent peak)',
'NMR tube caps and spacers'
],
safety_precautions=[
'NMR spectrometers have strong magnetic fields',
'Remove all ferromagnetic objects',
'Handle deuterated solvents with care',
'Proper waste disposal for solvents',
'Emergency shutoff procedures'
],
steps=[
ProtocolStep(
step_number=1,
description='Prepare sample solution',
duration=timedelta(minutes=10),
conditions={'concentration': '10-50 mg/mL'},
safety_notes=['Handle solvents in fume hood'],
quality_checks=['Verify sample solubility'],
critical_parameters={'solvent_choice': 'based_on_sample_solubility'}
),
ProtocolStep(
step_number=2,
description='Transfer solution to NMR tube',
duration=timedelta(minutes=5),
conditions={'tube_preparation': 'clean_and_dry'},
safety_notes=['Avoid introducing air bubbles']
),
ProtocolStep(
step_number=3,
description='Set up spectrometer parameters',
duration=timedelta(minutes=5),
conditions={'pulse_sequence': 'standard_1H_or_13C'},
critical_parameters={
'spectral_width': 'appropriate_for_nucleus',
'number_of_scans': '16-64',
'relaxation_delay': '1-2 seconds'
}
),
ProtocolStep(
step_number=4,
description='Acquire spectrum',
duration=timedelta(minutes=5),
conditions={'automation': 'instrument_controlled'},
quality_checks=['Check signal-to-noise ratio']
),
ProtocolStep(
step_number=5,
description='Process and analyze spectrum',
duration=timedelta(minutes=30),
conditions={'software': 'NMR_processing_software'},
quality_checks=['Verify peak integrations', 'Check chemical shifts'],
critical_parameters={'referencing': 'TMS_or_solvent_peak'}
),
ProtocolStep(
step_number=6,
description='Assign peaks to molecular structure',
duration=timedelta(hours=1),
conditions={'analysis': 'chemical_shift_tables'},
quality_checks=['Compare with literature values']
)
],
analytical_methods=[
'1H NMR (proton)',
'13C NMR (carbon)',
'2D NMR (COSY, HSQC, HMBC)',
'Variable temperature NMR',
'Diffusion-ordered spectroscopy (DOSY)'
],
expected_results={
'chemical_shift_range': 'Depends on nucleus',
'peak_multiplicity': 'Singlet, doublet, triplet, etc.',
'integration_accuracy': '±5%',
'spectral_resolution': '0.01-0.1 ppm'
},
troubleshooting={
'poor_signal': [
'Increase number of scans',
'Increase sample concentration',
'Check shimming',
'Clean NMR tube'
],
'broad_peaks': [
'Check sample purity',
'Adjust temperature',
'Check for paramagnetic impurities',
'Use better solvent'
],
'incorrect_shifts': [
'Check referencing',
'Verify solvent purity',
'Check for concentration effects',
'Compare with known compounds'
]
},
references=[
'Silverstein, R.M. Spectrometric Identification of Organic Compounds',
'Friebolin, H. Basic One- and Two-Dimensional NMR Spectroscopy',
'Claridge, T.D.W. High-Resolution NMR Techniques in Organic Chemistry'
],
estimated_duration=timedelta(hours=2),
difficulty_level='intermediate'
)
self.protocols['nmr_spectroscopy'] = nmr_protocol
def _add_mixture_protocols(self):
"""Add detailed protocols for mixture experiments"""
# Buffer Preparation Protocol
buffer_protocol = ExperimentProtocol(
experiment_id='buffer_preparation',
title='Buffer Solution Preparation',
overview='Preparation of buffered solutions with precise pH and capacity',
objective='Create stable pH environment for biochemical or chemical reactions',
required_equipment=[
'Analytical balance',
'Volumetric flask (various sizes)',
'pH meter',
'Magnetic stirrer',
'Graduated cylinder',
'Pipettes'
],
required_materials=[
'Buffer components (acid and conjugate base)',
'Distilled water',
'pH adjustment solution (strong acid/base)',
'Storage container'
],
safety_precautions=[
'Handle acids and bases with care',
'Wear appropriate PPE',
'Work in fume hood if volatile',
'Proper waste disposal'
],
steps=[
ProtocolStep(
step_number=1,
description='Calculate buffer composition using Henderson-Hasselbalch equation',
duration=timedelta(minutes=10),
conditions={'calculations': 'pH = pKa + log([A-]/[HA])'},
quality_checks=['Verify calculations']
),
ProtocolStep(
step_number=2,
description='Weigh solid buffer components',
duration=timedelta(minutes=5),
conditions={'precision': '±0.001 g'},
safety_notes=['Use clean spatula and balance']
),
ProtocolStep(
step_number=3,
description='Dissolve components in ~80% final volume of water',
duration=timedelta(minutes=10),
temperature=25.0,
conditions={'stirring': 'magnetic'},
quality_checks=['Ensure complete dissolution']
),
ProtocolStep(
step_number=4,
description='Adjust pH with strong acid/base',
duration=timedelta(minutes=15),
conditions={'incremental_addition': 'small_amounts'},
quality_checks=['Monitor pH continuously'],
critical_parameters={'target_ph': 'within_0.1_units'}
),
ProtocolStep(
step_number=5,
description='Bring to final volume with distilled water',
duration=timedelta(minutes=5),
temperature=25.0,
conditions={'mixing': 'thorough'},
critical_parameters={'volume_accuracy': '±0.1 mL'}
),
ProtocolStep(
step_number=6,
description='Verify final pH and buffer capacity',
duration=timedelta(minutes=10),
conditions={'testing': 'ph_measurement'},
quality_checks=['Check pH stability', 'Test buffer capacity']
)
],
analytical_methods=[
'pH Measurement',
'Conductivity Measurement',
'Titration for Buffer Capacity',
'UV-Vis Spectroscopy (if colored)'
],
expected_results={
'ph_accuracy': '±0.1 units',
'buffer_capacity': 'Depends on concentration',
'stability': 'Weeks to months when stored properly'
},
troubleshooting={
'ph_drift': [
'Check reagent purity',
'Verify calculations',
'Use fresh solutions',
'Consider contamination'
],
'precipitation': [
'Check solubility limits',
'Adjust ionic strength',
'Change buffer system',
'Lower concentration'
],
'low_buffer_capacity': [
'Increase concentration',
'Use different buffer system',
'Check for interfering substances'
]
},
references=[
'Good, N.E. et al. Biochemistry 5, 467 (1966)',
'Ferguson, W.J. et al. Anal. Biochem. 104, 300 (1980)',
'DOI: 10.1021/ac970856h (Buffer Preparation)'
],
estimated_duration=timedelta(hours=1),
difficulty_level='beginner'
)
self.protocols['buffer_preparation'] = buffer_protocol
def _add_synthesis_protocols(self):
"""Add detailed protocols for synthesis experiments"""
# Multi-step Synthesis Protocol
multistep_protocol = ExperimentProtocol(
experiment_id='multistep_synthesis',
title='Multi-step Organic Synthesis',
overview='Complex synthesis requiring multiple sequential reactions',
objective='Construct complex molecules through planned synthetic routes',
required_equipment=[
'Various glassware (flasks, condensers, separatory funnels)',
'Temperature control equipment',
'Stirring apparatus',
'Chromatography equipment',
'Spectroscopic instruments',
'Purification equipment'
],
required_materials=[
'Starting materials for each step',
'Reagents and catalysts',
'Solvents for each reaction',
'Purification materials',
'Analytical standards'
],
safety_precautions=[
'Risk assessment for each step',
'Proper PPE for all chemicals',
'Ventilation requirements',
'Emergency procedures',
'Waste handling protocols'
],
steps=[
ProtocolStep(
step_number=1,
description='Plan synthetic route with retrosynthetic analysis',
duration=timedelta(hours=2),
conditions={'strategy': 'retrosynthesis'},
quality_checks=['Literature search', 'Feasibility assessment']
),
ProtocolStep(
step_number=2,
description='Execute first reaction step',
duration=timedelta(hours=4),
conditions={'optimization': 'reaction_conditions'},
quality_checks=['Monitor by TLC/GC', 'Check yield']
),
ProtocolStep(
step_number=3,
description='Isolate and purify first intermediate',
duration=timedelta(hours=2),
conditions={'method': 'chromatography_or_crystallization'},
quality_checks=['Purity by spectroscopy', 'Yield calculation']
),
ProtocolStep(
step_number=4,
description='Execute subsequent reaction steps',
duration=timedelta(hours=4),
conditions={'sequential': 'step_by_step'},
quality_checks=['Progress monitoring', 'Intermediate characterization']
),
ProtocolStep(
step_number=5,
description='Final purification and characterization',
duration=timedelta(hours=3),
conditions={'comprehensive': 'full_analysis'},
quality_checks=['Complete spectroscopic analysis', 'Purity confirmation']
),
ProtocolStep(
step_number=6,
description='Overall yield calculation and route optimization',
duration=timedelta(hours=1),
conditions={'analysis': 'yield_optimization'},
quality_checks=['Compare with literature', 'Identify improvements']
)
],
analytical_methods=[
'Chromatographic methods (TLC, GC, HPLC)',
'Spectroscopic methods (NMR, IR, MS)',
'Thermal analysis (melting point, DSC)',
'Elemental analysis'
],
expected_results={
'overall_yield': '10-80% (depends on complexity)',
'purity': '>95% for final product',
'step_efficiencies': 'Variable by step'
},
troubleshooting={
'low_overall_yield': [
'Optimize individual steps',
'Consider protecting groups',
'Change synthetic route',
'Improve purification methods'
],
'side_reactions': [
'Adjust reaction conditions',
'Use selective reagents',
'Change order of steps',
'Add protecting groups'
],
'purification_difficulties': [
'Change chromatography conditions',
'Use alternative purification',
'Modify functional groups',
'Consider derivatization'
]
},
references=[
'Warren, S. Designing Organic Syntheses',
'Clayden, J. Organic Chemistry',
'DOI: 10.1002/anie.200600885 (Total Synthesis Reviews)'
],
estimated_duration=timedelta(days=1),
difficulty_level='expert'
)
self.protocols['multistep_synthesis'] = multistep_protocol
def get_protocol(self, experiment_id: str) -> Optional[ExperimentProtocol]:
"""Get detailed protocol for an experiment"""
return self.protocols.get(experiment_id)
def get_protocols_by_category(self, category: str) -> List[ExperimentProtocol]:
"""Get all protocols in a category"""
return [p for p in self.protocols.values() if p.experiment_id in self._get_experiments_by_category(category)]
def _get_experiments_by_category(self, category: str) -> List[str]:
"""Helper to get experiment IDs by category"""
# This would integrate with the experiment taxonomy
# For now, return hardcoded mappings
category_mappings = {
'chemical_reaction': ['aldol_condensation', 'catalytic_hydrogenation'],
'physical_process': ['recrystallization'],
'analytical_measurement': ['nmr_spectroscopy'],
'synthesis_combination': ['buffer_preparation', 'multistep_synthesis']
}
return category_mappings.get(category, [])
def search_protocols(self, query: str) -> List[ExperimentProtocol]:
"""Search protocols by title, description, or keywords"""
query_lower = query.lower()
results = []
for protocol in self.protocols.values():
if (query_lower in protocol.title.lower() or
query_lower in protocol.overview.lower() or
query_lower in protocol.objective.lower()):
results.append(protocol)
return results
def export_protocols(self, output_file: str = 'experiment_protocols.json'):
"""Export all protocols to JSON"""
protocols_data = {
'metadata': {
'version': '1.0.0',
'total_protocols': len(self.protocols),
'last_updated': '2025-01-21'
},
'protocols': {}
}
for exp_id, protocol in self.protocols.items():
protocols_data['protocols'][exp_id] = {
'title': protocol.title,
'overview': protocol.overview,
'objective': protocol.objective,
'difficulty_level': protocol.difficulty_level,
'estimated_duration_hours': protocol.estimated_duration.total_seconds() / 3600 if protocol.estimated_duration else None,
'steps_count': len(protocol.steps),
'required_equipment_count': len(protocol.required_equipment),
'safety_precautions': protocol.safety_precautions,
'analytical_methods': protocol.analytical_methods
}
with open(output_file, 'w') as f:
json.dump(protocols_data, f, indent=2, default=str)
return protocols_data
# Global protocols instance
experiment_protocols = ExperimentProtocols()
if __name__ == '__main__':
# Export protocols
protocols_data = experiment_protocols.export_protocols()
print(f"Exported {len(experiment_protocols.protocols)} detailed experiment protocols")
# Show sample protocols
print("\nSample detailed protocols:")
for exp_id in ['aldol_condensation', 'catalytic_hydrogenation', 'nmr_spectroscopy']:
if exp_id in experiment_protocols.protocols:
protocol = experiment_protocols.protocols[exp_id]
print(f"- {protocol.title}: {len(protocol.steps)} steps, {protocol.difficulty_level} level")