1+ import strutils
2+ import strformat
3+ import argparse
4+ import pedfile
5+ import sequtils
6+ import algorithm
7+
8+ proc pedrel_main * () =
9+ var argv = commandLineParams ()
10+ if argv[0 ] == " pedrel" :
11+ argv = argv[1 .. argv.high]
12+
13+ var p = newParser (" somalier pedrel" ):
14+ help (" report pairwise relationships from pedigree file" )
15+ option (" -o" , " --output" , help= " output file path" , default= " stdout" )
16+ option (" -m" , " --min-relatedness" , help= " minimum relatedness to report" , default= " 0.01" )
17+ arg (" pedfile" , help= " pedigry (fam) file path" )
18+
19+ let opts = p.parse (argv)
20+ if opts.help:
21+ quit 0
22+
23+ if opts.pedfile == " " :
24+ echo p.help
25+ quit " [somalier] pedfile argument required"
26+
27+ # Parse the pedigree file
28+ var samples = parse_ped (opts.pedfile)
29+
30+ let min_rel = parseFloat (opts.min_relatedness)
31+
32+ # Calculate pairwise relatedness for all sample pairs
33+ var output_file: File
34+ if opts.output == " stdout" :
35+ output_file = stdout
36+ else :
37+ if not open (output_file, opts.output, fmWrite):
38+ quit " [somalier] couldn't open output file: " & opts.output
39+
40+ # Write header
41+ output_file.write_line (" sample_a\t sample_b\t relatedness" )
42+
43+ # Iterate through all sample pairs and report those with min_rel threshold
44+ for i in 0 ..< samples.len:
45+ let sampleA = samples[i]
46+ for j in (i+ 1 )..< samples.len:
47+ let sampleB = samples[j]
48+ let rel = sampleA.relatedness (sampleB)
49+
50+ if rel > min_rel:
51+ # Ensure consistent ordering (alphabetical by sample ID)
52+ let (sample1, sample2) = if sampleA.id < sampleB.id:
53+ (sampleA.id, sampleB.id)
54+ else :
55+ (sampleB.id, sampleA.id)
56+ output_file.write_line (& " { sample1} \t { sample2} \t { rel:.6f } " )
57+
58+ if opts.output != " stdout" :
59+ output_file.close ()
60+ stderr.write_line (& " [somalier] wrote { samples.len} sample relationships to: { opts.output} " )
0 commit comments