1 module dparasail.alignment;
2 
3 import std.utf;
4 import core.stdc.stdlib : exit;
5 
6 import dparasail.result;
7 import dparasail.memory;
8 import dparasail.log;
9 import parasail;
10 
11 
12 /*
13 * Acts as a profile of settings for reusing 
14 * alignment settings
15 */
16 struct Parasail
17 {
18     /// alignment scoring matrix reference
19     private ParasailMatrix score_matrix;
20 
21     /// using database query?
22     private bool databaseQuery;
23 
24     /// gap open penalty (must be positive)
25     private int gapOpen;
26     
27     /// gap extension penalty (must be positive)
28     private int gapExt;
29 
30     /// parasail profile reference if doing
31     /// if doing database alignment
32     private ParasailProfile profile;
33 
34     /// query sequence if doing database alignment
35     private string s1;
36 
37     @disable this();
38 
39     /// use a prebuilt parasail scoring matrix
40     /// or an alphabet matrix
41     /// and a gap and ext penalty
42     this(string matrix, int open, int ext, int match = -1, int mismatch = 1)
43     {
44         this(matrix, "", open, ext, match, mismatch);
45     }
46 
47     /// use a prebuilt parasail scoring matrix
48     /// or an alphabet matrix
49     /// with a database sequence
50     /// and a gap and ext penalty
51     this(string matrix, string databaseSequence, int open, int ext, int match = -1, int mismatch = 1){
52         auto m = parasail_matrix_lookup(toUTFz!(char*)(matrix));
53 
54         if(m != null){
55             auto mCopy = parasail_matrix_copy(m);
56             this(mCopy, open, ext);
57         }else{
58             logWarning(__FUNCTION__, "Couldn't load matrix named " ~matrix ~", assuming alphabet");
59             if(m == null && (match == -1 || mismatch == 1)){
60                 logError(__FUNCTION__, "Couldn't load matrix and match and mismatch penalties are unset (-1, 1)");
61                 exit(-1);
62             }
63             auto alphabet = matrix;
64             logWarning(__FUNCTION__, "Attempting to create matrix from alphabet " ~alphabet);
65 
66             assert(match > 0, "match score must be > 0");
67             assert(mismatch < 0, "mismatch penalty/score must be < 0");
68 
69             auto mCreate = parasail_matrix_create(toUTFz!(char*)(alphabet), match, mismatch);
70             if(mCreate == null)
71             {
72                 logError(__FUNCTION__, "Couldn't create matrix from alphabet " ~alphabet);
73                 exit(-1);
74             }
75             this(mCreate, databaseSequence, open, ext);
76         }
77     }
78 
79     /// use a parasail_matrix_t directly
80     /// with a database sequence
81     /// and a gap and ext penalty
82     this(parasail_matrix_t * matrix, string databaseSequence, int open, int ext)
83     {
84         if(databaseSequence != "")
85         {
86             this.s1 = databaseSequence;
87             auto prof = parasail_profile_create_sat(toUTFz!(char*)(s1), cast(int) s1.length, matrix);
88             if(prof == null)
89             {
90                 logError(__FUNCTION__, "Couldn't create database profile from " ~databaseSequence);
91             }
92             this.profile = ParasailProfile(prof);
93         }
94         this.score_matrix = ParasailMatrix(matrix);
95         assert(open > 0, "gap open penalty must be greater than 0");
96         assert(ext > 0, "gap extension penalty must be greater than 0");
97         this.gapOpen = open;
98         this.gapExt = ext;
99     }
100 
101     /// use a parasail_matrix_t directly
102     /// and a gap and ext penalty
103     this(parasail_matrix_t * matrix, int open, int ext)
104     {
105         this.profile = ParasailProfile(cast(parasail_profile_t *) null);
106         this.score_matrix = ParasailMatrix(matrix);
107         assert(open > 0, "gap open penalty must be greater than 0");
108         assert(ext > 0, "gap extension penalty must be greater than 0");
109         this.gapOpen = open;
110         this.gapExt = ext;
111     }
112 
113     this(this){
114         this.score_matrix = score_matrix;
115         this.databaseQuery = databaseQuery;
116         this.gapOpen = gapOpen;
117         this.gapExt = gapExt;
118         this.profile = profile;
119         this.s1 = s1;
120     }
121 
122     /// get scoring matrix
123     auto scoreMatrix()
124     {
125         return this.score_matrix;
126     }
127 
128     /// run sw alignment
129     ParasailResult sw_striped(string s1, string s2)
130     {
131         if(!(this.profile is null))
132             logWarning(__FUNCTION__, "You are using sw align but a database profile is set");
133 
134         auto seq1 = toUTFz!(const char*)(s1);
135         auto seq2 = toUTFz!(const char*)(s2);
136         auto seq1Len = cast(const int) s1.length;
137         auto seq2Len = cast(const int) s2.length;
138         auto res = parasail_sw_trace_striped_16(seq1, seq1Len, seq2,
139                 seq2Len, this.gapOpen, this.gapExt, this.score_matrix);
140         return ParasailResult(&this, res, s1, s2);
141     }
142 
143     ParasailResult nw_scan(string s1, string s2)
144     {
145         if(!(this.profile is null))
146             logWarning(__FUNCTION__, "You are using nw align but a database profile is set");
147 
148         auto seq1 = toUTFz!(const char*)(s1);
149         auto seq2 = toUTFz!(const char*)(s2);
150         auto seq1Len = cast(const int) s1.length;
151         auto seq2Len = cast(const int) s2.length;
152         auto res = parasail_nw_trace_scan_16(seq1, seq1Len, seq2,
153                 seq2Len, this.gapOpen, this.gapExt, this.score_matrix);
154         return ParasailResult(&this, res, s1, s2);
155     }
156 
157 
158     ParasailResult aligner(string alg, string output_option = "trace",
159             string impl_option = "striped", string sol_width = "sat")(string s1, string s2)
160     {
161         if(!(this.profile is null))
162             logWarning(__FUNCTION__, "You are using aligner but a database profile is set");
163 
164         auto seq1 = toUTFz!(const char*)(s1);
165         auto seq2 = toUTFz!(const char*)(s2);
166         auto seq1Len = cast(const int) s1.length;
167         auto seq2Len = cast(const int) s2.length;
168         mixin("auto res = parasail_" ~ alg ~ "_" ~ output_option ~ "_" ~ impl_option ~ "_"
169                 ~ sol_width ~ "(seq1, seq1Len, seq2, seq2Len, this.gapOpen, this.gapExt, this.score_matrix);");
170         return ParasailResult(&this, res, s1, s2);
171     }
172 
173     ParasailResult databaseAligner(string alg, string impl_option = "striped")(string s2)
174     {
175         auto seq2 = toUTFz!(const char*)(s2);
176         auto seq2Len = cast(const int) s2.length;
177         if(this.profile is null){
178             logError(__FUNCTION__, "Cannot use databaseAligner when profile is not set");
179             exit(-1);
180         }
181         mixin("auto res = parasail_" ~ alg ~ "_" ~ impl_option
182                 ~ "_profile_sat(this.profile, seq2, seq2Len, gapOpen, gapExt);");
183         return ParasailResult(&this, res, this.s1, s2);
184     }
185 }