Skip to content

Commit

Permalink
QC tests passing to some extent; QC samples and processes generated c…
Browse files Browse the repository at this point in the history
…orrectly #329
  • Loading branch information
Zigur committed Aug 22, 2019
1 parent 8e692ca commit d8bc270
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 19 deletions.
35 changes: 23 additions & 12 deletions isatools/create/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -883,9 +883,9 @@ class QualityControlSample(Sample):

def __init__(self, **kwargs):
print('KWARGS are: {0}'.format(kwargs))
qc_sample_type = kwargs['qc_sample_type']
del kwargs['qc_sample_type']
super(QualityControlSample, self).__init__(**kwargs)
qc_sample_type = kwargs.get('qc_sample_type', None)
_kwargs = {key: val for key, val in kwargs.items() if key is not 'qc_sample_type'}
super(QualityControlSample, self).__init__(**_kwargs)
self.__qc_sample_type = None
if qc_sample_type:
self.qc_sample_type = qc_sample_type
Expand Down Expand Up @@ -1035,7 +1035,9 @@ def __init__(self, measurement_type, technology_type, id_=str(uuid.uuid4()), nod
pass

@classmethod
def generate_assay_plan_from_dict(cls, assay_plan_dict, validation_template=None, use_guids=False, **kwargs):
def generate_assay_plan_from_dict(cls, assay_plan_dict,
validation_template=None, quality_control=None,
use_guids=False, **kwargs):
"""
Alternative constructor that generates an AssayGraph object from a well structured dictionary
:param assay_plan_dict: dict
Expand Down Expand Up @@ -1113,6 +1115,8 @@ def generate_assay_plan_from_dict(cls, assay_plan_dict, validation_template=None
current_nodes.append(protocol_node)
previous_nodes = current_nodes
current_nodes = []
if quality_control:
res.quality_control = quality_control
return res

@property
Expand Down Expand Up @@ -1436,14 +1440,16 @@ def add_element_to_map(self, sample_node, assay_graph):

@classmethod
def from_sample_and_assay_plan_dict(cls, sample_type_dicts, *assay_plan_dicts, validation_template=None,
use_guids=False):
use_guids=False, quality_controls=[]):
"""
An alternative constructor that builds the SampleAndAssayPlan graph object from a schema provided as an
OrderedDict, which can optionally be validated against a validation_schema
:param sample_type_dicts: list of dicts
:param assay_plan_dicts: list of OrderedDicts
:param validation_template: dict/OrderedDict
:param use_guids: bool
:param quality_controls: list of QualityControl objects. Ideally should be as long as the number
of assay_plan_dicts provided
:return: SampleAndAssayPlan
"""
res = cls()
Expand All @@ -1460,6 +1466,7 @@ def from_sample_and_assay_plan_dict(cls, sample_type_dicts, *assay_plan_dicts, v
res.add_assay_graph_to_plan(AssayGraph.generate_assay_plan_from_dict(
assay_plan_dict,
id_=str(uuid.uuid4()) if use_guids else '{0}_{1}'.format(ASSAY_GRAPH, str(i).zfill(3)),
quality_control=quality_controls[i] if len(quality_controls) > i else None
))
for sample_node in res.sample_plan:
for assay_graph in res.assay_plan:
Expand All @@ -1470,9 +1477,10 @@ def __repr__(self):
s2a_map = {}
for [st, ags] in self.sample_to_assay_map.items():
s2a_map[st] = sorted({ag.id for ag in ags})
return '{0}.{1}(name={2.name}, sample_plan={2.sample_plan}, assay_plan={2.assay_plan}, ' \
sample_plan = sorted(self.sample_plan, key=lambda s_t: s_t.id)
return '{0}.{1}(name={2.name}, sample_plan={4}, assay_plan={2.assay_plan}, ' \
'sample_to_assay_map={3})'.format(
self.__class__.__module__, self.__class__.__name__, self, s2a_map
self.__class__.__module__, self.__class__.__name__, self, s2a_map, sample_plan
)

def __str__(self):
Expand Down Expand Up @@ -2065,7 +2073,7 @@ def _generate_samples(self, sources_map, sampling_protocol, performer, split_ass
for assay_graph in sample_assay_plan.assay_plan:
protocols.update({node for node in assay_graph.nodes if isinstance(node, Protocol)})
if split_assays_by_sample_type is True:
for sample_node in sample_assay_plan.sample_plan:
for sample_node in sorted(sample_assay_plan.sample_plan, key=lambda st: st.id):
if assay_graph in sample_assay_plan.sample_to_assay_map[sample_node]:
"""
if assay_graph.quality_control:
Expand Down Expand Up @@ -2157,12 +2165,15 @@ def _generate_assay(assay_graph, assay_samples, cell_name=''):
assay_graph.measurement_type
)
)
log.info('assay measurement type: {0} - technology type: {1}'.format(assay.measurement_type,
assay.technology_type))
for node in assay_graph.start_nodes:
size = node.size if isinstance(node, ProductNode) \
else node.replicates if isinstance(node, ProtocolNode) \
else 1
# print('Size: {0}'.format(size))
log.info('Size: {0}'.format(size))
for i, sample in enumerate(assay_samples):
log.info('Iteration: {0} - Sample: {1}'.format(i, sample.name))
for j in range(size):
processes, other_materials, data_files, _ = StudyDesign._generate_isa_elements_from_node(
node, assay_graph, ix=i*len(assay_samples)+j, processes=[], other_materials=[], data_files=[],
Expand All @@ -2171,7 +2182,7 @@ def _generate_assay(assay_graph, assay_samples, cell_name=''):
assay.other_material.extend(other_materials)
assay.process_sequence.extend(processes)
assay.data_files.extend(data_files)
print('i={0}, i={1}, num_processes={2}, num_assay_files={3}'.format(i, j, len(processes),
log.info('i={0}, i={1}, num_processes={2}, num_assay_files={3}'.format(i, j, len(processes),
len(data_files)))
return assay

Expand Down Expand Up @@ -2370,7 +2381,7 @@ def _generate_quality_control_samples(quality_control, study_cell, sample_size=0
dummy_source = QualityControlSource(
name=SOURCE_QC_SOURCE_NAME
)
qc_sources.insert(dummy_source)
qc_sources.append(dummy_source)
sample = QualityControlSample(
name='{0}'.format(QC_SAMPLE_NAME),
factor_values=[],
Expand All @@ -2384,7 +2395,7 @@ def _generate_quality_control_samples(quality_control, study_cell, sample_size=0
dummy_source = QualityControlSource(
name=SOURCE_QC_SOURCE_NAME
)
qc_sources.insert(dummy_source)
qc_sources.append(dummy_source)
sample = QualityControlSample(
name='{0}'.format(QC_SAMPLE_NAME),
factor_values=[],
Expand Down
40 changes: 33 additions & 7 deletions tests/test_create_models_study_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -1659,8 +1659,19 @@ def setUp(self):
(self.cell_follow_up, self.ms_sample_assay_plan)
]))
# Sample QC (for mass spectroscopy and other)
self.pre_run_sample_type = ProductNode(id_='pre/00', node_type=SAMPLE, name='water')
self.post_run_sample_type = ProductNode(id_='post/00', node_type=SAMPLE, name='ethanol')
self.pre_run_sample_type = ProductNode(
id_='pre/00', node_type=SAMPLE, name='water', size=5, characteristics=(
Characteristic(category='dilution', value=10, unit='mg/L'),
)
)
self.post_run_sample_type = ProductNode(
id_='post/00', node_type=SAMPLE, name='ethanol', size=5, characteristics=(
Characteristic(category='dilution', value=1000, unit='mg/L'),
Characteristic(category='dilution', value=100, unit='mg/L'),
Characteristic(category='dilution', value=10, unit='mg/L'),
Characteristic(category='dilution', value=1, unit='mg/L'),
Characteristic(category='dilution', value=0.1, unit='mg/L')
))
self.dummy_sample_type = ProductNode(id_='dummy/01', node_type=SAMPLE, name='dummy')
self.more_dummy_sample_type = ProductNode(id_='dummy/02', node_type=SAMPLE, name='more dummy')
self.interspersed_sample_types = [(self.dummy_sample_type, 20)]
Expand Down Expand Up @@ -1916,14 +1927,20 @@ def setUp(self):
return super(QualityControlServiceTest, self).setUp()

def test_expansion_of_single_mass_spectrometry_assay(self):
"""
ms_assay_graph = next(ag for ag in self.ms_sample_assay_plan.assay_plan
if ag.technology_type == ms_assay_dict['technology_type'])
self.assertIsInstance(ms_assay_graph, AssayGraph)
# ms_assay_graph.quality_control = self.qc
print(self.ms_sample_assay_plan.assay_plan)
ms_assay_graph.quality_control = self.qc
print('MS assay graph start nodes are: {0}'.format(ms_assay_graph.start_nodes))
"""
ms_sample_assay_plan = SampleAndAssayPlan.from_sample_and_assay_plan_dict(
sample_list, ms_assay_dict, quality_controls=[self.qc]
)
# print(self.ms_sample_assay_plan.assay_plan)
first_arm = StudyArm(name=TEST_STUDY_ARM_NAME_00, group_size=20, arm_map=OrderedDict([
(self.cell_screen, None), (self.cell_run_in, None),
(self.cell_single_treatment_00, self.ms_sample_assay_plan),
(self.cell_single_treatment_00, ms_sample_assay_plan),
(self.cell_follow_up, self.nmr_sample_assay_plan)
]))
second_arm = StudyArm(name=TEST_STUDY_ARM_NAME_01, group_size=10, arm_map=OrderedDict([
Expand All @@ -1939,7 +1956,7 @@ def test_expansion_of_single_mass_spectrometry_assay(self):
if assay.technology_type == ms_assay_dict['technology_type'])
expected_num_of_samples_ms_plan_first_arm = reduce(
lambda acc_value, sample_node: acc_value + sample_node.size,
self.ms_sample_assay_plan.sample_plan, 0) * first_arm.group_size
ms_sample_assay_plan.sample_plan, 0) * first_arm.group_size
ms_processes = [process for process in ms_assay_no_qc.process_sequence
if process.executes_protocol.name == 'mass spectrometry']
self.assertEqual(len(ms_processes), 2 * 2 * 2 * 2 * expected_num_of_samples_ms_plan_first_arm)
Expand All @@ -1953,7 +1970,16 @@ def test_expansion_of_single_mass_spectrometry_assay(self):
if assay.technology_type == ms_assay_dict['technology_type'])
self.assertIsInstance(ms_assay_no_qc, Assay)
self.assertIsInstance(ms_assay_with_qc, Assay)
# self.assertNotEqual(ms_assay_with_qc, ms_assay_no_qc)
self.assertNotEqual(ms_assay_with_qc, ms_assay_no_qc)
"""
ms_processes = [process for process in ms_assay_with_qc.process_sequence
if process.executes_protocol.name == 'mass spectrometry']
qc_samples_size = self.qc.pre_run_sample_type.size + self.qc.post_run_sample_type.size + \
expected_num_of_samples_ms_plan_first_arm // self.interspersed_sample_types[0][1]
print('expected qc_samples_size: {0}'.format(qc_samples_size))
self.assertEqual(len(ms_processes), 2 * 2 * 2 * 2 *
(expected_num_of_samples_ms_plan_first_arm + qc_samples_size))
"""


class TreatmentFactoryTest(unittest.TestCase):
Expand Down

0 comments on commit d8bc270

Please sign in to comment.