Aye10032's picture
download
raw
4.27 kB
import random
from contextlib import ExitStack
from pathlib import Path
from loguru import logger
from bioflow_sim.core.io import (
fastq_writer,
prepare_output_directory,
read_fasta,
validate_sample_name,
write_fastq_record,
write_json,
write_tsv,
)
from bioflow_sim.generators.contacts import (
ENZYMES,
contact_read_sequences,
find_restriction_sites,
sample_contact,
)
from bioflow_sim.generators.read_models import TECHNOLOGIES, introduce_errors
HIC_ENZYMES = tuple(sorted(ENZYMES))
def simulate_hic(
*,
reference: Path,
output_dir: Path,
sample: str,
enzyme_name: str,
reads: int,
read_length: int,
intra_rate: float,
mean_distance: int,
seed: int,
) -> dict[str, object]:
if reads < 1 or mean_distance < 1:
raise ValueError('reads and mean distance must be positive')
validate_sample_name(sample)
sequences = [(name, sequence) for name, _, sequence in read_fasta(reference)]
enzyme = ENZYMES[enzyme_name]
cut_sites = find_restriction_sites(sequences, enzyme)
prepare_output_directory(output_dir)
raw_dir = output_dir / 'raw'
rng = random.Random(seed)
illumina = TECHNOLOGIES['illumina-pe']
r1_path = raw_dir / f'{sample}_R1.fastq.gz'
r2_path = raw_dir / f'{sample}_R2.fastq.gz'
truth_rows: list[list[object]] = []
with ExitStack() as stack:
r1 = stack.enter_context(fastq_writer(r1_path))
r2 = stack.enter_context(fastq_writer(r2_path))
for ordinal in range(1, reads + 1):
contact = sample_contact(rng, cut_sites, intra_rate, mean_distance)
template1, template2 = contact_read_sequences(sequences, contact, read_length)
read1, s1, i1, d1 = introduce_errors(template1, rng, illumina)
read2, s2, i2, d2 = introduce_errors(template2, rng, illumina)
read_id = f'{sample}:{ordinal:09d}'
write_fastq_record(r1, f'{read_id}/1', read1, 'I' * len(read1))
write_fastq_record(r2, f'{read_id}/2', read2, 'I' * len(read2))
distance = abs(contact.right.position - contact.left.position) if contact.contact_type == 'intra' else '.'
truth_rows.append(
[
read_id,
contact.left.contig,
contact.left.position,
contact.right.contig,
contact.right.position,
contact.contact_type,
distance,
s1 + s2,
i1 + i2,
d1 + d2,
]
)
write_tsv(
raw_dir / 'restriction_sites.tsv',
['contig', 'cut_position_0based', 'enzyme', 'motif'],
([site.contig, site.position, enzyme.name, enzyme.motif] for site in cut_sites),
)
write_tsv(
raw_dir / 'library.tsv',
['sample_id', 'assay', 'enzyme', 'layout', 'read_length'],
[[sample, 'Hi-C', enzyme.name, 'paired-end', read_length]],
)
write_tsv(
output_dir / 'truth' / 'contacts.tsv',
[
'read_id',
'left_contig',
'left_cut_0based',
'right_contig',
'right_cut_0based',
'contact_type',
'distance',
'substitutions',
'insertions',
'deletions',
],
truth_rows,
)
metadata: dict[str, object] = {
'schema_version': 1,
'assay': 'hi-c',
'sample': sample,
'reference': str(reference.resolve()),
'seed': seed,
'read_pairs': reads,
'output_files': [
str(r1_path.relative_to(output_dir)),
str(r2_path.relative_to(output_dir)),
'raw/restriction_sites.tsv',
'raw/library.tsv',
],
'truth_files': ['truth/contacts.tsv'],
'parameters': {
'enzyme': enzyme.name,
'motif': enzyme.motif,
'read_length': read_length,
'intra_rate': intra_rate,
'mean_distance': mean_distance,
},
}
write_json(output_dir / 'manifest.json', metadata)
logger.success('Generated {} Hi-C read pairs in {}', reads, output_dir)
return metadata

Xet Storage Details

Size:
4.27 kB
·
Xet hash:
4ee0518d50e8fd060068095c6514744e3f45509377a5eeaf2454e0fadb211a2e

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.