Skip to content

Commit

Permalink
Debbuging cadnanov2 export of paranemic crossovers when both segments…
Browse files Browse the repository at this point in the history
… are in the 3' direction
  • Loading branch information
tcosmo committed Oct 17, 2024
1 parent 78fcc89 commit 369ccad
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ tests_outputs/
.vscode/
dist/
.mypy_cache/
test_paranemic.py
21 changes: 15 additions & 6 deletions scadnano/scadnano.py
Original file line number Diff line number Diff line change
Expand Up @@ -6609,10 +6609,15 @@ def _cadnano_v2_place_crossover(helix_from_dct: Dict[str, Any], helix_to_dct: Di
helix_to_dct[strand_type][start_to][:2] = [helix_from, start_from]
elif forward_from and forward_to:
helix_from_dct[strand_type][end_from - 1][2:] = [helix_to, start_to]
helix_to_dct[strand_type][end_to - 1][:2] = [helix_from, start_from]
helix_to_dct[strand_type][end_to-1][:2] = [helix_from, start_from]
if helix_from_dct["row"]%2 != helix_to_dct["row"]%2:
raise ValueError("Paranemic crossovers are only allowed between helices that have the same parity of row number, here helix num "+str(helix_from_dct['num'])+ " and helix num " + str(helix_to_dct['num']) + " have different parity of row number: respectively "+str(helix_from_dct["row"])+" and "+str( helix_to_dct["row"]))

elif not forward_from and not forward_to:
helix_from_dct[strand_type][start_from][2:] = [helix_to, end_to - 1]
helix_to_dct[strand_type][start_to][:2] = [helix_from, end_from - 1]
helix_to_dct[strand_type][end_to-1][:2] = [helix_from, start_from]
if helix_from_dct["row"]%2 != helix_to_dct["row"]%2:
raise ValueError("Paranemic crossovers are only allowed between helices that have the same parity of row number, here helix num "+str(helix_from_dct['num'])+ " and helix num " + str(helix_to_dct['num']) + " have different parity of row number: respectively "+str(helix_from_dct["row"])+" and "+str( helix_to_dct["row"]))

@staticmethod
def _cadnano_v2_color_of_stap(color: Color, domain: Domain) -> List[int]:
Expand Down Expand Up @@ -6650,6 +6655,9 @@ def _cadnano_v2_place_strand(self, strand: Strand, dct: dict,
next_helix = dct['vstrands'][next_helix_id]
self._cadnano_v2_place_crossover(which_helix, next_helix,
domain, next_domain, strand_type)




# if the strand is circular, we need to close the loop
if strand.circular:
Expand Down Expand Up @@ -6784,13 +6792,13 @@ def to_cadnano_v2_serializable(self, name: str = '') -> Dict[str, Any]:
if isinstance(domain, Loopout):
raise ValueError(
'We cannot handle designs with Loopouts as it is not a cadnano v2 concept')
right_direction: bool
cadnano_expected_direction: bool
if hasattr(strand, is_scaffold_key) and strand.is_scaffold:
right_direction = (domain.helix % 2 == int(not domain.forward))
cadnano_expected_direction = (domain.helix % 2 == int(not domain.forward))
else:
right_direction = not (domain.helix % 2 == int(not domain.forward))
cadnano_expected_direction = not (domain.helix % 2 == int(not domain.forward))

if not right_direction:
if not cadnano_expected_direction:
raise ValueError('We can only convert designs where even helices have the scaffold'
'going forward and odd helices have the scaffold going backward see '
f'the spec v2.txt Note 4. {domain}')
Expand All @@ -6803,6 +6811,7 @@ def to_cadnano_v2_serializable(self, name: str = '') -> Dict[str, Any]:

for strand in self.strands:
self._cadnano_v2_place_strand(strand, dct, helices_ids_reverse)


return dct

Expand Down
13 changes: 13 additions & 0 deletions tests/scadnano_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1629,6 +1629,19 @@ def test_paranemic_crossover(self) -> None:
output_design = sc.Design.from_cadnano_v2(json_dict=json.loads(output_json))
self.assertEqual(4, len(output_design.helices))

def test_paranemic_crossover_other_direction(self) -> None:
design = sc.Design.from_scadnano_file(
os.path.join(self.input_path, f'test_paranemic_crossover_other_direction.{self.ext}'))
# To help with debugging, uncomment these lines to write out the
# scadnano and/or cadnano file
#
# design.write_cadnano_v2_file(directory=self.output_path,
# filename='test_paranemic_crossover.json')
output_json = design.to_cadnano_v2_json()

output_design = sc.Design.from_cadnano_v2(json_dict=json.loads(output_json))
self.assertEqual(4, len(output_design.helices))

def test_parity_issue(self) -> None:
""" We do not design where the parity of the helix
does not correspond to the direction.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"version": "0.19.4",
"grid": "square",
"helices": [
{"grid_position": [19, 14], "idx": 1, "max_offset": 64},
{"grid_position": [19, 15], "idx": 0, "max_offset": 64},
{"grid_position": [19, 16], "idx": 3, "max_offset": 64},
{"grid_position": [19, 17], "idx": 2, "max_offset": 64}
],
"strands": [
{
"color": "#0066cc",
"is_scaffold": true,
"domains": [
{"helix": 3, "forward": false, "start": 8, "end": 24},
{"helix": 1, "forward": false, "start": 8, "end": 24}
]
},
{
"color": "#007200",
"domains": [
{"helix": 2, "forward": false, "start": 24, "end": 50},
{"helix": 0, "forward": false, "start": 24, "end": 50}
]
}
]
}

0 comments on commit 369ccad

Please sign in to comment.