Skip to content

Commit

Permalink
Merge pull request #133 from UC-Davis-molecular-computing/dev-export-…
Browse files Browse the repository at this point in the history
…helix-groups

Dev export helix groups
  • Loading branch information
dave-doty authored Sep 10, 2020
2 parents c5bdb1c + 627d45b commit 5ace679
Show file tree
Hide file tree
Showing 3 changed files with 1,951 additions and 15 deletions.
35 changes: 22 additions & 13 deletions scadnano/scadnano.py
Original file line number Diff line number Diff line change
Expand Up @@ -4133,23 +4133,19 @@ def _cadnano_v2_place_strand(self, strand: Strand, dct: dict,
self._cadnano_v2_place_crossover(which_helix, next_helix,
domain, next_domain, strand_type)

def _cadnano_v2_fill_blank(self, dct: dict, num_bases: int) -> Dict[int, int]:
def _cadnano_v2_fill_blank(self, dct: dict, num_bases: int, design_grid: Grid) -> Dict[int, int]:
"""Creates blank cadnanov2 helices in and initialized all their fields.
"""
helices_ids_reverse = {}
for i, helix in self.helices.items():
helix_dct: Dict[str, Any] = OrderedDict()
helix_dct['num'] = helix.idx

if self.grid == Grid.square:
if helix.grid_position is None:
raise ValueError('cannot have grid_position == None if grid is square')
if design_grid == Grid.square:
helix_dct['row'] = helix.grid_position[1]
helix_dct['col'] = helix.grid_position[0]

elif self.grid == Grid.honeycomb:
if helix.grid_position is None:
raise ValueError('cannot have grid_position == None if grid is honeycomb')
if design_grid == Grid.honeycomb:
helix_dct['row'], helix_dct['col'] = helix.grid_position[1], helix.grid_position[0]

helix_dct['scaf'] = []
Expand Down Expand Up @@ -4178,9 +4174,22 @@ def to_cadnano_v2(self) -> Dict[str, Any]:
dct: Dict[str, Any] = OrderedDict()
dct['vstrands'] = []

if self.__class__ != Design:
raise ValueError(
'Please export DNAOrigamiDesign only as we need to know which strand is the scaffold.')
'''Check if helix group are used or if only one grid is used'''
design_grid = None
if self._has_default_groups():
design_grid = self.grid
else:
gridUsed = {}
grid_type = None
for group_name in self.groups:
gridUsed[self.groups[group_name].grid] = True
grid_type = self.groups[group_name].grid
if len(gridUsed) > 1:
raise ValueError('Designs using helix groups can be exported to cadnano v2 \
only if all groups share the same grid type.')
else:
design_grid = grid_type


'''Figuring out the type of grid.
In cadnano v2, all helices have the same max offset
Expand All @@ -4194,9 +4203,9 @@ def to_cadnano_v2(self) -> Dict[str, Any]:
raise ValueError('must have helix.max_offset set')
num_bases = max(num_bases, helix.max_offset)

if self.grid == Grid.square:
if design_grid == Grid.square:
num_bases = self._get_multiple_of_x_sup_closest_to_y(32, num_bases)
elif self.grid == Grid.honeycomb:
elif design_grid == Grid.honeycomb:
num_bases = self._get_multiple_of_x_sup_closest_to_y(21, num_bases)
else:
raise NotImplementedError('We can export to cadnano v2 `square` and `honeycomb` grids only.')
Expand All @@ -4219,7 +4228,7 @@ def to_cadnano_v2(self) -> Dict[str, Any]:

'''Filling the helices with blank.
'''
helices_ids_reverse: Dict[int, int] = self._cadnano_v2_fill_blank(dct, num_bases)
helices_ids_reverse = self._cadnano_v2_fill_blank(dct, num_bases, design_grid)
'''Putting the scaffold in place.
'''

Expand Down
61 changes: 59 additions & 2 deletions tests/scadnano_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,7 +607,65 @@ class TestExportCadnanoV2(unittest.TestCase):
output_path = os.path.join('tests_outputs', folder)
ext = sc.default_scadnano_file_extension

def test_2_staple_2_helix_origami_extremely_simple(self) -> None:
def test_export_design_with_helix_group(self):
e = 'east'
s = 'south'
helices = [
sc.Helix(max_offset=24, group=s),
sc.Helix(max_offset=25, group=s),
]
helices.extend([
sc.Helix(max_offset=22, group=e),
sc.Helix(max_offset=23, group=e),
])

group_south = sc.HelixGroup(position=sc.Position3D(x=0, y=10, z=0),
grid=sc.square)
group_east = sc.HelixGroup(position=sc.Position3D(x=10, y=0, z=0), grid=sc.square)

groups = {
e: group_east,
s: group_south
}

design = sc.Design(helices=helices, groups=groups, strands=[])
design.write_scadnano_file(directory=self.input_path,
filename=f'test_export_design_with_helix_group.{self.ext}')
design.export_cadnano_v2(directory=self.output_path,
filename='test_export_design_with_helix_group.json')

def test_export_design_with_helix_group_not_same_grid(self):
e = 'east'
s = 'south'
helices = [
sc.Helix(max_offset=24, group=s),
sc.Helix(max_offset=25, group=s),
]
helices.extend([
sc.Helix(max_offset=22, group=e),
sc.Helix(max_offset=23, group=e),
])

group_south = sc.HelixGroup(position=sc.Position3D(x=0, y=10, z=0),
grid=sc.square)
group_east = sc.HelixGroup(position=sc.Position3D(x=10, y=0, z=0), grid=sc.honeycomb)

groups = {
e: group_east,
s: group_south
}

design = sc.Design(helices=helices, groups=groups, strands=[])
design.write_scadnano_file(directory=self.input_path,
filename=f'test_export_design_with_helix_group_not_same_grid.{self.ext}')

with self.assertRaises(ValueError) as context:
design.export_cadnano_v2(directory=self.output_path,
filename='test_export_design_with_helix_group_not_same_grid.json')
self.assertTrue('helix groups' in context.exception.args[0])


def test_2_staple_2_helix_origami_extremely_simple(self):
helices = [sc.Helix(max_offset=32), sc.Helix(max_offset=32)]
scaf_part = sc.Domain(helix=0, forward=True, start=0, end=32)
scaf = sc.Strand(domains=[scaf_part], is_scaffold=True)
Expand Down Expand Up @@ -676,7 +734,6 @@ def test_6_helix_origami_rectangle(self) -> None:
design.export_cadnano_v2(directory=self.output_path,
filename='test_6_helix_origami_rectangle.json')

@unittest.skip('DD: I cannot find where this file is. Is it supposed to be generated by some code?')
def test_6_helix_bundle_honeycomb(self) -> None:
design = sc.Design.from_scadnano_file(
os.path.join(self.input_path, f'test_6_helix_bundle_honeycomb.{self.ext}'))
Expand Down
Loading

0 comments on commit 5ace679

Please sign in to comment.