1 /*
2 Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008,2009,
3 2010,2011,2012
4 Whitehead Institute for Biomedical Research, Steve Rozen
5 (http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky.
6 All rights reserved.
7
8 This file is part of the primer3 suite and libraries.
9
10 The primer3 suite and libraries are free software;
11 you can redistribute them and/or modify them under the terms
12 of the GNU General Public License as published by the Free
13 Software Foundation; either version 2 of the License, or (at
14 your option) any later version.
15
16 This software is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this software (file gpl-2.0.txt in the source
23 distribution); if not, write to the Free Software
24 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <errno.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <math.h>
43 #include <limits.h>
44 #include <signal.h>
45 #include <float.h>
46 #include <string.h>
47 #include <ctype.h> /* toupper */
48
49 #ifdef __GNUC__
50 #include <ext/hash_map>
51 #else
52 #include <hash_map>
53 #endif
54
55 namespace std
56 {
57 using namespace __gnu_cxx;
58 }
59
60 #include "dpal.h"
61 #include "thal.h"
62 #include "oligotm.h"
63 #include "libprimer3.h"
64
65 /* #define's */
66
67 /*
68 * OPTIMIZE_OK_REGIONS 1 allows _optimize_ok_regions_list() to use the
69 * max/min product size info and the max/min oligo length to reduce
70 * the sizes of the ok regions (while still generating the same primer
71 * pairs in the same order). Set OPTIMIZE_OK_REGIONS to 0 confirm
72 * that the results do not change. (The output tags
73 * PRIMER_{LEFT,RIGHT,PAIR}_EXPLAIN _will_ likely change.)
74 */
75 #define OPTIMIZE_OK_REGIONS 1
76
77 #ifndef MAX_PRIMER_LENGTH
78 #define MAX_PRIMER_LENGTH 36
79 #endif
80 #if (MAX_PRIMER_LENGTH > DPAL_MAX_ALIGN)
81 #error "MAX_PRIMER_LENGTH must be <= DPAL_MAX_ALIGN"
82 #endif
83 #if (MAX_PRIMER_LENGTH > THAL_MAX_ALIGN)
84 # error "MAX_PRIMER_LENGTH must be <= THAL_MAX_ALIGN"
85 #endif
86 #define MAX_NN_TM_LENGTH 36 /* The maxium length for which to use the
87 nearest neighbor model when calculating
88 oligo Tms. */
89
90 #define MACRO_CAT_2(A,B) A##B
91 #define MACRO_VALUE_AS_STRING(A) MACRO_STRING(A)
92
93 #define PR_POSITION_PENALTY_IS_NULL(PA) \
94 (PR_DEFAULT_INSIDE_PENALTY == (PA)->inside_penalty \
95 && PR_DEFAULT_OUTSIDE_PENALTY == (PA)->outside_penalty)
96
97 #define INITIAL_LIST_LEN 2000 /* Initial size of oligo lists. */
98 #define INITIAL_NUM_RETURN 5 /* Initial space to allocate for pairs to
99 return. */
100
101 #define PAIR_OK 1
102 #define PAIR_FAILED 0
103
104 #define OK_OR_MUST_USE(H) (!p3_ol_has_any_problem(H) || (H)->must_use)
105
106 #define PR_UNDEFINED_INT_OPT INT_MIN
107 #define PR_UNDEFINED_DBL_OPT DBL_MIN
108
109 /* Undefined value for alignment score (meaning do not check) used for
110 maximum template mispriming or mishyb. */
111 #define PR_UNDEFINED_ALIGN_OPT -100.0
112
113 #define TRIMMED_SEQ_LEN(X) ((X)->incl_l)
114
115 typedef struct dpal_arg_holder {
116 dpal_args *local;
117 dpal_args *end;
118 dpal_args *local_end;
119 dpal_args *local_ambig;
120 dpal_args *local_end_ambig;
121 } dpal_arg_holder;
122 typedef struct thal_arg_holder {
123 thal_args *any;
124 thal_args *end1;
125 thal_args *end2;
126 thal_args *hairpin_th;
127 } thal_arg_holder;
128
129 static jmp_buf _jmp_buf;
130
131 static int thermodynamic_alignment_length_error = 0;
132 static char *thermodynamic_alignment_length_error_msg = NULL;
133
134 /* Variables needed in choose_pair_or_triple, need to be global
135 for memory de-allocation reasons. Full description given in the function. */
136 static int *max_j_seen;
137 static std::hash_map<int, primer_pair*> **pairs;
138
139 /* Function declarations. */
140
141 static void pr_set_default_global_args_1(p3_global_settings *);
142 static void pr_set_default_global_args_2(p3_global_settings *);
143 static void _adjust_seq_args(const p3_global_settings *pa,
144 seq_args *sa,
145 pr_append_str *nonfatal_err,
146 pr_append_str *warning);
147
148 static void _optimize_ok_regions_list(const p3_global_settings *pa,
149 seq_args *sa);
150
151 static int any_5_prime_ol_extension_has_problem(const primer_rec *);
152
153 static int p3_ol_is_uninitialized(const primer_rec *);
154
155 static int fake_a_sequence(seq_args *sa, const p3_global_settings *pa);
156
157 static int _pr_data_control(const p3_global_settings *,
158 const seq_args *,
159 pr_append_str *glob_err,
160 pr_append_str *nonfatal_err,
161 pr_append_str *warning);
162
163 static int _pr_need_pair_template_mispriming(const p3_global_settings *pa);
164 static int _pr_need_pair_template_mispriming_thermod(const p3_global_settings *pa);
165
166 static int _pr_need_template_mispriming(const p3_global_settings *);
167 static int _pr_need_template_mispriming_thermod(const p3_global_settings *);
168
169 static void _pr_substr(const char *, int, int, char *);
170
171
172 static int _check_and_adjust_intervals(seq_args *sa,
173 int seq_len,
174 int first_index,
175 pr_append_str * nonfatal_err,
176 pr_append_str *warning);
177
178 static int _check_and_adjust_overlap_pos(seq_args *sa,
179 int *list,
180 int *count,
181 const char *tag,
182 int seq_len,
183 int first_index,
184 pr_append_str * nonfatal_err,
185 pr_append_str *warning);
186
187 static int _check_and_adjust_1_interval(const char *,
188 int num,
189 interval_array_t,
190 int,
191 int first_index,
192 pr_append_str *err,
193 seq_args *,
194 pr_append_str
195 *warning, int);
196
197 static void sort_primer_array(oligo_array *);
198
199 static void add_pair(const primer_pair *, pair_array_t *);
200
201 static double align(const char *, const char*, const dpal_args *a);
202
203 static double align_thermod(const char *, const char *, const thal_args *a);
204
205 static int characterize_pair(p3retval *p,
206 const p3_global_settings *,
207 const seq_args *,
208 int, int, int,
209 primer_pair *,
210 const dpal_arg_holder*,
211 const thal_arg_holder*,
212 int update_stats);
213
214 static void choose_pair_or_triple(p3retval *,
215 const p3_global_settings *,
216 const seq_args *,
217 const dpal_arg_holder *,
218 const thal_arg_holder *,
219 const thal_arg_holder *,
220 pair_array_t *);
221
222 static int sequence_quality_is_ok(const p3_global_settings *, primer_rec *,
223 oligo_type,
224 const seq_args *, int, int,
225 oligo_stats *global_oligo_stats,
226 const args_for_one_oligo_or_primer *);
227
228 static int choose_internal_oligo(p3retval *,
229 const primer_rec *, const primer_rec *,
230 int *,
231 const seq_args *,
232 const p3_global_settings *,
233 const dpal_arg_holder *,
234 const thal_arg_holder *);
235
236 void compute_position_penalty(const p3_global_settings *,
237 const seq_args *,
238 primer_rec *, oligo_type);
239
240 static p3retval *create_p3retval(void);
241
242 static char dna_to_upper(char *, int);
243
244 static int find_stop_codon(const char *, int, int);
245
246 static void gc_and_n_content(int, int, const char *, primer_rec *);
247
248 static int make_detection_primer_lists(p3retval *,
249 const p3_global_settings *,
250 const seq_args *,
251 const dpal_arg_holder *,
252 const thal_arg_holder *);
253
254 static int make_complete_primer_lists(p3retval *retval,
255 const p3_global_settings *pa,
256 const seq_args *sa,
257 const dpal_arg_holder *dpal_arg_to_use,
258 const thal_arg_holder *thal_arg_to_use,
259 const thal_arg_holder *thal_oligo_arg_to_use);
260
261 static int add_primers_to_check(p3retval *retval,
262 const p3_global_settings *pa,
263 const seq_args *sa,
264 const dpal_arg_holder *dpal_arg_to_use,
265 const thal_arg_holder *thal_arg_to_use,
266 const thal_arg_holder *thal_oligo_arg_to_use);
267
268 static int pick_sequencing_primer_list(p3retval *retval,
269 const p3_global_settings *pa,
270 const seq_args *sa,
271 const dpal_arg_holder *dpal_arg_to_use,
272 const thal_arg_holder *thal_arg_to_use);
273
274 static int make_internal_oligo_list(p3retval *,
275 const p3_global_settings *,
276 const seq_args *,
277 const dpal_arg_holder *,
278 const thal_arg_holder *);
279
280 static int pick_only_best_primer(const int, const int,
281 oligo_array *,
282 const p3_global_settings *,
283 const seq_args *,
284 const dpal_arg_holder *,
285 const thal_arg_holder *,
286 p3retval *);
287
288 static int pick_primer_range(const int, const int, int *,
289 oligo_array *,
290 const p3_global_settings *,
291 const seq_args *,
292 const dpal_arg_holder *,
293 const thal_arg_holder *,
294 p3retval *retval);
295
296 static int add_one_primer(const char *, int *, oligo_array *,
297 const p3_global_settings *,
298 const seq_args *,
299 const dpal_arg_holder *,
300 const thal_arg_holder *,
301 p3retval *);
302
303 static int add_one_primer_by_position(int, int, int *,
304 oligo_array *,
305 const p3_global_settings *,
306 const seq_args *,
307 const dpal_arg_holder *,
308 const thal_arg_holder *,
309 p3retval *);
310
311 static int pick_primers_by_position(const int, const int,
312 int *,
313 oligo_array *,
314 const p3_global_settings *,
315 const seq_args *,
316 const dpal_arg_holder *,
317 const thal_arg_holder *,
318 p3retval *);
319
320 static double obj_fn(const p3_global_settings *, primer_pair *);
321
322 static int left_oligo_in_pair_overlaps_used_oligo(const primer_rec *left,
323 const primer_pair *best_pair,
324 int min_dist);
325
326 static int right_oligo_in_pair_overlaps_used_oligo(const primer_rec *right,
327 const primer_pair *best_pair,
328 int min_dist);
329
330 static int oligo_overlaps_interval(int, int,
331 const interval_array_t, int);
332
333 static void calc_and_check_oligo_features(const p3_global_settings *pa,
334 primer_rec *,
335 oligo_type,
336 const dpal_arg_holder*,
337 const thal_arg_holder*,
338 const seq_args *, oligo_stats *,
339 p3retval *,
340 const char *);
341
342 static void pr_append(pr_append_str *, const char *);
343
344 static void pr_append_new_chunk(pr_append_str *x, const char *s);
345
346 static int pair_spans_target(const primer_pair *, const seq_args *);
347 static void pr_append_w_sep(pr_append_str *, const char *, const char *);
348 static void* pr_safe_malloc(size_t x);
349 static void* pr_safe_realloc(void *p, size_t x);
350
351 static int compare_primer_pair(const void *, const void*);
352
353 static int primer_rec_comp(const void *, const void *);
354 static int print_list_header(FILE *, oligo_type, int, int, int);
355 static int print_oligo(FILE *, const seq_args *, int, const primer_rec *,
356 oligo_type, int, int,int);
357 static char *strstr_nocase(char *, char *);
358
359 static double p_obj_fn(const p3_global_settings *, primer_rec *, int );
360
361 static void oligo_compl(primer_rec *,
362 const args_for_one_oligo_or_primer *po_args,
363 oligo_stats *,
364 const dpal_arg_holder *,
365 const char *oligo_seq,
366 const char *revc_oligo_seq
367 );
368 static void oligo_compl_thermod(primer_rec *, /* TO DO 2012-06-01 -- update by removing last argument. */
369 const args_for_one_oligo_or_primer *po_args,
370 oligo_stats *,
371 const thal_arg_holder *,
372 const char *oligo_seq,
373 const char *revc_oligo_seq
374 );
375 static void oligo_hairpin(primer_rec *,
376 const args_for_one_oligo_or_primer *po_args,
377 oligo_stats *,
378 const thal_arg_holder *,
379 const char *oligo_seq
380 );
381
382 static void oligo_compute_sequence_and_reverse(primer_rec *,
383 const seq_args *,
384 oligo_type,
385 int*, int*,
386 char*, char*);
387
388 static void oligo_repeat_library_mispriming(primer_rec *,
389 const p3_global_settings *,
390 const seq_args *,
391 oligo_type,
392 oligo_stats *,
393 const dpal_arg_holder *);
394
395 static void oligo_template_mispriming(primer_rec *,
396 const p3_global_settings *,
397 const seq_args *,
398 oligo_type,
399 oligo_stats *,
400 const dpal_args *,
401 const thal_args *);
402
403 static int pair_repeat_sim(primer_pair *, const p3_global_settings *);
404
405 static void free_repeat_sim_score(p3retval *);
406 static void free_primer_repeat_sim_score(primer_rec *);
407
408 /* edited by T. Koressaar for lowercase masking: */
409 static int is_lowercase_masked(int position,
410 const char *sequence,
411 primer_rec *h,
412 oligo_stats *);
413
414 static int primer_must_match(const p3_global_settings *pa,
415 primer_rec *h,
416 oligo_stats *stats,
417 const char *input_oligo_seq,
418 char *match_three_prime,
419 char *match_five_prime);
420 static int compare_nucleotides(const char a, const char b);
421 static int test_must_match_parameters(char *test);
422
423 static void set_retval_both_stop_codons(const seq_args *sa, p3retval *retval);
424
425 /* Functions to set bitfield parameters for oligos (or primers) */
426 static void bf_set_overlaps_target(primer_rec *, int);
427 static int bf_get_overlaps_target(const primer_rec *);
428 static void bf_set_overlaps_excl_region(primer_rec *, int);
429 static int bf_get_overlaps_excl_region(const primer_rec *);
430 static void bf_set_infinite_pos_penalty(primer_rec *, int);
431 static int bf_get_infinite_pos_penalty(const primer_rec *);
432
433 /* Functions to record problems with oligos (or primers) */
434 static void initialize_op(primer_rec *);
435 static void op_set_completely_written(primer_rec *);
436 static void op_set_must_match_err(primer_rec *);
437 static void op_set_too_many_ns(primer_rec *);
438 static void op_set_overlaps_target(primer_rec *);
439 static void op_set_high_gc_content(primer_rec *);
440 static void op_set_low_gc_content(primer_rec *);
441 static void op_set_high_tm(primer_rec *);
442 static void op_set_low_tm(primer_rec *);
443 static void op_set_overlaps_excluded_region(primer_rec *);
444 static void op_set_not_in_any_ok_region(primer_rec *);
445 static void op_set_high_self_any(primer_rec *oligo);
446 static void op_set_high_self_end(primer_rec *oligo);
447 static void op_set_high_hairpin_th(primer_rec *oligo);
448 static void op_set_no_gc_glamp(primer_rec *);
449 static void op_set_too_many_gc_at_end(primer_rec *);
450 static void op_set_high_end_stability(primer_rec *);
451 static void op_set_high_poly_x(primer_rec *);
452 static void op_set_low_sequence_quality(primer_rec *);
453 static void op_set_low_end_sequence_quality(primer_rec *oligo);
454 static void op_set_high_similarity_to_non_template_seq(primer_rec *);
455 static void op_set_high_similarity_to_multiple_template_sites(primer_rec *);
456 static void op_set_overlaps_masked_sequence(primer_rec *);
457 static void op_set_too_long(primer_rec *);
458 static void op_set_too_short(primer_rec *);
459 static void op_set_does_not_amplify_orf(primer_rec *);
460 /* End functions to set problems in oligos */
461
462 /* Global static variables. */
463 static const char *primer3_copyright_char_star = "\n"
464 "Copyright (c) 1996,1997,1998,1999,2000,2001,2004,2006,2007,2008\n"
465 " 2009,2010,2011,2012\n"
466 "Whitehead Institute for Biomedical Research, Steve Rozen\n"
467 "(http://purl.com/STEVEROZEN/), Andreas Untergasser and Helen Skaletsky\n"
468 "All rights reserved.\n"
469 "\n"
470 " This file is part of the primer3 suite and libraries.\n"
471 "\n"
472 " The primer3 suite and libraries are free software;\n"
473 " you can redistribute them and/or modify them under the terms\n"
474 " of the GNU General Public License as published by the Free\n"
475 " Software Foundation; either version 2 of the License, or (at\n"
476 " your option) any later version.\n"
477 "\n"
478 " This software is distributed in the hope that it will be useful,\n"
479 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
480 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
481 " GNU General Public License for more details.\n"
482 "\n"
483 " You should have received a copy of the GNU General Public License\n"
484 " along with this software (file gpl-2.0.txt in the source\n"
485 " distribution); if not, write to the Free Software\n"
486 " Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
487 "\n"
488 "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
489 "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
490 "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
491 "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
492 "OWNERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
493 "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
494 "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
495 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
496 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
497 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
498 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
499 "\n";
500
501 static const char *pr_program_name = "probably primer3_core";
502
503 static const int use_end_for_th_template_mispriming = 1;
504
505 #define DEFAULT_OPT_GC_PERCENT PR_UNDEFINED_INT_OPT
506
507 /* Set the program name */
508 void
p3_set_program_name(const char * pname)509 p3_set_program_name(const char *pname)
510 {
511 pr_program_name = pname;
512 }
513
514 /* ============================================================ */
515 /* BEGIN functions for global settings */
516 /* ============================================================ */
517
518 /* Allocate space for global settings and fill in defaults */
519 p3_global_settings *
p3_create_global_settings()520 p3_create_global_settings()
521 {
522 p3_global_settings *r;
523
524 if (!(r = (p3_global_settings *) malloc(sizeof(*r)))) {
525 return NULL;
526 }
527
528 pr_set_default_global_args_2(r);
529
530 return r;
531 }
532
533 /* Allocate space for global settings and fill in defaults */
534 p3_global_settings *
p3_create_global_settings_default_version_1()535 p3_create_global_settings_default_version_1()
536 {
537 p3_global_settings *r;
538
539 if (!(r = (p3_global_settings *) malloc(sizeof(*r)))) {
540 return NULL;
541 }
542
543 pr_set_default_global_args_1(r);
544
545 return r;
546 }
547
548 /* Free the space of global settings */
549 void
p3_destroy_global_settings(p3_global_settings * a)550 p3_destroy_global_settings(p3_global_settings *a)
551 {
552 if (NULL != a) {
553 if (NULL != a->p_args.must_match_five_prime) {
554 free(a->p_args.must_match_five_prime);
555 }
556 if (NULL != a->p_args.must_match_three_prime) {
557 free(a->p_args.must_match_three_prime);
558 }
559 if (NULL != a->o_args.must_match_five_prime) {
560 free(a->o_args.must_match_five_prime);
561 }
562 if (NULL != a->o_args.must_match_three_prime) {
563 free(a->o_args.must_match_three_prime);
564 }
565 destroy_seq_lib(a->p_args.repeat_lib);
566 destroy_seq_lib(a->o_args.repeat_lib);
567 free(a);
568 }
569 }
570
571 static void
pr_set_default_global_args_2(p3_global_settings * a)572 pr_set_default_global_args_2(p3_global_settings *a)
573 /* Write the default values for default_values=2 into
574 the p3_global_settings struct */
575 {
576 pr_set_default_global_args_1(a);
577 a->tm_santalucia = santalucia_auto;
578 a->salt_corrections = santalucia;
579 a->thermodynamic_oligo_alignment = 1;
580 a->thermodynamic_template_alignment = 0;
581 a->p_args.divalent_conc = 1.5;
582 a->p_args.dntp_conc = 0.6;
583 a->lib_ambiguity_codes_consensus = 0;
584 }
585
586 /* Write the default values for default_values=1 into
587 the p3_global_settings struct */
588 static void
pr_set_default_global_args_1(p3_global_settings * a)589 pr_set_default_global_args_1(p3_global_settings *a)
590 {
591 memset(a, 0, sizeof(*a));
592
593 /* Arguments for primers ================================= */
594 a->p_args.opt_size = 20;
595 a->p_args.min_size = 18;
596 a->p_args.max_size = 27;
597
598 a->p_args.opt_tm = 60;
599 a->p_args.min_tm = 57;
600 a->p_args.max_tm = 63;
601
602 a->p_args.min_gc = 20.0;
603 a->p_args.opt_gc_content = DEFAULT_OPT_GC_PERCENT;
604 a->p_args.max_gc = 80.0;
605 a->p_args.salt_conc = 50.0;
606 a->p_args.divalent_conc = 0.0;
607 a->p_args.dntp_conc = 0.0;
608
609 a->p_args.dna_conc = 50.0;
610 a->p_args.num_ns_accepted = 0;
611 a->p_args.max_self_any = 8.0;
612 a->p_args.max_self_end = 3.0;
613 a->p_args.max_self_any_th = 47.0;
614 a->p_args.max_self_end_th = 47.0;
615 a->p_args.max_hairpin_th = 47.0;
616 a->p_args.max_poly_x = 5;
617 a->p_args.max_repeat_compl = 12.0;
618 a->p_args.min_quality = 0;
619 a->p_args.min_end_quality = 0;
620 a->p_args.max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
621 a->p_args.max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
622 /* The following apply only to primers (and not to internal
623 oligos). */
624 a->gc_clamp = 0;
625 a->max_end_gc = 5;
626
627 /* Weights for objective functions for oligos and pairs. */
628 a->p_args.weights.compl_any = 0;
629 a->p_args.weights.compl_any_th = 0;
630 a->p_args.weights.compl_end = 0;
631 a->p_args.weights.compl_end_th = 0;
632 a->p_args.weights.end_quality = 0;
633 a->p_args.weights.end_stability = 0;
634 a->p_args.weights.gc_content_gt = 0;
635 a->p_args.weights.gc_content_lt = 0;
636 a->p_args.weights.hairpin_th = 0;
637 a->p_args.weights.length_gt = 1;
638 a->p_args.weights.length_lt = 1;
639 a->p_args.weights.num_ns = 0;
640 a->p_args.weights.pos_penalty = 1;
641 a->p_args.weights.repeat_sim = 0;
642 a->p_args.weights.seq_quality = 0;
643 a->p_args.weights.temp_cutoff = 5;
644 a->p_args.weights.temp_gt = 1;
645 a->p_args.weights.temp_lt = 1;
646 a->p_args.weights.template_mispriming = 0.0;
647 a->p_args.weights.template_mispriming_th = 0.0;
648 a->p_args.must_match_five_prime = NULL;
649 a->p_args.must_match_three_prime = NULL;
650 /* End of weights for objective functions for oligos and pairs. */
651
652 /* End of arguments for primers =========================== */
653
654 a->max_diff_tm = 100.0;
655 a->tm_santalucia = breslauer_auto;
656 a->salt_corrections = schildkraut;
657 a->pair_compl_any = 8.0;
658 a->pair_compl_end = 3.0;
659 a->pair_compl_any_th = 47.0;
660 a->pair_compl_end_th = 47.0;
661 a->thermodynamic_oligo_alignment = 0;
662 a->thermodynamic_template_alignment = 0;
663 a->liberal_base = 0;
664 a->primer_task = generic;
665 a->pick_left_primer = 1;
666 a->pick_right_primer = 1;
667 a->pick_internal_oligo = 0;
668 a->first_base_index = 0;
669 a->num_return = 5;
670 a->pr_min[0] = 100;
671 a->pr_max[0] = 300;
672 a->num_intervals = 1;
673 a->pair_repeat_compl = 24.0;
674 a->quality_range_min = 0;
675 a->quality_range_max = 100;
676 a->outside_penalty = PR_DEFAULT_OUTSIDE_PENALTY;
677 a->inside_penalty = PR_DEFAULT_INSIDE_PENALTY;
678 a->max_end_stability = 100.0;
679 a->lowercase_masking = 0;
680 a->product_max_tm = PR_DEFAULT_PRODUCT_MAX_TM;
681 a->product_min_tm = PR_DEFAULT_PRODUCT_MIN_TM;
682 a->product_opt_tm = PR_UNDEFINED_DBL_OPT;
683 a->product_opt_size = PR_UNDEFINED_INT_OPT;
684 a->pair_max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
685 a->pair_max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
686 a->o_args.opt_size = 20;
687 a->o_args.min_size = 18;
688 a->o_args.max_size = 27;
689 a->o_args.opt_tm = 60.0;
690 a->o_args.min_tm = 57.0;
691 a->o_args.max_tm = 63.0;
692 a->o_args.min_gc = 20.0;
693 a->o_args.max_gc = 80.0;
694 a->o_args.opt_gc_content = DEFAULT_OPT_GC_PERCENT;
695 a->o_args.max_poly_x = 5;
696 a->o_args.salt_conc = 50.0;
697 a->o_args.divalent_conc = 0.0;
698 a->o_args.dntp_conc = 0.0;
699 a->o_args.dna_conc = 50.0;
700 a->o_args.num_ns_accepted = 0;
701 a->o_args.max_self_any = 12.0;
702 a->o_args.max_self_end = 12.0;
703 a->o_args.max_self_any_th = 47.0;
704 a->o_args.max_self_end_th = 47.0;
705 a->o_args.max_hairpin_th = 47.0;
706 a->o_args.max_repeat_compl= 12.0;
707
708 a->o_args.min_quality = 0;
709 a->o_args.min_end_quality = 0;
710 a->o_args.max_template_mispriming = PR_UNDEFINED_ALIGN_OPT;
711 a->o_args.max_template_mispriming_th = PR_UNDEFINED_ALIGN_OPT;
712 a->o_args.weights.temp_gt = 1;
713 a->o_args.weights.temp_lt = 1;
714 a->o_args.weights.length_gt = 1;
715 a->o_args.weights.length_lt = 1;
716 a->o_args.weights.gc_content_gt = 0;
717 a->o_args.weights.gc_content_lt = 0;
718 a->o_args.weights.compl_any = 0;
719 a->o_args.weights.compl_end = 0;
720 a->o_args.weights.compl_any_th = 0;
721 a->o_args.weights.compl_end_th = 0;
722 a->o_args.weights.hairpin_th = 0;
723 a->o_args.weights.num_ns = 0;
724 a->o_args.weights.repeat_sim = 0;
725 a->o_args.weights.seq_quality = 0;
726 a->o_args.weights.end_quality = 0;
727 a->o_args.must_match_five_prime = NULL;
728 a->o_args.must_match_three_prime = NULL;
729
730 a->pr_pair_weights.primer_quality = 1;
731 a->pr_pair_weights.io_quality = 0;
732 a->pr_pair_weights.diff_tm = 0;
733 a->pr_pair_weights.compl_any = 0;
734 a->pr_pair_weights.compl_end = 0;
735 a->pr_pair_weights.compl_any_th = 0;
736 a->pr_pair_weights.compl_end_th = 0;
737 a->pr_pair_weights.temp_cutoff = 5;
738 a->pr_pair_weights.repeat_sim = 0;
739
740 a->pr_pair_weights.product_tm_lt = 0;
741 a->pr_pair_weights.product_tm_gt = 0;
742 a->pr_pair_weights.product_size_lt = 0;
743 a->pr_pair_weights.product_size_gt = 0;
744
745 a->lib_ambiguity_codes_consensus = 1;
746 /* Set to 1 for backward compatibility. This _NOT_ what
747 one normally wants, since many libraries contain
748 strings of N, which then match every oligo (very bad).
749 */
750
751 a->min_left_three_prime_distance = -1;
752 a->min_right_three_prime_distance = -1;
753
754 a->sequencing.lead = 50;
755 a->sequencing.spacing = 500;
756 a->sequencing.interval = 250;
757 a->sequencing.accuracy = 20;
758
759 a->min_5_prime_overlap_of_junction = 7;
760 a->min_3_prime_overlap_of_junction = 4;
761
762 }
763
764 /* Add a pair of integers to an array of intervals */
765 int
p3_add_to_interval_array(interval_array_t2 * interval_arr,int i1,int i2)766 p3_add_to_interval_array(interval_array_t2 *interval_arr, int i1, int i2)
767 {
768 int c = interval_arr->count;
769 if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
770 interval_arr->pairs[c][0] = i1;
771 interval_arr->pairs[c][1] = i2;
772 interval_arr->count++;
773 return 0;
774 }
775
776 /* Add 2 pairs of integers to an array of 2 intervals */
777 int
p3_add_to_2_interval_array(interval_array_t4 * interval_arr,int i1,int i2,int i3,int i4)778 p3_add_to_2_interval_array(interval_array_t4 *interval_arr, int i1, int i2, int i3, int i4)
779 {
780 int c = interval_arr->count;
781 if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
782 /* for a region either both values are given, or none is given */
783 if (((i1 == -1) && (i2 != -1)) || ((i1 != -1) && (i2 == -1)))
784 return 2;
785 if (((i3 == -1) && (i4 != -1)) || ((i3 != -1) && (i4 == -1)))
786 return 2;
787 interval_arr->left_pairs[c][0] = i1;
788 interval_arr->left_pairs[c][1] = i2;
789 interval_arr->right_pairs[c][0] = i3;
790 interval_arr->right_pairs[c][1] = i4;
791 if ((i1 == -1) && (i2 == -1))
792 interval_arr->any_left = 1;
793 if ((i3 == -1) && (i4 == -1))
794 interval_arr->any_right = 1;
795 if ((i1 == -1) && (i2 == -1) && (i3 == -1) && (i4 == -1))
796 interval_arr->any_pair = 1;
797 interval_arr->count++;
798 return 0;
799 }
800
801 /* ============================================================ */
802 /* END functions for global settings */
803 /* ============================================================ */
804
805 int
interval_array_t2_count(const interval_array_t2 * array)806 interval_array_t2_count(const interval_array_t2 *array)
807 {
808 return array->count;
809 }
810
811 const int *
interval_array_t2_get_pair(const interval_array_t2 * array,int i)812 interval_array_t2_get_pair(const interval_array_t2 *array, int i)
813 {
814 if (i > array->count) abort();
815 if (i < 0) abort();
816 return array->pairs[i];
817 }
818
819 /* ============================================================ */
820 /* BEGIN functions for p3retval */
821 /* ============================================================ */
822
823 /* Allocate a new primer3 state. Return NULL if out of memory. Assuming
824 malloc sets errno to ENOMEM according to Unix98, set errno to ENOMEM
825 on out-of-memory error. */
826 static p3retval *
create_p3retval(void)827 create_p3retval(void)
828 {
829 p3retval *state = (p3retval *)malloc(sizeof(*state));
830 if (!state)
831 return NULL;
832
833 state->fwd.oligo
834 = (primer_rec *) malloc(sizeof(*state->fwd.oligo) * INITIAL_LIST_LEN);
835
836 state->rev.oligo
837 = (primer_rec *) malloc(sizeof(*state->rev.oligo) * INITIAL_LIST_LEN);
838
839 state->intl.oligo
840 = (primer_rec *) malloc(sizeof(*state->intl.oligo) * INITIAL_LIST_LEN);
841
842 if (state->fwd.oligo == NULL
843 || state->rev.oligo == NULL
844 || state->intl.oligo == NULL) {
845 free(state);
846 return NULL;
847 }
848
849 state->fwd.storage_size = INITIAL_LIST_LEN;
850 state->rev.storage_size = INITIAL_LIST_LEN;
851 state->intl.storage_size = INITIAL_LIST_LEN;
852
853 state->fwd.num_elem = 0;
854 state->rev.num_elem = 0;
855 state->intl.num_elem = 0;
856
857 state->fwd.type = OT_LEFT;
858 state->intl.type = OT_INTL;
859 state->rev.type = OT_RIGHT;
860
861 state->best_pairs.storage_size = 0;
862 state->best_pairs.pairs = NULL;
863 state->best_pairs.num_pairs = 0;
864
865 init_pr_append_str(&state->glob_err);
866 init_pr_append_str(&state->per_sequence_err);
867 init_pr_append_str(&state->warnings);
868
869 memset(&state->fwd.expl, 0, sizeof(state->fwd.expl));
870 memset(&state->rev.expl, 0, sizeof(state->rev.expl));
871 memset(&state->intl.expl, 0, sizeof(state->intl.expl));
872
873 memset(&state->best_pairs.expl, 0, sizeof(state->best_pairs.expl));
874
875 return state;
876 }
877 /* ============================================================ */
878 /* BEGIN functions for dpal_arg_holder */
879 /* ============================================================ */
880
881 /* Create the dpal arg holder */
882 dpal_arg_holder *
create_dpal_arg_holder()883 create_dpal_arg_holder ()
884 {
885
886 dpal_arg_holder *h
887 = (dpal_arg_holder *) pr_safe_malloc(sizeof(dpal_arg_holder));
888
889 h->local = (dpal_args *) pr_safe_malloc(sizeof(*h->local));
890 set_dpal_args(h->local);
891 h->local->flag = DPAL_LOCAL;
892
893 h->end = (dpal_args *) pr_safe_malloc(sizeof(*h->end));
894 set_dpal_args(h->end);
895 h->end->flag = DPAL_GLOBAL_END;
896
897 h->local_end = (dpal_args *) pr_safe_malloc(sizeof(*h->local_end));
898 set_dpal_args(h->local_end);
899 h->local_end->flag = DPAL_LOCAL_END;
900
901 h->local_ambig = (dpal_args *) pr_safe_malloc(sizeof(*h->local_ambig));
902 *h->local_ambig = *h->local;
903 PR_ASSERT(dpal_set_ambiguity_code_matrix(h->local_ambig));
904
905 h->local_end_ambig = (dpal_args *) pr_safe_malloc(sizeof(*h->local_end_ambig));
906 *h->local_end_ambig = *h->local_end;
907 PR_ASSERT(dpal_set_ambiguity_code_matrix(h->local_end_ambig));
908
909 return h;
910 }
911
912 /* Free the dpal arg holder */
913 void
destroy_dpal_arg_holder(dpal_arg_holder * h)914 destroy_dpal_arg_holder(dpal_arg_holder *h)
915 {
916 if (NULL != h) {
917 free(h->local);
918 free(h->end);
919 free(h->local_end);
920 free(h->local_ambig);
921 free(h->local_end_ambig);
922 free(h);
923 }
924 }
925
926 /* This is a static variable that is initialized once
927 in choose_primers(). We make this variable have
928 'file' scope, we do not have to remember to free the associated
929 storage after each call to choose_primers(). */
930 static dpal_arg_holder *dpal_arg_to_use = NULL;
931
932 /* ============================================================ */
933 /* END functions for dpal_arg_holder */
934 /* ============================================================ */
935
936 /* ============================================================ */
937 /* BEGIN functions for thal_arg_holder */
938 /* ============================================================ */
939 /* Create the thal arg holder */
940 thal_arg_holder *
create_thal_arg_holder(const args_for_one_oligo_or_primer * po_args)941 create_thal_arg_holder (const args_for_one_oligo_or_primer *po_args)
942 {
943
944 thal_arg_holder *h
945 = (thal_arg_holder *) pr_safe_malloc(sizeof(thal_arg_holder));
946
947 h->any = (thal_args *) pr_safe_malloc(sizeof(*h->any));
948 set_thal_default_args(h->any);
949 h->any->type = thal_any;
950 h->any->mv = po_args->salt_conc;
951 h->any->dv = po_args->divalent_conc;
952 h->any->dntp = po_args->dntp_conc;
953 h->any->dna_conc = po_args->dna_conc;
954
955 h->end1 = (thal_args *) pr_safe_malloc(sizeof(*h->end1));
956 set_thal_default_args(h->end1);
957 h->end1->type = thal_end1;
958 h->end1->mv = po_args->salt_conc;
959 h->end1->dv = po_args->divalent_conc;
960 h->end1->dntp = po_args->dntp_conc;
961 h->end1->dna_conc = po_args->dna_conc;
962
963 h->end2 = (thal_args *) pr_safe_malloc(sizeof(*h->end2));
964 set_thal_default_args(h->end2);
965 h->end2->type = thal_end2;
966 h->end2->mv = po_args->salt_conc;
967 h->end2->dv = po_args->divalent_conc;
968 h->end2->dntp = po_args->dntp_conc;
969 h->end2->dna_conc = po_args->dna_conc;
970
971 h->hairpin_th = (thal_args *) pr_safe_malloc(sizeof(*h->hairpin_th));
972 set_thal_default_args(h->hairpin_th);
973 h->hairpin_th->type = thal_hairpin;
974 h->hairpin_th->mv = po_args->salt_conc;
975 h->hairpin_th->dv = po_args->divalent_conc;
976 h->hairpin_th->dntp = po_args->dntp_conc;
977 h->hairpin_th->dna_conc = po_args->dna_conc;
978 h->hairpin_th->dimer = 0;
979
980 return h;
981 }
982
983 /* Free the thal arg holder */
984 void
destroy_thal_arg_holder(thal_arg_holder * h)985 destroy_thal_arg_holder(thal_arg_holder *h)
986 {
987 if (NULL != h) {
988 free(h->any);
989 free(h->end1);
990 free(h->end2);
991 free(h->hairpin_th);
992 free(h);
993 }
994 }
995
996 static thal_arg_holder *thal_arg_to_use = NULL;
997 static thal_arg_holder *thal_oligo_arg_to_use = NULL;
998 /* ============================================================ */
999 /* END functions for thal_arg_holder */
1000 /* ============================================================ */
1001
1002 /* Deallocate a primer3 state */
1003 void
destroy_p3retval(p3retval * state)1004 destroy_p3retval(p3retval *state)
1005 {
1006 if (!state)
1007 return;
1008
1009 free_repeat_sim_score(state);
1010 free(state->fwd.oligo);
1011 free(state->rev.oligo);
1012 free(state->intl.oligo);
1013 if (state->best_pairs.storage_size != 0 && state->best_pairs.pairs)
1014 free(state->best_pairs.pairs);
1015
1016 destroy_pr_append_str_data(&state->glob_err);
1017 destroy_pr_append_str_data(&state->per_sequence_err);
1018 destroy_pr_append_str_data(&state->warnings);
1019
1020 free(state);
1021 }
1022
1023 void
destroy_dpal_thal_arg_holder()1024 destroy_dpal_thal_arg_holder() {
1025 if(dpal_arg_to_use)
1026 destroy_dpal_arg_holder(dpal_arg_to_use);
1027 if(thal_arg_to_use)
1028 destroy_thal_arg_holder(thal_arg_to_use);
1029 if(thal_oligo_arg_to_use)
1030 destroy_thal_arg_holder(thal_oligo_arg_to_use);
1031 }
1032
1033 const oligo_array *
p3_get_rv_fwd(const p3retval * r)1034 p3_get_rv_fwd(const p3retval *r) {
1035 return &r->fwd;
1036 }
1037
1038 const oligo_array *
p3_get_rv_intl(const p3retval * r)1039 p3_get_rv_intl(const p3retval *r) {
1040 return &r->intl;
1041 }
1042
1043 const oligo_array *
p3_get_rv_rev(const p3retval * r)1044 p3_get_rv_rev(const p3retval *r) {
1045 return &r->rev;
1046 }
1047
1048 const pair_array_t *
p3_get_rv_best_pairs(const p3retval * r)1049 p3_get_rv_best_pairs(const p3retval *r) {
1050 return &r->best_pairs;
1051 }
1052
1053 /* ============================================================ */
1054 /* END functions for p3retval */
1055 /* ============================================================ */
1056
1057 /* ============================================================ */
1058 /* BEGIN functions for seq_arg_holder */
1059 /* ============================================================ */
1060
1061 /* Create and initialize a seq_args data structure */
1062 seq_args *
create_seq_arg()1063 create_seq_arg()
1064 {
1065 seq_args *r = (seq_args *) malloc(sizeof(*r));
1066 if (NULL == r) return NULL; /* Out of memory */
1067 memset(r, 0, sizeof(*r));
1068 r->start_codon_pos = PR_DEFAULT_START_CODON_POS;
1069 r->incl_l = -1; /* Indicates logical NULL. */
1070
1071 r->force_left_start = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
1072 r->force_left_end = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
1073 r->force_right_start = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
1074 r->force_right_end = PR_NULL_FORCE_POSITION; /* Indicates logical NULL. */
1075 r->primer_overlap_junctions_count = 0;
1076
1077 r->n_quality = 0;
1078 r->quality = NULL;
1079
1080 return r;
1081 }
1082
1083 /* Free a seq_arg data structure */
1084 void
destroy_seq_args(seq_args * sa)1085 destroy_seq_args(seq_args *sa)
1086 {
1087 if (NULL == sa) return;
1088 free(sa->internal_input);
1089 free(sa->left_input);
1090 free(sa->right_input);
1091 free(sa->sequence);
1092 free(sa->quality);
1093 free(sa->trimmed_seq);
1094
1095 /* edited by T. Koressaar for lowercase masking */
1096 free(sa->trimmed_orig_seq);
1097
1098 free(sa->upcased_seq);
1099 free(sa->upcased_seq_r);
1100 free(sa->sequence_name);
1101 free(sa);
1102 }
1103
1104 /* ============================================================ */
1105 /* END functions for seq_arg_holder */
1106 /* ============================================================ */
1107
1108
1109 /* Function used to de-allocate the memory used by the hash maps
1110 allocated in choose_pair_or_triple. */
free_pair_memory(int rev_num_elem)1111 static void free_pair_memory(int rev_num_elem)
1112 {
1113 std::hash_map<int, primer_pair*> *hmap;
1114 std::hash_map<int, primer_pair*>::iterator it;
1115 primer_pair *pp;
1116 int i;
1117
1118 free(max_j_seen);
1119 for (i=0; i<rev_num_elem; i++) {
1120 hmap = pairs[i];
1121 if (hmap) {
1122 for (it=hmap->begin(); it!=hmap->end(); it++) {
1123 pp = it->second;
1124 if (pp != NULL)
1125 delete pp;
1126 }
1127 delete hmap;
1128 }
1129 }
1130 free(pairs);
1131 }
1132
1133
1134 /* ============================================================ */
1135 /* BEGIN choose_primers() */
1136 /* The main primer3 interface */
1137 /* See libprimer3.h for documentation. */
1138 /* ============================================================ */
1139 p3retval *
choose_primers(const p3_global_settings * pa,seq_args * sa)1140 choose_primers(const p3_global_settings *pa,
1141 seq_args *sa)
1142 {
1143 /* Create retval and set were to find the results */
1144 p3retval *retval = create_p3retval();
1145 if (retval == NULL) return NULL;
1146
1147 PR_ASSERT(NULL != pa);
1148 PR_ASSERT(NULL != sa);
1149
1150 if (pa->dump) {
1151 printf("Start of choose_primers:\n");
1152 p3_print_args(pa, sa) ;
1153 }
1154
1155 /* Set the general output type */
1156 if (pa->pick_left_primer && pa->pick_right_primer) {
1157 retval->output_type = primer_pairs;
1158 } else {
1159 retval->output_type = primer_list;
1160 }
1161 if (pa->primer_task == pick_primer_list ||
1162 pa->primer_task == pick_sequencing_primers) {
1163 retval->output_type = primer_list;
1164 }
1165
1166 /*
1167 * For catching ENOMEM. WARNING: We can only use longjmp to escape
1168 * from errors that have been called through choose_primers().
1169 * Therefore, if we subsequently update other static functions in
1170 * this file to have external linkage then we need to check whether
1171 * they call (or use functions that in turn call) longjmp to handle
1172 * ENOMEM.
1173 */
1174 if (setjmp(_jmp_buf) != 0) {
1175 /* Check if this was a thermodynamic alignment length error. */
1176 if (thermodynamic_alignment_length_error == 1) {
1177 thermodynamic_alignment_length_error = 0;
1178 /* Set per sequence error */
1179 pr_append_new_chunk(&retval->per_sequence_err,
1180 thermodynamic_alignment_length_error_msg);
1181 free(thermodynamic_alignment_length_error_msg);
1182 thermodynamic_alignment_length_error_msg = NULL;
1183 /* Other necessary cleanup. */
1184 free_pair_memory(retval->rev.num_elem);
1185 return retval;
1186 }
1187 /* This was a memory error. */
1188 destroy_p3retval(retval);
1189 return NULL; /* If we get here, that means errno should be ENOMEM. */
1190 }
1191
1192 /* Change some parameters to fit the task */
1193 _adjust_seq_args(pa, sa, &retval->per_sequence_err,&retval->warnings);
1194
1195 if (pa->dump) {
1196 printf("After _adjust_seq_args\n");
1197 p3_print_args(pa, sa) ;
1198 }
1199
1200 if (!pr_is_empty(&retval->per_sequence_err)) return retval;
1201
1202 /* TO DO -- move the check below to pr_data_control and issue a
1203 warning if it fails. */
1204 /* if (pa->p_args.min_quality != 0
1205 && pa->p_args.min_end_quality < pa->p_args.min_quality)
1206 ... issue warning ...
1207 pa->p_args.min_end_quality = pa->p_args.min_quality; */
1208
1209 /* Check if the input in sa and pa makes sense */
1210 if (_pr_data_control(pa, sa,
1211 &retval->glob_err, /* Fatal errors */
1212 &retval->per_sequence_err, /* Non-fatal errors */
1213 &retval->warnings
1214 ) !=0 ) {
1215 return retval;
1216 }
1217
1218
1219 set_retval_both_stop_codons(sa, retval);
1220
1221 /* Set the parameters for alignment functions
1222 if dpal_arg_to_use, a static variable that has 'file'
1223 scope, has not yet been initialized. */
1224 if (dpal_arg_to_use == NULL)
1225 dpal_arg_to_use = create_dpal_arg_holder();
1226 if(thal_arg_to_use == NULL) {
1227 thal_arg_to_use = create_thal_arg_holder(&pa->p_args);
1228 } else {
1229 destroy_thal_arg_holder(thal_arg_to_use);
1230 thal_arg_to_use = create_thal_arg_holder(&pa->p_args);
1231 }
1232 if(thal_oligo_arg_to_use == NULL) {
1233 thal_oligo_arg_to_use = create_thal_arg_holder(&pa->o_args);
1234 } else {
1235 destroy_thal_arg_holder(thal_oligo_arg_to_use);
1236 thal_oligo_arg_to_use = create_thal_arg_holder(&pa->o_args);
1237 }
1238 if (pa->primer_task == pick_primer_list) {
1239 make_complete_primer_lists(retval, pa, sa,
1240 dpal_arg_to_use,thal_arg_to_use,thal_oligo_arg_to_use);
1241 } else if (pa->primer_task == pick_sequencing_primers) {
1242 pick_sequencing_primer_list(retval, pa, sa,
1243 dpal_arg_to_use,thal_arg_to_use);
1244 } else if (pa->primer_task == check_primers) {
1245 add_primers_to_check(retval, pa, sa,
1246 dpal_arg_to_use, thal_arg_to_use, thal_oligo_arg_to_use);
1247 } else { /* The general way to pick primers */
1248 /* Populate the forward and reverse primer lists */
1249 if (make_detection_primer_lists(retval, pa, sa,
1250 dpal_arg_to_use,thal_arg_to_use) != 0) {
1251 /* There was an error */
1252 return retval;
1253 }
1254 /* Populate the internal oligo lists */
1255 if ( pa->pick_internal_oligo) {
1256 if (make_internal_oligo_list(retval, pa, sa,
1257 dpal_arg_to_use,thal_oligo_arg_to_use) != 0) {
1258 /* There was an error*/
1259 return retval;
1260 }
1261 }
1262 }
1263
1264 if (pa->pick_right_primer &&
1265 (pa->primer_task != pick_sequencing_primers))
1266 sort_primer_array(&retval->rev);
1267
1268 if (pa->pick_left_primer &&
1269 (pa->primer_task != pick_sequencing_primers))
1270 sort_primer_array(&retval->fwd);
1271
1272 /* If we are returning a list of internal oligos, sort them by their
1273 'goodness'. We do not care if these are sorted if we end up in
1274 choose_pair_or_triple(), since this calls
1275 choose_internal_oligo(), which selects the best internal oligo
1276 for a given primer pair. */
1277 if (retval->output_type == primer_list && pa->pick_internal_oligo == 1)
1278 sort_primer_array(&retval->intl);
1279
1280 /* Select primer pairs if needed */
1281 if (retval->output_type == primer_pairs) {
1282 choose_pair_or_triple(retval, pa, sa, dpal_arg_to_use, thal_arg_to_use,
1283 thal_oligo_arg_to_use, &retval->best_pairs);
1284 }
1285
1286 if (pa->dump) {
1287 printf("End of choose_primers:\n");
1288 p3_print_args(pa, sa) ;
1289 }
1290
1291 return retval;
1292 }
1293 /* ============================================================ */
1294 /* END choose_primers() */
1295 /* ============================================================ */
1296
1297 /* ============================================================ */
1298 /* BEGIN choose_pair_or_triple
1299
1300 This function uses retval->fwd and retval->rev and
1301 updates the oligos in these array.
1302
1303 This function posibly uses retval->intl and updates its
1304 elements via choose_internal_oligo().
1305
1306 This function examines primer pairs or triples to find
1307 pa->num_return pairs or triples to return.
1308
1309 Results are returned in best_pairs and in
1310 retval->best_pairs.expl */
1311 /* ============================================================ */
1312 static void
choose_pair_or_triple(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,const thal_arg_holder * thal_oligo_arg_to_use,pair_array_t * best_pairs)1313 choose_pair_or_triple(p3retval *retval,
1314 const p3_global_settings *pa,
1315 const seq_args *sa,
1316 const dpal_arg_holder *dpal_arg_to_use,
1317 const thal_arg_holder *thal_arg_to_use,
1318 const thal_arg_holder *thal_oligo_arg_to_use,
1319 pair_array_t *best_pairs) {
1320 int i,j; /* Loop index. */
1321 int n_int; /* Index of the internal oligo */
1322 /*int *max_j_seen; */ /* The maximum value of j (loop index for forward primers)
1323 that has been examined for every reverse primer
1324 index (i) -- global variable now */
1325 int update_stats = 1; /* Flag to indicate whether pair_stats
1326 should be updated. */
1327 primer_pair h; /* The current pair which is being evaluated. */
1328 primer_pair the_best_pair; /* The best pair is being "remembered". */
1329 pair_stats *pair_expl = &retval->best_pairs.expl; /* For statistics */
1330
1331 int product_size_range_index = 0;
1332 int trace_me = 0;
1333 int the_best_i, the_best_j;
1334
1335 /* Hash maps used to store pairs that were computed */
1336
1337 /* std::hash_map<int, primer_pair*> **pairs; */
1338 /* pairs is an array of pointers to hash maps. It will be indexed
1339 by the indices of the reverse primers in retval->rev. -- global var now */
1340
1341 std::hash_map<int, primer_pair*> *hmap, *best_hmap = NULL;
1342 /* hmap and best_hmap will be pointers to hash maps also pointed to
1343 by elements of pairs. */
1344
1345 std::hash_map<int, primer_pair*>::iterator it;
1346 primer_pair *pp, *best_pp = NULL;
1347 int pair_found = 0;
1348
1349 pairs =
1350 (std::hash_map<int, primer_pair*>**)
1351 calloc (retval->rev.num_elem,
1352 sizeof(std::hash_map<int, primer_pair*>*));
1353 if (!pairs) longjmp(_jmp_buf, 1);
1354
1355 memset(&the_best_pair, 0, sizeof(the_best_pair));
1356 max_j_seen = (int *) malloc(sizeof(int) * retval->rev.num_elem);
1357 for (i = 0; i < retval->rev.num_elem; i++) max_j_seen[i] = -1;
1358
1359 /* Pick pairs till we have enough. */
1360 while(1) {
1361
1362 /* FIX ME, is this memset really needed? Apparently slow */
1363 memset(&the_best_pair, 0, sizeof(the_best_pair));
1364
1365 the_best_i = -1;
1366 the_best_j = -1;
1367 /* To start put penalty to the maximum */
1368 the_best_pair.pair_quality = DBL_MAX;
1369
1370 /* Iterate over the reverse primers. */
1371 for (i = 0; i < retval->rev.num_elem; i++) {
1372
1373 hmap = pairs[i];
1374 /* Pairs[i] is NULL if there has never been an assignment to
1375 pairs[i] because pairs was allocated by calloc, which
1376 sets the allocated memory to 0. */
1377
1378 /* Only use a primer that *might be* legal or that the caller
1379 has provided and specified as "must use". Primers are *NOT*
1380 FULLY ASSESSED until the call to characterize_pair(), in
1381 order to avoid expensive computations (mostly alignments)
1382 unless necessary. */
1383 if (!OK_OR_MUST_USE(&retval->rev.oligo[i])) {
1384 /* Can free the memory used by the hmap associated to this
1385 reverse primer */
1386 if (hmap) {
1387 for (it=hmap->begin(); it!=hmap->end(); it++) {
1388 /* it->second is the second element (i.e. the 'value', as
1389 opposed to the 'key'). */
1390 pp = it->second;
1391 delete pp;
1392 }
1393 if (hmap == best_hmap) best_hmap = NULL;
1394 delete hmap;
1395 hmap = NULL;
1396 pairs[i] = NULL;
1397 }
1398 continue;
1399 }
1400
1401 /* If the pair cannot be better than the one already
1402 * selected, then we can skip remaining reverse primers */
1403 if (pa->pr_pair_weights.primer_quality *
1404 (retval->rev.oligo[i].quality + retval->fwd.oligo[0].quality)
1405 > the_best_pair.pair_quality) {
1406 break;
1407 }
1408
1409 if (retval->rev.oligo[i].overlaps) {
1410 /* The stats will not keep track of the pair correctly
1411 after the first pass, because an oligo might
1412 have been legal on one pass but become illegal on
1413 a subsequent pass. */
1414 if (update_stats) {
1415 if (trace_me)
1416 fprintf(stderr,
1417 "i=%d, j=%d, overlaps_oligo_in_better_pair++\n",
1418 i, j);
1419 pair_expl->overlaps_oligo_in_better_pair++;
1420 }
1421 /* Can free the memory used by the hmap associated to this reverse primer */
1422 if (hmap) {
1423 for (it=hmap->begin(); it!=hmap->end(); it++) {
1424 /* it->second is the second element (i.e. the 'value', as
1425 opposed to the 'key'). */
1426 pp = it->second;
1427 delete pp;
1428 }
1429 if (hmap == best_hmap) best_hmap = NULL;
1430 delete hmap;
1431 hmap = NULL;
1432 pairs[i] = NULL;
1433 }
1434 continue;
1435 }
1436
1437 /* Loop over forward primers */
1438 for (j=0; j<retval->fwd.num_elem; j++) {
1439
1440 /* We check the reverse oligo again, because we may
1441 have determined that it is "not ok", even though
1442 (as a far as we knew), it was ok above. */
1443 if (!OK_OR_MUST_USE(&retval->rev.oligo[i])) {
1444 /* Can free the memory used by the hmap associated to this reverse primer */
1445 if (hmap) {
1446 for (it=hmap->begin(); it!=hmap->end(); it++) {
1447 /* it->second is the second element (i.e. the 'value', as
1448 opposed to the 'key'). */
1449 pp = it->second;
1450 delete pp;
1451 }
1452 if (hmap == best_hmap) best_hmap = NULL;
1453 delete hmap;
1454 hmap = NULL;
1455 pairs[i] = NULL;
1456 }
1457 break;
1458 }
1459
1460 /* Only use a primer that is legal, or that the caller
1461 has provided and specified as "must use". */
1462 if (!OK_OR_MUST_USE(&retval->fwd.oligo[j])) continue;
1463
1464 /* If the pair cannot be better than the one already
1465 * selected, then we can skip remaining forward primers
1466 * for this reverse primer */
1467 if (pa->pr_pair_weights.primer_quality *
1468 (retval->fwd.oligo[j].quality + retval->rev.oligo[i].quality)
1469 > the_best_pair.pair_quality) {
1470 break;
1471 }
1472
1473 /* Need to have this here because if we break just above, then,
1474 at a later iteration, we may need to examine the oligo
1475 pair with reverse oligo at i and forward oligo at j. */
1476 update_stats = 0;
1477 if (j > max_j_seen[i]) {
1478 if (trace_me)
1479 fprintf(stderr,
1480 "updates ON: i=%d, j=%d, max_j_seen[%d]=%d\n",
1481 i, j, i, max_j_seen[i]);
1482 max_j_seen[i] = j;
1483 if (trace_me)
1484 fprintf(stderr, "max_j_seen[%d] --> %d\n", i, max_j_seen[i]);
1485 if (trace_me) fprintf(stderr, "updates on\n");
1486 update_stats = 1;
1487 }
1488
1489 if (retval->fwd.oligo[j].overlaps) {
1490 /* The stats will not keep track of the pair correctly
1491 after the first pass, because an oligo might
1492 have been legal on one pass but become illegal on
1493 a subsequent pass. */
1494 if (update_stats) {
1495 if (trace_me)
1496 fprintf(stderr,
1497 "i=%d, j=%d, overlaps_oligo_in_better_pair++\n",
1498 i, j);
1499 pair_expl->overlaps_oligo_in_better_pair++;
1500 }
1501 continue;
1502 }
1503
1504 /* Some simple checks first, before searching the hashmap */
1505 int must_use = 0;
1506 if ((pa->primer_task == check_primers) ||
1507 ((retval->fwd.oligo[j].must_use != 0) &&
1508 (retval->rev.oligo[i].must_use != 0))) {
1509 must_use = 1;
1510 }
1511
1512 /* Determine if overlap with an overlap point is required, and
1513 if so, whether one of the primers in the pairs overlaps
1514 that point. */
1515 if ((sa->primer_overlap_junctions_count > 0)
1516 && !(retval->rev.oligo[i].overlaps_overlap_position
1517 || retval->fwd.oligo[j].overlaps_overlap_position)
1518 ) {
1519 if (update_stats) {
1520 pair_expl->considered++;
1521 pair_expl->does_not_overlap_a_required_point++;
1522 }
1523 if (!must_use) continue;
1524 }
1525
1526 /* Check product size now */
1527 double product_size
1528 = retval->rev.oligo[i].start - retval->fwd.oligo[j].start+1;
1529
1530 if (product_size < pa->pr_min[product_size_range_index] ||
1531 product_size > pa->pr_max[product_size_range_index]) {
1532 if (update_stats) {
1533 /* This line NEW */ if (!must_use)
1534 pair_expl->considered++;
1535 pair_expl->product++;
1536 }
1537 if (!must_use) continue;
1538 }
1539
1540 /* Check if pair was already computed */
1541 pair_found = 0;
1542 if (hmap) {
1543 it = hmap->find(j);
1544 if (it != hmap->end()) {
1545 pair_found = 1;
1546
1547 /* it->second is the second element (i.e. the 'value', as
1548 opposed to the 'key'). */
1549 pp = it->second;
1550 if (pp) {
1551 /* The pair was computed, it isn't illegal and it wasn't
1552 selected yet */
1553 if (update_stats) {
1554 pair_expl->considered++;
1555 if (trace_me)
1556 fprintf(stderr, "ok++\n");
1557 pair_expl->ok++;
1558 }
1559 /* Check if this is a better pair */
1560 if (compare_primer_pair(pp, &the_best_pair) < 0) {
1561 the_best_pair = *pp;
1562 the_best_i = i;
1563 the_best_j = j;
1564 best_hmap = hmap;
1565 best_pp = pp;
1566 }
1567
1568 /* There cannot be a better pair */
1569 if (the_best_pair.pair_quality == 0) {
1570 break;
1571 }
1572 } /* else - pp is NULL - it's illegal or already selected */
1573 }
1574 } else {
1575 /* Create this hashmap */
1576 hmap = new std::hash_map<int, primer_pair*>;
1577 if (!hmap)
1578 longjmp(_jmp_buf, 1);
1579 pairs[i] = hmap;
1580 }
1581
1582 if (!pair_found) {
1583 /* Characterize the pair. h is initialized by this
1584 call. */
1585 int tmp =
1586 characterize_pair(retval, pa, sa, j, i,
1587 product_size_range_index,
1588 &h, dpal_arg_to_use,
1589 thal_arg_to_use,
1590 update_stats);
1591 if (tmp == PAIR_OK) {
1592
1593 /* Choose internal oligo if needed */
1594 if (pa->pick_right_primer && pa->pick_left_primer
1595 && pa->pick_internal_oligo) {
1596 if (choose_internal_oligo(retval, h.left, h.right,
1597 &n_int, sa, pa,
1598 dpal_arg_to_use, thal_oligo_arg_to_use)!=0) {
1599
1600 /* We were UNable to choose an internal oligo. */
1601 if (update_stats) {
1602 pair_expl->internal++;
1603 }
1604
1605 /* Mark the pair as not good - the entry in the hash
1606 map will be a NULL */
1607 (*hmap)[j] = NULL;
1608 continue;
1609 } else {
1610 /* We DID choose an internal oligo, and we
1611 set h.intl to point to it. */
1612 h.intl = &retval->intl.oligo[n_int];
1613 }
1614 }
1615
1616 if (update_stats) {
1617 if (trace_me)
1618 fprintf(stderr, "ok++\n");
1619 pair_expl->ok++;
1620 }
1621
1622 /* Calculate the pair penalty */
1623 h.pair_quality = obj_fn(pa, &h);
1624 PR_ASSERT(h.pair_quality >= 0.0);
1625
1626 /* Save the pair */
1627 pp = new primer_pair;
1628 if (!pp)
1629 longjmp(_jmp_buf, 1);
1630 *pp = h;
1631 (*hmap)[j] = pp;
1632
1633 /* The current pair (h) is the new best pair if it is
1634 better than the best pair so far. */
1635 if (compare_primer_pair(&h, &the_best_pair) < 0) {
1636 the_best_pair = h;
1637 the_best_i = i;
1638 the_best_j = j;
1639 best_hmap = hmap;
1640 best_pp = pp;
1641 }
1642
1643 /* There cannot be a better pair */
1644 if (the_best_pair.pair_quality == 0) {
1645 break;
1646 }
1647 } else if (tmp == PAIR_FAILED) {
1648 /* Illegal pair */
1649 (*hmap)[j] = NULL;
1650 }
1651 }
1652 } /* for (j=0; j<retval->fwd.num_elem; j++) -- inner loop */
1653
1654 /* Check if there cannot be a better pair than best found */
1655 if (the_best_pair.pair_quality == 0) {
1656 break;
1657 }
1658
1659 } /* for (i = 0; i < retval->rev.num_elem; i++) --- outer loop */
1660
1661 if (the_best_pair.pair_quality == DBL_MAX){
1662 /* No pair was found. Try another product-size-range,
1663 if one exists. */
1664
1665 product_size_range_index++;
1666 /* Re-set the high-water marks for the indices
1667 for reverse and forward primers: */
1668 for (i = 0; i < retval->rev.num_elem; i++) max_j_seen[i] = -1;
1669
1670 if (!(product_size_range_index < pa->num_intervals)) {
1671 /* We ran out of product-size-ranges. Exit the while loop. */
1672 break;
1673
1674 /* Our bookkeeping was incorrect unless the assertion below is
1675 true. If num_intervals > 1 or min_three_*_prime_distance >
1676 -1 the assertion below might not be true. */
1677 PR_ASSERT(!((pa->num_intervals == 1) &&
1678 ((pa->min_left_three_prime_distance == -1) ||
1679 (pa->min_right_three_prime_distance == -1)))
1680 || (best_pairs->num_pairs == pair_expl->ok));
1681 }
1682
1683 } else {
1684 /* Store the best primer for output */
1685
1686 if (trace_me)
1687 fprintf(stderr, "ADD pair i=%d, j=%d\n", the_best_i, the_best_j);
1688
1689 add_pair(&the_best_pair, best_pairs);
1690
1691 /* Mark the pair as already selected */
1692 delete best_pp;
1693 (*best_hmap)[the_best_j] = NULL;
1694
1695 /* Update the overlaps flags */
1696 for (i = 0; i < retval->rev.num_elem; i++) {
1697 if (right_oligo_in_pair_overlaps_used_oligo(&retval->rev.oligo[i],
1698 &the_best_pair,
1699 pa->min_right_three_prime_distance)) {
1700 retval->rev.oligo[i].overlaps = 1;
1701 }
1702 }
1703 for (j = 0; j < retval->fwd.num_elem; j++) {
1704 if (left_oligo_in_pair_overlaps_used_oligo(&retval->fwd.oligo[j],
1705 &the_best_pair,
1706 pa->min_left_three_prime_distance)) {
1707 retval->fwd.oligo[j].overlaps = 1;
1708 }
1709 }
1710
1711 /* If we have enough then stop the while loop */
1712 if (pa->num_return == best_pairs->num_pairs) {
1713 break;
1714 }
1715 }
1716 } /* end of while(continue_trying == 1) */
1717
1718 /* Final cleanup of dynamically allocated storage for this
1719 function. */
1720 free_pair_memory(retval->rev.num_elem);
1721 }
1722 /* ============================================================ */
1723 /* END choose_pair_or_triple */
1724 /* ============================================================ */
1725
1726 /* ============================================================ */
1727 /* BEGIN choose_internal_oligo */
1728 /* Choose best internal oligo for given pair of left and right
1729 primers. */
1730 /* ============================================================ */
1731 static int
choose_internal_oligo(p3retval * retval,const primer_rec * left,const primer_rec * right,int * nm,const seq_args * sa,const p3_global_settings * pa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use)1732 choose_internal_oligo(p3retval *retval,
1733 const primer_rec *left,
1734 const primer_rec *right,
1735 int *nm,
1736 const seq_args *sa,
1737 const p3_global_settings *pa,
1738 const dpal_arg_holder *dpal_arg_to_use,
1739 const thal_arg_holder *thal_arg_to_use
1740 )
1741 {
1742 int i,k;
1743 double min;
1744 char oligo_seq[MAX_PRIMER_LENGTH+1], revc_oligo_seq[MAX_PRIMER_LENGTH+1];
1745 primer_rec *h;
1746 min = 1000000.;
1747 i = -1;
1748
1749 for (k=0; k < retval->intl.num_elem; k++) {
1750 h = &retval->intl.oligo[k]; /* h is the record for the oligo currently
1751 under consideration */
1752
1753 if ((h->start > (left->start + (left->length-1)))
1754 && ((h->start + (h->length-1))
1755 < (right->start-right->length+1))
1756 && (h->quality < min)
1757 && (OK_OR_MUST_USE(h))) {
1758
1759 if (h->self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==0) {
1760
1761 _pr_substr(sa->trimmed_seq, h->start, h->length, oligo_seq);
1762 p3_reverse_complement(oligo_seq, revc_oligo_seq);
1763
1764 oligo_compl(h, &pa->o_args, &retval->intl.expl,
1765 dpal_arg_to_use, oligo_seq, revc_oligo_seq);
1766 if (!OK_OR_MUST_USE(h)) continue;
1767 }
1768
1769 if (h->self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
1770 _pr_substr(sa->trimmed_seq, h->start, h->length, oligo_seq);
1771 p3_reverse_complement(oligo_seq, revc_oligo_seq);
1772
1773 oligo_compl_thermod(h, &pa->o_args, &retval->intl.expl,
1774 thal_oligo_arg_to_use, oligo_seq, oligo_seq);
1775 if (!OK_OR_MUST_USE(h)) continue;
1776 }
1777 if(h->hairpin_th == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
1778 _pr_substr(sa->trimmed_seq, h->start, h->length, oligo_seq);
1779 oligo_hairpin(h, &pa->o_args,
1780 &retval->intl.expl, thal_oligo_arg_to_use,
1781 oligo_seq);
1782 if (!OK_OR_MUST_USE(h)) continue;
1783 }
1784
1785 if (h->repeat_sim.score == NULL) {
1786 oligo_repeat_library_mispriming(h, pa, sa, OT_INTL, &retval->intl.expl,
1787 dpal_arg_to_use);
1788 if (!OK_OR_MUST_USE(h)) continue;
1789 }
1790
1791 min = h->quality;
1792 i=k;
1793
1794 } /* if ((h->start.... */
1795
1796 } /* for (k=0;..... */
1797
1798 *nm = i;
1799 if(*nm < 0) return 1;
1800 return 0;
1801 }
1802 /* ============================================================ */
1803 /* END choose_internal_oligo */
1804 /* ============================================================ */
1805
1806
1807
1808 /*
1809 Translate the values in the stats struct into an warning string.
1810 Call this function only if the 'stat's contains the _errors_
1811 associated with a given primer i.e. that primer was supplied by the
1812 caller and pick_anyway is set.
1813 */
1814 void
add_must_use_warnings(pr_append_str * warning,const char * text,const oligo_stats * stats)1815 add_must_use_warnings(pr_append_str *warning,
1816 const char* text,
1817 const oligo_stats *stats)
1818 {
1819 const char *sep = "/";
1820 pr_append_str s;
1821
1822 s.data = NULL;
1823 s.storage_size = 0;
1824
1825 if (stats->size_min) pr_append_w_sep(&s, sep, "Too short");
1826 if (stats->size_max) pr_append_w_sep(&s, sep, "Too long");
1827 if (stats->ns) pr_append_w_sep(&s, sep, "Too many Ns");
1828 if (stats->target) pr_append_w_sep(&s, sep, "Overlaps Target");
1829 if (stats->excluded) pr_append_w_sep(&s, sep, "Overlaps Excluded Region");
1830 if (stats->gc) pr_append_w_sep(&s, sep, "Unacceptable GC content");
1831 if (stats->gc_clamp) pr_append_w_sep(&s, sep, "No GC clamp");
1832 if (stats->temp_min) pr_append_w_sep(&s, sep, "Tm too low");
1833 if (stats->temp_max) pr_append_w_sep(&s, sep, "Tm too high");
1834 if (stats->compl_any) pr_append_w_sep(&s, sep, "High self complementarity");
1835 if (stats->compl_end)
1836 pr_append_w_sep(&s, sep, "High end self complementarity");
1837 if (stats->hairpin_th) pr_append_w_sep(&s, sep, "High hairpin stability (thermod. approach)");
1838 if (stats->repeat_score)
1839 pr_append_w_sep(&s, sep, "High similarity to mispriming or mishyb library");
1840 if (stats->poly_x) pr_append_w_sep(&s, sep, "Long poly-X");
1841 if (stats->seq_quality) pr_append_w_sep(&s, sep, "Low sequence quality");
1842 if (stats->stability) pr_append_w_sep(&s, sep, "High 3' stability");
1843 if (stats->no_orf) pr_append_w_sep(&s, sep, "Would not amplify any ORF");
1844 if (stats->not_in_any_left_ok_region) pr_append_w_sep(&s, sep, "Not in any ok left region");
1845 if (stats->not_in_any_right_ok_region) pr_append_w_sep(&s, sep, "Not in any ok right region");
1846
1847 /* edited by T. Koressaar for lowercase masking: */
1848 if (stats->gmasked)
1849 pr_append_w_sep(&s, sep, "Masked with lowercase letter");
1850
1851 if (stats->must_match_fail)
1852 pr_append_w_sep(&s, sep, "Failed must_match requirements");
1853
1854 if (s.data) {
1855 pr_append_new_chunk(warning, text);
1856 pr_append(warning, " is unacceptable: ");
1857 pr_append(warning, s.data);
1858 free(s.data);
1859 }
1860 }
1861
1862 /*
1863 Also see the documentation in librimer3.h,
1864 p3_global_settings.min_{left/right_}three_prime_distance.
1865
1866 If min_dist == -1, return 0
1867
1868 If min_dist == 0:
1869 Return 1 if the left or the right
1870 primer is identical to the left or right
1871 primer (respectively) in best_pair.
1872
1873 Otherwise return 0.
1874
1875 If min_dist > 0:
1876 Return 1 if EITHER:
1877 (1) The 3' end of the left primer in pair is
1878 < min_dist from the 3' end of the left primer
1879 in best_pair
1880 OR
1881 (2) The 3' end of the right primer in pair is
1882 < min_dist from the 3' end of the right primer
1883 in best_pair
1884
1885 */
1886
1887 static int
right_oligo_in_pair_overlaps_used_oligo(const primer_rec * right,const primer_pair * best_pair,int min_dist)1888 right_oligo_in_pair_overlaps_used_oligo(const primer_rec *right,
1889 const primer_pair *best_pair,
1890 int min_dist)
1891 {
1892 int best_pos, pair_pos;
1893
1894 if (min_dist == -1)
1895 return 0;
1896
1897 best_pos = best_pair->right->start - best_pair->right->length + 1;
1898
1899 pair_pos = right->start - right->length + 1;
1900
1901 if ((abs(best_pos - pair_pos) < min_dist)
1902 && (min_dist != 0)) { return 1; }
1903
1904 if ((best_pair->right->length == right->length)
1905 && (best_pair->right->start == right->start)
1906 && (min_dist == 0)) {
1907 return 1;
1908 }
1909
1910 return 0;
1911 }
1912
1913 static int
left_oligo_in_pair_overlaps_used_oligo(const primer_rec * left,const primer_pair * best_pair,int min_dist)1914 left_oligo_in_pair_overlaps_used_oligo(const primer_rec *left,
1915 const primer_pair *best_pair,
1916 int min_dist)
1917 {
1918 int best_pos, pair_pos;
1919
1920 if (min_dist == -1)
1921 return 0;
1922
1923 best_pos = best_pair->left->start + best_pair->left->length - 1;
1924
1925 pair_pos = left->start + left->length - 1;
1926
1927 if ((abs(best_pos - pair_pos) < min_dist)
1928 && (min_dist != 0)) { return 1; }
1929
1930 if ((best_pair->left->length == left->length)
1931 && (best_pair->left->start == left->start)
1932 && (min_dist == 0)) {
1933 return 1;
1934 }
1935
1936 return 0;
1937 }
1938
1939 /* Add 'pair' to 'retpair'; always appends. */
1940 static void
add_pair(const primer_pair * pair,pair_array_t * retpair)1941 add_pair(const primer_pair *pair,
1942 pair_array_t *retpair)
1943 {
1944 /* If array is not initialised, initialise it with the size of pairs
1945 to return */
1946 if (0 == retpair->storage_size) {
1947 retpair->storage_size = INITIAL_NUM_RETURN;
1948 retpair->pairs
1949 = (primer_pair *)
1950 pr_safe_malloc(retpair->storage_size * sizeof(*retpair->pairs));
1951 } else {
1952 if (retpair->storage_size == retpair->num_pairs) {
1953 /* We need more space, so realloc double the space*/
1954 retpair->storage_size *= 2;
1955 retpair->pairs
1956 = (primer_pair *)
1957 pr_safe_realloc(retpair->pairs,
1958 retpair->storage_size * sizeof(*retpair->pairs));
1959 }
1960 }
1961 /* Copy the pair into the storage place */
1962 retpair->pairs[retpair->num_pairs] = *pair;
1963 retpair->num_pairs++;
1964 }
1965
1966 /*
1967 * Make lists of acceptable left and right primers. After return, the
1968 * lists are stored in retval->fwd.oligo and retval->rev.oligo and the
1969 * coresponding list sizes are stored in retval->fwd.num_elem and
1970 * retval->rev.num_elem. Return 1 if one of lists is empty or if
1971 * leftmost left primer and rightmost right primer do not provide
1972 * sufficient product size.
1973 */
1974 static int
make_detection_primer_lists(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use)1975 make_detection_primer_lists(p3retval *retval,
1976 const p3_global_settings *pa,
1977 const seq_args *sa,
1978 const dpal_arg_holder *dpal_arg_to_use,
1979 const thal_arg_holder *thal_arg_to_use)
1980 {
1981 int left, right;
1982 int length, start;
1983 int i,n,/*k,*/ pr_min;
1984 int tar_l, tar_r, f_b, r_b;
1985 pair_stats *pair_expl = &retval->best_pairs.expl; /* To store the statistics for pairs */
1986
1987 /* Var to save the very left and very right primer */
1988 left = right = 0;
1989
1990 /* Set pr_min to the very smallest
1991 allowable product size. */
1992 pr_min = INT_MAX;
1993 for (i=0; i < pa->num_intervals; i++)
1994 if(pa->pr_min[i] < pr_min)
1995 pr_min = pa->pr_min[i];
1996
1997 /* Get the length of the sequence */
1998 PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
1999
2000 tar_r = 0; /* Target start position */
2001 tar_l = n; /* Target length */
2002
2003 /* Iterate over target array */
2004 for (i=0; i < sa->tar2.count; i++) {
2005
2006 /* Select the rightmost target start */
2007 if (sa->tar2.pairs[i][0] > tar_r)
2008 tar_r = sa->tar2.pairs[i][0];
2009
2010 /* Select the rightmost target end */
2011 if (sa->tar2.pairs[i][0] + sa->tar2.pairs[i][1] - 1 < tar_l)
2012 tar_l = sa->tar2.pairs[i][0] + sa->tar2.pairs[i][1] - 1;
2013 }
2014
2015 if (_PR_DEFAULT_POSITION_PENALTIES(pa)) {
2016 if (0 == tar_r) tar_r = n;
2017 if (tar_l == n) tar_l = 0;
2018 } else {
2019 tar_r = n;
2020 tar_l = 0;
2021 }
2022
2023 /* We use some global information to restrict the region
2024 of the input sequence in which we generate candidate
2025 oligos. */
2026 if (retval->output_type == primer_list && pa->pick_left_primer == 1)
2027 f_b = n - 1;
2028 else if (tar_r - 1 < n - pr_min + pa->p_args.max_size - 1
2029 && !(pa->pick_anyway && sa->left_input))
2030 f_b=tar_r - 1;
2031 else
2032 f_b = n - pr_min + pa->p_args.max_size-1;
2033
2034 if (pa->pick_left_primer) {
2035 /* We will need a left primer. */
2036 left=n; right=0;
2037 length = f_b - pa->p_args.min_size + 1;
2038 start = pa->p_args.min_size - 1;
2039
2040 /* Use the primer provided */
2041 if (sa->left_input) {
2042 add_one_primer(sa->left_input, &left, &retval->fwd,
2043 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2044
2045 }
2046 /* Pick primers at one position */
2047 else if(sa->force_left_start > -1 ||
2048 sa->force_left_end > -1) {
2049 pick_primers_by_position(sa->force_left_start, sa->force_left_end,
2050 &left, &retval->fwd, pa, sa,
2051 dpal_arg_to_use, thal_arg_to_use, retval);
2052 }
2053 /* Or pick all good in the given range */
2054 else {
2055 pick_primer_range(start, length, &left, &retval->fwd,
2056 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2057 }
2058
2059 } /* if (pa->pick_left_primer) */
2060 if (retval->output_type == primer_list && pa->pick_right_primer == 1)
2061 r_b = 0;
2062 else if (tar_l+1>pr_min - pa->p_args.max_size
2063 && !(pa->pick_anyway && sa->right_input))
2064 r_b = tar_l+1;
2065 else
2066 r_b = pr_min - pa->p_args.max_size;
2067
2068 if ( pa->pick_right_primer ) {
2069
2070 /* We will need a right primer */
2071 length = n-pa->p_args.min_size - r_b + 1;
2072 start = r_b;
2073
2074 /* Use the primer provided */
2075 if (sa->right_input) {
2076 add_one_primer(sa->right_input, &right, &retval->rev,
2077 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2078 /* pick_right_primers(start, length, &right, &retval->rev,
2079 pa, sa, dpal_arg_to_use, retval);*/
2080
2081 }
2082 /* Pick primers at one position */
2083 else if(sa->force_right_start > -1 ||
2084 sa->force_right_end > -1) {
2085 pick_primers_by_position(sa->force_right_start, sa->force_right_end,
2086 &right, &retval->rev, pa, sa,
2087 dpal_arg_to_use, thal_arg_to_use, retval);
2088 }
2089 /* Or pick all good in the given range */
2090 else {
2091 pick_primer_range(start, length, &right, &retval->rev,
2092 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2093 }
2094 }
2095
2096 /*
2097 * Return 1 if either the left primer list or the right primer
2098 * list is empty or if leftmost left primer and
2099 * rightmost right primer do not provide sufficient product size.
2100 */
2101
2102 if ((pa->pick_left_primer && 0 == retval->fwd.num_elem)
2103 || ((pa->pick_right_primer) && 0 == retval->rev.num_elem)) {
2104 return 1;
2105 } else if (!((sa->right_input)
2106 && (sa->left_input))
2107 && pa->pick_left_primer
2108 && pa->pick_right_primer
2109 && (right - left) < (pr_min - 1)) {
2110 pair_expl->product = 1;
2111 pair_expl->considered = 1;
2112 return 1;
2113 } else return 0;
2114 } /* make_detection_primer_lists */
2115
2116 /*
2117 * Make complete list of acceptable internal oligos in retval->intl.oligo.
2118 * and place the number of valid elements in mid in retval->intl.num_elem. Return 1 if
2119 * there are no acceptable internal oligos; otherwise return 0.
2120 */
2121 static int
make_internal_oligo_list(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use)2122 make_internal_oligo_list(p3retval *retval,
2123 const p3_global_settings *pa,
2124 const seq_args *sa,
2125 const dpal_arg_holder *dpal_arg_to_use,
2126 const thal_arg_holder *thal_arg_to_use)
2127 {
2128 int ret;
2129 int left = 0;
2130
2131 /* Use the primer provided */
2132 if ((sa->internal_input) || (pa->primer_task == check_primers)){
2133 ret = add_one_primer(sa->internal_input, &left, &retval->intl,
2134 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2135 }
2136 else {
2137 /* Pick all good in the given range */
2138
2139 /* Use the settings to select a proper range */
2140 int length = strlen(sa->trimmed_seq) - pa->o_args.min_size;
2141 int start = pa->o_args.min_size - 1;
2142 int left = 0;
2143
2144 ret = pick_primer_range(start, length, &left, &retval->intl,
2145 pa, sa, dpal_arg_to_use, thal_arg_to_use,
2146 retval);
2147 }
2148 return ret;
2149 } /* make_internal_oligo_list */
2150
2151 /*
2152 * Make lists of acceptable left and right primers. After return, the
2153 * lists are stored in retval->fwd.oligo and retval->rev.oligo and the
2154 * coresponding list sizes are stored in retval->fwd.num_elem and
2155 * retval->rev.num_elem. Return 1 if one of lists is empty or if
2156 * leftmost left primer and rightmost right primer do not provide
2157 * sufficient product size.
2158 */
2159 static int
make_complete_primer_lists(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,const thal_arg_holder * thal_oligo_arg_to_use)2160 make_complete_primer_lists(p3retval *retval,
2161 const p3_global_settings *pa,
2162 const seq_args *sa,
2163 const dpal_arg_holder *dpal_arg_to_use,
2164 const thal_arg_holder *thal_arg_to_use,
2165 const thal_arg_holder *thal_oligo_arg_to_use)
2166 {
2167 int extreme;
2168 int length, start;
2169 int n;
2170
2171 /* Get the length of the sequence */
2172 PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2173 if (pa->pick_left_primer) {
2174 /* We will need a left primer. */
2175 extreme = 0;
2176 length = n - pa->p_args.min_size;
2177 start = pa->p_args.min_size - 1;
2178
2179 /* Pick all good in the given range */
2180 pick_primer_range(start, length, &extreme, &retval->fwd,
2181 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2182
2183 } /* if (pa->pick_left_primer) */
2184 if ( pa->pick_right_primer ) {
2185 /* We will need a right primer */
2186 extreme = n;
2187 length = n - pa->p_args.min_size + 1;
2188 start = 0;
2189
2190 /* Pick all good in the given range */
2191 pick_primer_range(start, length, &extreme, &retval->rev,
2192 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2193 }
2194
2195 if ( pa->pick_internal_oligo ) {
2196 /* We will need a internal oligo */
2197 length = n - pa->o_args.min_size;
2198 start = pa->o_args.min_size - 1;
2199 extreme = 0;
2200
2201 /* Pick all good in the given range */
2202 pick_primer_range(start, length, &extreme, &retval->intl,
2203 pa, sa, dpal_arg_to_use, thal_oligo_arg_to_use, retval);
2204 }
2205
2206 return 0;
2207 } /* make_complete_primer_lists */
2208
2209 /*
2210 * Add caller-specified primers to retval->fwd, retval->rev, and/or
2211 * retval->intl. The primers do not have to be "legal". It is possible
2212 * to add more than one primer to retval->fwd, etc, if the input
2213 * primer is found in multiple locations in the template. Similar to
2214 * make_complete_primer_lists.
2215 */
2216 static int
add_primers_to_check(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,const thal_arg_holder * thal_oligo_arg_to_use)2217 add_primers_to_check(p3retval *retval,
2218 const p3_global_settings *pa,
2219 const seq_args *sa,
2220 const dpal_arg_holder *dpal_arg_to_use,
2221 const thal_arg_holder *thal_arg_to_use,
2222 const thal_arg_holder *thal_oligo_arg_to_use)
2223 {
2224 int extreme = 0; /* Required when calling add_one_primer
2225 but not used in the current function. */
2226
2227 if (sa->left_input) {
2228 add_one_primer(sa->left_input, &extreme, &retval->fwd,
2229 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2230 }
2231
2232 if (sa->right_input) {
2233 add_one_primer(sa->right_input, &extreme, &retval->rev,
2234 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2235 }
2236
2237 if (sa->internal_input) {
2238 add_one_primer(sa->internal_input, &extreme, &retval->intl,
2239 pa, sa, dpal_arg_to_use, thal_oligo_arg_to_use, retval);
2240 }
2241
2242 return 0;
2243 } /* add_primers_to_check */
2244
2245 /*
2246 * Make lists of acceptable left and right primers. After return, the
2247 * lists are stored in retval->fwd.oligo and retval->rev.oligo and the
2248 * coresponding list sizes are stored in retval->fwd.num_elem and
2249 * retval->rev.num_elem. Return 1 if one of lists is empty or if
2250 * leftmost left primer and rightmost right primer do not provide
2251 * sufficient product size.
2252 */
2253 static int
pick_sequencing_primer_list(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use)2254 pick_sequencing_primer_list(p3retval *retval,
2255 const p3_global_settings *pa,
2256 const seq_args *sa,
2257 const dpal_arg_holder *dpal_arg_to_use,
2258 const thal_arg_holder *thal_arg_to_use)
2259 {
2260 int length, start;
2261 int n, rest_accuracy;
2262 int primer_nr; /* number of primers we need to pick */
2263 int tar_n; /* counter for the targets */
2264 int step_nr; /* counter to step through the targets */
2265 int sequenced_len; /* bp sequenced in good quality */
2266 int extra_seq; /* bp sequenced additionally on both sides */
2267
2268 /* best location for the 3' end of the fwd primer: */
2269 int pr_position_f;
2270
2271 /* best location for the 3' end of the rev primer: */
2272 int pr_position_r;
2273
2274 /* Get the length of the sequence */
2275 PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2276
2277 /* For each target needed loop*/
2278 for (tar_n=0; tar_n < sa->tar2.count; tar_n++) {
2279
2280 /* Calculate the amount of primers needed */
2281 primer_nr = 1;
2282 if ((pa->pick_left_primer) && (pa->pick_right_primer)){
2283 sequenced_len = pa->sequencing.interval;
2284 while(sequenced_len < sa->tar2.pairs[tar_n][1]) {
2285 primer_nr++;
2286 sequenced_len = pa->sequencing.spacing * (primer_nr - 1)
2287 + pa->sequencing.interval;
2288 }
2289 } else {
2290 sequenced_len = pa->sequencing.spacing;
2291 while(sequenced_len < sa->tar2.pairs[tar_n][1]) {
2292 primer_nr++;
2293 sequenced_len = pa->sequencing.spacing * primer_nr;
2294 }
2295 }
2296 /* Calculate the overlap on the sides */
2297 extra_seq = (sequenced_len - sa->tar2.pairs[tar_n][1]) / 2;
2298
2299 /* Pick primers for each position */
2300 for ( step_nr = 0 ; step_nr < primer_nr ; step_nr++ ) {
2301 pr_position_f = sa->tar2.pairs[tar_n][0] - extra_seq
2302 + ( pa->sequencing.spacing * step_nr )
2303 - pa->sequencing.lead;
2304 if ((pa->pick_left_primer) && (pa->pick_right_primer)) {
2305 pr_position_r = sa->tar2.pairs[tar_n][0] - extra_seq
2306 + ( pa->sequencing.spacing * step_nr )
2307 + pa->sequencing.interval
2308 + pa->sequencing.lead;
2309 } else {
2310 pr_position_r = sa->tar2.pairs[tar_n][0] - extra_seq
2311 + ( pa->sequencing.spacing * (step_nr+1))
2312 + pa->sequencing.lead;
2313 }
2314 /* Check if calculated positions make sense */
2315 /* position_f cannot be outside included region */
2316 if (pr_position_f < (pa->p_args.min_size -1)) {
2317 pr_position_f = pa->p_args.min_size - 1;
2318 }
2319 if (pr_position_f > (n - pa->p_args.min_size - 1)) {
2320 pr_position_f = n - pa->p_args.min_size - 1;
2321 /* Actually this should never happen */
2322 pr_append_new_chunk(&retval->warnings,
2323 "Calculation error in forward "
2324 "sequencing position calculation");
2325 }
2326 /* position_r cannot be outside included region */
2327 if (pr_position_r < (pa->p_args.min_size - 1)) {
2328 pr_position_r = pa->p_args.min_size - 1;
2329 /* Actually this should never happen */
2330 pr_append_new_chunk(&retval->warnings,
2331 "Calculation error in reverse "
2332 "sequencing position calculation");
2333 }
2334 if (pr_position_r > (n - pa->p_args.min_size - 1)) {
2335 pr_position_r = n - pa->p_args.min_size - 1;
2336 }
2337 /* Now all pr_positions are within the sequence */
2338 if (pa->pick_left_primer) {
2339 /* Set the start and length for the regions */
2340 start = pr_position_f - pa->sequencing.accuracy;
2341 if (start < 0) {
2342 rest_accuracy = pr_position_f + 1;
2343 start = 0;
2344 } else {
2345 rest_accuracy = pa->sequencing.accuracy;
2346 }
2347 length = rest_accuracy + pa->sequencing.accuracy ;
2348 if ((start + length) > n) {
2349 length = n - start;
2350 }
2351 /* Pick all good in the given range */
2352 pick_only_best_primer(start, length, &retval->fwd,
2353 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2354 }
2355 if (pa->pick_right_primer) {
2356 start = pr_position_r - pa->sequencing.accuracy;
2357 if (start < 0) {
2358 rest_accuracy = pr_position_r + 1;
2359 start = 0;
2360 } else {
2361 rest_accuracy = pa->sequencing.accuracy;
2362 }
2363 length = rest_accuracy + pa->sequencing.accuracy ;
2364 if ((start + length) > n) {
2365 length = n - start;
2366 }
2367 /* Pick all good in the given range */
2368 pick_only_best_primer(start, length, &retval->rev,
2369 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2370 }
2371 }
2372
2373 } /* End of Target Loop */
2374
2375 /* Print an error if not all primers will be printed */
2376 if (retval->fwd.num_elem > pa->num_return
2377 || retval->rev.num_elem > pa->num_return) {
2378 pr_append_new_chunk( &retval->warnings,
2379 "Increase PRIMER_NUM_RETURN to obtain all sequencing primers");
2380 }
2381
2382 return 0;
2383 } /* pick_sequencing_primer_list */
2384
2385 static void
add_oligo_to_oligo_array(oligo_array * oarray,primer_rec orec)2386 add_oligo_to_oligo_array(oligo_array *oarray, primer_rec orec) {
2387 /* Allocate some space for primers if needed */
2388 if (NULL == oarray->oligo) {
2389 oarray->storage_size = INITIAL_LIST_LEN;
2390 oarray->oligo
2391 = (primer_rec *)
2392 pr_safe_malloc(sizeof(*oarray->oligo) * oarray->storage_size);
2393 }
2394 /* If there is no space on the array, allocate new space */
2395 if ((oarray->num_elem + 1) >= oarray->storage_size) { /* TO DO, is +1 really needed? */
2396 oarray->storage_size += (oarray->storage_size >> 1);
2397 oarray->oligo
2398 = (primer_rec *)
2399 pr_safe_realloc(oarray->oligo,
2400 oarray->storage_size * sizeof(*oarray->oligo));
2401 }
2402 oarray->oligo[oarray->num_elem] = orec;
2403 oarray->num_elem++;
2404 }
2405
2406 /* pick_primer_range picks all primers which have their 3' end in the range
2407 * from start to start+length and store only the best *oligo */
2408 static int
pick_only_best_primer(const int start,const int length,oligo_array * oligo,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,p3retval * retval)2409 pick_only_best_primer(const int start,
2410 const int length,
2411 oligo_array *oligo,
2412 const p3_global_settings *pa,
2413 const seq_args *sa,
2414 const dpal_arg_holder *dpal_arg_to_use,
2415 const thal_arg_holder *thal_arg_to_use,
2416 p3retval *retval)
2417 {
2418 /* Variables for the loop */
2419 int i, j, primer_size_small, primer_size_large;
2420 int n, found_primer;
2421 char number[20];
2422 char *p_number = &number[0];
2423 int temp_value;
2424
2425 /* Array to store one primer sequences in */
2426 char oligo_seq[MAX_PRIMER_LENGTH+1];
2427
2428 /* Struct to store the primer parameters in */
2429 primer_rec h;
2430 primer_rec best;
2431 memset(&h, 0, sizeof(primer_rec));
2432 memset(&best, 0, sizeof(primer_rec));
2433 best.quality = 1000.00;
2434 found_primer = 0;
2435
2436 /* Set n to the length of included region */
2437 PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2438
2439 /* Conditions for primer length */
2440 if (oligo->type == OT_INTL) {
2441 primer_size_small=pa->o_args.min_size;
2442 primer_size_large=pa->o_args.max_size;
2443 }
2444 else {
2445 primer_size_small=pa->p_args.min_size;
2446 primer_size_large=pa->p_args.max_size;
2447 }
2448
2449 /* Loop over locations in the sequence */
2450 for(i = start + length - 1; i >= start; i--) {
2451 oligo_seq[0] = '\0';
2452
2453 /* Loop over possible primer lengths, from min to max */
2454 for (j = primer_size_small; j <= primer_size_large; j++) {
2455 /* Set the length of the primer */
2456 h.length = j;
2457
2458 /* Set repeat_sim to NULL as indicator that the repeat_sim
2459 struct is not initialized. */
2460 h.repeat_sim.score = NULL;
2461
2462 /* Figure out positions for left primers and internal oligos */
2463 if (oligo->type != OT_RIGHT) {
2464 /* Break if the primer is bigger than the sequence left */
2465 if(i-j < -1) continue;
2466
2467 /* Set the start of the primer */
2468 h.start = i - j + 1;
2469
2470 /* Put the real primer sequence in oligo_seq */
2471 _pr_substr(sa->trimmed_seq, h.start, j, oligo_seq);
2472 } else {
2473 /* Figure out positions for reverse primers */
2474 /* Break if the primer is bigger than the sequence left*/
2475 if(i+j > n) continue;
2476
2477 /* Set the start of the primer */
2478 h.start = i+j-1;
2479
2480 /* Put the real primer sequence in s */
2481 _pr_substr(sa->trimmed_seq, i, j, oligo_seq);
2482
2483 }
2484
2485 /* Do not force primer3 to use this oligo */
2486 h.must_use = 0;
2487
2488 h.overlaps = 0;
2489
2490 /* Add it to the considered statistics */
2491 oligo->expl.considered++;
2492 /* Calculate all the primer parameters */
2493 calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
2494 sa, &oligo->expl, retval, oligo_seq);
2495
2496 /* If primer has to be used or is OK */
2497 if (OK_OR_MUST_USE(&h)) {
2498 /* Calculate the penalty */
2499 h.quality = p_obj_fn(pa, &h, oligo->type);
2500 /* Save the primer in the array */
2501 if (h.quality < best.quality) {
2502 /* Free memory used by previous best primer. */
2503 free_primer_repeat_sim_score(&best);
2504 best = h;
2505 found_primer = 1;
2506 } else {
2507 /* Free memory used by this primer. */
2508 free_primer_repeat_sim_score(&h);
2509 }
2510 }
2511 else {
2512 /* Free memory used by this primer. */
2513 free_primer_repeat_sim_score(&h);
2514 if (any_5_prime_ol_extension_has_problem(&h)) {
2515 /* Break from the inner for loop, because there is no
2516 legal longer oligo with the same 3' sequence. */
2517 break;
2518 }
2519 }
2520 } /* j: Loop over possible primer length from min to max */
2521 } /* i: Loop over the sequence */
2522
2523 if (found_primer == 1) {
2524 /* Add the best to the array */
2525 add_oligo_to_oligo_array(oligo, best);
2526 /* Update statistics with how many primers are good */
2527 oligo->expl.ok = oligo->expl.ok + 1;
2528 } else {
2529 if (oligo->type == OT_RIGHT) {
2530 pr_append_new_chunk(&retval->warnings, "No right primer found in range ");
2531 } else {
2532 pr_append_new_chunk(&retval->warnings, "No left primer found in range ");
2533 }
2534 temp_value = start + pa->first_base_index;
2535 sprintf(p_number, "%d", temp_value);
2536 pr_append(&retval->warnings, p_number);
2537 pr_append(&retval->warnings, " - ");
2538 temp_value = start + length + pa->first_base_index;
2539 sprintf(p_number, "%d", temp_value);
2540 pr_append(&retval->warnings, p_number);
2541 }
2542 if (oligo->num_elem == 0) return 1;
2543 else return 0;
2544 } /* pick_only_best_primer */
2545
2546 /* pick_primer_range picks all legal primers in the range from start
2547 to start+length and stores them in *oligo */
2548 static int
pick_primer_range(const int start,const int length,int * extreme,oligo_array * oligo,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,p3retval * retval)2549 pick_primer_range(const int start, const int length, int *extreme,
2550 oligo_array *oligo, const p3_global_settings *pa,
2551 const seq_args *sa,
2552 const dpal_arg_holder *dpal_arg_to_use,
2553 const thal_arg_holder *thal_arg_to_use,
2554 p3retval *retval)
2555 {
2556 /* Variables for the loop */
2557 int i, j;
2558 int primer_size_small, primer_size_large;
2559 int pr_min, n;
2560
2561 /* Array to store one primer sequences in */
2562 char oligo_seq[MAX_PRIMER_LENGTH+1];
2563
2564 /* Struct to store the primer parameters in */
2565 primer_rec h;
2566 memset(&h, 0, sizeof(primer_rec));
2567
2568 /* Set pr_min to the very smallest
2569 allowable product size. */
2570 pr_min = INT_MAX;
2571 for (i=0; i < pa->num_intervals; i++)
2572 if(pa->pr_min[i] < pr_min)
2573 pr_min = pa->pr_min[i];
2574
2575 /* Set n to the length of included region */
2576 PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2577
2578 if (oligo->type == OT_INTL) {
2579 primer_size_small=pa->o_args.min_size;
2580 primer_size_large=pa->o_args.max_size;
2581 }
2582 else {
2583 primer_size_small=pa->p_args.min_size;
2584 primer_size_large=pa->p_args.max_size;
2585 }
2586
2587 /* Loop over locations in the sequence */
2588 for(i = start + length; i >= start; i--) {
2589 oligo_seq[0] = '\0';
2590
2591 /* Loop over possible primer lengths, from min to max */
2592 for (j = primer_size_small; j <= primer_size_large; j++) {
2593
2594 /* Set the length of the primer */
2595 h.length = j;
2596
2597 /* Figure out positions for left primers and internal oligos */
2598 if (oligo->type != OT_RIGHT) {
2599 /* Check if the product is of sufficient size */
2600 if (i-j > n-pr_min-1 && retval->output_type == primer_pairs
2601 && oligo->type == OT_LEFT) continue;
2602
2603 /* Break if the primer is bigger than the sequence left */
2604 if (i-j < -1) break;
2605
2606 /* Set the start of the primer */
2607 h.start = i - j + 1;
2608
2609 /* Put the real primer sequence in oligo_seq */
2610 _pr_substr(sa->trimmed_seq, h.start, j, oligo_seq);
2611 } else {
2612 /* Figure out positions for reverse primers */
2613 /* Check if the product is of sufficient size */
2614 if (i+j < pr_min && retval->output_type == primer_pairs) continue;
2615
2616 /* Break if the primer is bigger than the sequence left*/
2617 if (i+j > n) break;
2618
2619 /* Set the start of the primer */
2620 h.start = i+j-1;
2621
2622 /* Put the real primer sequence in s */
2623 _pr_substr(sa->trimmed_seq, i, j, oligo_seq);
2624
2625 }
2626
2627 /* Do not force primer3 to use this oligo */
2628 h.must_use = 0;
2629
2630 h.overlaps = 0;
2631
2632 /* Add it to the considered statistics */
2633 oligo->expl.considered++;
2634 /* Calculate all the primer parameters */
2635 calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
2636 sa, &oligo->expl, retval, oligo_seq);
2637 /* If primer has to be used or is OK */
2638 if (OK_OR_MUST_USE(&h)) {
2639 /* Calculate the penalty */
2640 h.quality = p_obj_fn(pa, &h, oligo->type);
2641 /* Save the primer in the array */
2642 add_oligo_to_oligo_array(oligo, h);
2643 /* Update the most extreme primer variable */
2644 if (( h.start < *extreme) && (oligo->type != OT_RIGHT))
2645 *extreme = h.start;
2646 /* Update the most extreme primer variable */
2647 if ((h.start > *extreme) && (oligo->type == OT_RIGHT))
2648 *extreme = h.start;
2649 } else {
2650 /* Free memory used by this primer. */
2651 free_primer_repeat_sim_score(&h);
2652 if (any_5_prime_ol_extension_has_problem(&h)) {
2653 /* Break from the inner for loop, because there is no
2654 legal longer oligo with the same 3' sequence. */
2655 break;
2656 }
2657 }
2658 } /* j: Loop over possible primer length from min to max */
2659 } /* i: Loop over the sequence */
2660
2661 /* Update statistics with how many primers are good */
2662 oligo->expl.ok = oligo->num_elem;
2663
2664 if (oligo->num_elem == 0) return 1;
2665 else return 0;
2666 } /* pick_primer_range */
2667
2668 /* add_one_primer finds one primer in the trimmed sequence and stores
2669 * it in *oligo The main difference to the general fuction is that it
2670 * calculates its length and it will add a primer of any length to the
2671 * list */
2672 static int
add_one_primer(const char * primer,int * extreme,oligo_array * oligo,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,p3retval * retval)2673 add_one_primer(const char *primer, int *extreme, oligo_array *oligo,
2674 const p3_global_settings *pa,
2675 const seq_args *sa,
2676 const dpal_arg_holder *dpal_arg_to_use,
2677 const thal_arg_holder *thal_arg_to_use,
2678 p3retval *retval) {
2679 /* Variables for the loop */
2680 int i, j;
2681 int n;
2682
2683 /* Array to store one primer sequences in */
2684 char oligo_seq[MAX_PRIMER_LENGTH+1] , test_oligo[MAX_PRIMER_LENGTH+1];
2685
2686 /* Struct to store the primer parameters in */
2687 primer_rec h;
2688 memset(&h, 0, sizeof(primer_rec));
2689
2690 /* Copy *primer into test_oligo */
2691 test_oligo[0] = '\0';
2692 if (oligo->type != OT_RIGHT) {
2693 strncat(test_oligo, primer, MAX_PRIMER_LENGTH);
2694 } else {
2695 p3_reverse_complement(primer, test_oligo);
2696 }
2697
2698 PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2699
2700 /* This time we already know the size of the primer */
2701 j = strlen(primer);
2702
2703 /* Loop over the whole sequence */
2704 for(i = strlen(sa->trimmed_seq); i >= 0; i--) {
2705 oligo_seq[0] = '\0';
2706
2707 /* Set the length of the primer */
2708 h.length = j;
2709
2710 /* Figure out positions for forward primers */
2711 if (oligo->type != OT_RIGHT) {
2712 /* Break if the primer is bigger than the sequence left*/
2713 if(i-j < -1) continue;
2714
2715 /* Set the start of the primer */
2716 h.start = i - j +1;
2717
2718 /* Put the real primer sequence in s */
2719 _pr_substr(sa->trimmed_seq, h.start, j, oligo_seq);
2720 }
2721 /* Figure out positions for reverse primers */
2722 else {
2723 /* Break if the primer is bigger than the sequence left*/
2724 if(i+j>n) continue;
2725
2726 /* Set the start of the primer */
2727 h.start=i+j-1;
2728
2729 /* Put the real primer sequence in s */
2730 _pr_substr(sa->trimmed_seq, i, j, oligo_seq);
2731 }
2732
2733 /* Compare the primer with the sequence */
2734 if (strcmp_nocase(test_oligo, oligo_seq))
2735 continue;
2736
2737 /* Force primer3 to use this oligo */
2738 h.must_use = (1 && pa->pick_anyway);
2739
2740 h.overlaps = 0;
2741
2742 /* Add it to the considered statistics */
2743 oligo->expl.considered++;
2744
2745 /* Calculate all the primer parameters */
2746 calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
2747 sa, &oligo->expl, retval, oligo_seq);
2748
2749 /* If primer has to be used or is OK */
2750 if (OK_OR_MUST_USE(&h)) {
2751 /* Calculate the penalty */
2752 h.quality = p_obj_fn(pa, &h, oligo->type);
2753 /* Save the primer in the array */
2754 add_oligo_to_oligo_array(oligo, h);
2755 /* Update the most extreme primer variable */
2756 if ((h.start < *extreme) && (oligo->type != OT_RIGHT))
2757 *extreme = h.start;
2758 /* Update the most extreme primer variable */
2759 if ((h.start > *extreme) && (oligo->type == OT_RIGHT))
2760 *extreme = h.start;
2761 } else {
2762 /* Free memory used by this primer. */
2763 free_primer_repeat_sim_score(&h);
2764 }
2765 } /* i: Loop over the sequence */
2766 /* Update array with how many primers are good */
2767 /* Update statistics with how many primers are good */
2768 oligo->expl.ok = oligo->num_elem;
2769
2770 if (oligo->num_elem == 0) return 1;
2771 else {
2772 if (oligo->num_elem > 1) {
2773 pr_append_new_chunk(&retval->warnings,
2774 "More than one position in template for input oligo ");
2775 pr_append(&retval->warnings, primer);
2776 }
2777 return 0; /* Success */
2778 }
2779 }
2780
2781 /* add_one_primer finds one primer in the trimmed sequence and stores
2782 * it in *oligo The main difference to the general fuction is that it
2783 * calculates its length and it will add a primer of any length to the
2784 * list */
2785 static int
add_one_primer_by_position(int start,int length,int * extreme,oligo_array * oligo,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,p3retval * retval)2786 add_one_primer_by_position(int start, int length, int *extreme, oligo_array *oligo,
2787 const p3_global_settings *pa,
2788 const seq_args *sa,
2789 const dpal_arg_holder *dpal_arg_to_use,
2790 const thal_arg_holder *thal_arg_to_use,
2791 p3retval *retval) {
2792 /* Variables for the loop */
2793 int i;
2794 int n, found_primer;
2795
2796 /* Array to store one primer sequences in */
2797 char oligo_seq[MAX_PRIMER_LENGTH+1];
2798
2799 /* Struct to store the primer parameters in */
2800 primer_rec h;
2801 memset(&h, 0, sizeof(primer_rec));
2802
2803 /* Retun 1 for no primer found */
2804 found_primer = 1;
2805
2806 PR_ASSERT(INT_MAX > (n=strlen(sa->trimmed_seq)));
2807
2808 /* Just to be sure */
2809 if (start < 0) {
2810 return 1;
2811 }
2812 if (start >= n) {
2813 return 1;
2814 }
2815 if (oligo->type != OT_RIGHT) {
2816 if ((start + length) > n) {
2817 return 1;
2818 }
2819 } else {
2820 if ((start - length + 1) < 0) {
2821 return 1;
2822 }
2823 }
2824
2825 oligo_seq[0] = '\0';
2826
2827 /* Set the length of the primer */
2828 h.length = length;
2829
2830 /* Figure out positions for forward primers */
2831 if (oligo->type != OT_RIGHT) {
2832 /* Set the start of the primer */
2833 h.start = start;
2834
2835 /* Put the real primer sequence in s */
2836 _pr_substr(sa->trimmed_seq, h.start, length, oligo_seq);
2837 }
2838 /* Figure out positions for reverse primers */
2839 else {
2840 i = start - length + 1;
2841 /* Set the start of the primer */
2842 h.start = start;
2843
2844 /* Put the real primer sequence in s */
2845 _pr_substr(sa->trimmed_seq, i, length, oligo_seq);
2846 }
2847
2848 /* Force primer3 to use this oligo */
2849 h.must_use = (1 && pa->pick_anyway);
2850
2851 h.overlaps = 0;
2852
2853 /* Add it to the considered statistics */
2854 oligo->expl.considered++;
2855
2856 /* Calculate all the primer parameters */
2857 calc_and_check_oligo_features(pa, &h, oligo->type, dpal_arg_to_use, thal_arg_to_use,
2858 sa, &oligo->expl, retval, oligo_seq);
2859
2860 /* If primer has to be used or is OK */
2861 if (OK_OR_MUST_USE(&h)) {
2862 /* Calculate the penalty */
2863 h.quality = p_obj_fn(pa, &h, oligo->type);
2864 /* Save the primer in the array */
2865 add_oligo_to_oligo_array(oligo, h);
2866 found_primer = 0;
2867 /* Update the most extreme primer variable */
2868 if (( h.start < *extreme) &&
2869 (oligo->type != OT_RIGHT))
2870 *extreme = h.start;
2871 /* Update the most extreme primer variable */
2872 if (( h.start > *extreme) &&
2873 (oligo->type == OT_RIGHT))
2874 *extreme = h.start;
2875 /* Update the number of primers */
2876 } else {
2877 /* Free memory used by this primer. */
2878 free_primer_repeat_sim_score(&h);
2879 }
2880 /* Update array with how many primers are good */
2881 /* Update statistics with how many primers are good */
2882 oligo->expl.ok = oligo->num_elem;
2883
2884 /* return 0 for success */
2885 return found_primer;
2886 }
2887
2888 static int
pick_primers_by_position(const int start,const int end,int * extreme,oligo_array * oligo,const p3_global_settings * pa,const seq_args * sa,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,p3retval * retval)2889 pick_primers_by_position(const int start, const int end, int *extreme,
2890 oligo_array *oligo, const p3_global_settings *pa,
2891 const seq_args *sa,
2892 const dpal_arg_holder *dpal_arg_to_use,
2893 const thal_arg_holder *thal_arg_to_use,
2894 p3retval *retval)
2895 {
2896 int found_primer, length, j, ret, new_start;
2897 found_primer = 1;
2898 ret = 1;
2899
2900 if(start > -1 && end > -1) {
2901 if (oligo->type != OT_RIGHT) {
2902 length = end - start + 1;
2903 } else {
2904 length = start - end + 1;
2905 }
2906
2907 found_primer = add_one_primer_by_position(start, length, extreme, oligo,
2908 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2909 return found_primer;
2910 } else if (start > -1) {
2911 /* Loop over possible primer lengths, from min to max */
2912 ret = 0;
2913 for (j = pa->p_args.min_size; j <= pa->p_args.max_size; j++) {
2914 ret += add_one_primer_by_position(start, j, extreme, oligo,
2915 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2916 if (ret == 0) {
2917 found_primer = 0;
2918 }
2919 }
2920 return found_primer;
2921 } else if (end > -1) {
2922 /* Loop over possible primer lengths, from min to max */
2923 ret = 0;
2924 for (j = pa->p_args.min_size; j <= pa->p_args.max_size; j++) {
2925 if (oligo->type != OT_RIGHT) {
2926 new_start = end - j + 1;
2927 } else {
2928 new_start = end + j - 1;
2929 }
2930 ret += add_one_primer_by_position(new_start, j, extreme, oligo,
2931 pa, sa, dpal_arg_to_use, thal_arg_to_use, retval);
2932 if (ret == 0) {
2933 found_primer = 0;
2934 }
2935 }
2936 return found_primer;
2937 } else {
2938 /* Actually this should never happen */
2939 pr_append_new_chunk(&retval->warnings,
2940 "Calculation error in forced primer position calculation");
2941 return 1;
2942 }
2943 }
2944
2945 /*
2946 * Compute various characteristics of the oligo, and determine
2947 * if it is acceptable.
2948 */
2949 #define OUTSIDE_START_WT 30.0
2950 #define INSIDE_START_WT 20.0
2951 #define INSIDE_STOP_WT 100.0
2952 #define OUTSIDE_STOP_WT 0.5
2953 static void
calc_and_check_oligo_features(const p3_global_settings * pa,primer_rec * h,oligo_type otype,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,const seq_args * sa,oligo_stats * stats,p3retval * retval,const char * input_oligo_seq)2954 calc_and_check_oligo_features(const p3_global_settings *pa,
2955 primer_rec *h,
2956 oligo_type otype,
2957 const dpal_arg_holder *dpal_arg_to_use,
2958 const thal_arg_holder *thal_arg_to_use,
2959 const seq_args *sa,
2960 oligo_stats *stats,
2961 p3retval *retval,
2962
2963 /* This is 5'->3' on the template sequence: */
2964 const char *input_oligo_seq
2965 )
2966 {
2967 int i, j, k, for_i, gc_count;
2968 int three_prime_pos; /* position of 3' base of oligo */
2969 oligo_type l = otype;
2970 int poly_x, max_poly_x;
2971 int must_use = h->must_use;
2972 int three_conditions
2973 = (must_use || pa->file_flag || retval->output_type == primer_list);
2974 const char *seq = sa->trimmed_seq;
2975 const thal_args *thal_args_for_template_mispriming
2976 = use_end_for_th_template_mispriming
2977 ? thal_arg_to_use->end1
2978 : thal_arg_to_use->any;
2979
2980 char s1_rev[MAX_PRIMER_LENGTH+1];
2981 const char *oligo_seq;
2982 const char *revc_oligo_seq;
2983
2984 const args_for_one_oligo_or_primer *po_args;
2985
2986 /* Initialize slots in h */
2987 initialize_op(h);
2988 h->overlaps = 0;
2989
2990 /* Set repeat_sim to NULL as indicator that the repeat_sim
2991 struct is not initialized. */
2992 h->repeat_sim.score = NULL;
2993
2994 h->gc_content = h->num_ns = 0;
2995 h->overlaps_overlap_position = 0;
2996 h->template_mispriming = h->template_mispriming_r = ALIGN_SCORE_UNDEF;
2997 h->template_mispriming_ok = 0;
2998
2999 PR_ASSERT(OT_LEFT == l || OT_RIGHT == l || OT_INTL == l);
3000
3001 p3_reverse_complement(input_oligo_seq, s1_rev);
3002 if (OT_RIGHT == l) {
3003 oligo_seq = s1_rev;
3004 revc_oligo_seq = input_oligo_seq;
3005 } else {
3006 oligo_seq = input_oligo_seq;
3007 revc_oligo_seq = s1_rev;
3008 }
3009
3010 if (OT_INTL == l) {
3011 po_args = &pa->o_args;
3012 } else {
3013 po_args = &pa->p_args;
3014 }
3015
3016 /* Set j and k, and sanity check */
3017 if (OT_LEFT == otype || OT_INTL == otype) {
3018 j = h->start;
3019 three_prime_pos = k = j+h->length-1;
3020 } else {
3021 three_prime_pos = j = h->start-h->length+1;
3022 k = h->start;
3023 }
3024 PR_ASSERT(k >= 0);
3025 PR_ASSERT(k < TRIMMED_SEQ_LEN(sa));
3026
3027 if ((otype == OT_LEFT) && !PR_START_CODON_POS_IS_NULL(sa)
3028 /* Make sure the primer would amplify at least part of
3029 the ORF. */
3030 && (0 != (h->start - sa->start_codon_pos) % 3
3031 || h->start <= retval->upstream_stop_codon
3032 || (retval->stop_codon_pos != -1
3033 && h->start >= retval->stop_codon_pos))) {
3034 stats->no_orf++;
3035 op_set_does_not_amplify_orf(h);
3036 if (!pa->pick_anyway) return;
3037 }
3038
3039 /* edited by T. Koressaar for lowercase masking */
3040 if(pa->lowercase_masking == 1) {
3041 if (is_lowercase_masked(three_prime_pos,
3042 sa->trimmed_orig_seq,
3043 h, stats)) {
3044 if (!must_use) return;
3045 }
3046 }
3047 /* end T. Koressar's changes */
3048
3049 /* edited by A. Untergasser for forcing sequence use */
3050 if ((po_args->must_match_five_prime != NULL) or
3051 (po_args->must_match_three_prime != NULL)) {
3052 if (primer_must_match(pa, h, stats, oligo_seq,
3053 po_args->must_match_three_prime,
3054 po_args->must_match_five_prime)) {
3055 if (!must_use) {
3056 op_set_must_match_err(h);
3057 return;
3058 }
3059 }
3060 }
3061 /* end A. Untergasser's changes */
3062
3063 gc_and_n_content(j, k-j+1, sa->trimmed_seq, h);
3064
3065 if (h->num_ns > po_args->num_ns_accepted) {
3066 op_set_too_many_ns(h);
3067 stats->ns++;
3068 if (!must_use) return;
3069 }
3070
3071 /* Upstream error checking has ensured that we use non-default position
3072 penalties only when there is 0 or 1 target. */
3073 PR_ASSERT(sa->tar2.count <= 1 || _PR_DEFAULT_POSITION_PENALTIES(pa));
3074
3075 if (pa->primer_task == pick_sequencing_primers) {
3076 h->position_penalty = 0.0;
3077 } else if (l != OT_INTL
3078 && _PR_DEFAULT_POSITION_PENALTIES(pa)
3079 && oligo_overlaps_interval(j, k-j+1, sa->tar2.pairs, sa->tar2.count)) {
3080 h->position_penalty = 0.0;
3081 bf_set_infinite_pos_penalty(h,1);
3082 bf_set_overlaps_target(h,1);
3083 } else if (l != OT_INTL && !_PR_DEFAULT_POSITION_PENALTIES(pa)
3084 && 1 == sa->tar2.count) {
3085 compute_position_penalty(pa, sa, h, l);
3086 if (bf_get_infinite_pos_penalty(h)) {
3087 bf_set_overlaps_target(h,1);
3088 }
3089 } else {
3090 h->position_penalty = 0.0;
3091 bf_set_infinite_pos_penalty(h,0);
3092 }
3093
3094 if (!PR_START_CODON_POS_IS_NULL(sa)) {
3095 if (OT_LEFT == l) {
3096 if (sa->start_codon_pos > h->start)
3097 h->position_penalty
3098 = (sa->start_codon_pos - h->start) * OUTSIDE_START_WT;
3099 else
3100 h->position_penalty
3101 = (h->start - sa->start_codon_pos) * INSIDE_START_WT;
3102 } else if (OT_RIGHT == l) {
3103
3104 if (-1 == retval->stop_codon_pos) {
3105 h->position_penalty = (TRIMMED_SEQ_LEN(sa) - h->start - 1) * INSIDE_STOP_WT;
3106 } else if (retval->stop_codon_pos < h->start) {
3107 h->position_penalty
3108 = (h->start - retval->stop_codon_pos) * OUTSIDE_STOP_WT;
3109 } else {
3110 h->position_penalty
3111 = (retval->stop_codon_pos - h->start) * INSIDE_STOP_WT;
3112 }
3113 }
3114 }
3115
3116 /* TO DO Simplify logic here */
3117 if (l != OT_INTL
3118 && oligo_overlaps_interval(j, k-j+1, sa->excl2.pairs, sa->excl2.count))
3119 bf_set_overlaps_excl_region(h,1);
3120
3121 if (l == OT_INTL
3122 && oligo_overlaps_interval(j, k-j+1, sa->excl_internal2.pairs,
3123 sa->excl_internal2.count))
3124 bf_set_overlaps_excl_region(h,1);
3125
3126 if(l != OT_INTL && bf_get_overlaps_target(h)) {
3127 op_set_overlaps_target(h);
3128 stats->target++;
3129 if (!must_use) return;
3130 }
3131
3132 if(bf_get_overlaps_excl_region(h)){
3133 op_set_overlaps_excluded_region(h);
3134 stats->excluded++;
3135 if (!must_use) return;
3136 }
3137
3138 /* Check if the oligo is included in any ok region */
3139 if ((l == OT_LEFT) && (sa->ok_regions.count > 0) && (!sa->ok_regions.any_left)) {
3140 int included = 0;
3141 for (i=0; i<sa->ok_regions.count; i++) {
3142 if ((j >= sa->ok_regions.left_pairs[i][0]) &&
3143 (k <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1)) {
3144 included = 1;
3145 break;
3146 }
3147 }
3148 if (!included) {
3149 op_set_not_in_any_ok_region(h);
3150 stats->not_in_any_left_ok_region++;
3151 if (!must_use) return;
3152 }
3153 }
3154 if ((l == OT_RIGHT) && (sa->ok_regions.count > 0) && (!sa->ok_regions.any_right)) {
3155 int included = 0;
3156 for (i=0; i<sa->ok_regions.count; i++) {
3157 if ((j >= sa->ok_regions.right_pairs[i][0]) &&
3158 (k <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)) {
3159 included = 1;
3160 break;
3161 }
3162 }
3163 if (!included) {
3164 op_set_not_in_any_ok_region(h);
3165 stats->not_in_any_right_ok_region++;
3166 if (!must_use) return;
3167 }
3168 }
3169
3170 if (h->gc_content < po_args->min_gc) {
3171 op_set_low_gc_content(h);
3172 stats->gc++;
3173 if (!must_use) return;
3174 } else if (h->gc_content > po_args->max_gc) {
3175 op_set_high_gc_content(h);
3176 stats->gc++;
3177 if (!must_use) return;
3178 }
3179
3180 if (OT_LEFT == l || OT_RIGHT == l) {
3181 /* gc_clamp is applicable only to primers (as opposed
3182 to primers and hybridzations oligos. */
3183 for (i = 0; i < pa->gc_clamp; i++) {
3184 /* We want to look at the 3' end of the oligo being
3185 assessed, so we look in the 5' end of its reverse-complement */
3186 if (revc_oligo_seq[i] != 'G' && revc_oligo_seq[i] != 'C') {
3187 op_set_no_gc_glamp(h);
3188 stats->gc_clamp++;
3189 if (!must_use) return; else break;
3190 }
3191 }
3192 }
3193
3194 #if 0
3195 /* Old code, works */
3196 if(pa->gc_clamp != 0){
3197 if(OT_LEFT == l) {
3198 for(i=k-pa->gc_clamp+1; i<= k; i++)if(seq[i] !='G'&&seq[i] !='C'){
3199 op_set_no_gc_glamp(h);
3200 stats->gc_clamp++;
3201 if (!must_use) return; else break;
3202 }
3203 }
3204 if(OT_RIGHT == l){
3205 for(i=j; i<j+pa->gc_clamp; i++)if(seq[i] != 'G' && seq[i] != 'C'){
3206 op_set_no_gc_glamp(h);
3207 stats->gc_clamp++;
3208 if (!must_use) return; else break;
3209 }
3210 }
3211 }
3212 #endif
3213
3214 if (pa->max_end_gc < 5
3215 && (OT_LEFT == l || OT_RIGHT == l)) {
3216 /* The CGs are only counted in the END of primers (as opposed
3217 to primers and hybridzations oligos. */
3218 gc_count=0;
3219 for (i = 0; i < 5; i++) {
3220 /* We want to look at the 3' end of the oligo being
3221 assessed, so we look in the 5' end of its reverse-complement */
3222 if (revc_oligo_seq[i] == 'G' || revc_oligo_seq[i] == 'C') {
3223 gc_count++;
3224 }
3225 }
3226 if (gc_count > pa->max_end_gc) {
3227 op_set_too_many_gc_at_end(h);
3228 stats->gc_end_high++;
3229 if (!must_use) return;
3230 }
3231 }
3232
3233 /* Tentative interface for generic oligo testing
3234 function */
3235 if (!sequence_quality_is_ok(pa, h, l, sa, j, k,
3236 stats, po_args)
3237 && !must_use) return;
3238
3239 max_poly_x = po_args->max_poly_x;
3240 if (max_poly_x > 0) {
3241 poly_x = 1;
3242 for(i=j+1;i<=k;i++){
3243 if(seq[i] == seq[i-1]||seq[i] == 'N'){
3244 poly_x++;
3245 if(poly_x > max_poly_x){
3246 op_set_high_poly_x(h);
3247 stats->poly_x++;
3248 if (!must_use) return; else break;
3249 }
3250 }
3251 else poly_x = 1;
3252 }
3253 }
3254
3255 h->temp /* Oligo/primer melting temperature */
3256 = seqtm(oligo_seq, po_args->dna_conc,
3257 po_args->salt_conc,
3258 po_args->divalent_conc,
3259 po_args->dntp_conc,
3260 MAX_NN_TM_LENGTH,
3261 pa->tm_santalucia,
3262 pa->salt_corrections);
3263
3264 if (h->temp < po_args->min_tm) {
3265 op_set_low_tm(h);
3266 stats->temp_min++;
3267 if (!must_use) return;
3268 }
3269
3270 if (h->temp > po_args->max_tm) {
3271 op_set_high_tm(h);
3272 stats->temp_max++;
3273 if (!must_use) return;
3274 }
3275
3276 /* End stability is applicable only to primers
3277 (not to oligos) */
3278 if (OT_LEFT == l || OT_RIGHT == l) {
3279 if ((h->end_stability = end_oligodg(oligo_seq, 5,
3280 pa->tm_santalucia))
3281 > pa->max_end_stability) {
3282 /* Must not be called on a hybridization probe / internal oligo: */
3283 op_set_high_end_stability(h);
3284 stats->stability++;
3285 if (!must_use) return;
3286 }
3287 }
3288
3289 if ((must_use
3290 || pa->file_flag
3291 || retval->output_type == primer_list
3292 || po_args->weights.compl_any
3293 || po_args->weights.compl_end)
3294 && pa->thermodynamic_oligo_alignment==0) {
3295
3296 oligo_compl(h, po_args,
3297 stats, dpal_arg_to_use,
3298 oligo_seq, revc_oligo_seq);
3299
3300 if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
3301 PR_ASSERT(!p3_ol_is_ok(h));
3302 return;
3303 }
3304 } else {
3305 /* Thermodynamical approach: for primers only */
3306 if ((must_use
3307 || pa->file_flag
3308 || retval->output_type == primer_list
3309 || po_args->weights.compl_any_th
3310 || po_args->weights.compl_end_th)
3311 && pa->thermodynamic_oligo_alignment==1
3312 )
3313 {
3314 oligo_compl_thermod(h, po_args,
3315 stats, thal_arg_to_use,
3316 oligo_seq, oligo_seq);
3317 /* input_oligo_seq, input_oligo_seq);*/
3318 /* oligo_seq, revc_oligo_seq); */
3319 if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
3320 PR_ASSERT(!p3_ol_is_ok(h));
3321 return;
3322 }
3323 } else {
3324 h->self_any = h->self_end = ALIGN_SCORE_UNDEF;
3325 }
3326 }
3327
3328 if ((three_conditions
3329 || po_args->weights.hairpin_th
3330 #if 0
3331 || po_args->weights.compl_any_th /* Triinu, is this needed? */
3332 || po_args->weights.compl_end_th /* Triinu, is this needed? */
3333 #endif
3334 )
3335 && pa->thermodynamic_oligo_alignment==1
3336 ) {
3337 oligo_hairpin(h, po_args,
3338 stats, thal_arg_to_use,
3339 /* input_oligo_seq);*/
3340 oligo_seq);
3341 if ((!(p3_ol_is_uninitialized(h))) && !must_use) {
3342 PR_ASSERT(!p3_ol_is_ok(h));
3343 return;
3344 }
3345 } else {
3346 /* This will get calculated later if necessary, in characterize_pair. */
3347 h->hairpin_th = ALIGN_SCORE_UNDEF;
3348 }
3349 /* end of thermod. approach */
3350
3351
3352 #if 0
3353 /* FIX ME FIXME */
3354 if (((must_use
3355 || pa->file_flag
3356 || retval->output_type == primer_list
3357 || po_args->weights.repeat_sim
3358 || ((OT_RIGHT == l || OT_LEFT == l)
3359 && pa->p_args.weights.template_mispriming))
3360
3361 && pa->thermodynamic_oligo_alignment==0)
3362 || (pa->thermodynamic_oligo_alignment==1 && po_args->weights.repeat_sim)) {
3363
3364 oligo_repeat_library_mispriming(h, pa, sa, l, stats,
3365 dpal_arg_to_use);
3366 if (pa->thermodynamic_template_alignment==0 && OK_OR_MUST_USE(h)) {
3367 oligo_template_mispriming(h, pa, sa, l, stats,
3368 dpal_arg_to_use->local_end,
3369 thal_args_for_template_mispriming);
3370 }
3371 }
3372
3373 if ((must_use
3374 || pa->file_flag
3375 || retval->output_type == primer_list
3376 || ((OT_RIGHT == l || OT_LEFT == l)
3377 && pa->p_args.weights.template_mispriming_th))
3378
3379 && pa->thermodynamic_template_alignment==1)
3380 {
3381
3382 oligo_template_mispriming(h, pa, sa, l, stats,
3383 dpal_arg_to_use->local_end,
3384 thal_args_for_template_mispriming);
3385 }
3386 /* END FIX ME FIXME */
3387 #else
3388
3389 if (three_conditions || po_args->weights.repeat_sim) {
3390 oligo_repeat_library_mispriming(h, pa, sa, l, stats,
3391 dpal_arg_to_use);
3392 }
3393
3394
3395 if (!OK_OR_MUST_USE(h)) return;
3396
3397 if (three_conditions
3398 ||
3399 ( /* Do we need template mispriming for the penalty function? */
3400 (OT_RIGHT == l || OT_LEFT == l)
3401 &&
3402 (
3403 (pa->p_args.weights.template_mispriming && !pa->thermodynamic_template_alignment)
3404 ||
3405 (pa->p_args.weights.template_mispriming_th && pa->thermodynamic_template_alignment)
3406 )
3407 )
3408 ) {
3409 if (OK_OR_MUST_USE(h)) {
3410 oligo_template_mispriming(h, pa, sa, l, stats,
3411 dpal_arg_to_use->local_end,
3412 thal_args_for_template_mispriming);
3413 }
3414 }
3415
3416 #endif
3417
3418 if (h->length > po_args->max_size ) {
3419 op_set_too_long(h);
3420 stats->size_max ++;
3421 if (!must_use) return;
3422 }
3423
3424 if (h->length < po_args->min_size ) {
3425 op_set_too_short(h);
3426 stats->size_min ++;
3427 if (!must_use) return;
3428 }
3429
3430 for (for_i=0; for_i < sa->primer_overlap_junctions_count; for_i++) {
3431 if (OT_LEFT == l
3432 && ((h->start + pa->min_5_prime_overlap_of_junction - 1)
3433 <= sa->primer_overlap_junctions[for_i])
3434 && ((h->start + h->length - pa->min_3_prime_overlap_of_junction))
3435 > sa->primer_overlap_junctions[for_i]) {
3436 h->overlaps_overlap_position = 1;
3437 /* no need to continue checking */
3438 break;
3439 }
3440 if (OT_RIGHT == l
3441 && ((h->start - h->length + pa->min_3_prime_overlap_of_junction)
3442 <= sa->primer_overlap_junctions[for_i])
3443 && ((h->start - pa->min_5_prime_overlap_of_junction + 1))
3444 > sa->primer_overlap_junctions[for_i]) {
3445 h->overlaps_overlap_position = 1;
3446 /* no need to continue checking */
3447 break;
3448 }
3449 }
3450
3451 /* FIX ME FIXME Steve, is this really needed? */
3452 op_set_completely_written(h);
3453
3454 } /* calc_and_check_oligo_features */
3455 #undef OUTSIDE_START_WT
3456 #undef INSIDE_START_WT
3457 #undef INSIDE_STOP_WT
3458 #undef OUTSIDE_STOP_WT
3459
3460 /* Calculate the minimum sequence quality and the minimum sequence
3461 quality of the 3' end of a primer or oligo. Set h->seq_quality
3462 and h->seq_end_quality with these values. Return 1 (== ok)
3463 if sa->quality is undefined. Otherwise, return 1 (ok)
3464 if h->seq_quality and h->seq_end_quality are within
3465 range, or else return 0.
3466 */
3467 static int
sequence_quality_is_ok(const p3_global_settings * pa,primer_rec * h,oligo_type l,const seq_args * sa,int j,int k,oligo_stats * global_oligo_stats,const args_for_one_oligo_or_primer * po_args)3468 sequence_quality_is_ok(const p3_global_settings *pa,
3469 primer_rec *h,
3470 oligo_type l,
3471 const seq_args *sa,
3472 int j, int k,
3473 oligo_stats *global_oligo_stats,
3474 const args_for_one_oligo_or_primer *po_args) {
3475 int i, min_q, min_q_end, m, q;
3476 int retval = 1;
3477
3478 if (NULL == sa->quality) {
3479 h->seq_end_quality = h->seq_quality = pa->quality_range_max;
3480 return 1;
3481 }
3482
3483 q = pa->quality_range_max;
3484
3485 min_q = po_args->min_quality;
3486 if (OT_LEFT == l || OT_RIGHT == l) {
3487 min_q_end = po_args->min_end_quality;
3488 } else {
3489 min_q_end = min_q;
3490 }
3491
3492 if (OT_LEFT == l || OT_INTL == l) {
3493
3494 for(i = k-4; i <= k; i++) {
3495 if(i < j) continue;
3496 m = sa->quality[i + sa->incl_s];
3497 if (m < q) q = m;
3498 }
3499 min_q_end = q;
3500
3501 for(i = j; i<=k-5; i++) {
3502 m = sa->quality[i + sa->incl_s];
3503 if (m < q) q = m;
3504 }
3505 min_q = q;
3506
3507 } else if (OT_RIGHT == l) {
3508 for(i = j; i < j+5; i++) {
3509 if(i > k) break;
3510 m = sa->quality[i + sa->incl_s];
3511 if (m < q) q = m;
3512 }
3513 min_q_end = q;
3514
3515 for(i = j+5; i <= k; i++) {
3516 m = sa->quality[i + sa->incl_s];
3517 if (m < q) q = m;
3518 }
3519 min_q = q;
3520 } else {
3521 PR_ASSERT(0); /* Programming error. */
3522 }
3523
3524 h->seq_quality = min_q;
3525 h->seq_end_quality = min_q_end;
3526
3527 if (h->seq_quality < po_args->min_quality) {
3528 op_set_low_sequence_quality(h);
3529 global_oligo_stats->seq_quality++;
3530 retval = 0;
3531 return retval;
3532 }
3533
3534 if (OT_LEFT == l || OT_RIGHT == l) {
3535 if (h->seq_end_quality < po_args->min_end_quality) {
3536 op_set_low_end_sequence_quality(h);
3537 global_oligo_stats->seq_quality++;
3538 retval = 0;
3539 }
3540 }
3541 return retval;
3542 }
3543
3544 /*
3545 * Set h->gc_content to the GC % of the 'len' bases starting at 'start' in
3546 * 'sequence' (excluding 'N's). Set h->num_ns to the number of 'N's in that
3547 * subsequence.
3548 */
3549 static void
gc_and_n_content(int start,int len,const char * sequence,primer_rec * h)3550 gc_and_n_content(int start, int len,
3551 const char *sequence,
3552 primer_rec *h)
3553 {
3554 const char* p = &sequence[start];
3555 const char* stop = p + len;
3556 int num_gc = 0, num_gcat = 0, num_n = 0;
3557 while (p < stop) {
3558 if ('N' == *p)
3559 num_n++;
3560 else {
3561 num_gcat++;
3562 if ('C' == *p || 'G' == *p) num_gc++;
3563 }
3564 p++;
3565 }
3566 h->num_ns = num_n;
3567 if (0 == num_gcat) h->gc_content= 0.0;
3568 else h->gc_content = 100.0 * ((double)num_gc)/num_gcat;
3569 }
3570
3571 static int
oligo_overlaps_interval(int start,int len,const interval_array_t intervals,int num_intervals)3572 oligo_overlaps_interval(int start,
3573 int len,
3574 const interval_array_t intervals,
3575 int num_intervals)
3576 {
3577 int i;
3578 int last = start + len - 1;
3579 for (i = 0; i < num_intervals; i++)
3580 if (!(last < intervals[i][0]
3581 || start > (intervals[i][0] + intervals[i][1] - 1)))
3582 return 1;
3583 return 0;
3584 }
3585
3586 /* Calculate the part of the objective function due to one primer. */
3587 static double
p_obj_fn(const p3_global_settings * pa,primer_rec * h,int j)3588 p_obj_fn(const p3_global_settings *pa,
3589 primer_rec *h,
3590 int j) {
3591 double sum;
3592
3593 sum = 0;
3594 if (j == OT_LEFT || j == OT_RIGHT) {
3595 if(pa->p_args.weights.temp_gt && h->temp > pa->p_args.opt_tm)
3596 sum += pa->p_args.weights.temp_gt * (h->temp - pa->p_args.opt_tm);
3597 if (pa->p_args.weights.temp_lt && h->temp < pa->p_args.opt_tm)
3598 sum += pa->p_args.weights.temp_lt * (pa->p_args.opt_tm - h->temp);
3599
3600 if (pa->p_args.weights.gc_content_gt && h->gc_content > pa->p_args.opt_gc_content)
3601 sum += pa->p_args.weights.gc_content_gt
3602 * (h->gc_content - pa->p_args.opt_gc_content);
3603 if (pa->p_args.weights.gc_content_lt && h->gc_content < pa->p_args.opt_gc_content)
3604 sum += pa->p_args.weights.gc_content_lt
3605 * (pa->p_args.opt_gc_content - h->gc_content);
3606
3607 if (pa->p_args.weights.length_lt && h->length < pa->p_args.opt_size)
3608 sum += pa->p_args.weights.length_lt * (pa->p_args.opt_size - h->length);
3609 if (pa->p_args.weights.length_gt && h->length > pa->p_args.opt_size)
3610 sum += pa->p_args.weights.length_gt * (h->length - pa->p_args.opt_size);
3611
3612 /* BEGIN: secondary structures */
3613 if (pa->thermodynamic_oligo_alignment==0) {
3614
3615 if (pa->p_args.weights.compl_any)
3616 sum += pa->p_args.weights.compl_any * h->self_any;
3617 if (pa->p_args.weights.compl_end)
3618 sum += pa->p_args.weights.compl_end * h->self_end;
3619
3620 } else if (pa->thermodynamic_oligo_alignment==1) {
3621
3622 if (pa->p_args.weights.compl_any_th) {
3623 if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->self_any)
3624 sum += pa->p_args.weights.compl_any_th
3625 * (h->self_any - (h->temp - pa->p_args.weights.temp_cutoff - 1.0)); /* -1.0 is added for the case where == */
3626 else
3627 sum += pa->p_args.weights.compl_any_th
3628 * (1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->self_any));
3629 }
3630
3631 if (pa->p_args.weights.compl_end_th) {
3632 if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->self_end)
3633 sum += pa->p_args.weights.compl_end_th
3634 * (h->self_end - (h->temp - pa->p_args.weights.temp_cutoff - 1.0));
3635 else
3636 sum += pa->p_args.weights.compl_end_th
3637 * (1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->self_end));
3638 }
3639
3640 if (pa->p_args.weights.hairpin_th) {
3641 if ((h->temp - pa->p_args.weights.temp_cutoff) <= h->hairpin_th)
3642 sum += pa->p_args.weights.hairpin_th
3643 * (h->hairpin_th - (h->temp - pa->p_args.weights.temp_cutoff - 1.0));
3644 else
3645 sum += pa->p_args.weights.hairpin_th
3646 * (1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - h->hairpin_th));
3647 }
3648
3649 } else {
3650 PR_ASSERT(0)
3651 /* Programming error,
3652 illegal value for pa->thermodynamic_oligo_alignment */
3653 }
3654 /* END: secondary structures */
3655
3656 if (pa->p_args.weights.num_ns)
3657 sum += pa->p_args.weights.num_ns * h->num_ns;
3658 if(pa->p_args.weights.repeat_sim)
3659 sum += pa->p_args.weights.repeat_sim
3660 * h->repeat_sim.score[h->repeat_sim.max];
3661 if (!bf_get_overlaps_target(h)) {
3662 /* We might be evaluating p_obj_fn with h->target if
3663 the client supplied 'pick_anyway' and specified
3664 a primer or oligo. */
3665 PR_ASSERT(!(bf_get_infinite_pos_penalty(h)));
3666 if(pa->p_args.weights.pos_penalty)
3667 sum += pa->p_args.weights.pos_penalty * h->position_penalty;
3668 }
3669 if(pa->p_args.weights.end_stability)
3670 sum += pa->p_args.weights.end_stability * h->end_stability;
3671
3672 /* FIX ME QUALITY WT Change here */
3673 if(pa->p_args.weights.seq_quality)
3674 sum += pa->p_args.weights.seq_quality *
3675 (pa->quality_range_max - h->seq_quality); /* Look for end seq quality */
3676
3677 if (pa->p_args.weights.template_mispriming && pa->thermodynamic_template_alignment==0) {
3678 PR_ASSERT(oligo_max_template_mispriming(h) != ALIGN_SCORE_UNDEF);
3679 sum += pa->p_args.weights.template_mispriming *
3680 oligo_max_template_mispriming(h);
3681 }
3682
3683 if (pa->p_args.weights.template_mispriming_th && pa->thermodynamic_template_alignment==1) {
3684
3685 PR_ASSERT(oligo_max_template_mispriming_thermod(h) != ALIGN_SCORE_UNDEF);
3686
3687 if((h->temp - pa->p_args.weights.temp_cutoff) <= oligo_max_template_mispriming_thermod(h))
3688 sum += pa->p_args.weights.template_mispriming_th *
3689 (oligo_max_template_mispriming_thermod(h) - (h->temp - pa->p_args.weights.temp_cutoff - 1.0));
3690 if((h->temp - pa->p_args.weights.temp_cutoff) > oligo_max_template_mispriming_thermod(h))
3691 sum += pa->p_args.weights.template_mispriming_th *
3692 (1/(h->temp - pa->p_args.weights.temp_cutoff + 1.0 - oligo_max_template_mispriming_thermod(h)));
3693 }
3694 return sum;
3695 } else if (j == OT_INTL) {
3696 if(pa->o_args.weights.temp_gt && h->temp > pa->o_args.opt_tm)
3697 sum += pa->o_args.weights.temp_gt * (h->temp - pa->o_args.opt_tm);
3698 if(pa->o_args.weights.temp_lt && h->temp < pa->o_args.opt_tm)
3699 sum += pa->o_args.weights.temp_lt * (pa->o_args.opt_tm - h->temp);
3700
3701 if(pa->o_args.weights.gc_content_gt && h->gc_content > pa->o_args.opt_gc_content)
3702 sum += pa->o_args.weights.gc_content_gt
3703 * (h->gc_content - pa->o_args.opt_gc_content);
3704 if(pa->o_args.weights.gc_content_lt && h->gc_content < pa->o_args.opt_gc_content)
3705 sum += pa->o_args.weights.gc_content_lt
3706 * (pa->o_args.opt_gc_content - h->gc_content);
3707
3708 if(pa->o_args.weights.length_lt && h->length < pa->o_args.opt_size)
3709 sum += pa->o_args.weights.length_lt * (pa->o_args.opt_size - h->length);
3710 if(pa->o_args.weights.length_gt && h->length > pa->o_args.opt_size)
3711 sum += pa->o_args.weights.length_gt * (h->length - pa->o_args.opt_size);
3712 if(pa->o_args.weights.compl_any && pa->thermodynamic_oligo_alignment==0)
3713 sum += pa->o_args.weights.compl_any * h->self_any;
3714 if(pa->o_args.weights.compl_end && pa->thermodynamic_oligo_alignment==0)
3715 sum += pa->o_args.weights.compl_end * h->self_end;
3716
3717 /* begin thermodynamical approach */
3718 if (pa->thermodynamic_oligo_alignment==1) {
3719
3720 if (pa->o_args.weights.compl_any_th) {
3721 if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->self_any)
3722 sum +=
3723 pa->o_args.weights.compl_any_th
3724 * (h->self_any - (h->temp - pa->o_args.weights.temp_cutoff - 1.0)); /* -1.0 is added for the case where == */
3725 else
3726 sum +=
3727 pa->o_args.weights.compl_any_th
3728 * (1/(h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->self_any));
3729 }
3730
3731 if (pa->o_args.weights.compl_end_th) {
3732 if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->self_end)
3733 sum +=
3734 pa->o_args.weights.compl_end_th
3735 * (h->self_end - (h->temp - pa->o_args.weights.temp_cutoff - 1.0));
3736 else
3737 sum +=
3738 pa->o_args.weights.compl_end_th
3739 * (1/(h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->self_end));
3740 }
3741
3742 if (pa->o_args.weights.hairpin_th) {
3743 if ((h->temp - pa->o_args.weights.temp_cutoff) <= h->hairpin_th)
3744 sum += pa->o_args.weights.hairpin_th * (h->hairpin_th - (h->temp - pa->o_args.weights.temp_cutoff - 1.0));
3745 else
3746 sum += pa->o_args.weights.hairpin_th * (1/(h->temp - pa->o_args.weights.temp_cutoff + 1.0 - h->hairpin_th));
3747 }
3748 }
3749 /* end thermodynamical approach */
3750
3751 if(pa->o_args.weights.num_ns)
3752 sum += pa->o_args.weights.num_ns * h->num_ns;
3753 if(pa->o_args.weights.repeat_sim)
3754 sum += pa->o_args.weights.repeat_sim
3755 * h->repeat_sim.score[h->repeat_sim.max];
3756
3757 /* FIX ME QUALITY WT */
3758 if(pa->o_args.weights.seq_quality)
3759 sum += pa->o_args.weights.seq_quality *
3760 (pa->quality_range_max - h->seq_quality);
3761
3762 return sum;
3763 } else {
3764 PR_ASSERT(0); /* Programmig error. */
3765 }
3766 }
3767
3768 /* Return max of h->template_mispriming and h->template_mispriming_r (max
3769 template mispriming on either strand). */
3770 double
oligo_max_template_mispriming(const primer_rec * h)3771 oligo_max_template_mispriming(const primer_rec *h) {
3772 return h->template_mispriming > h->template_mispriming_r ?
3773 h->template_mispriming : h->template_mispriming_r;
3774 }
3775
3776 double
oligo_max_template_mispriming_thermod(const primer_rec * h)3777 oligo_max_template_mispriming_thermod(const primer_rec *h) {
3778 return h->template_mispriming > h->template_mispriming_r ?
3779 h->template_mispriming : h->template_mispriming_r;
3780 }
3781
3782 /* Sort a given primer array by penalty */
3783 static void
sort_primer_array(oligo_array * oligo)3784 sort_primer_array(oligo_array *oligo)
3785 {
3786 qsort(&oligo->oligo[0], oligo->num_elem, sizeof(*oligo->oligo),
3787 primer_rec_comp);
3788 }
3789
3790 /* Compare function for sorting primer records. */
3791 static int
primer_rec_comp(const void * x1,const void * x2)3792 primer_rec_comp(const void *x1, const void *x2)
3793 {
3794 const primer_rec *a1 = (const primer_rec *) x1;
3795 const primer_rec *a2 = (const primer_rec *) x2;
3796
3797 if(a1->quality < a2->quality) return -1;
3798 if (a1->quality > a2->quality) return 1;
3799
3800 /*
3801 * We want primer_rec_comp to always return a non-0 result, because
3802 * different implementations of qsort differ in how they treat "equal"
3803 * elements, making it difficult to compare test output on different
3804 * systems.
3805 */
3806 if(a1->start > a2->start) return -1;
3807 if(a1->start < a2->start) return 1;
3808 if(a1->length < a2->length) return -1;
3809 return 1;
3810 }
3811
3812 /* Compare function for sorting primer records. */
3813 static int
compare_primer_pair(const void * x1,const void * x2)3814 compare_primer_pair(const void *x1, const void *x2)
3815 {
3816 const primer_pair *a1 = (const primer_pair *) x1;
3817 const primer_pair *a2 = (const primer_pair *) x2;
3818 const double epsilon = 1e-6;
3819 int y1, y2;
3820
3821 if ((a1->pair_quality + epsilon) < a2->pair_quality) return -1;
3822 if (a1->pair_quality > (a2->pair_quality + epsilon)) return 1;
3823
3824 /*
3825 * The following statements ensure that we get a stable order that
3826 * is the same on all systems.
3827 */
3828
3829 y1 = a1->left->start;
3830 y2 = a2->left->start;
3831 if (y1 > y2) return -1; /* prefer left primers to the right. */
3832 if (y1 < y2) return 1;
3833
3834 y1 = a1->right->start;
3835 y2 = a2->right->start;
3836 if (y1 < y2) return -1; /* prefer right primers to the left. */
3837 if (y1 > y2) return 1;
3838
3839 y1 = a1->left->length;
3840 y2 = a2->left->length;
3841 if (y1 < y2) return -1; /* prefer shorter primers. */
3842 if (y1 > y2) return 1;
3843
3844 y1 = a1->right->length;
3845 y2 = a2->right->length;
3846 if (y1 < y2) return -1; /* prefer shorter primers. */
3847 if (y1 > y2) return 1;
3848
3849 return 0;
3850 }
3851
3852 /*
3853 * Defines parameter values for given primer pair. Returns PAIR_OK if the pair is
3854 * acceptable; PAIR_FAILED otherwise. This function sets the
3855 * various elements of *ppair, and also calculates some key EXPENSIVE
3856 * parameters for individual primers if they have not been set yet.
3857 */
3858 static int
characterize_pair(p3retval * retval,const p3_global_settings * pa,const seq_args * sa,int m,int n,int int_num,primer_pair * ppair,const dpal_arg_holder * dpal_arg_to_use,const thal_arg_holder * thal_arg_to_use,int update_stats)3859 characterize_pair(p3retval *retval,
3860 const p3_global_settings *pa,
3861 const seq_args *sa,
3862 int m, int n, int int_num,
3863 primer_pair *ppair,
3864 const dpal_arg_holder *dpal_arg_to_use,
3865 const thal_arg_holder *thal_arg_to_use,
3866 int update_stats) {
3867 char s1[MAX_PRIMER_LENGTH+1], s2[MAX_PRIMER_LENGTH+1],
3868 s1_rev[MAX_PRIMER_LENGTH+1], s2_rev[MAX_PRIMER_LENGTH+1];
3869 double compl_end;
3870 pair_stats *pair_expl = &retval->best_pairs.expl;
3871 int must_use = 0;
3872 double min_oligo_tm;
3873 int i;
3874 const thal_args *thal_args_for_template_mispriming
3875 = use_end_for_th_template_mispriming
3876 ? thal_arg_to_use->end1
3877 : thal_arg_to_use->any;
3878
3879 memset(ppair, 0, sizeof(*ppair));
3880
3881 ppair->left = &retval->fwd.oligo[m];
3882 ppair->right = &retval->rev.oligo[n];
3883 ppair->product_size = retval->rev.oligo[n].start - retval->fwd.oligo[m].start+1;
3884
3885 ppair->target = 0;
3886 ppair->compl_any = ppair->compl_end = 0;
3887 if (update_stats) {
3888 pair_expl->considered++;
3889 }
3890
3891 if (pa->primer_task == check_primers) {
3892 must_use = 1;
3893 }
3894
3895 /* We must use the pair if the caller specifed
3896 both the left and the right primer. */
3897 if (ppair->left->must_use != 0 &&
3898 ppair->right->must_use != 0) {
3899
3900 /* But if caller specified primers are in
3901 reversed order we cannot analyze them
3902 as a pair. */
3903 if (ppair->product_size < 1) {
3904 pair_expl->reversed++;
3905 return PAIR_FAILED;
3906 }
3907
3908 must_use = 1;
3909 }
3910
3911 ppair->must_use = must_use;
3912
3913 if (sa->tar2.count > 0) {
3914 if (pair_spans_target(ppair, sa)) {
3915 ppair->target = 1;
3916 } else {
3917 ppair->target = -1;
3918 if (update_stats) { pair_expl->target++; }
3919 if (!must_use) return PAIR_FAILED;
3920 }
3921 }
3922
3923 /* ============================================================= */
3924
3925 /* Check that the pair is included in one of the specified ok regions */
3926 if ((sa->ok_regions.count > 0) && (!sa->ok_regions.any_pair)) {
3927 int included = 0;
3928 int l_start = ppair->left->start, l_end = ppair->left->start + ppair->left->length - 1;
3929 int r_start = ppair->right->start - ppair->right->length + 1, r_end = ppair->right->start;
3930 for (i=0; i<sa->ok_regions.count; i++) {
3931 if (sa->ok_regions.left_pairs[i][0] == -1) {
3932 /* any left primer, check right primer */
3933 if ((r_start >= sa->ok_regions.right_pairs[i][0]) &&
3934 (r_end <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)) {
3935 included = 1;
3936 break;
3937 }
3938 } else if (sa->ok_regions.right_pairs[i][0] == -1) {
3939 /* any right primer, check the left primer */
3940 if ((l_start >= sa->ok_regions.left_pairs[i][0]) &&
3941 (l_end <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1)) {
3942 included = 1;
3943 break;
3944 }
3945 } else {
3946 /* check both primers */
3947 if ((l_start >= sa->ok_regions.left_pairs[i][0]) &&
3948 (l_end <= sa->ok_regions.left_pairs[i][0] + sa->ok_regions.left_pairs[i][1] - 1) &&
3949 (r_start >= sa->ok_regions.right_pairs[i][0]) &&
3950 (r_end <= sa->ok_regions.right_pairs[i][0] + sa->ok_regions.right_pairs[i][1] - 1)) {
3951 included = 1;
3952 break;
3953 }
3954 }
3955 }
3956 if (!included) {
3957 if (update_stats) { pair_expl->not_in_any_ok_region++; }
3958 if (!must_use) return PAIR_FAILED;
3959 }
3960 }
3961
3962 /* ============================================================= */
3963 /* Compute product Tm and related parameters; check constraints. */
3964
3965 if (ppair->right->start - ppair->left->start + 1 <= 0) {
3966 fprintf(stderr, "temporary");
3967 }
3968 PR_ASSERT(ppair->right->start - ppair->left->start + 1 > 0)
3969 ppair->product_tm
3970 = long_seq_tm(sa->trimmed_seq, ppair->left->start,
3971 ppair->right->start - ppair->left->start + 1,
3972 /* TO DO -- skewed, it would be better to not use p_args elements here */
3973 pa->p_args.salt_conc,
3974 pa->p_args.divalent_conc,
3975 pa->p_args.dntp_conc);
3976
3977 PR_ASSERT(ppair->product_tm != OLIGOTM_ERROR);
3978
3979 min_oligo_tm
3980 = ppair->left->temp > ppair->right->temp ? ppair->right->temp : ppair->left->temp;
3981 ppair->product_tm_oligo_tm_diff = ppair->product_tm - min_oligo_tm;
3982 ppair->t_opt_a = 0.3 * min_oligo_tm + 0.7 * ppair->product_tm - 14.9;
3983
3984 if (pa->product_min_tm != PR_DEFAULT_PRODUCT_MIN_TM
3985 && ppair->product_tm < pa->product_min_tm) {
3986 if (update_stats) { pair_expl->low_tm++; }
3987 if (!must_use) return PAIR_FAILED;
3988 }
3989
3990 if (pa->product_max_tm != PR_DEFAULT_PRODUCT_MAX_TM
3991 && ppair->product_tm > pa->product_max_tm) {
3992 if (update_stats) { pair_expl->high_tm++; }
3993 if (!must_use) return PAIR_FAILED;
3994 }
3995
3996 ppair->diff_tm = fabs(retval->fwd.oligo[m].temp - retval->rev.oligo[n].temp);
3997 if (ppair->diff_tm > pa->max_diff_tm) {
3998 if (update_stats) { pair_expl->temp_diff++; }
3999 if (!must_use) return PAIR_FAILED;
4000 }
4001
4002 /* End of product-temperature related computations. */
4003 /* ============================================================= */
4004
4005
4006 /* ============================================================= */
4007 /* BEGIN "EXPENSIVE" computations on _individual_ primers
4008 in the pair. These have been postponed until
4009 this point in the interests of efficiency.
4010 */
4011
4012 /* ============================================================= */
4013 /* Estimate secondary structure and primer-dimer of _individual_
4014 primers if not already calculated. */
4015
4016 /* s1 is the forward oligo. */
4017 _pr_substr(sa->trimmed_seq,
4018 retval->fwd.oligo[m].start,
4019 retval->fwd.oligo[m].length,
4020 s1);
4021
4022 /* s2 is the reverse oligo. */
4023 _pr_substr(sa->trimmed_seq,
4024 retval->rev.oligo[n].start - retval->rev.oligo[n].length + 1,
4025 retval->rev.oligo[n].length,
4026 s2);
4027
4028 p3_reverse_complement(s1, s1_rev);
4029 p3_reverse_complement(s2, s2_rev);
4030
4031
4032 if (retval->fwd.oligo[m].self_any == ALIGN_SCORE_UNDEF
4033 && pa->thermodynamic_oligo_alignment==0) {
4034 /* We have not yet computed the 'self_any' paramter,
4035 which is an estimate of self primer-dimer and secondary
4036 structure propensity. */
4037 oligo_compl(&retval->fwd.oligo[m], &pa->p_args,
4038 &retval->fwd.expl, dpal_arg_to_use, s1, s1_rev);
4039
4040 if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
4041 pair_expl->considered--;
4042 if (!must_use) return PAIR_FAILED;
4043 }
4044 }
4045 /* Thermodynamic approach, fwd-primer */
4046 if (retval->fwd.oligo[m].self_any == ALIGN_SCORE_UNDEF
4047 && pa->thermodynamic_oligo_alignment==1) {
4048 oligo_compl_thermod(&retval->fwd.oligo[m], &pa->p_args,
4049 &retval->fwd.expl, thal_arg_to_use, s1, s1); /* ! s1, s1_rev */
4050
4051 if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
4052 pair_expl->considered--;
4053 if (!must_use) return PAIR_FAILED;
4054 }
4055 }
4056 if (retval->fwd.oligo[m].hairpin_th == ALIGN_SCORE_UNDEF
4057 && pa->thermodynamic_oligo_alignment==1) {
4058 oligo_hairpin(&retval->fwd.oligo[m], &pa->p_args,
4059 &retval->fwd.expl, thal_arg_to_use, s1);
4060 if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
4061 pair_expl->considered--;
4062 if (!must_use) return PAIR_FAILED;
4063 }
4064 }
4065
4066 /* End of thermodynamic approach */
4067
4068 if (retval->rev.oligo[n].self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==0) {
4069 oligo_compl(&retval->rev.oligo[n], &pa->p_args,
4070 &retval->rev.expl, dpal_arg_to_use, s2_rev, s2);
4071
4072 if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
4073 pair_expl->considered--;
4074 if (!must_use) return PAIR_FAILED;
4075 }
4076 }
4077 /* Thermodynamic approach */
4078 if (retval->rev.oligo[n].self_any == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
4079 oligo_compl_thermod(&retval->rev.oligo[n], &pa->p_args,
4080 &retval->rev.expl, thal_arg_to_use, s2_rev, s2_rev); /* s2_rev, s2 */
4081
4082 if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
4083 pair_expl->considered--;
4084 if (!must_use) return PAIR_FAILED;
4085 }
4086 }
4087 if (retval->rev.oligo[n].hairpin_th == ALIGN_SCORE_UNDEF && pa->thermodynamic_oligo_alignment==1) {
4088 oligo_hairpin(&retval->rev.oligo[n], &pa->p_args,
4089 &retval->rev.expl, thal_arg_to_use, s2_rev);
4090 if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
4091 pair_expl->considered--;
4092 if (!must_use) return PAIR_FAILED;
4093 }
4094 }
4095
4096 /* End of thermodynamic approach */
4097 /* End of secondary structure and primer-dimer of _individual_
4098 primers. */
4099 /* ============================================================= */
4100
4101
4102 /* ============================================================= */
4103 /* Mispriming of _individual_ primers to template and
4104 to repeat libraries. */
4105
4106 if (retval->fwd.oligo[m].repeat_sim.score == NULL) {
4107 /* We have not yet checked the oligo against the repeat library. */
4108 oligo_repeat_library_mispriming(&retval->fwd.oligo[m], pa, sa, OT_LEFT,
4109 &retval->fwd.expl,dpal_arg_to_use);
4110 if (OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
4111 oligo_template_mispriming(&retval->fwd.oligo[m], pa, sa, OT_LEFT,
4112 &retval->fwd.expl,
4113 dpal_arg_to_use->local_end,
4114 thal_args_for_template_mispriming);
4115 }
4116 if (!OK_OR_MUST_USE(&retval->fwd.oligo[m])) {
4117 pair_expl->considered--;
4118 if (!must_use) return PAIR_FAILED;
4119 }
4120 }
4121
4122 if (retval->rev.oligo[n].repeat_sim.score == NULL) {
4123 oligo_repeat_library_mispriming(&retval->rev.oligo[n], pa, sa, OT_RIGHT,
4124 &retval->rev.expl, dpal_arg_to_use);
4125 if (OK_OR_MUST_USE(&retval->rev.oligo[n])) {
4126 oligo_template_mispriming(&retval->rev.oligo[n], pa, sa, OT_RIGHT,
4127 &retval->rev.expl,
4128 dpal_arg_to_use->local_end,
4129 thal_args_for_template_mispriming);
4130 }
4131 if (!OK_OR_MUST_USE(&retval->rev.oligo[n])) {
4132 pair_expl->considered--;
4133 if (!must_use) return PAIR_FAILED;
4134 }
4135 }
4136
4137 /* End of mispriming of _individual_ primers to template and
4138 to repeat libraries. */
4139 /* ============================================================= */
4140
4141
4142 /* ============================================================= */
4143 /*
4144 * Similarity between s1 and s2 is equivalent to complementarity between
4145 * s2's complement and s1. (Both s1 and s2 are taken from the same strand.)
4146 */
4147 if(pa->thermodynamic_oligo_alignment==0) {
4148 ppair->compl_any = align(s1, s2, dpal_arg_to_use->local);
4149 if (ppair->compl_any > pa->pair_compl_any) {
4150 if (update_stats) { pair_expl->compl_any++; }
4151 if (!must_use) return PAIR_FAILED;
4152 }
4153
4154 ppair->compl_end = align(s1, s2, dpal_arg_to_use->end);
4155 if (ppair->compl_end > pa->pair_compl_end) {
4156 if (update_stats) { pair_expl->compl_end++; }
4157 if (!must_use) return PAIR_FAILED;
4158 }
4159 } else {
4160 /* thermodynamical approach */
4161 ppair->compl_any = align_thermod(s1, s2_rev, thal_arg_to_use->any);
4162 if (ppair->compl_any > pa->pair_compl_any_th) {
4163 if (update_stats) {
4164 pair_expl->compl_any++;
4165 }
4166 if (!must_use) return PAIR_FAILED;
4167 }
4168 ppair->compl_end = align_thermod(s1, s2_rev, thal_arg_to_use->end1);
4169 compl_end = align_thermod(s1, s2_rev, thal_arg_to_use->end2); /* Triinu Please check */
4170 if (ppair->compl_end < compl_end) {
4171 ppair->compl_end = compl_end;
4172 }
4173 if (ppair->compl_end > pa->pair_compl_end_th) {
4174 if (update_stats) {
4175 pair_expl->compl_end++;
4176 }
4177 if (!must_use) return PAIR_FAILED;
4178 }
4179 }
4180
4181 /*
4182 * It is conceivable (though unlikely) that
4183 * align(s2_rev, s1_rev, end_args) > align(s1,s2,end_args).
4184 */
4185 if (pa->thermodynamic_oligo_alignment==0 && (compl_end = align(s2_rev, s1_rev, dpal_arg_to_use->end))
4186 > ppair->compl_end) {
4187 if (compl_end > pa->p_args.max_self_end) {
4188 if (update_stats) { pair_expl->compl_end++; }
4189 if (!must_use) return PAIR_FAILED;
4190 }
4191 ppair->compl_end = compl_end;
4192 }
4193
4194 if ((ppair->repeat_sim = pair_repeat_sim(ppair, pa))
4195 > pa->pair_repeat_compl) {
4196 if (update_stats) { pair_expl->repeat_sim++; }
4197 if (!must_use) return PAIR_FAILED;
4198 }
4199 /* thermodynamic approach */
4200 if (pa->thermodynamic_oligo_alignment==1 &&
4201 ((compl_end = align_thermod(s2, s1_rev, thal_arg_to_use->end1)) > ppair->compl_end ||
4202 (compl_end = align_thermod(s2, s1_rev, thal_arg_to_use->end2)) > ppair->compl_end)) {
4203 if (compl_end > pa->p_args.max_self_end_th) {
4204 if (update_stats) {
4205 pair_expl->compl_end++;
4206 }
4207 if (!must_use) return PAIR_FAILED;
4208 }
4209 ppair->compl_end = compl_end;
4210 }
4211
4212 /* ============================================================= */
4213
4214
4215 /* ============================================================= */
4216 /* Calculate _pair_ mispriming, if necessary. */
4217
4218 if (pa->thermodynamic_template_alignment == 0) {
4219 if (!_pr_need_pair_template_mispriming(pa))
4220 ppair->template_mispriming = ALIGN_SCORE_UNDEF;
4221 else {
4222 PR_ASSERT(ppair->left->template_mispriming != ALIGN_SCORE_UNDEF);
4223 PR_ASSERT(ppair->left->template_mispriming_r != ALIGN_SCORE_UNDEF);
4224 PR_ASSERT(ppair->right->template_mispriming != ALIGN_SCORE_UNDEF);
4225 PR_ASSERT(ppair->right->template_mispriming_r != ALIGN_SCORE_UNDEF);
4226 ppair->template_mispriming =
4227 ppair->left->template_mispriming + ppair->right->template_mispriming_r;
4228 if ((ppair->left->template_mispriming_r + ppair->right->template_mispriming)
4229 > ppair->template_mispriming)
4230 ppair->template_mispriming
4231 = ppair->left->template_mispriming_r + ppair->right->template_mispriming;
4232
4233 if (pa->pair_max_template_mispriming >= 0.0
4234 && ppair->template_mispriming > pa->pair_max_template_mispriming) {
4235 if (update_stats) { pair_expl->template_mispriming++; }
4236 if (!must_use) return PAIR_FAILED;
4237 }
4238 }
4239 } else { /* thermodynamic approach */
4240 if (!_pr_need_pair_template_mispriming_thermod(pa))
4241 ppair->template_mispriming = ALIGN_SCORE_UNDEF;
4242 else {
4243 PR_ASSERT(ppair->left->template_mispriming != ALIGN_SCORE_UNDEF);
4244 PR_ASSERT(ppair->left->template_mispriming_r != ALIGN_SCORE_UNDEF);
4245 PR_ASSERT(ppair->right->template_mispriming != ALIGN_SCORE_UNDEF);
4246 PR_ASSERT(ppair->right->template_mispriming_r != ALIGN_SCORE_UNDEF);
4247 ppair->template_mispriming =
4248 ppair->left->template_mispriming + ppair->right->template_mispriming_r;
4249 if ((ppair->left->template_mispriming_r + ppair->right->template_mispriming)
4250 > ppair->template_mispriming)
4251 ppair->template_mispriming
4252 = ppair->left->template_mispriming_r + ppair->right->template_mispriming;
4253
4254 if (pa->pair_max_template_mispriming_th
4255 && ppair->template_mispriming > pa->pair_max_template_mispriming_th) {
4256 if (update_stats) {
4257 pair_expl->template_mispriming++;
4258 }
4259 if (!must_use) return PAIR_FAILED;
4260 }
4261 }
4262 }
4263
4264 /* End of calculating _pair_ mispriming if necessary. */
4265 /* ============================================================= */
4266
4267 return PAIR_OK;
4268 } /* characterize_pair */
4269
4270
4271 /*
4272 */
4273 void
compute_position_penalty(const p3_global_settings * pa,const seq_args * sa,primer_rec * h,oligo_type o_type)4274 compute_position_penalty(const p3_global_settings *pa,
4275 const seq_args *sa,
4276 primer_rec *h,
4277 oligo_type o_type)
4278 {
4279 int three_prime_base;
4280 int inside_flag = 0;
4281 int target_begin, target_end;
4282
4283 PR_ASSERT(OT_LEFT == o_type || OT_RIGHT == o_type);
4284 PR_ASSERT(1 == sa->tar2.count);
4285 target_begin = sa->tar2.pairs[0][0];
4286 target_end = target_begin + sa->tar2.pairs[0][1] - 1;
4287
4288 three_prime_base = OT_LEFT == o_type
4289 ? h->start + h->length - 1 : h->start - h->length + 1;
4290 bf_set_infinite_pos_penalty(h,1);
4291 h->position_penalty = 0.0;
4292
4293 if (OT_LEFT == o_type) {
4294 if (three_prime_base <= target_end) {
4295 bf_set_infinite_pos_penalty(h,0);
4296 if (three_prime_base < target_begin)
4297 h->position_penalty = target_begin - three_prime_base - 1;
4298 else {
4299 h->position_penalty = three_prime_base - target_begin + 1;
4300 inside_flag = 1;
4301 }
4302 }
4303 } else { /* OT_RIGHT == o_type */
4304 if (three_prime_base >= target_begin) {
4305 bf_set_infinite_pos_penalty(h,0);
4306 if (three_prime_base > target_end) {
4307 h->position_penalty = three_prime_base - target_end - 1;
4308 } else {
4309 h->position_penalty = target_end - three_prime_base + 1;
4310 inside_flag = 1;
4311 }
4312 }
4313 }
4314 if (!inside_flag)
4315 h->position_penalty *= pa->outside_penalty;
4316 else {
4317 h->position_penalty *= pa->inside_penalty;
4318 }
4319 }
4320
4321 /*
4322 * Return 1 if 'pair' spans any target (in sa->tar); otherwise return 0; An
4323 * oligo pair spans a target, t, if the last base of the left primer is to
4324 * left of the last base of t and the first base of the right primer is to
4325 * the right of the first base of t. Of course the primers must
4326 * still be in a legal position with respect to each other.
4327 */
4328 static int
pair_spans_target(const primer_pair * pair,const seq_args * sa)4329 pair_spans_target(const primer_pair *pair, const seq_args *sa)
4330 {
4331 int i;
4332 int last_of_left = pair->left->start + pair->left->length - 1;
4333 int first_of_right = pair->right->start - pair->right->length + 1;
4334 int target_first, target_last;
4335 for (i = 0; i < sa->tar2.count; i++) {
4336 target_first = sa->tar2.pairs[i][0];
4337 target_last = target_first + sa->tar2.pairs[i][1] - 1;
4338 if (last_of_left <= target_last
4339 && first_of_right >= target_first
4340 && last_of_left < first_of_right)
4341 return 1;
4342 }
4343 return 0;
4344 }
4345
4346 /*
4347 * Return the value of the objective function value for given primer pair.
4348 * We must know that the pair is acceptable before calling obj_fn.
4349 */
4350 static double
obj_fn(const p3_global_settings * pa,primer_pair * h)4351 obj_fn(const p3_global_settings *pa, primer_pair *h)
4352 {
4353 double sum;
4354 double lower_tm;
4355
4356 sum = 0.0;
4357 lower_tm = h->right->temp;
4358 if(h->left->temp < h->right->temp) lower_tm = h->left->temp;
4359
4360 if(pa->pr_pair_weights.primer_quality) /* HERE 1 */
4361 sum += pa->pr_pair_weights.primer_quality * (h->left->quality + h->right->quality);
4362
4363 if(pa->pr_pair_weights.io_quality && pa->pick_right_primer
4364 && pa->pick_left_primer && pa->pick_internal_oligo)
4365 sum += pa->pr_pair_weights.io_quality * h->intl->quality;
4366
4367 if(pa->pr_pair_weights.diff_tm)
4368 sum += pa->pr_pair_weights.diff_tm * h->diff_tm;
4369
4370 if (pa->thermodynamic_oligo_alignment==0) {
4371 if (pa->pr_pair_weights.compl_any)
4372 sum += pa->pr_pair_weights.compl_any * h->compl_any;
4373 if (pa->pr_pair_weights.compl_end)
4374 sum += pa->pr_pair_weights.compl_end * h->compl_end;
4375 } else if (pa->thermodynamic_oligo_alignment==1) {
4376
4377 if (pa->pr_pair_weights.compl_any_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->compl_any))
4378 sum += pa->pr_pair_weights.compl_any_th * (h->compl_any - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0));
4379 if (pa->pr_pair_weights.compl_any_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->compl_any))
4380 sum += pa->pr_pair_weights.compl_any_th * (1/(lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->compl_any));
4381
4382 if (pa->pr_pair_weights.compl_end_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->compl_end))
4383 sum += pa->pr_pair_weights.compl_end_th * (h->compl_end - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0));
4384 if (pa->pr_pair_weights.compl_end_th && ((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->compl_end))
4385 sum += pa->pr_pair_weights.compl_end_th * (1/(lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->compl_end));
4386 } else {
4387 PR_ASSERT(0);
4388 /* Programming error */
4389 }
4390
4391 if(pa->pr_pair_weights.product_tm_lt && h->product_tm < pa->product_opt_tm)
4392 sum += pa->pr_pair_weights.product_tm_lt *
4393 (pa->product_opt_tm - h->product_tm);
4394
4395 if(pa->pr_pair_weights.product_tm_gt && h->product_tm > pa->product_opt_tm)
4396 sum += pa->pr_pair_weights.product_tm_gt *
4397 (h->product_tm - pa->product_opt_tm);
4398
4399 if(pa->pr_pair_weights.product_size_lt &&
4400 h->product_size < pa->product_opt_size)
4401 sum += pa->pr_pair_weights.product_size_lt *
4402 (pa->product_opt_size - h->product_size);
4403
4404 if(pa->pr_pair_weights.product_size_gt &&
4405 h->product_size > pa->product_opt_size)
4406 sum += pa->pr_pair_weights.product_size_gt *
4407 (h->product_size - pa->product_opt_size);
4408
4409 if(pa->pr_pair_weights.repeat_sim)
4410 sum += pa->pr_pair_weights.repeat_sim * h->repeat_sim;
4411
4412 if (pa->pr_pair_weights.template_mispriming && pa->thermodynamic_template_alignment==0) {
4413 PR_ASSERT(pa->pr_pair_weights.template_mispriming >= 0.0);
4414 PR_ASSERT(h->template_mispriming >= 0.0);
4415 sum += pa->pr_pair_weights.template_mispriming * h->template_mispriming;
4416 }
4417 if (pa->pr_pair_weights.template_mispriming_th && pa->thermodynamic_template_alignment==1) {
4418 PR_ASSERT(pa->pr_pair_weights.template_mispriming_th >= 0.0);
4419 PR_ASSERT(h->template_mispriming >= 0.0);
4420 if((lower_tm - pa->pr_pair_weights.temp_cutoff) <= h->template_mispriming)
4421 sum += pa->pr_pair_weights.template_mispriming_th *
4422 (h->template_mispriming - (lower_tm - pa->pr_pair_weights.temp_cutoff - 1.0));
4423 if((lower_tm - pa->pr_pair_weights.temp_cutoff) > h->template_mispriming)
4424 sum += pa->pr_pair_weights.template_mispriming_th *
4425 (1/(lower_tm - pa->pr_pair_weights.temp_cutoff + 1.0 - h->template_mispriming));
4426 }
4427 PR_ASSERT(sum >= 0.0);
4428 return sum;
4429 }
4430
4431 static double
align(const char * s1,const char * s2,const dpal_args * a)4432 align(const char *s1,
4433 const char *s2,
4434 const dpal_args *a) {
4435 dpal_results r;
4436 if(a->flag == DPAL_LOCAL || a->flag == DPAL_LOCAL_END) {
4437 if (strlen(s2) < 3) {
4438 /* For extremely short alignments we simply
4439 max out the score, because the dpal subroutines
4440 for these cannot handle this case.
4441 TO DO: this can probably be corrected in dpal. */
4442 return strlen(s2);
4443 }
4444 }
4445 dpal((const unsigned char *) s1, (const unsigned char *) s2, a, &r);
4446 PR_ASSERT(r.score <= SHRT_MAX);
4447 if (r.score == DPAL_ERROR_SCORE) {
4448 /* There was an error. */
4449 if (errno == ENOMEM) {
4450 longjmp(_jmp_buf, 1);
4451 } else {
4452 /* This branch is taken only if there is a programming error, in
4453 that s1 or s2 were NULL or contained an illegal character. We
4454 try to print some debugging information before aborting. */
4455 fprintf(stderr, "%s", r.msg);
4456 /* Always false, causes an abort: */
4457 PR_ASSERT(r.score != DPAL_ERROR_SCORE);
4458 }
4459 }
4460 return ((r.score < 0.0) ? 0.0 : r.score / PR_ALIGN_SCORE_PRECISION);
4461 }
4462
4463 /* Helper function */
4464 static int
_set_string(char ** loc,const char * new_string)4465 _set_string(char **loc, const char *new_string) {
4466 if (*loc) {
4467 free(*loc);
4468 }
4469 if (!(*loc = (char *) malloc(strlen(new_string) + 1)))
4470 return 1; /* ENOMEM */
4471 strcpy(*loc, new_string);
4472 return 0;
4473 }
4474
4475 static double
align_thermod(const char * s1,const char * s2,const thal_args * a)4476 align_thermod(const char *s1,
4477 const char *s2,
4478 const thal_args *a)
4479 {
4480 int thal_trace=0;
4481 thal_results r;
4482 thal((const unsigned char *) s1, (const unsigned char *) s2, a, &r);
4483 if (thal_trace) {
4484 fprintf(stdout,
4485 "thal, thal_args, type=%d maxLoop=%d mv=%f dv=%f "
4486 "dntp=%f dna_conc=%f, temp=%f, temponly=%d dimer=%d\n",
4487 a->type, a->maxLoop, a->mv, a->dv, a->dntp, a->dna_conc,
4488 a->temp, a->temponly, a->dimer);
4489 fprintf(stdout,
4490 "thal: s1=%s s2=%s temp=%f msg=%s end1=%d end2=%d\n",
4491 s1, s2, r.temp, r.msg, r.align_end_1, r.align_end_2);
4492 }
4493 PR_ASSERT(r.temp <= DBL_MAX);
4494 if (r.temp == THAL_ERROR_SCORE)
4495 {
4496 /* There was an error. */
4497 if (errno == ENOMEM) {
4498 longjmp(_jmp_buf, 1);
4499 } else {
4500 /* This branch is taken if there is an error other than
4501 ENOMEM, in which case we treat it as a per sequence error.
4502 */
4503 /* Save the error string */
4504 if (!_set_string(&thermodynamic_alignment_length_error_msg, r.msg)) {
4505 thermodynamic_alignment_length_error = 1;
4506 }
4507 longjmp(_jmp_buf, 1);
4508 }
4509 }
4510 return ((r.temp < 0.0) ? 0.0 : (double) (r.temp));
4511 }
4512
4513 /* Return the sequence of oligo in
4514 a ****static***** buffer. The
4515 sequence returned is changed at the
4516 next call to pr_oligo_sequence. */
4517 char *
pr_oligo_sequence(const seq_args * sa,const primer_rec * oligo)4518 pr_oligo_sequence(const seq_args *sa,
4519 const primer_rec *oligo)
4520 {
4521 static char s[MAX_PRIMER_LENGTH+1];
4522 int seq_len;
4523 PR_ASSERT(NULL != sa);
4524 PR_ASSERT(NULL != oligo);
4525 seq_len = strlen(sa->sequence);
4526 PR_ASSERT(oligo->start + sa->incl_s >= 0);
4527 PR_ASSERT(oligo->start + sa->incl_s + oligo->length <= seq_len);
4528 _pr_substr(sa->sequence, sa->incl_s + oligo->start, oligo->length, s);
4529 return &s[0];
4530 }
4531
4532 char *
pr_oligo_rev_c_sequence(const seq_args * sa,const primer_rec * o)4533 pr_oligo_rev_c_sequence(const seq_args *sa,
4534 const primer_rec *o)
4535 {
4536 static char s[MAX_PRIMER_LENGTH+1], s1[MAX_PRIMER_LENGTH+1];
4537 int seq_len, start;
4538 PR_ASSERT(NULL != sa);
4539 PR_ASSERT(NULL != o);
4540 seq_len = strlen(sa->sequence);
4541 start = sa->incl_s + o->start - o->length + 1;
4542 PR_ASSERT(start >= 0);
4543 PR_ASSERT(start + o->length <= seq_len);
4544 _pr_substr(sa->sequence, start, o->length, s);
4545 p3_reverse_complement(s,s1);
4546 return &s1[0];
4547 }
4548
4549 /* Calculate self complementarity (both h->self_any and h->self_end)
4550 which we use as an approximation for both secondary structure and
4551 self primer-dimer. */
4552 static void
oligo_compl(primer_rec * h,const args_for_one_oligo_or_primer * po_args,oligo_stats * ostats,const dpal_arg_holder * dpal_arg_to_use,const char * oligo_seq,const char * revc_oligo_seq)4553 oligo_compl(primer_rec *h,
4554 const args_for_one_oligo_or_primer *po_args,
4555 oligo_stats *ostats,
4556 const dpal_arg_holder *dpal_arg_to_use,
4557 const char *oligo_seq,
4558 const char *revc_oligo_seq)
4559 {
4560 PR_ASSERT(h != NULL);
4561
4562 h->self_any = align(oligo_seq, revc_oligo_seq, dpal_arg_to_use->local);
4563 if (h->self_any > po_args->max_self_any) {
4564 op_set_high_self_any(h);
4565 ostats->compl_any++;
4566 ostats->ok--;
4567 if (!h->must_use) return;
4568 }
4569
4570 h->self_end = align(oligo_seq, revc_oligo_seq, dpal_arg_to_use->end);
4571 if (h->self_end > po_args->max_self_end) {
4572 op_set_high_self_end(h);
4573 ostats->compl_end++;
4574 ostats->ok--;
4575 if (!h->must_use) return;
4576 }
4577 }
4578
4579 static void
oligo_compl_thermod(primer_rec * h,const args_for_one_oligo_or_primer * po_args,oligo_stats * ostats,const thal_arg_holder * thal_arg_to_use,const char * oligo_seq,const char * revc_oligo_seq)4580 oligo_compl_thermod(primer_rec *h,
4581 const args_for_one_oligo_or_primer *po_args,
4582 oligo_stats *ostats,
4583 const thal_arg_holder *thal_arg_to_use,
4584 const char *oligo_seq,
4585 const char *revc_oligo_seq)
4586 {
4587
4588 PR_ASSERT(h != NULL);
4589 h->self_any = align_thermod(oligo_seq, revc_oligo_seq, thal_arg_to_use->any);
4590 if(h->self_any > po_args->max_self_any_th) {
4591 op_set_high_self_any(h);
4592 ostats->compl_any++;
4593 ostats->ok--;
4594 if (!h->must_use) return;
4595 }
4596 h->self_end = align_thermod(oligo_seq, revc_oligo_seq, thal_arg_to_use->end1);
4597 if(h->self_end > po_args->max_self_end_th){
4598 op_set_high_self_end(h);
4599 ostats->compl_end++;
4600 ostats->ok--;
4601 if (!h->must_use) return;
4602 }
4603 }
4604
4605 static void
oligo_hairpin(primer_rec * h,const args_for_one_oligo_or_primer * po_args,oligo_stats * ostats,const thal_arg_holder * thal_arg_to_use,const char * oligo_seq)4606 oligo_hairpin(primer_rec *h,
4607 const args_for_one_oligo_or_primer *po_args,
4608 oligo_stats *ostats,
4609 const thal_arg_holder *thal_arg_to_use,
4610 const char *oligo_seq)
4611 {
4612 PR_ASSERT(h != NULL);
4613 h->hairpin_th = align_thermod(oligo_seq, oligo_seq, thal_arg_to_use->hairpin_th);
4614 if(h->hairpin_th > po_args->max_hairpin_th) {
4615 op_set_high_hairpin_th(h);
4616 ostats->hairpin_th++;
4617 ostats->ok--;
4618 return;
4619 }
4620 }
4621
4622 static void
primer_mispriming_to_template(primer_rec * h,const p3_global_settings * pa,const seq_args * sa,oligo_type l,oligo_stats * ostats,int first,int last,const char * s,const char * s_r,const dpal_args * align_args)4623 primer_mispriming_to_template(primer_rec *h,
4624 const p3_global_settings *pa,
4625 const seq_args *sa,
4626 oligo_type l,
4627 oligo_stats *ostats,
4628 int first,
4629 int last,
4630 /* The oligo sequence: */
4631 const char *s,
4632 /* s reverse complemented: */
4633 const char *s_r,
4634 const dpal_args *align_args
4635 )
4636 {
4637 const char *oseq;
4638 char *target, *target_r;
4639 int tmp, seqlen;
4640 int debug = 0;
4641 int first_untrimmed, last_untrimmed;
4642 /* Indexes of first and last bases of the oligo in sa->seq,
4643 that is, WITHIN THE TOTAL SEQUENCE INPUT. */
4644
4645 /* first, last are indexes of first and last bases of the oligo in
4646 sa->trimmed_seq, that is, WITHIN THE INCLUDED REGION. */
4647
4648 char tmp_char;
4649 double tmp_score;
4650
4651 seqlen = strlen(sa->upcased_seq);
4652 first_untrimmed = sa->incl_s + first;
4653 last_untrimmed = sa->incl_s + last;
4654
4655 if (l == OT_LEFT) {
4656 oseq = &s[0];
4657 target = &sa->upcased_seq[0];
4658 target_r = &sa->upcased_seq_r[0];
4659 } else { /* l == OT_RIGHT */
4660 if (debug)
4661 fprintf(stderr, "first_untrimmed = %d, last_untrimmed = %d\n",
4662 first_untrimmed, last_untrimmed);
4663 oseq = &s_r[0];
4664 target = &sa->upcased_seq_r[0];
4665 target_r = &sa->upcased_seq[0];
4666 /* We need to adjust first_untrimmed and last_untrimmed so that
4667 they are correct in the reverse-complemented
4668 sequence.
4669 */
4670 tmp = (seqlen - last_untrimmed) - 1;
4671 last_untrimmed = (seqlen - first_untrimmed) - 1;
4672 first_untrimmed = tmp;
4673 }
4674
4675 /* 1. Align to the template 5' of the oligo. */
4676 tmp_char = target[first_untrimmed];
4677 target[first_untrimmed] = '\0';
4678
4679 tmp_score = align(oseq, target, align_args);
4680
4681 if (debug) {
4682 if (l == OT_LEFT) fprintf(stderr, "\n************ OLIGO = LEFT\n");
4683 else fprintf(stderr, "\n************ OLIGO = RIGHT\n");
4684 fprintf(stderr, "first_untrimmed = %d, last_untrimmed = %d,first = %d, last = %d\n",
4685 first_untrimmed, last_untrimmed, first, last);
4686
4687 fprintf(stderr, "5' of oligo: Score %f aligning %s against %s\n\n", tmp_score,
4688 oseq, target);
4689 }
4690
4691 target[first_untrimmed] = tmp_char;
4692
4693 /* 2. Align to the template 3' of the oligo. */
4694 h->template_mispriming
4695 = align(oseq, &target[0] + last_untrimmed + 1, align_args);
4696
4697 if (debug)
4698 fprintf(stderr, "3' of oligo Score %f aligning %s against %s\n\n",
4699 h->template_mispriming, oseq, &target[0] + last_untrimmed + 1);
4700
4701 /* 3. Take the max of 1. and 2. */
4702 if (tmp_score > h->template_mispriming)
4703 h->template_mispriming = tmp_score;
4704
4705 /* 4. Align to the reverse strand of the template. */
4706 h->template_mispriming_r
4707 = align(oseq, target_r, align_args);
4708
4709 if (debug)
4710 fprintf(stderr, "other strand Score %f aligning %s against %s\n\n",
4711 h->template_mispriming_r, oseq, target_r);
4712
4713 if (pa->p_args.max_template_mispriming >= 0) {
4714 if (oligo_max_template_mispriming(h)
4715 > pa->p_args.max_template_mispriming) {
4716 op_set_high_similarity_to_multiple_template_sites(h);
4717 if (OT_LEFT == l || OT_RIGHT == l ) {
4718 ostats->template_mispriming++;
4719 ostats->ok--;
4720 } else PR_ASSERT(0); /* Should not get here. */
4721 } else {
4722 /* This oligo is ok, mark it so we do not do this check again. */
4723 h->template_mispriming_ok = 1;
4724 }
4725 }
4726 }
4727
4728 static void
primer_mispriming_to_template_thermod(primer_rec * h,const p3_global_settings * pa,const seq_args * sa,oligo_type l,oligo_stats * ostats,int first,int last,const char * s,const char * s_r,const thal_args * align_args)4729 primer_mispriming_to_template_thermod(primer_rec *h,
4730 const p3_global_settings *pa,
4731 const seq_args *sa,
4732 oligo_type l,
4733 oligo_stats *ostats,
4734 int first,
4735 int last,
4736 /* The oligo sequence: */
4737 const char *s,
4738 /* s reverse complemented: */
4739 const char *s_r,
4740 const thal_args *align_args)
4741 {
4742 const char *oseq;
4743 char *target, *target_r;
4744 int tmp, seqlen;
4745 int debug = 0;
4746 int first_untrimmed, last_untrimmed;
4747 /* Indexes of first and last bases of the oligo in sa->seq,
4748 * that is, WITHIN THE TOTAL SEQUENCE INPUT. */
4749
4750 /* first, last are indexes of first and last bases of the oligo in
4751 * sa->trimmed_seq, that is, WITHIN THE INCLUDED REGION. */
4752
4753 char tmp_char;
4754 double tmp_score;
4755
4756 seqlen = strlen(sa->upcased_seq);
4757 first_untrimmed = sa->incl_s + first;
4758 last_untrimmed = sa->incl_s + last;
4759
4760 if (l == OT_RIGHT) {
4761 oseq = &s_r[0];
4762 target = &sa->upcased_seq[0];
4763 target_r = &sa->upcased_seq_r[0];
4764 } else { /* l == OT_RIGHT */
4765 if (debug)
4766 fprintf(stdout, "first_untrimmed = %d, last_untrimmed = %d\n",
4767 first_untrimmed, last_untrimmed);
4768 oseq = &s[0];
4769 target = &sa->upcased_seq_r[0];
4770 target_r = &sa->upcased_seq[0];
4771 /* We need to adjust first_untrimmed and last_untrimmed so that
4772 * they are correct in the reverse-complemented
4773 * sequence.
4774 * */
4775 tmp = (seqlen - last_untrimmed) - 1;
4776 last_untrimmed = (seqlen - first_untrimmed) - 1;
4777 first_untrimmed = tmp;
4778 }
4779
4780 /* 1. Align to the template 5' of the oligo. */
4781 /* tmp_char = target_r[first_untrimmed]; Corrected 2012-05-30 */
4782 tmp_char = target[first_untrimmed];
4783 target[first_untrimmed] = '\0';
4784
4785 tmp_score = align_thermod(oseq, target, align_args);
4786
4787 if (debug) {
4788 if (l == OT_LEFT) fprintf(stdout, "\n************ OLIGO = LEFT\n");
4789 else fprintf(stdout, "\n************ OLIGO = RIGHT\n");
4790 fprintf(stdout, "first_untrimmed = %d, last_untrimmed = %d, first = %d, last = %d\n",
4791 first_untrimmed, last_untrimmed, first, last);
4792
4793 fprintf(stdout, "5' of oligo: Score %f aligning %s against %s\n\n", tmp_score,
4794 oseq, target);
4795 }
4796 target[first_untrimmed] = tmp_char;
4797
4798 /* 2. Align to the template 3' of the oligo. */
4799 h->template_mispriming
4800 = align_thermod(oseq, &target[0] + last_untrimmed + 1, align_args);
4801
4802 if (debug)
4803 fprintf(stdout, "3' of oligo Score %f aligning %s against %s\n\n",
4804 h->template_mispriming, oseq, &target[0] + last_untrimmed + 1);
4805
4806 /* 3. Take the max of 1. and 2. */
4807 if (tmp_score > h->template_mispriming)
4808 h->template_mispriming = tmp_score;
4809
4810 /* 4. Align to the reverse strand of the template. */
4811 h->template_mispriming_r
4812 = align_thermod(oseq, target_r, align_args);
4813
4814 if (debug)
4815 fprintf(stdout,
4816 "In primer_mispriming_to_template_thermod\n"
4817 " other strand Score %f aligning %s against %s\n\n",
4818 h->template_mispriming_r, oseq, target_r);
4819
4820 if (pa->p_args.max_template_mispriming_th >= 0) {
4821 if (oligo_max_template_mispriming_thermod(h)
4822 > pa->p_args.max_template_mispriming_th) {
4823 op_set_high_similarity_to_multiple_template_sites(h);
4824 if (OT_LEFT == l || OT_RIGHT == l ) {
4825 ostats->template_mispriming++;
4826 ostats->ok--;
4827 }
4828 else PR_ASSERT(0); /* Should not get here. */
4829 } else {
4830 /* This oligo is ok, mark it so we do not do this check again. */
4831 h->template_mispriming_ok = 1;
4832 }
4833 }
4834 }
4835
4836 static void
oligo_compute_sequence_and_reverse(primer_rec * h,const seq_args * sa,oligo_type l,int * first,int * last,char * s,char * s_r)4837 oligo_compute_sequence_and_reverse(primer_rec *h,
4838 const seq_args *sa,
4839 oligo_type l,
4840 int *first, int *last,
4841 char *s, char *s_r)
4842 {
4843 *first = (OT_LEFT == l || OT_INTL == l)
4844 ? h->start
4845 : h->start - h->length + 1;
4846 *last = (OT_LEFT == l || OT_INTL == l)
4847 ? h->start + h->length - 1
4848 : h->start;
4849
4850 _pr_substr(sa->trimmed_seq, *first, h->length, s);
4851 p3_reverse_complement(s, s_r);
4852 }
4853
4854 /* Possible improvement -- pass in the oligo sequences */
4855 static void
oligo_repeat_library_mispriming(primer_rec * h,const p3_global_settings * pa,const seq_args * sa,oligo_type l,oligo_stats * ostats,const dpal_arg_holder * dpal_arg_to_use)4856 oligo_repeat_library_mispriming(primer_rec *h,
4857 const p3_global_settings *pa,
4858 const seq_args *sa,
4859 oligo_type l,
4860 oligo_stats *ostats,
4861 const dpal_arg_holder *dpal_arg_to_use)
4862 {
4863 char
4864 s[MAX_PRIMER_LENGTH+1], /* Will contain the oligo sequence. */
4865 s_r[MAX_PRIMER_LENGTH+1]; /* Will contain s reverse complemented. */
4866
4867 double w;
4868 const seq_lib *lib;
4869 int i;
4870 int first, last; /* Indexes of first and last bases of the oligo in
4871 sa->trimmed_seq, that is, WITHIN THE INCLUDED
4872 REGION. */
4873 int min, max;
4874 short max_lib_compl;
4875
4876 /* First, check the oligo against the repeat library. */
4877 if (OT_INTL == l) {
4878 lib = pa->o_args.repeat_lib;
4879 max_lib_compl = (short) pa->o_args.max_repeat_compl;
4880 } else {
4881 lib = pa->p_args.repeat_lib;
4882 max_lib_compl = (short) pa->p_args.max_repeat_compl;
4883 }
4884
4885 oligo_compute_sequence_and_reverse(h, sa, l, &first, &last, s, s_r);
4886
4887 /*
4888 * Calculate maximum similarity to sequences from user defined repeat
4889 * library. Compare it with maximum allowed repeat similarity.
4890 */
4891
4892 if (seq_lib_num_seq(lib) > 0) {
4893 /* Library exists and is non-empty. */
4894
4895 h->repeat_sim.score =
4896 (double *) pr_safe_malloc(lib->seq_num * sizeof(double));
4897 h->repeat_sim.max = h->repeat_sim.min = 0;
4898 max = min = 0;
4899 h->repeat_sim.name = lib->names[0];
4900
4901 for (i = 0; i < lib->seq_num; i++) {
4902 if (OT_LEFT == l)
4903 w = lib->weight[i] *
4904 align(s, lib->seqs[i],
4905 (pa->lib_ambiguity_codes_consensus
4906 ? dpal_arg_to_use->local_end_ambig
4907 : dpal_arg_to_use->local_end));
4908
4909 else if (OT_INTL == l)
4910 w = lib->weight[i] *
4911 align(s, lib->seqs[i],
4912 (pa->lib_ambiguity_codes_consensus
4913 ? dpal_arg_to_use->local_ambig
4914 : dpal_arg_to_use->local));
4915
4916 else
4917 w = lib->weight[i] *
4918 align(s_r, lib->rev_compl_seqs[i],
4919 (pa->lib_ambiguity_codes_consensus
4920 ? dpal_arg_to_use->local_end_ambig
4921 : dpal_arg_to_use->local));
4922
4923
4924 if (w > SHRT_MAX || w < SHRT_MIN) {
4925 abort(); /* TO DO, propagate error */
4926 /* This check is necessary for the next 9 lines */
4927 }
4928 h->repeat_sim.score[i] = w;
4929 if(w > max){
4930 max = (int) w;
4931 h->repeat_sim.max = i;
4932 h->repeat_sim.name = lib->names[i];
4933 }
4934 if(w < min){
4935 min = (int) w;
4936 h->repeat_sim.min = i;
4937 }
4938
4939 if (w > max_lib_compl) {
4940 op_set_high_similarity_to_non_template_seq(h);
4941 ostats->repeat_score++;
4942 ostats->ok--;
4943 if (!h->must_use) return;
4944 } /* if w > max_lib_compl */
4945 } /* for */
4946 } /* if library exists and is non-empty */
4947 /* End of checking against the repeat library */
4948 }
4949
4950 /* This function carries out either the old "dpal" alignment or the
4951 thermodynamic alignment, depending on the value of
4952 pa->thermodynamic_template_alignment. */
4953 static void
oligo_template_mispriming(primer_rec * h,const p3_global_settings * pa,const seq_args * sa,oligo_type l,oligo_stats * ostats,const dpal_args * d_align_args,const thal_args * t_align_args)4954 oligo_template_mispriming(primer_rec *h,
4955 const p3_global_settings *pa,
4956 const seq_args *sa,
4957 oligo_type l,
4958 oligo_stats *ostats,
4959 const dpal_args *d_align_args,
4960 const thal_args *t_align_args)
4961 {
4962 char
4963 s[MAX_PRIMER_LENGTH+1], /* Will contain the oligo sequence. */
4964 s_r[MAX_PRIMER_LENGTH+1]; /* Will contain s reverse complemented. */
4965
4966 int first, last; /* Indexes of first and last bases of the oligo in
4967 sa->trimmed_seq, that is, WITHIN THE INCLUDED
4968 REGION. */
4969
4970 /* Check if we already did this and the oligo was ok. */
4971 if (h->template_mispriming_ok) {
4972 return;
4973 }
4974
4975 oligo_compute_sequence_and_reverse(h, sa, l, &first, &last, s, s_r);
4976
4977 /* Calculate maximum similarity to ectopic sites in the template. */
4978 if (l == OT_RIGHT || l == OT_LEFT) {
4979 if (pa->thermodynamic_template_alignment == 0 && _pr_need_template_mispriming(pa))
4980 primer_mispriming_to_template(h, pa, sa, l,
4981 ostats, first,
4982 last, s, s_r, d_align_args);
4983 if (pa->thermodynamic_template_alignment == 1 && _pr_need_template_mispriming_thermod(pa))
4984 primer_mispriming_to_template_thermod(h, pa, sa, l,
4985 ostats, first,
4986 last, s, s_r, t_align_args);
4987 }
4988 }
4989
4990 static int
pair_repeat_sim(primer_pair * h,const p3_global_settings * pa)4991 pair_repeat_sim(primer_pair *h,
4992 const p3_global_settings *pa) {
4993 int i, n, max, w;
4994 primer_rec *fw, *rev;
4995
4996 fw = h->left;
4997 rev = h->right;
4998
4999 max = 0;
5000 n = seq_lib_num_seq(pa->p_args.repeat_lib);
5001 if(n == 0) return 0;
5002 h->rep_name = pa->p_args.repeat_lib->names[0] ;
5003 for (i = 0; i < n; i++) {
5004 if ((w = (int) (fw->repeat_sim.score[i] +
5005 rev->repeat_sim.score[i])) > max) {
5006 max = w;
5007 h->rep_name = pa->p_args.repeat_lib->names[i] ;
5008 }
5009 }
5010 return max;
5011 }
5012
5013 static void
set_retval_both_stop_codons(const seq_args * sa,p3retval * retval)5014 set_retval_both_stop_codons(const seq_args *sa, p3retval *retval) {
5015 /* The position of the intial base of the rightmost stop codon that
5016 * is to the left of sa->start_codon_pos; valid only if
5017 * sa->start_codon_pos is "not null". We will not want to include
5018 * a stop codon to the right of the the start codon in the
5019 * amplicon. */
5020 retval->upstream_stop_codon = find_stop_codon(sa->trimmed_seq,
5021 sa->start_codon_pos, -1);
5022 retval->upstream_stop_codon += sa->incl_s;
5023 retval->stop_codon_pos = find_stop_codon(sa->trimmed_seq,
5024 sa->start_codon_pos, 1);
5025 retval->stop_codon_pos += sa->incl_s;
5026 }
5027
5028 /*
5029 * 's' is the sequence in which to find the stop codon.
5030 * 'start' is the position of a start codon.
5031 *
5032 * There are two modes depending on 'direction'.
5033 *
5034 * If direction is 1:
5035 *
5036 * Return the index of the first stop codon to the right of
5037 * 'start' in 's' (in same frame).
5038 * If there is no such stop codon return -1.
5039 *
5040 * If direction is -1:
5041 *
5042 * If 'start' is negative then return -1.
5043 * Otherwise return the index the first stop codon to left of 'start'.
5044 * If there is no such stop codon return -1.
5045 *
5046 * Note: we don't insist that the start codon be ATG, since in some
5047 * cases the caller will not have the full sequence in 's', nor even
5048 * know the postion of the start codon relative to s.
5049 */
5050 static int
find_stop_codon(const char * s,int start,int direction)5051 find_stop_codon(const char* s,
5052 int start,
5053 int direction) {
5054 const char *p, *q;
5055 int increment = 3 * direction;
5056 int len = strlen(s);
5057
5058 PR_ASSERT(s != NULL);
5059 PR_ASSERT(direction == 1 || direction == -1);
5060 PR_ASSERT(len >= 3);
5061 PR_ASSERT(start <= (len - 3));
5062
5063 if (start < 0) {
5064 if (direction == 1)
5065 while (start < 0) start += increment;
5066 else
5067 return -1;
5068 }
5069
5070 for (p = &s[start];
5071 p >= &s[0]
5072 && *p
5073 && *(p + 1)
5074 && *(p + 2);
5075 p += increment) {
5076 if ('T' != *p && 't' != *p) continue;
5077 q = p + 1;
5078 if ('A' == *q || 'a' == *q) {
5079 q++;
5080 if ('G' == *q || 'g' == *q || 'A' == *q || 'a' == *q)
5081 return p - &s[0];
5082 } else if ('G' == *q || 'g' == *q) {
5083 q++;
5084 if ('A' == *q || 'a' == *q)
5085 return p - &s[0];
5086 }
5087 }
5088 return -1;
5089 }
5090
5091 int
strcmp_nocase(const char * s1,const char * s2)5092 strcmp_nocase(const char *s1, const char *s2)
5093 {
5094 static char M[UCHAR_MAX];
5095 static int f = 0;
5096 int i;
5097 const char *p, *q;
5098
5099 if(f != 1){
5100 for(i = 0; i < UCHAR_MAX; i++) M[i] = i;
5101 i = 'a'; M[i] = 'A'; i = 'b'; M[i] = 'B'; i = 'c'; M[i] = 'C';
5102 i = 'A'; M[i] = 'a'; i = 'B'; M[i] = 'b'; i = 'C'; M[i] = 'c';
5103 i = 'd'; M[i] = 'D'; i = 'e'; M[i] = 'E'; i = 'f'; M[i] = 'F';
5104 i = 'D'; M[i] = 'd'; i = 'E'; M[i] = 'e'; i = 'F'; M[i] = 'f';
5105 i = 'g'; M[i] = 'G'; i = 'h'; M[i] = 'H'; i = 'i'; M[i] = 'I';
5106 i = 'G'; M[i] = 'g'; i = 'H'; M[i] = 'h'; i = 'I'; M[i] = 'i';
5107 i = 'k'; M[i] = 'K'; i = 'l'; M[i] = 'L'; i = 'm'; M[i] = 'M';
5108 i = 'K'; M[i] = 'k'; i = 'L'; M[i] = 'l'; i = 'M'; M[i] = 'm';
5109 i = 'n'; M[i] = 'N'; i = 'o'; M[i] = 'O'; i = 'p'; M[i] = 'P';
5110 i = 'N'; M[i] = 'n'; i = 'O'; M[i] = 'o'; i = 'P'; M[i] = 'p';
5111 i = 'q'; M[i] = 'Q'; i = 'r'; M[i] = 'R'; i = 's'; M[i] = 'S';
5112 i = 'Q'; M[i] = 'q'; i = 'R'; M[i] = 'r'; i = 'S'; M[i] = 's';
5113 i = 't'; M[i] = 'T'; i = 'u'; M[i] = 'U'; i = 'v'; M[i] = 'V';
5114 i = 'T'; M[i] = 't'; i = 'U'; M[i] = 'u'; i = 'V'; M[i] = 'v';
5115 i = 'w'; M[i] = 'W'; i = 'x'; M[i] = 'X'; i = 'y'; M[i] = 'Y';
5116 i = 'W'; M[i] = 'w'; i = 'X'; M[i] = 'x'; i = 'Y'; M[i] = 'y';
5117 i = 'z'; M[i] = 'Z'; i = 'Z'; M[i] = 'z'; i = 'j'; M[i] = 'J';
5118 i = 'J'; M[i] = 'j';
5119 f = 1;
5120 }
5121
5122 if(s1 == NULL || s2 == NULL) return 1;
5123 if(strlen(s1) != strlen(s2)) return 1;
5124 p = s1; q = s2;
5125 while(*p != '\0' && *p != '\n' && *q != '\0' && *q != '\n'){
5126 i = *p;
5127 if(*p == *q || M[i] == *q ) {p++; q++; continue;}
5128
5129 return 1;
5130 }
5131 return 0;
5132 }
5133
5134 static void
free_repeat_sim_score(p3retval * state)5135 free_repeat_sim_score(p3retval *state)
5136 {
5137 int i;
5138
5139 for (i = 0; i < state->fwd.num_elem; i++) {
5140 if (state->fwd.oligo[i].repeat_sim.score != NULL) {
5141 free(state->fwd.oligo[i].repeat_sim.score);
5142 state->fwd.oligo[i].repeat_sim.score = NULL;
5143 }
5144 }
5145
5146 for (i = 0; i < state->rev.num_elem; i++) {
5147 if (state->rev.oligo[i].repeat_sim.score != NULL) {
5148 free(state->rev.oligo[i].repeat_sim.score);
5149 state->rev.oligo[i].repeat_sim.score = NULL;
5150 }
5151 }
5152
5153 for (i = 0; i < state->intl.num_elem; i++) {
5154 if (state->intl.oligo[i].repeat_sim.score != NULL) {
5155 free(state->intl.oligo[i].repeat_sim.score);
5156 state->intl.oligo[i].repeat_sim.score = NULL;
5157 }
5158 }
5159 }
5160
5161 static void
free_primer_repeat_sim_score(primer_rec * h)5162 free_primer_repeat_sim_score(primer_rec *h)
5163 {
5164 if (h->repeat_sim.score != NULL) {
5165 free(h->repeat_sim.score);
5166 h->repeat_sim.score = NULL;
5167 }
5168 }
5169
5170 /*
5171 Edited by T. Koressaar for lowercase masking. This function checks
5172 if the 3' end of the primer has been masked by lowercase letter.
5173 Function created/Added by Eric Reppo, July 9, 2002
5174 */
5175 static int
is_lowercase_masked(int position,const char * sequence,primer_rec * h,oligo_stats * global_oligo_stats)5176 is_lowercase_masked(int position,
5177 const char *sequence,
5178 primer_rec *h,
5179 oligo_stats *global_oligo_stats)
5180 {
5181 const char* p = &sequence[position];
5182 if ('a' == *p || 'c' == *p ||'g' == *p || 't' == *p) {
5183 op_set_overlaps_masked_sequence(h);
5184 global_oligo_stats->gmasked++;
5185 return 1;
5186 }
5187 return 0;
5188 }
5189
5190 /*
5191 Edited by A. Untergasser
5192 */
5193 static int
primer_must_match(const p3_global_settings * pa,primer_rec * h,oligo_stats * global_oligo_stats,const char * input_oligo_seq,char * match_three_prime,char * match_five_prime)5194 primer_must_match(const p3_global_settings *pa, primer_rec *h, oligo_stats *global_oligo_stats,
5195 /* This is 5'->3' on the template sequence: */
5196 const char *input_oligo_seq, char *match_three_prime, char *match_five_prime)
5197 {
5198 const char *seq;
5199 char *test;
5200 int length = h->length - 5;
5201 if (match_five_prime != NULL) {
5202 seq = input_oligo_seq;
5203 test = match_five_prime;
5204 for (int i = 0; i < 5; i++) {
5205 if (!compare_nucleotides(*seq, *test)) {
5206 global_oligo_stats->must_match_fail++;
5207 return 1;
5208 }
5209 seq++;
5210 test++;
5211 }
5212 }
5213 if (match_three_prime != NULL) {
5214 seq = input_oligo_seq;
5215 test = match_three_prime;
5216 seq = seq + length;
5217 for (int i = 0; i < 5; i++) {
5218 if (!compare_nucleotides(*seq, *test)) {
5219 global_oligo_stats->must_match_fail++;
5220 return 1;
5221 }
5222 seq++;
5223 test++;
5224 }
5225 }
5226 return 0;
5227 }
5228
5229 /* For a [NACTG] is allowed, for b [NACTGRYWSMKBHDV].*/
compare_nucleotides(const char a,const char b)5230 static int compare_nucleotides(const char a, const char b)
5231 {
5232 char x = a;
5233 char y = b;
5234 /* Convert to uppercase */
5235 if(a >= 'a' && a <= 'z'){
5236 x = ('A' + a - 'a');
5237 }
5238 if(b >= 'b' && b <= 'z'){
5239 y = ('A' + b - 'a');
5240 }
5241
5242 if ( x == y ) {
5243 return 1;
5244 }
5245 if (( x == 'N') or (y == 'N')) {
5246 return 1;
5247 }
5248 if (x == 'A') {
5249 if ((y == 'R') or (y == 'W') or (y == 'M') or
5250 (y == 'H') or (y == 'D') or (y == 'V')){
5251 return 1;
5252 }
5253 }
5254 if (x == 'G') {
5255 if ((y == 'R') or (y == 'S') or (y == 'K') or
5256 (y == 'B') or (y == 'D') or (y == 'V')){
5257 return 1;
5258 }
5259 }
5260 if (x == 'C') {
5261 if ((y == 'Y') or (y == 'S') or (y == 'M') or
5262 (y == 'B') or (y == 'H') or (y == 'V')){
5263 return 1;
5264 }
5265 }
5266 if (x == 'T') {
5267 if ((y == 'Y') or (y == 'W') or (y == 'K') or
5268 (y == 'B') or (y == 'H') or (y == 'D')){
5269 return 1;
5270 }
5271 }
5272 return 0;
5273 }
5274
test_must_match_parameters(char * test)5275 static int test_must_match_parameters(char *test)
5276 {
5277 int i = 0;
5278 char x;
5279 while (*test != '\0') {
5280 /* First to UPPER letters */
5281 if ((*test >= 'a') && (*test <= 'z')){
5282 x = ('A' + (*test) - 'a');
5283 } else {
5284 x = *test;
5285 }
5286 /* Second check that it is in Range A-Z */
5287 if ((x < 'A') || (x > 'Z')){
5288 return 1;
5289 }
5290 /* Check it is NACTGRYWSMKBHDV */
5291 if ((x == 'N') ||
5292 (x == 'A') || (x == 'C') ||
5293 (x == 'T') || (x == 'G') ||
5294 (x == 'R') || (x == 'Y') ||
5295 (x == 'W') || (x == 'S') ||
5296 (x == 'M') || (x == 'K') ||
5297 (x == 'B') || (x == 'H') ||
5298 (x == 'D') || (x == 'V')){
5299 test++;
5300 i++;
5301 } else {
5302 return 1;
5303 }
5304 }
5305 /* Check it is 5 letters */
5306 if (i != 5) {
5307 return 1;
5308 }
5309 return 0;
5310 }
5311
5312 /* Put substring of seq starting at n with length m into s. */
5313 void
_pr_substr(const char * seq,int n,int m,char * s)5314 _pr_substr(const char *seq, int n, int m, char *s)
5315 {
5316 int i;
5317 for(i=n;i<n+m;i++)s[i-n]=seq[i];
5318 s[m]='\0';
5319 }
5320
5321 /* Reverse and complement the sequence seq and put the result in s.
5322 WARNING: It is up the caller to ensure that s points to enough
5323 space. */
5324 void
p3_reverse_complement(const char * seq,char * s)5325 p3_reverse_complement(const char *seq, char *s)
5326 {
5327 const char *p = seq;
5328 char *q = s;
5329
5330 while (*p != '\0') p++;
5331 p--;
5332 while (p >= seq) {
5333 switch (*p)
5334 {
5335 case 'A': *q='T'; break;
5336 case 'C': *q='G'; break;
5337 case 'G': *q='C'; break;
5338 case 'T': *q='A'; break;
5339 case 'U': *q='A'; break;
5340
5341 case 'B': *q='V'; break;
5342 case 'D': *q='H'; break;
5343 case 'H': *q='D'; break;
5344 case 'V': *q='B'; break;
5345 case 'R': *q='Y'; break;
5346 case 'Y': *q='R'; break;
5347 case 'K': *q='M'; break;
5348 case 'M': *q='K'; break;
5349 case 'S': *q='S'; break;
5350 case 'W': *q='W'; break;
5351
5352 case 'N': *q='N'; break;
5353
5354 case 'a': *q='t'; break;
5355 case 'c': *q='g'; break;
5356 case 'g': *q='c'; break;
5357 case 't': *q='a'; break;
5358 case 'u': *q='a'; break;
5359
5360 case 'b': *q='v'; break;
5361 case 'd': *q='h'; break;
5362 case 'h': *q='d'; break;
5363 case 'v': *q='b'; break;
5364 case 'r': *q='y'; break;
5365 case 'y': *q='r'; break;
5366 case 'k': *q='m'; break;
5367 case 'm': *q='k'; break;
5368 case 's': *q='s'; break;
5369 case 'w': *q='w'; break;
5370
5371 case 'n': *q='n'; break;
5372 }
5373 p--; q++;
5374 }
5375 *q = '\0';
5376 }
5377
5378 int
_pr_need_template_mispriming(const p3_global_settings * pa)5379 _pr_need_template_mispriming(const p3_global_settings *pa) {
5380 return
5381 pa->p_args.max_template_mispriming >= 0
5382 || pa->p_args.weights.template_mispriming > 0.0
5383 || _pr_need_pair_template_mispriming(pa);
5384 }
5385 int
_pr_need_template_mispriming_thermod(const p3_global_settings * pa)5386 _pr_need_template_mispriming_thermod(const p3_global_settings *pa) {
5387 return
5388 pa->p_args.max_template_mispriming_th >= 0
5389 || pa->p_args.weights.template_mispriming_th > 0.0
5390 || _pr_need_pair_template_mispriming_thermod(pa);
5391 }
5392
5393 int
_pr_need_pair_template_mispriming(const p3_global_settings * pa)5394 _pr_need_pair_template_mispriming(const p3_global_settings *pa)
5395 {
5396 return
5397 pa->pair_max_template_mispriming >= 0
5398 || pa->pr_pair_weights.template_mispriming > 0.0;
5399 }
5400
5401 int
_pr_need_pair_template_mispriming_thermod(const p3_global_settings * pa)5402 _pr_need_pair_template_mispriming_thermod(const p3_global_settings *pa)
5403 {
5404 return
5405 pa->pair_max_template_mispriming_th >= 0
5406 || pa->pr_pair_weights.template_mispriming_th > 0.0;
5407 }
5408
5409 /* Upcase a DNA string, s, in place. If amibiguity_code_ok is false,
5410 then the characters acgtnACGTN are 'recognized' and upcased. If
5411 ambiguity_code_ok is true, then the IUB/IUPAC ambiguity codes are
5412 also 'recognized' and upcased.
5413
5414 Change any unrecognized letters in *s to 'N"
5415
5416 Return the first unrecognized letter, if
5417 any, that is seen. Otherwise return '\0'. */
5418 static char
dna_to_upper(char * s,int ambiguity_code_ok)5419 dna_to_upper(char * s, int ambiguity_code_ok)
5420 {
5421 char *p = s;
5422 int unrecognized_base = '\0';
5423 while (*p) {
5424 switch (*p) {
5425 case 'a': case 'A': *p='A'; break;
5426 case 'c': case 'C': *p='C'; break;
5427 case 'g': case 'G': *p='G'; break;
5428 case 't': case 'T': *p='T'; break;
5429 case 'n': case 'N': *p='N'; break;
5430 default:
5431 if (ambiguity_code_ok) {
5432 switch (*p) {
5433 case 'r': case 'R': *p = 'R'; break;
5434 case 'y': case 'Y': *p = 'Y'; break;
5435 case 'm': case 'M': *p = 'M'; break;
5436 case 'w': case 'W': *p = 'W'; break;
5437 case 's': case 'S': *p = 'S'; break;
5438 case 'k': case 'K': *p = 'K'; break;
5439 case 'd': case 'D': *p = 'D'; break;
5440 case 'h': case 'H': *p = 'H'; break;
5441 case 'v': case 'V': *p = 'V'; break;
5442 case 'b': case 'B': *p = 'B'; break;
5443 }
5444 } else {
5445 if (!unrecognized_base) unrecognized_base = *p;
5446 *p = 'N';
5447 }
5448 break;
5449 }
5450 p++;
5451 }
5452 return unrecognized_base;
5453 }
5454
5455 static char *
strstr_nocase(char * s1,char * s2)5456 strstr_nocase(char *s1, char *s2) {
5457 int n1, n2;
5458 char *p, q, *tmp;
5459
5460 if(s1 == NULL || s2 == NULL) return NULL;
5461 n1 = strlen(s1); n2 = strlen(s2);
5462 if(n1 < n2) return NULL;
5463
5464 tmp = (char *) pr_safe_malloc(n1 + 1);
5465 strcpy(tmp, s1);
5466
5467 q = *tmp; p = tmp;
5468 while(q != '\0' && q != '\n'){
5469 q = *(p + n2);
5470 *(p + n2) = '\0';
5471 if(strcmp_nocase(p, s2)){
5472 *(p + n2) = q; p++; continue;
5473 }
5474 else {free(tmp); return p;}
5475 }
5476 free(tmp); return NULL;
5477 }
5478
5479 #define CHECK if (r > bsize || r < 0) return "Internal error, not enough space for \"explain\" string"; bufp += r; bsize -= r
5480 #define SP_AND_CHECK(FMT, VAL) { r = sprintf(bufp, FMT, VAL); CHECK; }
5481 #define IF_SP_AND_CHECK(FMT, VAL) { if (VAL) { SP_AND_CHECK(FMT, VAL) } }
5482 const char *
p3_pair_explain_string(const pair_stats * pair_expl)5483 p3_pair_explain_string(const pair_stats *pair_expl)
5484 {
5485 /* WARNING WARNING WARNING
5486
5487 Static, fixed-size buffer. If you add more calls to SP_AND_CHECK or
5488 IF_SP_AND_CHECK, you need to make sure the buffer cannot overflow.
5489 */
5490
5491 static char buf[10000];
5492 char *bufp = buf;
5493 size_t bsize = 10000;
5494 size_t r;
5495
5496 SP_AND_CHECK("considered %d", pair_expl->considered)
5497 IF_SP_AND_CHECK(", no target %d", pair_expl->target)
5498 IF_SP_AND_CHECK(", unacceptable product size %d", pair_expl->product)
5499 IF_SP_AND_CHECK(", low product Tm %d", pair_expl->low_tm)
5500 IF_SP_AND_CHECK(", high product Tm %d", pair_expl->high_tm)
5501 IF_SP_AND_CHECK(", tm diff too large %d",pair_expl->temp_diff)
5502 IF_SP_AND_CHECK(", high any compl %d", pair_expl->compl_any)
5503 IF_SP_AND_CHECK(", high end compl %d", pair_expl->compl_end)
5504 IF_SP_AND_CHECK(", no internal oligo %d", pair_expl->internal)
5505 IF_SP_AND_CHECK(", high mispriming library similarity %d",
5506 pair_expl->repeat_sim)
5507 IF_SP_AND_CHECK(", no overlap of required point %d",
5508 pair_expl->does_not_overlap_a_required_point)
5509 IF_SP_AND_CHECK(", primer in pair overlaps a primer in a better pair %d",
5510 pair_expl->overlaps_oligo_in_better_pair)
5511 IF_SP_AND_CHECK(", high template mispriming score %d",
5512 pair_expl->template_mispriming)
5513 IF_SP_AND_CHECK(", not in any ok region %d",
5514 pair_expl->not_in_any_ok_region);
5515 IF_SP_AND_CHECK(", left primer to right of right primer %d",
5516 pair_expl->reversed);
5517
5518 SP_AND_CHECK(", ok %d", pair_expl->ok)
5519
5520 return buf;
5521 }
5522
5523 const char *
p3_oligo_explain_string(const oligo_stats * stat)5524 p3_oligo_explain_string(const oligo_stats *stat)
5525 {
5526 /* WARNING WARNING WARNING
5527
5528 Static, fixed-size buffer. If you add more calls to SP_AND_CHECK or
5529 IF_SP_AND_CHECK, you need to make sure the buffer cannot overflow.
5530 */
5531
5532 static char buf[10000];
5533 char *bufp = buf;
5534 size_t bsize = 10000;
5535 size_t r;
5536
5537 SP_AND_CHECK("considered %d", stat->considered)
5538 IF_SP_AND_CHECK(", would not amplify any of the ORF %d", stat->no_orf)
5539 IF_SP_AND_CHECK(", too many Ns %d", stat->ns)
5540 IF_SP_AND_CHECK(", overlap target %d", stat->target)
5541 IF_SP_AND_CHECK(", overlap excluded region %d", stat->excluded)
5542 IF_SP_AND_CHECK(", GC content failed %d", stat->gc)
5543 IF_SP_AND_CHECK(", GC clamp failed %d", stat->gc_clamp)
5544 IF_SP_AND_CHECK(", low tm %d", stat->temp_min)
5545 IF_SP_AND_CHECK(", high tm %d", stat->temp_max)
5546 IF_SP_AND_CHECK(", high any compl %d", stat->compl_any)
5547 IF_SP_AND_CHECK(", high end compl %d", stat->compl_end)
5548 IF_SP_AND_CHECK(", high hairpin stability %d", stat->hairpin_th)
5549 IF_SP_AND_CHECK(", high repeat similarity %d", stat->repeat_score)
5550 IF_SP_AND_CHECK(", long poly-x seq %d", stat->poly_x)
5551 IF_SP_AND_CHECK(", low sequence quality %d", stat->seq_quality)
5552 IF_SP_AND_CHECK(", high 3' stability %d", stat->stability)
5553 IF_SP_AND_CHECK(", high template mispriming score %d",
5554 stat->template_mispriming)
5555 IF_SP_AND_CHECK(", lowercase masking of 3' end %d",stat->gmasked)
5556 IF_SP_AND_CHECK(", failed must_match requirements %d",stat->must_match_fail)
5557 IF_SP_AND_CHECK(", not in any ok left region %d",
5558 stat->not_in_any_left_ok_region)
5559 IF_SP_AND_CHECK(", not in any ok right region %d",
5560 stat->not_in_any_right_ok_region)
5561 SP_AND_CHECK(", ok %d", stat->ok)
5562 return buf;
5563 }
5564 #undef CHECK
5565 #undef SP_AND_CHECK
5566 #undef IF_SP_AND_CHEC
5567
5568 const char *
p3_get_oligo_array_explain_string(const oligo_array * oligo_array)5569 p3_get_oligo_array_explain_string(const oligo_array *oligo_array)
5570 {
5571 return p3_oligo_explain_string(&oligo_array->expl);
5572 }
5573
5574 const char *
p3_get_pair_array_explain_string(const pair_array_t * pair_array)5575 p3_get_pair_array_explain_string(const pair_array_t *pair_array)
5576 {
5577 return p3_pair_explain_string(&pair_array->expl);
5578 }
5579
5580 const char *
libprimer3_release(void)5581 libprimer3_release(void)
5582 {
5583 return "libprimer3 release 2.3.6";
5584 }
5585
5586 const char *
primer3_copyright(void)5587 primer3_copyright(void)
5588 {
5589 return primer3_copyright_char_star;
5590 }
5591
5592 /* ============================================================ */
5593 /* BEGIN Internal and external functions for pr_append_str */
5594 /* ============================================================ */
5595
5596 void
init_pr_append_str(pr_append_str * s)5597 init_pr_append_str(pr_append_str *s)
5598 {
5599 s->data = NULL;
5600 s->storage_size = 0;
5601 }
5602
5603 const char *
pr_append_str_chars(const pr_append_str * x)5604 pr_append_str_chars(const pr_append_str *x)
5605 {
5606 return x->data;
5607 }
5608
5609 pr_append_str *
create_pr_append_str()5610 create_pr_append_str()
5611 {
5612 /* We cannot use pr_safe_malloc here
5613 because this function will be called outside
5614 of the setjmp(....) */
5615 pr_append_str *ret;
5616
5617 ret = (pr_append_str *) malloc(sizeof(pr_append_str));
5618 if (NULL == ret) return NULL;
5619 init_pr_append_str(ret);
5620 return ret;
5621 }
5622
5623 void
destroy_pr_append_str_data(pr_append_str * str)5624 destroy_pr_append_str_data(pr_append_str *str)
5625 {
5626 if (NULL == str) return;
5627 free(str->data);
5628 str->data = NULL;
5629 }
5630
5631 void
destroy_pr_append_str(pr_append_str * str)5632 destroy_pr_append_str(pr_append_str *str)
5633 {
5634 if (str == NULL) return;
5635 destroy_pr_append_str_data(str);
5636 free(str);
5637 }
5638
5639 int
pr_append_external(pr_append_str * x,const char * s)5640 pr_append_external(pr_append_str *x, const char *s)
5641 {
5642 int xlen, slen;
5643
5644 PR_ASSERT(NULL != s);
5645 PR_ASSERT(NULL != x);
5646
5647 if (NULL == x->data) {
5648 x->storage_size = 24;
5649 x->data = (char *) malloc(x->storage_size);
5650 if (NULL == x->data) return 1; /* out of memory */
5651 *x->data = '\0';
5652 }
5653 xlen = strlen(x->data);
5654 slen = strlen(s);
5655 if (xlen + slen + 1 > x->storage_size) {
5656 x->storage_size += 2 * (slen + 1);
5657 x->data = (char *) realloc(x->data, x->storage_size);
5658 if (NULL == x->data) return 1; /* out of memory */
5659 }
5660 strcpy(x->data + xlen, s);
5661 return 0;
5662 }
5663
5664 static void
pr_append_new_chunk(pr_append_str * x,const char * s)5665 pr_append_new_chunk(pr_append_str *x, const char *s)
5666 {
5667 PR_ASSERT(NULL != x)
5668 if (NULL == s) return;
5669 pr_append_w_sep(x, "; ", s);
5670 }
5671
5672 int
pr_append_new_chunk_external(pr_append_str * x,const char * s)5673 pr_append_new_chunk_external(pr_append_str *x, const char *s)
5674 {
5675 PR_ASSERT(NULL != x)
5676 if (NULL == s) return 0;
5677 return(pr_append_w_sep_external(x, "; ", s));
5678 }
5679
5680 int
pr_append_w_sep_external(pr_append_str * x,const char * sep,const char * s)5681 pr_append_w_sep_external(pr_append_str *x,
5682 const char *sep,
5683 const char *s)
5684 {
5685 PR_ASSERT(NULL != x)
5686 PR_ASSERT(NULL != s)
5687 PR_ASSERT(NULL != sep)
5688 if (pr_is_empty(x)) {
5689 return(pr_append_external(x, s));
5690 } else {
5691 return(pr_append_external(x, sep)
5692 || pr_append_external(x, s));
5693 }
5694 }
5695
5696 void
pr_set_empty(pr_append_str * x)5697 pr_set_empty(pr_append_str *x)
5698 {
5699 PR_ASSERT(NULL != x);
5700 if (NULL != x->data) *x->data = '\0';
5701 }
5702
5703 int
pr_is_empty(const pr_append_str * x)5704 pr_is_empty( const pr_append_str *x)
5705 {
5706 PR_ASSERT(NULL != x);
5707 return NULL == x->data || '\0' == *x->data;
5708 }
5709
5710 static void
pr_append_w_sep(pr_append_str * x,const char * sep,const char * s)5711 pr_append_w_sep(pr_append_str *x,
5712 const char *sep,
5713 const char *s)
5714 {
5715 if (pr_append_w_sep_external(x, sep, s)) longjmp(_jmp_buf, 1);
5716 }
5717
5718 static void
pr_append(pr_append_str * x,const char * s)5719 pr_append(pr_append_str *x,
5720 const char *s)
5721 {
5722 if (pr_append_external(x, s)) longjmp(_jmp_buf, 1);
5723 }
5724
5725 /* ============================================================ */
5726 /* END internal and external functions for pr_append_str */
5727 /* ============================================================ */
5728
5729
5730 /* =========================================================== */
5731 /* Malloc and realloc wrappers that longjmp() on failure */
5732 /* =========================================================== */
5733 static void *
pr_safe_malloc(size_t x)5734 pr_safe_malloc(size_t x)
5735 {
5736 void *r = malloc(x);
5737 if (NULL == r) longjmp(_jmp_buf, 1);
5738 return r;
5739 }
5740
5741 static void *
pr_safe_realloc(void * p,size_t x)5742 pr_safe_realloc(void *p, size_t x)
5743 {
5744 void *r = realloc(p, x);
5745 if (NULL == r) longjmp(_jmp_buf, 1);
5746 return r;
5747 }
5748
5749 /* =========================================================== */
5750 /* End of malloc/realloc wrappers. */
5751 /* =========================================================== */
5752
5753
5754 /* ============================================================ */
5755 /* START functions which check and modify the input */
5756 /* ============================================================ */
5757
5758 /* Fuction to set the included region and fix the start positions */
5759 static void
_adjust_seq_args(const p3_global_settings * pa,seq_args * sa,pr_append_str * nonfatal_err,pr_append_str * warning)5760 _adjust_seq_args(const p3_global_settings *pa,
5761 seq_args *sa,
5762 pr_append_str *nonfatal_err,
5763 pr_append_str *warning)
5764 {
5765 int seq_len, inc_len;
5766
5767 /* Create a seq for check primers if needed */
5768 if (pa->primer_task == check_primers) {
5769 if (NULL == sa->sequence) {
5770 fake_a_sequence(sa, pa);
5771 }
5772 }
5773 if (pa->primer_task == pick_sequencing_primers && sa->incl_l != -1) {
5774 pr_append_new_chunk(nonfatal_err,
5775 "Task pick_sequencing_primers cannot be combined with included region");
5776 return;
5777 }
5778
5779 /*
5780 Complain if there is no sequence; We need to check this
5781 error here, because this function cannot do its work if
5782 sa->sequence == NULL
5783 */
5784 if (NULL == sa->sequence) {
5785 if (pa->primer_task == check_primers) {
5786 pr_append_new_chunk(nonfatal_err, "No primers provided");
5787 } else {
5788 pr_append_new_chunk(nonfatal_err, "Missing SEQUENCE tag");
5789 }
5790 return;
5791 }
5792
5793 seq_len = strlen(sa->sequence);
5794
5795 /* For pick_cloning_primers set the forced positions */
5796 if (pa->primer_task == pick_cloning_primers) {
5797 if(sa->incl_l == -1) {
5798 sa->force_left_start = pa->first_base_index;
5799 sa->force_right_start = seq_len + pa->first_base_index - 1;
5800 } else {
5801 sa->force_left_start = sa->incl_s;
5802 sa->force_right_start = sa->incl_s + sa->incl_l - 1;
5803 }
5804 }
5805
5806 /* For pick_discriminative_primers set the forced positions */
5807 if (pa->primer_task == pick_discriminative_primers) {
5808 /* Changed here from incl_s and incl_l to sa->tar2->pairs[0][0/1] */
5809 if (sa->tar2.count != 1) {
5810 pr_append_new_chunk(nonfatal_err,
5811 "Task pick_discriminative_primers requires exactly one SEQUENCE_TARGET");
5812 }
5813 sa->force_left_end = sa->tar2.pairs[0][0];
5814 sa->force_right_end = sa->tar2.pairs[0][0] + sa->tar2.pairs[0][1] - 1;
5815 }
5816
5817 /* If no included region is specified,
5818 * use the whole sequence as included region */
5819 if (sa->incl_l == -1) {
5820 sa->incl_l = seq_len;
5821 sa->incl_s = pa->first_base_index;
5822 }
5823
5824 /* Generate at least one target */
5825 if (pa->primer_task == pick_sequencing_primers && sa->tar2.count == 0) {
5826 sa->tar2.pairs[0][0] = pa->first_base_index;
5827 sa->tar2.pairs[0][1] = seq_len;
5828 sa->tar2.count = 1;
5829 }
5830
5831 /* Fix the start of the included region and start codon */
5832 sa->incl_s -= pa->first_base_index;
5833 sa->start_codon_pos -= pa->first_base_index;
5834
5835 /* Fix the start */
5836 sa->force_left_start -= pa->first_base_index;
5837 sa->force_left_end -= pa->first_base_index;
5838 sa->force_right_start -= pa->first_base_index;
5839 sa->force_right_end -= pa->first_base_index;
5840
5841 /* Make it relative to included region */
5842 sa->force_left_start -= sa->incl_s;
5843 sa->force_left_end -= sa->incl_s;
5844 sa->force_right_start -= sa->incl_s;
5845 sa->force_right_end -= sa->incl_s;
5846
5847 inc_len = sa->incl_s + sa->incl_l - 1;
5848
5849 if ((sa->incl_l < INT_MAX) && (sa->incl_s > -1)
5850 && (sa->incl_l > -1) && (inc_len < seq_len) ) {
5851 /* Copies inluded region into trimmed_seq */
5852 sa->trimmed_seq = (char *) pr_safe_malloc(sa->incl_l + 1);
5853 _pr_substr(sa->sequence, sa->incl_s, sa->incl_l, sa->trimmed_seq);
5854
5855 /* Copies inluded region into trimmed_orig_seq */
5856 /* edited by T. Koressaar for lowercase masking */
5857 sa->trimmed_orig_seq = (char *) pr_safe_malloc(sa->incl_l + 1);
5858 _pr_substr(sa->sequence, sa->incl_s, sa->incl_l, sa->trimmed_orig_seq);
5859
5860 /* Copies the whole sequence into upcased_seq */
5861 sa->upcased_seq = (char *) pr_safe_malloc(strlen(sa->sequence) + 1);
5862 strcpy(sa->upcased_seq, sa->sequence);
5863 dna_to_upper(sa->upcased_seq, 1);
5864 /* We do not need to check for illegal characters in the return
5865 from dna_to_upper(), because errors are checked in
5866 _pr_data_control sa->trimmed_seq. */
5867
5868 /* Copies the reverse complement of the whole sequence into upcased_seq_r */
5869 sa->upcased_seq_r = (char *) pr_safe_malloc(strlen(sa->sequence) + 1);
5870 p3_reverse_complement(sa->upcased_seq, sa->upcased_seq_r);
5871 }
5872
5873 if (_check_and_adjust_intervals(sa,
5874 seq_len,
5875 pa->first_base_index,
5876 nonfatal_err, warning)) {
5877 return;
5878 }
5879
5880 if (_check_and_adjust_overlap_pos(sa,
5881 sa->primer_overlap_junctions,
5882 &sa->primer_overlap_junctions_count,
5883 "SEQUENCE_OVERLAP_JUNCTION_LIST",
5884 seq_len,
5885 pa->first_base_index,
5886 nonfatal_err, warning)) {
5887 return;
5888 }
5889
5890 /* Update ok regions, if non empty */
5891 if (sa->ok_regions.count > 0) {
5892 _optimize_ok_regions_list(pa, sa);
5893 }
5894
5895 }
5896
5897 /*
5898 * This function uses the max/min product size info and the max/min
5899 * oligo length in order to reduce the ranges of the ok regions. On
5900 * some imputs this improves speed dramatically.
5901 */
5902 static void
_optimize_ok_regions_list(const p3_global_settings * pa,seq_args * sa)5903 _optimize_ok_regions_list(const p3_global_settings *pa,
5904 seq_args *sa)
5905 {
5906 /* We do this only if we enabled the optimization and
5907 * the primers were NOT specified. */
5908 if (!OPTIMIZE_OK_REGIONS || (sa->left_input) || (sa->right_input)) {
5909 return;
5910 }
5911
5912 /* If any pair is allowed, no point in doing this */
5913 if (sa->ok_regions.any_pair) {
5914 return;
5915 }
5916
5917 int pmin = INT_MAX;
5918 int pmax = 0;
5919 int omin = pa->p_args.min_size;
5920 int omax = pa->p_args.max_size;
5921
5922 /* Determine min/max product size */
5923 for (int i=0; i<pa->num_intervals; i++) {
5924 if (pa->pr_min[i] < pmin) { pmin = pa->pr_min[i]; }
5925 if (pa->pr_max[i] > pmax) { pmax = pa->pr_max[i]; }
5926 }
5927
5928 /* Update each region */
5929 for (int i=0; i<sa->ok_regions.count; i++) {
5930 int ls = -1, le = -1, rs = -1, re = -1;
5931 int new_ls = -1, new_le = -1, new_rs = -1, new_re = -1;
5932 if (sa->ok_regions.left_pairs[i][0] != -1) {
5933 ls = sa->ok_regions.left_pairs[i][0];
5934 le = sa->ok_regions.left_pairs[i][0]
5935 + sa->ok_regions.left_pairs[i][1] - 1;
5936 }
5937 if (sa->ok_regions.right_pairs[i][0] != -1) {
5938 rs = sa->ok_regions.right_pairs[i][0];
5939 re = sa->ok_regions.right_pairs[i][0]
5940 + sa->ok_regions.right_pairs[i][1] - 1;
5941 }
5942 /* Compute new right region based on left range and min/max values
5943 of product size and oligo length */
5944 if (ls != -1) {
5945 new_rs = ls + pmin - omax - 1; /* -1 just to be safe */
5946 new_re = le - omin + pmax + 1; /* +1 just to be safe */
5947 /* Adjust the ranges */
5948 if ((rs == -1) || (new_rs > rs)) { rs = new_rs; }
5949 if ((re == -1) || (new_re < re)) { re = new_re; }
5950 if (rs < 0) { rs = 0; }
5951 if (re > (signed) strlen(sa->sequence)) { re = strlen(sa->sequence); }
5952 }
5953 /* Compute new left region based on right range and min/max values
5954 of product size and oligo length */
5955 if (rs != -1) {
5956 new_ls = rs + omin - pmax - 1; /* -1 just to be safe */
5957 new_le = re - pmin + omax + 1; /* +1 just to be safe */
5958 /* Adjust the ranges */
5959 if ((ls == -1) || (new_ls > ls)) { ls = new_ls; }
5960 if ((le == -1) || (new_le < le)) { le = new_le; }
5961 if (ls < 0) { ls = 0; }
5962 if (le > (signed) strlen(sa->sequence)) { le = strlen(sa->sequence); }
5963 }
5964 /* Temporary testing fprintf: */
5965 /* fprintf(stderr, "Adjusted range [%d,%d,%d,%d] to [%d,%d,%d,%d],
5966 pmin is %d, pmax is %d, omin is %d, omax is %d\n",
5967 sa->ok_regions.left_pairs[i][0],
5968 sa->ok_regions.left_pairs[i][0] +
5969 sa->ok_regions.left_pairs[i][1] - 1,
5970 sa->ok_regions.right_pairs[i][0],
5971 sa->ok_regions.right_pairs[i][0] +
5972 sa->ok_regions.right_pairs[i][1] - 1, ls, le, rs, re,
5973 pmin, pmax, omin, omax);
5974 */
5975 sa->ok_regions.left_pairs[i][0] = ls;
5976 sa->ok_regions.left_pairs[i][1] = le - ls + 1;
5977 sa->ok_regions.right_pairs[i][0] = rs;
5978 sa->ok_regions.right_pairs[i][1] = re - rs + 1;
5979 }
5980 /* any_left and any_right not true anymore */
5981 sa->ok_regions.any_left = 0;
5982 sa->ok_regions.any_right = 0;
5983 }
5984
5985 /*
5986 * Return 1 on error, 0 on success. fake_a_sequence creates a sequence
5987 * out of the provided primers and puts them in sa.
5988 */
5989
5990 static int
fake_a_sequence(seq_args * sa,const p3_global_settings * pa)5991 fake_a_sequence(seq_args *sa, const p3_global_settings *pa)
5992 {
5993 int i, product_size, space, ns_to_fill;
5994 char *rev = NULL;
5995 int ns_to_fill_first, ns_to_fill_second;
5996
5997 /* Determine the product size */
5998 if ( pa->product_opt_size == PR_UNDEFINED_INT_OPT){
5999 product_size = pa->pr_max[0] - pa->pr_min[0];
6000 } else {
6001 product_size = pa->product_opt_size;
6002 }
6003
6004 space = product_size + 1;
6005 ns_to_fill = product_size;
6006
6007
6008 /* Calculate how many Ns have to be added */
6009 if (sa->left_input){
6010 ns_to_fill = ns_to_fill - strlen(sa->left_input);
6011 }
6012 if (sa->right_input){
6013 ns_to_fill = ns_to_fill - strlen(sa->right_input);
6014 rev = (char *) pr_safe_malloc(strlen(sa->right_input) + 1);
6015 p3_reverse_complement(sa->right_input, rev);
6016 }
6017 if (sa->internal_input){
6018 ns_to_fill = ns_to_fill - strlen(sa->internal_input);
6019 }
6020 /* Return if there are no primers provided */
6021 if (ns_to_fill == product_size + 1){
6022 return 0;
6023 }
6024 ns_to_fill_first = ns_to_fill / 2;
6025 ns_to_fill_second = ns_to_fill - ns_to_fill_first;
6026 /* Allocate the space for the sequence */
6027 sa->sequence = (char *) pr_safe_malloc(space);
6028 *sa->sequence = '\0';
6029 /* Copy over the primers */
6030 if (sa->left_input){
6031 strcat(sa->sequence, sa->left_input);
6032 }
6033
6034 /* Add the Ns*/
6035 for (i = 0; i < ns_to_fill_first; i++ ) {
6036 strcat(sa->sequence, "N\0");
6037 }
6038 if (sa->internal_input){
6039 strcat(sa->sequence, sa->internal_input);
6040 }
6041 for (i = 0; i < ns_to_fill_second; i++ ) {
6042 strcat(sa->sequence, "N\0");
6043 }
6044 if (sa->right_input){
6045 strcat(sa->sequence, rev);
6046 }
6047 free(rev);
6048 return 0;
6049 }
6050
6051 /*
6052 * Return 1 on error, 0 on success. Set sa->trimmed_seq and possibly modify
6053 * sa->tar. Upcase and check all bases in sa->trimmed_seq.
6054 * TO DO -- this would probably be cleaner if it only
6055 * checked, rather than updated, sa.
6056 */
6057 /* Check if the input in sa and pa makes sense */
6058 int
_pr_data_control(const p3_global_settings * pa,const seq_args * sa,pr_append_str * glob_err,pr_append_str * nonfatal_err,pr_append_str * warning)6059 _pr_data_control(const p3_global_settings *pa,
6060 const seq_args *sa,
6061 pr_append_str *glob_err,
6062 pr_append_str *nonfatal_err,
6063 pr_append_str *warning)
6064 {
6065 static char s1[MAX_PRIMER_LENGTH+1];
6066 int i, pr_min, seq_len;
6067 char offending_char = '\0';
6068
6069 seq_len = strlen(sa->sequence);
6070
6071 /* If sequence quality is provided, is it as long as the sequence? */
6072 if (sa->n_quality !=0 && sa->n_quality != seq_len)
6073 pr_append_new_chunk(nonfatal_err,
6074 "Error in sequence quality data");
6075
6076 if ((pa->min_left_three_prime_distance < -1) ||
6077 (pa->min_right_three_prime_distance < -1))
6078 pr_append_new_chunk(nonfatal_err,
6079 "Minimum 3' distance must be >= -1 "
6080 "(min_*_three_prime_distance)");
6081
6082 if ((pa->p_args.min_quality != 0 || pa->o_args.min_quality != 0)
6083 && sa->n_quality == 0)
6084 pr_append_new_chunk(nonfatal_err, "Sequence quality data missing");
6085
6086 if (pa->first_base_index < PR_NULL_FORCE_POSITION) {
6087 pr_append_new_chunk(glob_err, "Value too small at tag PRIMER_FIRST_BASE_INDEX");
6088 return 1;
6089 }
6090
6091 if (pa->p_args.max_template_mispriming > SHRT_MAX && pa->thermodynamic_template_alignment == 0) {
6092 pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_MAX_TEMPLATE_MISPRIMING");
6093 return 1;
6094 }
6095
6096 if (pa->pair_max_template_mispriming > SHRT_MAX && pa->thermodynamic_template_alignment == 0) {
6097 pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_PAIR_MAX_TEMPLATE_MISPRIMING");
6098 return 1;
6099 }
6100
6101 if (pa->p_args.max_repeat_compl > SHRT_MAX && pa->thermodynamic_oligo_alignment == 0) {
6102 pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_MAX_LIBRARY_MISPRIMING");
6103 return 1;
6104 }
6105
6106 if (pa->o_args.max_repeat_compl > SHRT_MAX && pa->thermodynamic_oligo_alignment == 0) {
6107 pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_INTERNAL_MAX_LIBRARY_MISHYB");
6108 return 1;
6109 }
6110
6111 if (pa->pair_repeat_compl > SHRT_MAX && pa->thermodynamic_oligo_alignment == 0) {
6112 pr_append_new_chunk(glob_err, "Value too large at tag PRIMER_PAIR_MAX_LIBRARY_MISPRIMING");
6113 return 1;
6114 }
6115
6116 if (pa->o_args.max_template_mispriming >= 0 && pa->thermodynamic_template_alignment==0)
6117 pr_append_new_chunk(glob_err,
6118 "PRIMER_INTERNAL_MAX_TEMPLATE_MISHYB is not supported");
6119 if (pa->o_args.max_template_mispriming_th >= 0 && pa->thermodynamic_template_alignment==1)
6120 pr_append_new_chunk(glob_err,
6121 "PRIMER_INTERNAL_MAX_TEMPLATE_MISHYB_TH is not supported");
6122 if (pa->p_args.min_size < 1)
6123 pr_append_new_chunk(glob_err, "PRIMER_MIN_SIZE must be >= 1");
6124
6125 if (pa->p_args.max_size > MAX_PRIMER_LENGTH) {
6126 pr_append_new_chunk(glob_err,
6127 "PRIMER_MAX_SIZE exceeds built-in maximum of ");
6128 pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
6129 return 1;
6130 }
6131
6132 if (pa->p_args.opt_size > pa->p_args.max_size) {
6133 pr_append_new_chunk(glob_err,
6134 "PRIMER_{OPT,DEFAULT}_SIZE > PRIMER_MAX_SIZE");
6135 return 1;
6136 }
6137
6138 if (pa->p_args.opt_size < pa->p_args.min_size) {
6139 pr_append_new_chunk(glob_err,
6140 "PRIMER_{OPT,DEFAULT}_SIZE < PRIMER_MIN_SIZE");
6141 return 1;
6142 }
6143
6144 if (pa->o_args.max_size > MAX_PRIMER_LENGTH) {
6145 pr_append_new_chunk(glob_err,
6146 "PRIMER_INTERNAL_MAX_SIZE exceeds built-in maximum");
6147 return 1;
6148 }
6149
6150 if (pa->o_args.opt_size > pa->o_args.max_size) {
6151 pr_append_new_chunk(glob_err,
6152 "PRIMER_INTERNAL_{OPT,DEFAULT}_SIZE > MAX_SIZE");
6153 return 1;
6154 }
6155
6156 if (pa->o_args.opt_size < pa->o_args.min_size) {
6157 pr_append_new_chunk(glob_err,
6158 "PRIMER_INTERNAL_{OPT,DEFAULT}_SIZE < MIN_SIZE");
6159 return 1;
6160 }
6161
6162 /* A GC clamp can not be bigger then the primer */
6163 if (pa->gc_clamp > pa->p_args.min_size) {
6164 pr_append_new_chunk(glob_err,
6165 "PRIMER_GC_CLAMP > PRIMER_MIN_SIZE");
6166 return 1;
6167 }
6168
6169 /* Must be >= 0 and <= 5 */
6170 if ((pa->max_end_gc < 0)
6171 || (pa->max_end_gc > 5)) {
6172 pr_append_new_chunk(glob_err,
6173 "PRIMER_MAX_END_GC must be between 0 to 5");
6174 return 1;
6175 }
6176
6177 /* Product size must be provided */
6178 if (0 == pa->num_intervals) {
6179 pr_append_new_chunk( glob_err,
6180 "Empty value for PRIMER_PRODUCT_SIZE_RANGE");
6181 return 1;
6182 }
6183 for (i = 0; i < pa->num_intervals; i++) {
6184 if (pa->pr_min[i] > pa->pr_max[i] || pa->pr_min[i] < 0) {
6185 pr_append_new_chunk(glob_err,
6186 "Illegal element in PRIMER_PRODUCT_SIZE_RANGE");
6187 return 1;
6188 }
6189 }
6190
6191 pr_min = INT_MAX;
6192 /* Check if the primer is bigger then the product */
6193 for(i=0;i<pa->num_intervals;i++)
6194 if(pa->pr_min[i]<pr_min) pr_min=pa->pr_min[i];
6195
6196 if (pa->p_args.max_size > pr_min) {
6197 pr_append_new_chunk(glob_err,
6198 "PRIMER_MAX_SIZE > min PRIMER_PRODUCT_SIZE_RANGE");
6199 return 1;
6200 }
6201
6202 if ((pa->pick_internal_oligo == 1 )
6203 && pa->o_args.max_size > pr_min) {
6204 pr_append_new_chunk(glob_err,
6205 "PRIMER_INTERNAL_MAX_SIZE > min PRIMER_PRODUCT_SIZE_RANGE");
6206 return 1;
6207 }
6208
6209 /* There must be at least one primer returned */
6210 if (pa->num_return < 1) {
6211 pr_append_new_chunk(glob_err,
6212 "PRIMER_NUM_RETURN < 1");
6213 return 1;
6214 }
6215
6216 if ((pa->p_args.must_match_five_prime != NULL) && (strlen(pa->p_args.must_match_five_prime) != 5)) {
6217 pr_append_new_chunk(glob_err,
6218 "PRIMER_MUST_MATCH_FIVE_PRIME must have 5 characters");
6219 return 1;
6220 }
6221 if ((pa->p_args.must_match_three_prime != NULL) && (strlen(pa->p_args.must_match_three_prime) != 5)) {
6222 pr_append_new_chunk(glob_err,
6223 "PRIMER_MUST_MATCH_THREE_PRIME must have 5 characters");
6224 return 1;
6225 }
6226 if ((pa->o_args.must_match_five_prime != NULL) && (strlen(pa->o_args.must_match_five_prime) != 5)) {
6227 pr_append_new_chunk(glob_err,
6228 "PRIMER_INTERNAL_MUST_MATCH_FIVE_PRIME must have 5 characters");
6229 return 1;
6230 }
6231 if ((pa->o_args.must_match_three_prime != NULL) && (strlen(pa->o_args.must_match_three_prime) != 5)) {
6232 pr_append_new_chunk(glob_err,
6233 "PRIMER_INTERNAL_MUST_MATCH_THREE_PRIME must have 5 characters");
6234 return 1;
6235 }
6236
6237 if (sa->incl_l >= INT_MAX) {
6238 pr_append_new_chunk(nonfatal_err, "Value for SEQUENCE_INCLUDED_REGION too large");
6239 return 1;
6240 }
6241
6242 if (sa->incl_s < 0 || sa->incl_l < 0
6243 || sa->incl_s + sa->incl_l > seq_len) {
6244 pr_append_new_chunk(nonfatal_err, "Illegal value for SEQUENCE_INCLUDED_REGION");
6245 return 1;
6246 }
6247
6248 /* The product must fit in the included region */
6249 if (sa->incl_l < pr_min && pa->pick_left_primer == 1
6250 && pa->pick_right_primer == 1) {
6251 if (pa->primer_task == check_primers) {
6252 pr_append_new_chunk(warning,
6253 "SEQUENCE_INCLUDED_REGION length < min PRIMER_PRODUCT_SIZE_RANGE");
6254 } else if (pa->primer_task != pick_primer_list) {
6255 pr_append_new_chunk(nonfatal_err,
6256 "SEQUENCE_INCLUDED_REGION length < min PRIMER_PRODUCT_SIZE_RANGE");
6257 }
6258
6259 if (pa->primer_task == generic) {
6260 return 1;
6261 }
6262 }
6263
6264 if (pa->max_end_stability < 0) {
6265 pr_append_new_chunk(nonfatal_err,
6266 "PRIMER_MAX_END_STABILITY must be non-negative");
6267 return 1;
6268 }
6269
6270 /* Is the startodon ATG and in the incl. region */
6271 if (!PR_START_CODON_POS_IS_NULL(sa)) {
6272 if (!PR_POSITION_PENALTY_IS_NULL(pa)) {
6273 pr_append_new_chunk(nonfatal_err,
6274 "Cannot accept both SEQUENCE_START_CODON_POSITION and non-default ");
6275 pr_append(nonfatal_err,
6276 "arguments for PRIMER_INSIDE_PENALTY or PRIMER_OUTSIDE_PENALTY");
6277 }
6278 if (sa->start_codon_pos > (sa->incl_s + sa->incl_l - 3)) {
6279 pr_append_new_chunk(nonfatal_err,
6280 "Start codon position not contained in SEQUENCE_INCLUDED_REGION");
6281 return 1;
6282 } else {
6283 if (sa->start_codon_pos >= 0
6284 && ((sa->sequence[sa->start_codon_pos] != 'A'
6285 && sa->sequence[sa->start_codon_pos] != 'a')
6286 || (sa->sequence[sa->start_codon_pos + 1] != 'T'
6287 && sa->sequence[sa->start_codon_pos + 1] != 't')
6288 || (sa->sequence[sa->start_codon_pos + 2] != 'G'
6289 && sa->sequence[sa->start_codon_pos + 2] != 'g'))) {
6290 pr_append_new_chunk(nonfatal_err,
6291 "No start codon at SEQUENCE_START_CODON_POSITION");
6292 return 1;
6293 }
6294 }
6295 }
6296
6297 if (NULL != sa->quality) {
6298 if(pa->p_args.min_quality != 0 && pa->p_args.min_quality < pa->quality_range_min) {
6299 pr_append_new_chunk(glob_err,
6300 "PRIMER_MIN_QUALITY < PRIMER_QUALITY_RANGE_MIN");
6301 return 1;
6302 }
6303 if (pa->p_args.min_quality != 0 && pa->p_args.min_quality > pa->quality_range_max) {
6304 pr_append_new_chunk(glob_err,
6305 "PRIMER_MIN_QUALITY > PRIMER_QUALITY_RANGE_MAX");
6306 return 1;
6307 }
6308 if (pa->o_args.min_quality != 0 && pa->o_args.min_quality <pa->quality_range_min) {
6309 pr_append_new_chunk(glob_err,
6310 "PRIMER_INTERNAL_MIN_QUALITY < PRIMER_QUALITY_RANGE_MIN");
6311 return 1;
6312 }
6313 if (pa->o_args.min_quality != 0 && pa->o_args.min_quality > pa->quality_range_max) {
6314 pr_append_new_chunk(glob_err,
6315 "PRIMER_INTERNAL_MIN_QUALITY > PRIMER_QUALITY_RANGE_MAX");
6316 return 1;
6317 }
6318 for(i=0; i < sa->n_quality; i++) {
6319 if(sa->quality[i] < pa->quality_range_min ||
6320 sa->quality[i] > pa->quality_range_max) {
6321 pr_append_new_chunk(nonfatal_err,
6322 "Sequence quality score out of range");
6323 return 1;
6324 }
6325 }
6326 }
6327 else if (pa->p_args.weights.seq_quality || pa->o_args.weights.seq_quality) {
6328 pr_append_new_chunk(nonfatal_err,
6329 "Sequence quality is part of objective function but sequence quality is not defined");
6330 return 1;
6331 }
6332
6333 if ((offending_char = dna_to_upper(sa->trimmed_seq, 0))) {
6334 if (pa->liberal_base) {
6335 pr_append_new_chunk(warning,
6336 "Unrecognized base in input sequence");
6337 }
6338 else {
6339 pr_append_new_chunk(nonfatal_err,
6340 "Unrecognized base in input sequence");
6341 return 1;
6342 }
6343 }
6344
6345 if (pa->p_args.opt_tm < pa->p_args.min_tm
6346 || pa->p_args.opt_tm > pa->p_args.max_tm) {
6347 pr_append_new_chunk(glob_err,
6348 "Optimum primer Tm lower than minimum or higher than maximum");
6349 return 1;
6350 }
6351
6352 if (pa->o_args.opt_tm < pa->o_args.min_tm
6353 || pa->o_args.opt_tm > pa->o_args.max_tm) {
6354 pr_append_new_chunk(glob_err,
6355 "Optimum internal oligo Tm lower than minimum or higher than maximum");
6356 return 1;
6357 }
6358
6359 if (pa->p_args.min_gc > pa->p_args.max_gc
6360 || pa->p_args.min_gc > 100
6361 || pa->p_args.max_gc < 0){
6362 pr_append_new_chunk(glob_err,
6363 "Illegal value for PRIMER_MAX_GC and PRIMER_MIN_GC");
6364 return 1;
6365 }
6366
6367 if (pa->o_args.min_gc > pa->o_args.max_gc
6368 || pa->o_args.min_gc > 100
6369 || pa->o_args.max_gc < 0) {
6370 pr_append_new_chunk(glob_err,
6371 "Illegal value for PRIMER_INTERNAL_OLIGO_GC");
6372 return 1;
6373 }
6374 if (pa->p_args.num_ns_accepted < 0) {
6375 pr_append_new_chunk(glob_err,
6376 "Illegal value for PRIMER_MAX_NS_ACCEPTED");
6377 return 1;
6378 }
6379 if (pa->o_args.num_ns_accepted < 0){
6380 pr_append_new_chunk(glob_err,
6381 "Illegal value for PRIMER_INTERNAL_MAX_NS_ACCEPTED");
6382 return 1;
6383 }
6384 if (pa->p_args.max_self_any < 0 || pa->p_args.max_self_any > SHRT_MAX
6385 || pa->p_args.max_self_end < 0 || pa->p_args.max_self_end > SHRT_MAX
6386 || pa->pair_compl_any < 0 || pa->pair_compl_any > SHRT_MAX
6387 || pa->pair_compl_end < 0 || pa->pair_compl_end > SHRT_MAX) {
6388 pr_append_new_chunk(glob_err,
6389 "Illegal value for primer complementarity restrictions");
6390 return 1;
6391 }
6392
6393 if (pa->p_args.max_self_any_th < 0
6394 || pa->p_args.max_self_end_th < 0 || pa->p_args.max_hairpin_th < 0
6395 || pa->pair_compl_any_th < 0 || pa->pair_compl_end_th < 0) {
6396 pr_append_new_chunk(glob_err,
6397 "Illegal value for primer complementarity restrictions (thermod. approach)");
6398 return 1;
6399 }
6400
6401 if( pa->o_args.max_self_any < 0 || pa->o_args.max_self_any > SHRT_MAX
6402 || pa->o_args.max_self_end < 0 || pa->o_args.max_self_end > SHRT_MAX) {
6403 pr_append_new_chunk(glob_err,
6404 "Illegal value for internal oligo complementarity restrictions");
6405 return 1;
6406 }
6407
6408 if( pa->o_args.max_self_any_th < 0
6409 || pa->o_args.max_self_end_th < 0 || pa->o_args.max_hairpin_th < 0) {
6410 pr_append_new_chunk(glob_err,
6411 "Illegal value for internal oligo complementarity restrictions");
6412 return 1;
6413 }
6414
6415 if (pa->p_args.salt_conc <= 0 || pa->p_args.dna_conc<=0){
6416 pr_append_new_chunk(glob_err,
6417 "Illegal value for primer salt or dna concentration");
6418 return 1;
6419 }
6420
6421 if((pa->p_args.dntp_conc < 0 && pa->p_args.divalent_conc !=0 )
6422 || pa->p_args.divalent_conc<0){ /* added by T.Koressaar */
6423 pr_append_new_chunk(glob_err, "Illegal value for primer divalent salt or dNTP concentration");
6424 return 1;
6425 }
6426
6427 if(pa->o_args.salt_conc<=0||pa->o_args.dna_conc<=0){
6428 pr_append_new_chunk(glob_err,
6429 "Illegal value for internal oligo salt or dna concentration");
6430 return 1;
6431 }
6432
6433 if((pa->o_args.dntp_conc<0 && pa->o_args.divalent_conc!=0)
6434 || pa->o_args.divalent_conc < 0) { /* added by T.Koressaar */
6435 pr_append_new_chunk(glob_err,
6436 "Illegal value for internal oligo divalent salt or dNTP concentration");
6437 return 1;
6438 }
6439
6440 if (!_PR_DEFAULT_POSITION_PENALTIES(pa) && sa->tar2.count > 1) {
6441 pr_append_new_chunk(nonfatal_err,
6442 "Non-default inside penalty or outside penalty ");
6443 pr_append(nonfatal_err,
6444 "is valid only when number of targets <= 1");
6445 }
6446 if (!_PR_DEFAULT_POSITION_PENALTIES(pa) && 0 == sa->tar2.count) {
6447 pr_append_new_chunk(warning,
6448 "Non-default inside penalty or outside penalty ");
6449 pr_append(warning,
6450 "has no effect when number of targets is 0");
6451 }
6452 if (pa->pick_internal_oligo != 1 && sa->internal_input) {
6453 pr_append_new_chunk(nonfatal_err,
6454 "Not specified to pick internal oligos");
6455 pr_append(nonfatal_err,
6456 " but a specific internal oligo is provided");
6457 }
6458 if (sa->internal_input) {
6459 if (strlen(sa->internal_input) > MAX_PRIMER_LENGTH) {
6460 pr_append_new_chunk(glob_err,
6461 "Specified internal oligo exceeds built-in maximum of ");
6462 pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
6463 return 1;
6464 }
6465 if (strlen(sa->internal_input) > (unsigned) pa->o_args.max_size)
6466 pr_append_new_chunk(warning,
6467 "Specified internal oligo > PRIMER_INTERNAL_MAX_SIZE");
6468
6469 if (strlen(sa->internal_input) < (unsigned) pa->o_args.min_size)
6470 pr_append_new_chunk(warning,
6471 "Specified internal oligo < PRIMER_INTERNAL_MIN_SIZE");
6472
6473 if (!strstr_nocase(sa->sequence, sa->internal_input))
6474 pr_append_new_chunk(nonfatal_err,
6475 "Specified internal oligo not in sequence");
6476 else if (!strstr_nocase(sa->trimmed_seq, sa->internal_input))
6477 pr_append_new_chunk(nonfatal_err,
6478 "Specified internal oligo not in Included Region");
6479 }
6480 if (sa->left_input) {
6481 if (strlen(sa->left_input) > MAX_PRIMER_LENGTH) {
6482 pr_append_new_chunk(glob_err,
6483 "Specified left primer exceeds built-in maximum of ");
6484 pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
6485 return 1;
6486 }
6487 if (strlen(sa->left_input) > (unsigned) pa->p_args.max_size)
6488 pr_append_new_chunk(warning,
6489 "Specified left primer > PRIMER_MAX_SIZE");
6490 if (strlen(sa->left_input) < (unsigned) pa->p_args.min_size)
6491 pr_append_new_chunk(warning,
6492 "Specified left primer < PRIMER_MIN_SIZE");
6493 if (!strstr_nocase(sa->sequence, sa->left_input))
6494 pr_append_new_chunk(nonfatal_err,
6495 "Specified left primer not in sequence");
6496 else if (!strstr_nocase(sa->trimmed_seq, sa->left_input))
6497 pr_append_new_chunk(nonfatal_err,
6498 "Specified left primer not in Included Region");
6499 }
6500 if (sa->right_input) {
6501 if (strlen(sa->right_input) > MAX_PRIMER_LENGTH) {
6502 pr_append_new_chunk(glob_err,
6503 "Specified right primer exceeds built-in maximum of ");
6504 pr_append(glob_err, MACRO_VALUE_AS_STRING(MAX_PRIMER_LENGTH));
6505 return 1;
6506 }
6507 if (strlen(sa->right_input) < (unsigned) pa->p_args.min_size)
6508 pr_append_new_chunk(warning,
6509 "Specified right primer < PRIMER_MIN_SIZE");
6510 if (strlen(sa->right_input) > (unsigned) pa->p_args.max_size) {
6511 pr_append_new_chunk(warning,
6512 "Specified right primer > PRIMER_MAX_SIZE");
6513 } else { /* We do not want to overflow s1. */
6514 p3_reverse_complement(sa->right_input,s1);
6515 if (!strstr_nocase(sa->sequence, s1))
6516 pr_append_new_chunk(nonfatal_err,
6517 "Specified right primer not in sequence");
6518 else if (!strstr_nocase(sa->trimmed_seq, s1))
6519 pr_append_new_chunk(nonfatal_err,
6520 "Specified right primer not in Included Region");
6521 }
6522 }
6523
6524 if ((pa->pr_pair_weights.product_tm_lt ||
6525 pa->pr_pair_weights.product_tm_gt)
6526 && pa->product_opt_tm == PR_UNDEFINED_DBL_OPT) {
6527 pr_append_new_chunk(glob_err,
6528 "Product temperature is part of objective function while optimum temperature is not defined");
6529 return 1;
6530 }
6531
6532 if((pa->pr_pair_weights.product_size_lt ||
6533 pa->pr_pair_weights.product_size_gt)
6534 && pa->product_opt_size == PR_UNDEFINED_INT_OPT){
6535 pr_append_new_chunk(glob_err,
6536 "Product size is part of objective function while optimum size is not defined");
6537 return 1;
6538 }
6539
6540 if ((pa->p_args.weights.gc_content_lt ||
6541 pa->p_args.weights.gc_content_gt)
6542 && pa->p_args.opt_gc_content == DEFAULT_OPT_GC_PERCENT) {
6543 pr_append_new_chunk(glob_err,
6544 "Primer GC content is part of objective function while optimum gc_content is not defined");
6545 return 1;
6546 }
6547
6548 if ((pa->o_args.weights.gc_content_lt ||
6549 pa->o_args.weights.gc_content_gt)
6550 && pa->o_args.opt_gc_content == DEFAULT_OPT_GC_PERCENT) {
6551 pr_append_new_chunk(glob_err,
6552 "Hyb probe GC content is part of objective function "
6553 "while optimum gc_content is not defined");
6554 return 1;
6555 }
6556
6557 if ((pa->pick_internal_oligo != 1) &&
6558 (pa->pr_pair_weights.io_quality)) {
6559 pr_append_new_chunk(glob_err,
6560 "Internal oligo quality is part of objective function "
6561 "while internal oligo choice is not required");
6562 return 1;
6563 }
6564
6565 if (pa->p_args.weights.repeat_sim && (!seq_lib_num_seq(pa->p_args.repeat_lib))) {
6566 pr_append_new_chunk(glob_err,
6567 "Mispriming score is part of objective function, but mispriming library is not defined");
6568 return 1;
6569 }
6570
6571 if (pa->o_args.weights.repeat_sim && (!seq_lib_num_seq(pa->o_args.repeat_lib))) {
6572 pr_append_new_chunk(glob_err,
6573 "Internal oligo mispriming score is part of objective function while mishyb library is not defined");
6574 return 1;
6575 }
6576
6577 if (pa->pr_pair_weights.repeat_sim && (!(seq_lib_num_seq(pa->p_args.repeat_lib)))) {
6578 pr_append_new_chunk(glob_err,
6579 "Mispriming score is part of objective function, "
6580 "but mispriming library is not defined");
6581 return 1;
6582 }
6583
6584 if(pa->pr_pair_weights.io_quality
6585 && pa->pick_internal_oligo == 0 ) {
6586 pr_append_new_chunk(glob_err,
6587 "Internal oligo quality is part of objective function"
6588 " while internal oligo choice is not required");
6589 return 1;
6590 }
6591
6592 if (pa->sequencing.lead < 0) {
6593 pr_append_new_chunk(glob_err,
6594 "Illegal value for PRIMER_SEQUENCING_LEAD");
6595 return 1;
6596 }
6597
6598 if (pa->sequencing.interval < 0) {
6599 pr_append_new_chunk(glob_err,
6600 "Illegal value for PRIMER_SEQUENCING_INTERVAL");
6601 return 1;
6602 }
6603
6604 if (pa->sequencing.accuracy < 0) {
6605 pr_append_new_chunk(glob_err,
6606 "Illegal value for PRIMER_SEQUENCING_ACCURACY");
6607 return 1;
6608 }
6609
6610 if (pa->sequencing.spacing < 0) {
6611 pr_append_new_chunk(glob_err,
6612 "Illegal value for PRIMER_SEQUENCING_SPACING");
6613 return 1;
6614 }
6615
6616 if(pa->sequencing.interval > pa->sequencing.spacing) {
6617 pr_append_new_chunk(glob_err,
6618 "PRIMER_SEQUENCING_INTERVAL > PRIMER_SEQUENCING_SPACING");
6619 return 1;
6620 }
6621
6622 if(pa->sequencing.accuracy > pa->sequencing.spacing) {
6623 pr_append_new_chunk(glob_err,
6624 "PRIMER_SEQUENCING_ACCURACY > PRIMER_SEQUENCING_SPACING");
6625 return 1;
6626 }
6627
6628 if(pa->sequencing.lead > pa->sequencing.spacing) {
6629 pr_append_new_chunk(glob_err,
6630 "PRIMER_SEQUENCING_LEAD > PRIMER_SEQUENCING_SPACING");
6631 return 1;
6632 }
6633
6634 if((sa->force_left_start > -1) && (sa->force_left_end > -1)
6635 && (sa->force_left_start > sa->force_left_end)) {
6636 pr_append_new_chunk(glob_err,
6637 "SEQUENCE_FORCE_LEFT_START > SEQUENCE_FORCE_LEFT_END");
6638 return 1;
6639 }
6640
6641 if((sa->force_right_end > -1) && (sa->force_right_start > -1)
6642 && (sa->force_right_end > sa->force_right_start)) {
6643 pr_append_new_chunk(glob_err,
6644 "SEQUENCE_FORCE_RIGHT_END > SEQUENCE_FORCE_RIGHT_START");
6645 return 1;
6646 }
6647
6648 if (pa->min_5_prime_overlap_of_junction < 1) {
6649 pr_append_new_chunk(glob_err,
6650 "Illegal value for PRIMER_MIN_5_PRIME_OVERLAP_OF_JUNCTION");
6651 return 1;
6652 }
6653
6654 if (pa->min_3_prime_overlap_of_junction < 1) {
6655 pr_append_new_chunk(glob_err,
6656 "Illegal value for PRIMER_MIN_3_PRIME_OVERLAP_OF_JUNCTION");
6657 return 1;
6658 }
6659
6660 if ((sa->primer_overlap_junctions_count > 0) &&
6661 (pa->min_5_prime_overlap_of_junction > (pa->p_args.max_size / 2))) {
6662 pr_append_new_chunk(glob_err,
6663 "PRIMER_MIN_5_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2");
6664 return 1;
6665 }
6666
6667 if ((sa->primer_overlap_junctions_count > 0) &&
6668 (pa->min_3_prime_overlap_of_junction > (pa->p_args.max_size / 2))) {
6669 pr_append_new_chunk(glob_err,
6670 "PRIMER_MIN_3_PRIME_OVERLAP_OF_JUNCTION > PRIMER_MAX_SIZE / 2");
6671 return 1;
6672 }
6673
6674 if (pa->p_args.divalent_conc > 0.0 && pa->p_args.dntp_conc <= 0.0) {
6675 pr_append_new_chunk(warning,
6676 "PRIMER_SALT_DIVALENT > 0.0 "
6677 "but PRIMER_DNTP_CONC <= 0.0; "
6678 "use reasonable value for PRIMER_DNTP_CONC");
6679 }
6680
6681 if ((pa->p_args.must_match_five_prime != NULL) &&
6682 (test_must_match_parameters(pa->p_args.must_match_five_prime))) {
6683 pr_append_new_chunk(glob_err,
6684 "Illegal values for PRIMER_MUST_MATCH_FIVE_PRIME");
6685 return 1;
6686 }
6687
6688 if ((pa->p_args.must_match_three_prime != NULL) &&
6689 (test_must_match_parameters(pa->p_args.must_match_three_prime))) {
6690 pr_append_new_chunk(glob_err,
6691 "Illegal values for PRIMER_MUST_MATCH_THREE_PRIME");
6692 return 1;
6693 }
6694
6695 if ((pa->o_args.must_match_five_prime != NULL) &&
6696 (test_must_match_parameters(pa->o_args.must_match_five_prime))) {
6697 pr_append_new_chunk(glob_err,
6698 "Illegal values for PRIMER_INTERNAL_MUST_MATCH_FIVE_PRIME");
6699 return 1;
6700 }
6701
6702 if ((pa->o_args.must_match_three_prime != NULL) &&
6703 (test_must_match_parameters(pa->o_args.must_match_three_prime))) {
6704 pr_append_new_chunk(glob_err,
6705 "Illegal values for PRIMER_INTERNAL_MUST_MATCH_THREE_PRIME");
6706 return 1;
6707 }
6708
6709 return (NULL == nonfatal_err->data && NULL == glob_err->data) ? 0 : 1;
6710 } /* _pr_data_control */
6711
6712 static int
_check_and_adjust_overlap_pos(seq_args * sa,int * list,int * count,const char * tag,int seq_len,int first_index,pr_append_str * nonfatal_err,pr_append_str * warning)6713 _check_and_adjust_overlap_pos(seq_args *sa,
6714 int *list,
6715 int *count,
6716 const char *tag,
6717 int seq_len,
6718 int first_index,
6719 pr_append_str *nonfatal_err,
6720 pr_append_str *warning) {
6721 int i;
6722 int outside_warning_issued = 0;
6723 char buffer[255];
6724
6725 if (*count == 0) {
6726 return 0;
6727 }
6728
6729 for (i = 0; i < *count; i++) {
6730 /* Subtract first_index from the "must overlap" positions */
6731 list[i] -= first_index;
6732
6733 if (list[i] >= seq_len) {
6734 sprintf(buffer, "%s beyond end of sequence", tag);
6735 pr_append_new_chunk(nonfatal_err, buffer);
6736 return 1;
6737 }
6738
6739 if (list[i] < 0) {
6740 sprintf(buffer, "Negative %s length", tag);
6741 pr_append_new_chunk(nonfatal_err, buffer);
6742 return 1;
6743 }
6744
6745 /* Cause the intron positions to be relative to the included region. */
6746 list[i] -= sa->incl_s;
6747
6748 /* Check that intron positions are within the included region. */
6749 if (list[i] < 0
6750 || list[i] > sa->incl_l) {
6751 if (!outside_warning_issued) {
6752 sprintf(buffer, "%s outside of INCLUDED_REGION", tag);
6753 pr_append_new_chunk(warning, buffer);
6754 outside_warning_issued = 1;
6755 }
6756 }
6757 }
6758
6759 return 0;
6760 }
6761
6762 static int
_check_and_adjust_intervals(seq_args * sa,int seq_len,int first_index,pr_append_str * nonfatal_err,pr_append_str * warning)6763 _check_and_adjust_intervals(seq_args *sa,
6764 int seq_len,
6765 int first_index,
6766 pr_append_str * nonfatal_err,
6767 pr_append_str *warning) {
6768
6769 if (_check_and_adjust_1_interval("TARGET",
6770 sa->tar2.count,
6771 sa->tar2.pairs,
6772 seq_len,
6773 first_index,
6774 nonfatal_err, sa, warning, 0)
6775 == 1) return 1;
6776 sa->start_codon_pos -= sa->incl_s;
6777
6778 if (_check_and_adjust_1_interval("EXCLUDED_REGION",
6779 sa->excl2.count, sa->excl2.pairs,
6780 seq_len, first_index,
6781 nonfatal_err, sa, warning, 0)
6782 == 1) return 1;
6783
6784 if (_check_and_adjust_1_interval("PRIMER_INTERNAL_OLIGO_EXCLUDED_REGION",
6785 sa->excl_internal2.count,
6786 sa->excl_internal2.pairs,
6787 seq_len,
6788 first_index,
6789 nonfatal_err, sa, warning, 0)
6790 == 1) return 1;
6791 if (_check_and_adjust_1_interval("PRIMER_PAIR_OK_REGION_LIST",
6792 sa->ok_regions.count,
6793 sa->ok_regions.left_pairs,
6794 seq_len,
6795 first_index,
6796 nonfatal_err, sa, warning, 1)
6797 == 1) return 1;
6798 if (_check_and_adjust_1_interval("PRIMER_PAIR_OK_REGION_LIST",
6799 sa->ok_regions.count,
6800 sa->ok_regions.right_pairs,
6801 seq_len,
6802 first_index,
6803 nonfatal_err, sa, warning, 1)
6804 == 1) return 1;
6805 return 0;
6806 }
6807
6808 /*
6809 * Check intervals, and add any errors to err.
6810 * Update the start of each interval to
6811 * be relative to the start of the included region.
6812 */
6813 static int
_check_and_adjust_1_interval(const char * tag_name,int num_intervals,interval_array_t intervals,int seq_len,int first_index,pr_append_str * err,seq_args * sa,pr_append_str * warning,int empty_allowed)6814 _check_and_adjust_1_interval(const char *tag_name,
6815 int num_intervals,
6816 interval_array_t intervals,
6817 int seq_len,
6818 int first_index,
6819 pr_append_str *err,
6820 seq_args *sa,
6821 pr_append_str *warning,
6822 int empty_allowed)
6823 {
6824 int i;
6825 int outside_warning_issued = 0;
6826
6827 /* Subtract the first_index from the start positions in the interval
6828 array */
6829 for (i = 0; i < num_intervals; i++) {
6830 if (empty_allowed && (intervals[i][0] == -1) && (intervals[i][1] == -1))
6831 continue;
6832 if (empty_allowed && (((intervals[i][0] == -1) && (intervals[i][1] != -1))
6833 || ((intervals[i][0] != -1) && (intervals[i][1] == -1)))) {
6834 pr_append_new_chunk(err, tag_name);
6835 pr_append(err, " illegal interval");
6836 return 1;
6837 }
6838 intervals[i][0] -= first_index;
6839 }
6840
6841 for (i=0; i < num_intervals; i++) {
6842 if (empty_allowed && (intervals[i][0] == -1) && (intervals[i][1] == -1))
6843 continue;
6844 if (intervals[i][0] + intervals[i][1] > seq_len) {
6845 pr_append_new_chunk(err, tag_name);
6846 pr_append(err, " beyond end of sequence");
6847 return 1;
6848 }
6849 /* Cause the interval start to be relative to the included region. */
6850 intervals[i][0] -= sa->incl_s;
6851 /* Check that intervals are within the included region. */
6852 if (intervals[i][0] < 0
6853 || intervals[i][0] + intervals[i][1] > sa->incl_l) {
6854 if (!outside_warning_issued) {
6855 pr_append_new_chunk(warning, tag_name);
6856 pr_append(warning,
6857 " outside of INCLUDED_REGION");
6858 outside_warning_issued = 1;
6859 }
6860 }
6861 if (intervals[i][1] < 0) {
6862 pr_append_new_chunk(err, "Negative ");
6863 pr_append(err, tag_name);
6864 pr_append(err, " length");
6865 return 1;
6866 }
6867 }
6868 return 0;
6869 } /* _check_and_adjust_intervals */
6870
6871 /* ============================================================ */
6872 /* END functions that check and modify the input */
6873 /* ============================================================ */
6874
6875 /* ============================================================ */
6876 /* BEGIN create primer files functions */
6877 /* ============================================================ */
6878
6879 /* START OF WHAT SHOULD GO TO IO_PRIMER_FILES.C */
6880
6881 /*
6882 Creates up to three files, the names of which are based on the
6883 argument 'file_name'. One file is a table of forward primers, one
6884 a table of reverse primers, and one a table of internal
6885 hybridization oligos, depending on what the caller to
6886 choose_primers() requested (in the 'pa' argument). Returns 0 on
6887 success, 1 on error. On error, check errno for ENOMEM. Used to
6888 implement P3_FILE_FLAG=1.
6889 */
6890 int
p3_print_oligo_lists(const p3retval * retval,const seq_args * sa,const p3_global_settings * pa,pr_append_str * err,const char * file_name)6891 p3_print_oligo_lists(const p3retval *retval,
6892 const seq_args *sa,
6893 const p3_global_settings *pa,
6894 pr_append_str *err,
6895 const char *file_name)
6896 {
6897 /* Figure out if the sequence starts at position 1 or 0 */
6898 int first_base_index = pa->first_base_index;
6899 int ret;
6900 /* Start building up a filename */
6901 char *file;
6902 FILE *fh;
6903
6904 if (setjmp(_jmp_buf) != 0) {
6905 return 1; /* If we get here, that means we returned via a longjmp.
6906 In this case errno should be ENOMEM. */
6907
6908 }
6909
6910 file = (char *) malloc(strlen(sa->sequence_name) + 5);
6911 if (NULL == file) return 1; /* ENOMEM */
6912
6913 /* Check if the left primers have to be printed */
6914 if( pa->pick_left_primer ) {
6915 /* Create the file name and open file*/
6916 strcpy(file, sa->sequence_name);
6917 strcat(file, ".for");
6918 if (!(fh = fopen(file,"w"))) {
6919 if (pr_append_new_chunk_external(err, "Unable to open file "))
6920 return 1;
6921 if (pr_append_external(err, file)) return 1;
6922 if (pr_append_external(err, " for writing")) return 1;
6923 free(file);
6924 return 1;
6925 }
6926
6927 /* Print the content to the file */
6928 ret =
6929 p3_print_one_oligo_list(sa, retval->fwd.num_elem,
6930 retval->fwd.oligo, OT_LEFT,
6931 first_base_index, NULL != pa->p_args.repeat_lib,
6932 fh,pa->thermodynamic_oligo_alignment);
6933 fclose(fh);
6934 if (ret) return 1;
6935 }
6936
6937 /* Check if the right primers have to be printed */
6938 if (pa->pick_right_primer) {
6939 strcpy(file, sa->sequence_name);
6940 strcat(file, ".rev");
6941 if (!(fh = fopen(file,"w"))) {
6942 pr_append_new_chunk(err, "Unable to open file ");
6943 pr_append(err, file);
6944 pr_append(err, " for writing");
6945 free(file);
6946 return 1;
6947 }
6948 /* Print the content to the file */
6949 ret = p3_print_one_oligo_list(sa, retval->rev.num_elem,
6950 retval->rev.oligo, OT_RIGHT,
6951 first_base_index, NULL != pa->p_args.repeat_lib,
6952 fh, pa->thermodynamic_oligo_alignment);
6953
6954 fclose(fh);
6955 if (ret) return 1;
6956 }
6957
6958 /* Check if the internal oligos have to be printed */
6959 if (pa->pick_internal_oligo) {
6960 /* Create the file name and open file*/
6961 strcpy(file, sa->sequence_name);
6962 strcat(file, ".int");
6963 if (!(fh = fopen(file,"w"))) {
6964 if (pr_append_new_chunk_external(err, "Unable to open file "))
6965 return 1;
6966 if (pr_append_external(err, file)) return 1;
6967 if (pr_append_external(err, " for writing")) return 1;
6968 free(file);
6969 return 1;
6970 }
6971 /* Print the content to the file */
6972 ret = p3_print_one_oligo_list(sa, retval->intl.num_elem,
6973 retval->intl.oligo, OT_INTL,
6974 first_base_index,
6975 NULL != pa->o_args.repeat_lib,
6976 fh, pa->thermodynamic_oligo_alignment);
6977 fclose(fh);
6978 if (ret) return 1;
6979 }
6980 free(file);
6981 return 0;
6982 }
6983
6984 /* Print out the content of one primer array */
6985 /* Return 1 on error, otherwise 0. */
6986 int
p3_print_one_oligo_list(const seq_args * sa,int n,const primer_rec * oligo_arr,const oligo_type o_type,const int first_base_index,const int print_lib_sim,FILE * fh,const int thermodynamic_oligo_alignment)6987 p3_print_one_oligo_list(const seq_args *sa,
6988 int n,
6989 const primer_rec *oligo_arr,
6990 const oligo_type o_type,
6991 const int first_base_index,
6992 const int print_lib_sim,
6993 FILE *fh,
6994 const int thermodynamic_oligo_alignment)
6995 {
6996 int i;
6997
6998 /* Print out the header for the table */
6999 if (print_list_header(fh, o_type, first_base_index, print_lib_sim, thermodynamic_oligo_alignment))
7000 return 1; /* error */
7001 /* Iterate over the array */
7002 for (i = 0; i < n; i++) {
7003 /* Print each single oligo */
7004 if (print_oligo(fh, sa, i, &oligo_arr[i], o_type,
7005 first_base_index, print_lib_sim, thermodynamic_oligo_alignment))
7006 return 1; /* error */
7007 }
7008 return 0; /* success */
7009 }
7010
7011 static int
print_list_header(FILE * fh,oligo_type type,int first_base_index,int print_lib_sim,int thermodynamic_oligo_alignment)7012 print_list_header(FILE *fh,
7013 oligo_type type,
7014 int first_base_index,
7015 int print_lib_sim,
7016 int thermodynamic_oligo_alignment)
7017 {
7018 int ret;
7019 ret = fprintf(fh, "ACCEPTABLE %s\n",
7020 OT_LEFT == type ? "LEFT PRIMERS"
7021 : OT_RIGHT == type ? "RIGHT PRIMERS" : "INTERNAL OLIGOS");
7022 if (ret < 0) return 1;
7023
7024 ret = fprintf(fh, " %4d-based ",
7025 first_base_index);
7026 if (ret < 0) return 1;
7027
7028 if(thermodynamic_oligo_alignment)
7029 ret = fprintf(fh, "# self self hair-");
7030 else
7031 ret = fprintf(fh, "# self self");
7032 if (ret < 0) return 1;
7033 if (print_lib_sim)
7034 /* ret = fprintf(fh, "# self self lib qual-\n"); */
7035 ret = fprintf(fh, " lib");
7036 if (ret < 0) return 1;
7037 ret = fprintf(fh, " qual-\n");
7038 if (ret < 0) return 1;
7039
7040 ret = fprintf(fh, " # sequence start ln ");
7041 if (ret < 0) return 1;
7042
7043 ret = fprintf(fh, "N GC%% Tm");
7044 if (ret < 0) return 1;
7045 if(thermodynamic_oligo_alignment)
7046 ret = fprintf(fh, " any_th end_th pin");
7047 else
7048 ret = fprintf(fh, " any end");
7049 if (ret < 0) return 1;
7050 if (print_lib_sim)
7051 ret = fprintf(fh, " sim lity\n");
7052 else
7053 ret = fprintf(fh, " lity\n");
7054
7055 if (ret < 0) return 1;
7056 return 0;
7057 }
7058
7059 static int
print_oligo(FILE * fh,const seq_args * sa,int index,const primer_rec * h,oligo_type type,int first_base_index,int print_lib_sim,int thermodynamical_approach)7060 print_oligo(FILE *fh,
7061 const seq_args *sa,
7062 int index,
7063 const primer_rec *h,
7064 oligo_type type,
7065 int first_base_index,
7066 int print_lib_sim,
7067 int thermodynamical_approach)
7068 {
7069 int ret;
7070
7071 /* WARNING, *p points to static storage that is overwritten on next
7072 call to pr_oligo_sequence or pr_oligo_rev_c_sequence. */
7073 char *p =
7074 (OT_RIGHT != type)
7075 ? pr_oligo_sequence(sa, h)
7076 : pr_oligo_rev_c_sequence(sa, h);
7077
7078 ret = fprintf(fh,
7079 "%4d %-30s %5d %2d %2d %5.2f %5.3f %5.2f %5.2f",
7080 index, p, h->start+sa->incl_s + first_base_index,
7081 h->length,
7082 h->num_ns, h->gc_content, h->temp,
7083 h->self_any,
7084 h->self_end);
7085 if (ret < 0) return 1;
7086
7087 if (1==thermodynamical_approach) {
7088 ret = fprintf(fh, " %5.2f", h->hairpin_th);
7089 if (ret < 0) return 1;
7090 }
7091
7092 if (ret < 0) return 1;
7093 if (print_lib_sim) {
7094 PR_ASSERT(h->repeat_sim.score != NULL);
7095 ret = fprintf(fh, " %5.2f",
7096 h->repeat_sim.score[h->repeat_sim.max]);
7097 if (ret < 0) return 1;
7098 }
7099 ret = fprintf(fh, " %6.3f\n", h->quality);
7100 if (ret < 0) return 1;
7101 else return 0;
7102 }
7103
7104 /* END OF WHAT SHOULD GO TO IO_PRIMER_FILES.C */
7105
7106 /* ============================================================ */
7107 /* END create primer files functions */
7108 /* ============================================================ */
7109
7110 /* ============================================================
7111 * BEGIN p3_read_line, a utility used
7112 * both for reading boulder input and for reading sequence
7113 * libraries.
7114 * ============================================================ */
7115
7116 /* Read a line of any length from file. Return NULL on end of file,
7117 * otherwise return a pointer to static storage containing the line. Any
7118 * trailing newline is stripped off. Be careful -- there is only
7119 * one static buffer, so subsequent calls will replace the string
7120 * pointed to by the return value.
7121 * Used in seq_lib functions and also exported
7122 * used in p3_read_line and seq_lib functions
7123 * */
7124 #define INIT_BUF_SIZE 1024
7125
7126 char*
p3_read_line(FILE * file)7127 p3_read_line(FILE *file)
7128 {
7129 static size_t ssz;
7130 static char *s = NULL;
7131
7132 size_t remaining_size;
7133 char *p, *n;
7134
7135 if (NULL == s) {
7136 ssz = INIT_BUF_SIZE;
7137 s = (char *) pr_safe_malloc(ssz);
7138 }
7139 p = s;
7140 remaining_size = ssz;
7141 while (1) {
7142 if (fgets(p, remaining_size, file) == NULL) /* End of file. */
7143 return p == s ? NULL : s;
7144
7145 if ((n = strchr(p, '\n')) != NULL) {
7146 *n = '\0';
7147 return s;
7148 }
7149
7150 /* We did not get the whole line. */
7151
7152 /*
7153 * The following assertion is a bit of hack, a at least for 32-bit
7154 * machines, because we will usually run out of address space first.
7155 * Really we should treat an over-long line as an input error, but
7156 * since an over-long line is unlikely and we do want to provide some
7157 * protection....
7158 */
7159 PR_ASSERT(ssz <= INT_MAX);
7160 if (ssz >= INT_MAX / 2)
7161 ssz = INT_MAX;
7162 else {
7163 ssz *= 2;
7164 }
7165 s = (char *) pr_safe_realloc(s, ssz);
7166 p = strchr(s, '\0');
7167 remaining_size = ssz - (p - s);
7168 }
7169 }
7170
7171 /* ============================================================ */
7172 /* END p3_read_line */
7173 /* ============================================================ */
7174
7175 /* ============================================================ */
7176 /* BEGIN 'get' functions for seq_args */
7177 /* ============================================================ */
7178
7179 const interval_array_t2 *
p3_get_sa_tar2(const seq_args * sargs)7180 p3_get_sa_tar2(const seq_args *sargs) {
7181 return &sargs->tar2 ;
7182 }
7183
7184 const interval_array_t2 *
p3_get_sa_excl2(const seq_args * sargs)7185 p3_get_sa_excl2(const seq_args *sargs) {
7186 return &sargs->excl2 ;
7187 }
7188
7189 const interval_array_t2 *
p3_get_sa_excl_internal2(const seq_args * sargs)7190 p3_get_sa_excl_internal2(const seq_args *sargs) {
7191 return &sargs->excl_internal2 ;
7192 }
7193
7194 const interval_array_t4 *
p3_get_sa_ok_regions(const seq_args * sargs)7195 p3_get_sa_ok_regions(const seq_args *sargs)
7196 {
7197 return &sargs->ok_regions;
7198 }
7199
7200 const int*
p3_get_sa_overlap_junctions(const seq_args * sargs)7201 p3_get_sa_overlap_junctions(const seq_args *sargs)
7202 {
7203 return sargs->primer_overlap_junctions;
7204 }
7205
7206 /* ============================================================ */
7207 /* END 'get' functions for seq_args */
7208 /* ============================================================ */
7209
7210 int
p3_get_sa_n_quality(seq_args * sargs)7211 p3_get_sa_n_quality(seq_args *sargs) {
7212 return sargs->n_quality ;
7213 }
7214
7215 /* ============================================================ */
7216 /* BEGIN 'set' functions for seq_args */
7217 /* ============================================================ */
7218
7219 int
p3_set_sa_sequence(seq_args * sargs,const char * sequence)7220 p3_set_sa_sequence(seq_args *sargs, const char *sequence) {
7221 return _set_string(&sargs->sequence, sequence) ;
7222 }
7223
7224 void
p3_set_sa_primer_sequence_quality(seq_args * sargs,int quality)7225 p3_set_sa_primer_sequence_quality(seq_args *sargs, int quality) {
7226 sargs->quality[sargs->n_quality++] = quality ;
7227 }
7228
7229 int
p3_set_sa_sequence_name(seq_args * sargs,const char * sequence_name)7230 p3_set_sa_sequence_name(seq_args *sargs, const char* sequence_name) {
7231 return _set_string(&sargs->sequence_name, sequence_name);
7232 }
7233
7234 int
p3_set_sa_left_input(seq_args * sargs,const char * s)7235 p3_set_sa_left_input(seq_args *sargs, const char *s) {
7236 return _set_string(&sargs->left_input, s);
7237 }
7238
7239 int
p3_set_sa_right_input(seq_args * sargs,const char * s)7240 p3_set_sa_right_input(seq_args *sargs, const char *s) {
7241 return _set_string(&sargs->right_input, s);
7242 }
7243
7244 int
p3_set_sa_internal_input(seq_args * sargs,const char * s)7245 p3_set_sa_internal_input(seq_args *sargs, const char *s) {
7246 return _set_string(&sargs->internal_input, s);
7247 }
7248
7249 void
p3_set_sa_incl_s(seq_args * sargs,int incl_s)7250 p3_set_sa_incl_s(seq_args *sargs, int incl_s) {
7251 sargs->incl_s = incl_s;
7252 }
7253
7254 void
p3_set_sa_incl_l(seq_args * sargs,int incl_l)7255 p3_set_sa_incl_l(seq_args *sargs, int incl_l) {
7256 sargs->incl_l = incl_l;
7257 }
7258
7259 void
p3_set_sa_empty_quality(seq_args * sargs)7260 p3_set_sa_empty_quality(seq_args *sargs) {
7261 sargs->n_quality = 0;
7262 }
7263
7264 void
p3_sa_add_to_quality_array(seq_args * sargs,int quality)7265 p3_sa_add_to_quality_array(seq_args *sargs, int quality) {
7266 int n = sargs->n_quality;
7267 if (sargs->quality_storage_size == 0) {
7268 sargs->quality_storage_size = 3000;
7269 sargs->quality
7270 = (int *)
7271 pr_safe_malloc(sizeof(*sargs->quality)
7272 * sargs->quality_storage_size);
7273 }
7274 if (n > sargs->quality_storage_size) {
7275 sargs->quality_storage_size *= 2;
7276 sargs->quality
7277 = (int *)
7278 pr_safe_realloc(sargs->quality,
7279 sizeof(*sargs->quality)
7280 * sargs->quality_storage_size);
7281 }
7282 sargs->quality[n] = quality;
7283 sargs->n_quality++;
7284 }
7285
7286 int
p3_sa_add_to_overlap_junctions_array(seq_args * sargs,int overlap)7287 p3_sa_add_to_overlap_junctions_array(seq_args *sargs, int overlap)
7288 {
7289 int c = sargs->primer_overlap_junctions_count;
7290 if (c >= PR_MAX_INTERVAL_ARRAY) return 1;
7291 sargs->primer_overlap_junctions[sargs->primer_overlap_junctions_count++] = overlap;
7292 return 0;
7293 }
7294
7295 void
p3_set_sa_start_codon_pos(seq_args * sargs,int start_codon_pos)7296 p3_set_sa_start_codon_pos(seq_args *sargs, int start_codon_pos) {
7297 sargs->start_codon_pos = start_codon_pos;
7298 }
7299
7300 int
p3_add_to_sa_tar2(seq_args * sargs,int n1,int n2)7301 p3_add_to_sa_tar2(seq_args *sargs, int n1, int n2) {
7302 return p3_add_to_interval_array(&sargs->tar2, n1, n2);
7303 }
7304
7305 int
p3_add_to_sa_excl2(seq_args * sargs,int n1,int n2)7306 p3_add_to_sa_excl2(seq_args *sargs, int n1, int n2) {
7307 return p3_add_to_interval_array(&sargs->excl2, n1, n2);
7308 }
7309
7310 int
p3_add_to_sa_excl_internal2(seq_args * sargs,int n1,int n2)7311 p3_add_to_sa_excl_internal2(seq_args *sargs, int n1, int n2) {
7312 return p3_add_to_interval_array(&sargs->excl_internal2, n1, n2);
7313 }
7314
7315 int
p3_add_to_sa_ok_regions(seq_args * sargs,int l1,int l2,int r1,int r2)7316 p3_add_to_sa_ok_regions(seq_args *sargs, int l1, int l2, int r1, int r2)
7317 {
7318 return p3_add_to_2_interval_array(&sargs->ok_regions, l1, l2, r1, r2);
7319 }
7320
7321 /* ============================================================ */
7322 /* END 'set' functions for seq_args */
7323 /* ============================================================ */
7324
7325 /* ============================================================ */
7326 /* BEGIN 'get' functions for p3_global_settings */
7327 /* ============================================================ */
7328
7329 args_for_one_oligo_or_primer *
p3_get_gs_p_args(p3_global_settings * p)7330 p3_get_gs_p_args(p3_global_settings * p) {
7331 return &p->p_args;
7332 }
7333
7334 args_for_one_oligo_or_primer *
p3_get_gs_o_args(p3_global_settings * p)7335 p3_get_gs_o_args(p3_global_settings * p) {
7336 return &p->o_args;
7337 }
7338
7339 /* ============================================================ */
7340 /* END 'get' functions for p3_global_settings */
7341 /* ============================================================ */
7342
7343
7344 /* ============================================================ */
7345 /* BEGIN 'set' functions for p3_global_settings */
7346 /* ============================================================ */
7347
7348 void
p3_set_gs_prmin(p3_global_settings * p,int val,int i)7349 p3_set_gs_prmin (p3_global_settings * p , int val, int i) {
7350 p->pr_min[i] = val ;
7351 }
7352
7353 void
p3_set_gs_prmax(p3_global_settings * p,int val,int i)7354 p3_set_gs_prmax (p3_global_settings * p , int val, int i) {
7355 p->pr_max[i] = val ;
7356 }
7357
7358 void
p3_set_gs_primer_opt_size(p3_global_settings * p,int val)7359 p3_set_gs_primer_opt_size(p3_global_settings * p , int val) {
7360 p->p_args.opt_size = val ;
7361 }
7362
7363 void
p3_set_gs_primer_min_size(p3_global_settings * p,int val)7364 p3_set_gs_primer_min_size(p3_global_settings * p , int val) {
7365 p->p_args.min_size = val ;
7366 }
7367
7368 void
p3_set_gs_primer_max_size(p3_global_settings * p,int val)7369 p3_set_gs_primer_max_size(p3_global_settings * p , int val) {
7370 p->p_args.max_size = val ;
7371 }
7372
7373 void
p3_set_gs_primer_max_poly_x(p3_global_settings * p,int val)7374 p3_set_gs_primer_max_poly_x(p3_global_settings * p , int val) {
7375 p->p_args.max_poly_x = val;
7376
7377 }
7378
7379 void
p3_set_gs_primer_opt_tm(p3_global_settings * p,double d)7380 p3_set_gs_primer_opt_tm(p3_global_settings * p , double d) {
7381 p->p_args.opt_tm = d ;
7382 }
7383
7384 void
p3_set_gs_primer_opt_gc_percent(p3_global_settings * p,double d)7385 p3_set_gs_primer_opt_gc_percent(p3_global_settings * p , double d) {
7386 p->p_args.opt_gc_content = d ;
7387 }
7388
7389 void
p3_set_gs_primer_min_tm(p3_global_settings * p,double d)7390 p3_set_gs_primer_min_tm(p3_global_settings * p , double d) {
7391 p->p_args.min_tm = d ;
7392 }
7393 void
p3_set_gs_primer_max_tm(p3_global_settings * p,double d)7394 p3_set_gs_primer_max_tm(p3_global_settings * p , double d) {
7395 p->p_args.max_tm = d;
7396 }
7397
7398 void
p3_set_gs_primer_max_diff_tm(p3_global_settings * p,double val)7399 p3_set_gs_primer_max_diff_tm(p3_global_settings * p , double val) {
7400 p->max_diff_tm = val;
7401 }
7402
7403 void
p3_set_gs_primer_tm_santalucia(p3_global_settings * p,tm_method_type val)7404 p3_set_gs_primer_tm_santalucia(p3_global_settings * p,
7405 tm_method_type val) {
7406 p->tm_santalucia = val ;
7407 }
7408
7409 void
p3_set_gs_primer_salt_corrections(p3_global_settings * p,salt_correction_type val)7410 p3_set_gs_primer_salt_corrections(p3_global_settings * p,
7411 salt_correction_type val) {
7412 p->salt_corrections = val;
7413 }
7414
7415 void
p3_set_gs_primer_min_gc(p3_global_settings * p,double val)7416 p3_set_gs_primer_min_gc(p3_global_settings * p , double val) {
7417 p->p_args.min_gc = val ;
7418 }
7419
7420 void
p3_set_gs_primer_max_gc(p3_global_settings * p,double val)7421 p3_set_gs_primer_max_gc(p3_global_settings * p , double val) {
7422 p->p_args.max_gc = val ;
7423 }
7424
7425 void
p3_set_gs_primer_salt_conc(p3_global_settings * p,double val)7426 p3_set_gs_primer_salt_conc(p3_global_settings * p , double val) {
7427 p->p_args.salt_conc = val ;
7428 }
7429
7430 void
p3_set_gs_primer_divalent_conc(p3_global_settings * p,double val)7431 p3_set_gs_primer_divalent_conc(p3_global_settings * p , double val)
7432 {
7433 p->p_args.divalent_conc = val;
7434 }
7435
7436 void
p3_set_gs_primer_dntp_conc(p3_global_settings * p,double val)7437 p3_set_gs_primer_dntp_conc(p3_global_settings * p , double val)
7438 {
7439 p->p_args.dntp_conc = val ;
7440 }
7441
7442 void
p3_set_gs_primer_dna_conc(p3_global_settings * p,double val)7443 p3_set_gs_primer_dna_conc(p3_global_settings * p , double val)
7444 {
7445 p->p_args.dna_conc = val ;
7446 }
7447
7448 void
p3_set_gs_primer_num_ns_accepted(p3_global_settings * p,int val)7449 p3_set_gs_primer_num_ns_accepted(p3_global_settings * p , int val)
7450 {
7451 p->p_args.num_ns_accepted = val ;
7452 }
7453
7454 void
p3_set_gs_primer_product_opt_size(p3_global_settings * p,int val)7455 p3_set_gs_primer_product_opt_size(p3_global_settings * p , int val)
7456 {
7457 p->product_opt_size = val ;
7458 }
7459
7460 void
p3_set_gs_primer_self_any(p3_global_settings * p,double val)7461 p3_set_gs_primer_self_any(p3_global_settings * p , double val)
7462 {
7463 p->p_args.max_self_any = val;
7464 }
7465
7466 void
p3_set_gs_primer_self_any_th(p3_global_settings * p,double val)7467 p3_set_gs_primer_self_any_th(p3_global_settings * p , double val)
7468 {
7469 p->p_args.max_self_any_th = val;
7470 }
7471
7472 void
p3_set_gs_primer_self_end(p3_global_settings * p,double val)7473 p3_set_gs_primer_self_end(p3_global_settings * p , double val)
7474 {
7475 p->p_args.max_self_end = val; /* (short) (val * 100); */
7476 }
7477
7478 void
p3_set_gs_primer_self_end_th(p3_global_settings * p,double val)7479 p3_set_gs_primer_self_end_th(p3_global_settings * p , double val)
7480 {
7481 p->p_args.max_self_end_th = val;
7482 }
7483
7484 void
p3_set_gs_primer_hairpin_th(p3_global_settings * p,double val)7485 p3_set_gs_primer_hairpin_th(p3_global_settings * p , double val) {
7486 p->p_args.max_hairpin_th = val;
7487 }
7488
7489 void /* Called in primer3_boulder_main.c. */
p3_set_gs_primer_file_flag(p3_global_settings * p,int file_flag)7490 p3_set_gs_primer_file_flag(p3_global_settings * p , int file_flag)
7491 {
7492 p->file_flag = file_flag;
7493 }
7494
7495 void
p3_set_gs_pick_anyway(p3_global_settings * p,int pick_anyway)7496 p3_set_gs_pick_anyway(p3_global_settings * p , int pick_anyway)
7497 {
7498 p->pick_anyway = pick_anyway ;
7499 }
7500
7501 void
p3_set_gs_gc_clamp(p3_global_settings * p,int gc_clamp)7502 p3_set_gs_gc_clamp(p3_global_settings * p , int gc_clamp)
7503 {
7504 p->gc_clamp = gc_clamp;
7505 }
7506
7507 void
p3_set_gs_primer_liberal_base(p3_global_settings * p,int val)7508 p3_set_gs_primer_liberal_base(p3_global_settings * p , int val) {
7509 p->liberal_base = val;
7510 }
7511
7512 void
p3_set_gs_primer_first_base_index(p3_global_settings * p,int first_base_index)7513 p3_set_gs_primer_first_base_index(p3_global_settings * p , int first_base_index){
7514 p->first_base_index = first_base_index;
7515 }
7516
7517 void
p3_set_gs_primer_num_return(p3_global_settings * p,int val)7518 p3_set_gs_primer_num_return(p3_global_settings * p , int val) {
7519 p->num_return = val ;
7520 }
7521
7522 void
p3_set_gs_primer_min_quality(p3_global_settings * p,int val)7523 p3_set_gs_primer_min_quality(p3_global_settings * p , int val) {
7524 p->p_args.min_quality = val ;
7525 }
7526
7527 void
p3_set_gs_primer_min_end_quality(p3_global_settings * p,int val)7528 p3_set_gs_primer_min_end_quality(p3_global_settings * p , int val) {
7529 p->p_args.min_end_quality = val ;
7530 }
7531
7532 void
p3_set_gs_primer_quality_range_min(p3_global_settings * p,int val)7533 p3_set_gs_primer_quality_range_min(p3_global_settings * p , int val) {
7534 p->quality_range_min = val ;
7535 }
7536
7537 void
p3_set_gs_primer_quality_range_max(p3_global_settings * p,int val)7538 p3_set_gs_primer_quality_range_max(p3_global_settings * p , int val) {
7539 p->quality_range_max = val ;
7540 }
7541
7542 void
p3_set_gs_primer_product_max_tm(p3_global_settings * p,double val)7543 p3_set_gs_primer_product_max_tm(p3_global_settings * p , double val) {
7544 p->product_max_tm = val ;
7545 }
7546
7547 void
p3_set_gs_primer_product_min_tm(p3_global_settings * p,double val)7548 p3_set_gs_primer_product_min_tm(p3_global_settings * p , double val) {
7549 p->product_min_tm = val ;
7550 }
7551
7552 void
p3_set_gs_primer_product_opt_tm(p3_global_settings * p,double val)7553 p3_set_gs_primer_product_opt_tm(p3_global_settings * p , double val) {
7554 p->product_opt_tm = val ;
7555 }
7556
7557 void
p3_set_gs_primer_task(p3_global_settings * pa,char * task_tmp)7558 p3_set_gs_primer_task(p3_global_settings * pa , char * task_tmp)
7559 {
7560 if (!strcmp_nocase(task_tmp, "pick_pcr_primers")) {
7561 pa->primer_task = generic;
7562 pa->pick_left_primer = 1;
7563 pa->pick_right_primer = 1;
7564 pa->pick_internal_oligo = 0;
7565 } else if (!strcmp_nocase(task_tmp, "pick_pcr_primers_and_hyb_probe")) {
7566 pa->primer_task = generic;
7567 pa->pick_left_primer = 1;
7568 pa->pick_right_primer = 1;
7569 pa->pick_internal_oligo = 1;
7570 } else if (!strcmp_nocase(task_tmp, "pick_left_only")) {
7571 pa->primer_task = generic;
7572 pa->pick_left_primer = 1;
7573 pa->pick_right_primer = 0;
7574 pa->pick_internal_oligo = 0;
7575 } else if (!strcmp_nocase(task_tmp, "pick_right_only")) {
7576 pa->primer_task = generic;
7577 pa->pick_left_primer = 0;
7578 pa->pick_right_primer = 1;
7579 pa->pick_internal_oligo = 0;
7580 } else if (!strcmp_nocase(task_tmp, "pick_hyb_probe_only")) {
7581 pa->primer_task = generic;
7582 pa->pick_left_primer = 0;
7583 pa->pick_right_primer = 0;
7584 pa->pick_internal_oligo = 1;
7585 } else if (!strcmp_nocase(task_tmp, "generic")) {
7586 pa->primer_task = generic;
7587 } else if (!strcmp_nocase(task_tmp, "pick_detection_primers")) {
7588 pa->primer_task = generic; /* Deliberate duplication for
7589 backward compatibility. */
7590 } else if (!strcmp_nocase(task_tmp, "pick_cloning_primers")) {
7591 pa->primer_task = pick_cloning_primers;
7592 } else if (!strcmp_nocase(task_tmp, "pick_discriminative_primers")) {
7593 pa->primer_task = pick_discriminative_primers;
7594 } else if (!strcmp_nocase(task_tmp, "pick_sequencing_primers")) {
7595 pa->primer_task = pick_sequencing_primers;
7596 } else if (!strcmp_nocase(task_tmp, "pick_primer_list")) {
7597 pa->primer_task = pick_primer_list;
7598 } else if (!strcmp_nocase(task_tmp, "check_primers")) {
7599 pa->primer_task = check_primers;
7600 }
7601 }
7602
7603 void
p3_set_gs_primer_pick_right_primer(p3_global_settings * p,int pick_right_primer)7604 p3_set_gs_primer_pick_right_primer(p3_global_settings * p , int pick_right_primer)
7605 {
7606 p->pick_right_primer = pick_right_primer;
7607 }
7608
7609 void
p3_set_gs_primer_pick_internal_oligo(p3_global_settings * p,int pick_internal_oligo)7610 p3_set_gs_primer_pick_internal_oligo(p3_global_settings * p , int pick_internal_oligo)
7611 {
7612 p->pick_internal_oligo = pick_internal_oligo;
7613 }
7614
7615 void
p3_set_gs_primer_pick_left_primer(p3_global_settings * p,int pick_left_primer)7616 p3_set_gs_primer_pick_left_primer(p3_global_settings * p , int pick_left_primer) {
7617 p->pick_left_primer = pick_left_primer;
7618 }
7619
7620 void
p3_set_gs_primer_internal_oligo_opt_size(p3_global_settings * p,int val)7621 p3_set_gs_primer_internal_oligo_opt_size(p3_global_settings * p , int val) {
7622 p->o_args.opt_size = val ;
7623 }
7624
7625 void
p3_set_gs_primer_internal_oligo_max_size(p3_global_settings * p,int val)7626 p3_set_gs_primer_internal_oligo_max_size(p3_global_settings * p , int val) {
7627 p->o_args.max_size = val ;
7628 }
7629
7630 void
p3_set_gs_primer_internal_oligo_min_size(p3_global_settings * p,int val)7631 p3_set_gs_primer_internal_oligo_min_size(p3_global_settings * p , int val) {
7632 p->o_args.min_size = val ;
7633 }
7634
7635 void
p3_set_gs_primer_internal_oligo_max_poly_x(p3_global_settings * p,int val)7636 p3_set_gs_primer_internal_oligo_max_poly_x(p3_global_settings * p , int val) {
7637 p->o_args.max_poly_x = val ;
7638 }
7639
7640 void
p3_set_gs_primer_internal_oligo_opt_tm(p3_global_settings * p,double val)7641 p3_set_gs_primer_internal_oligo_opt_tm(p3_global_settings * p , double val) {
7642 p->o_args.opt_tm = val ;
7643 }
7644
7645 void
p3_set_gs_primer_internal_oligo_opt_gc_percent(p3_global_settings * p,double val)7646 p3_set_gs_primer_internal_oligo_opt_gc_percent(p3_global_settings * p , double val) {
7647 p->o_args.opt_gc_content = val ;
7648 }
7649
7650 void
p3_set_gs_primer_internal_oligo_max_tm(p3_global_settings * p,double val)7651 p3_set_gs_primer_internal_oligo_max_tm(p3_global_settings * p , double val) {
7652 p->o_args.max_tm = val ;
7653 }
7654
7655 void
p3_set_gs_primer_internal_oligo_min_tm(p3_global_settings * p,double val)7656 p3_set_gs_primer_internal_oligo_min_tm(p3_global_settings * p , double val) {
7657 p->o_args.min_tm = val ;
7658 }
7659
7660 void
p3_set_gs_primer_internal_oligo_min_gc(p3_global_settings * p,double val)7661 p3_set_gs_primer_internal_oligo_min_gc(p3_global_settings * p , double val) {
7662 p->o_args.min_gc = val ;
7663 }
7664
7665 void
p3_set_gs_primer_internal_oligo_max_gc(p3_global_settings * p,double val)7666 p3_set_gs_primer_internal_oligo_max_gc(p3_global_settings * p , double val) {
7667 p->o_args.max_gc = val ;
7668 }
7669
7670 void
p3_set_gs_primer_internal_oligo_salt_conc(p3_global_settings * p,double val)7671 p3_set_gs_primer_internal_oligo_salt_conc(p3_global_settings * p , double val) {
7672 p->o_args.salt_conc = val ;
7673 }
7674
7675 void
p3_set_gs_primer_internal_oligo_divalent_conc(p3_global_settings * p,double val)7676 p3_set_gs_primer_internal_oligo_divalent_conc(p3_global_settings * p , double val) {
7677 p->o_args.divalent_conc = val ;
7678 }
7679
7680 void
p3_set_gs_primer_internal_oligo_dntp_conc(p3_global_settings * p,double val)7681 p3_set_gs_primer_internal_oligo_dntp_conc(p3_global_settings * p , double val) {
7682 p->o_args.dntp_conc = val ;
7683 }
7684
7685 void
p3_set_gs_primer_internal_oligo_dna_conc(p3_global_settings * p,double val)7686 p3_set_gs_primer_internal_oligo_dna_conc(p3_global_settings * p , double val) {
7687 p->o_args.dna_conc = val ;
7688 }
7689
7690 void
p3_set_gs_primer_internal_oligo_num_ns(p3_global_settings * p,int val)7691 p3_set_gs_primer_internal_oligo_num_ns(p3_global_settings * p , int val) {
7692 p->o_args.num_ns_accepted = val ;
7693 }
7694
7695 void
p3_set_gs_primer_internal_oligo_min_quality(p3_global_settings * p,int val)7696 p3_set_gs_primer_internal_oligo_min_quality(p3_global_settings * p , int val) {
7697 p->o_args.min_quality = val ;
7698 }
7699
7700 void
p3_set_gs_primer_internal_oligo_self_any(p3_global_settings * p,double val)7701 p3_set_gs_primer_internal_oligo_self_any(p3_global_settings * p , double val) {
7702 p->o_args.max_self_any = val;
7703 }
7704
7705 void
p3_set_gs_primer_internal_oligo_self_any_th(p3_global_settings * p,double val)7706 p3_set_gs_primer_internal_oligo_self_any_th(p3_global_settings * p , double val) {
7707 p->o_args.max_self_any_th = val;
7708 }
7709
7710 void
p3_set_gs_primer_internal_oligo_self_end(p3_global_settings * p,double val)7711 p3_set_gs_primer_internal_oligo_self_end(p3_global_settings * p , double val) {
7712 p->o_args.max_self_end = val; /* (short) (val * 100); */
7713 }
7714
7715 void
p3_set_gs_primer_internal_oligo_self_end_th(p3_global_settings * p,double val)7716 p3_set_gs_primer_internal_oligo_self_end_th(p3_global_settings * p , double val) {
7717 p->o_args.max_self_end_th = val;
7718 }
7719
7720 void
p3_set_gs_primer_internal_oligo_hairpin_th(p3_global_settings * p,double val)7721 p3_set_gs_primer_internal_oligo_hairpin_th(p3_global_settings * p , double val) {
7722 p->o_args.max_hairpin_th = val;
7723 }
7724
7725
7726 void
p3_set_gs_primer_max_mispriming(p3_global_settings * p,double val)7727 p3_set_gs_primer_max_mispriming(p3_global_settings * p , double val) {
7728 p->p_args.max_repeat_compl = val;
7729 }
7730
7731 void
p3_set_gs_primer_internal_oligo_max_mishyb(p3_global_settings * p,double val)7732 p3_set_gs_primer_internal_oligo_max_mishyb(p3_global_settings * p , double val) {
7733 p->o_args.max_repeat_compl = val;
7734 }
7735
7736 void
p3_set_gs_primer_pair_max_mispriming(p3_global_settings * p,double val)7737 p3_set_gs_primer_pair_max_mispriming(p3_global_settings * p , double val) {
7738 p->pair_repeat_compl = val;
7739 }
7740
7741 void
p3_set_gs_primer_max_template_mispriming(p3_global_settings * p,double val)7742 p3_set_gs_primer_max_template_mispriming(p3_global_settings * p , double val) {
7743 p->p_args.max_template_mispriming = val;
7744 }
7745
7746 void
p3_set_gs_primer_max_template_mispriming_th(p3_global_settings * p,double val)7747 p3_set_gs_primer_max_template_mispriming_th(p3_global_settings * p , double val) {
7748 p->p_args.max_template_mispriming_th = val;
7749 }
7750
7751 void
p3_set_gs_primer_lib_ambiguity_codes_consensus(p3_global_settings * p,int val)7752 p3_set_gs_primer_lib_ambiguity_codes_consensus(p3_global_settings * p , int val) {
7753 p->lib_ambiguity_codes_consensus = val ;
7754 }
7755
7756 void
p3_set_gs_primer_inside_penalty(p3_global_settings * p,double val)7757 p3_set_gs_primer_inside_penalty(p3_global_settings * p , double val) {
7758 p->inside_penalty = val ;
7759 }
7760
7761 void
p3_set_gs_primer_outside_penalty(p3_global_settings * p,double val)7762 p3_set_gs_primer_outside_penalty(p3_global_settings * p , double val) {
7763 p->outside_penalty = val ;
7764 }
7765
7766 void
p3_set_gs_primer_mispriming_library(p3_global_settings * p,char * path)7767 p3_set_gs_primer_mispriming_library(p3_global_settings * p , char * path) {
7768 /* TO DO: Re-factor this? TO DO: Check for errors */
7769 p->p_args.repeat_lib = read_and_create_seq_lib(path, "mispriming library") ;
7770 }
7771
7772 void
p3_set_gs_primer_internal_oligo_mishyb_library(p3_global_settings * p,char * path)7773 p3_set_gs_primer_internal_oligo_mishyb_library(p3_global_settings * p , char * path) {
7774 /* TO DO: Re-factor this? TO DO: Check for errors */
7775 p->o_args.repeat_lib = read_and_create_seq_lib(path, "internal oligio mishyb library") ;
7776 }
7777
7778 void
p3_set_gs_primer_max_end_stability(p3_global_settings * p,double val)7779 p3_set_gs_primer_max_end_stability(p3_global_settings * p , double val) {
7780 p->max_end_stability = val ;
7781 }
7782
7783 void
p3_set_gs_primer_lowercase_masking(p3_global_settings * p,int val)7784 p3_set_gs_primer_lowercase_masking(p3_global_settings * p , int val) {
7785 p->lowercase_masking = val ;
7786 }
7787
7788 void
p3_set_gs_primer_thermodynamic_oligo_alignment(p3_global_settings * p,int val)7789 p3_set_gs_primer_thermodynamic_oligo_alignment(p3_global_settings * p , int val) {
7790 p->thermodynamic_oligo_alignment = val ;
7791 }
7792
7793 void
p3_set_gs_primer_thermodynamic_template_alignment(p3_global_settings * p,int val)7794 p3_set_gs_primer_thermodynamic_template_alignment(p3_global_settings * p , int val) {
7795 p->thermodynamic_template_alignment = val ;
7796 }
7797
7798 void
p3_set_gs_primer_wt_tm_gt(p3_global_settings * p,double val)7799 p3_set_gs_primer_wt_tm_gt(p3_global_settings * p , double val) {
7800 p->p_args.weights.temp_gt = val ;
7801 }
7802
7803 void
p3_set_gs_primer_wt_tm_lt(p3_global_settings * p,double val)7804 p3_set_gs_primer_wt_tm_lt(p3_global_settings * p , double val) {
7805 p->p_args.weights.temp_lt = val ;
7806 }
7807
7808 void
p3_set_gs_primer_wt_gc_percent_gt(p3_global_settings * p,double val)7809 p3_set_gs_primer_wt_gc_percent_gt(p3_global_settings * p , double val) {
7810 p->p_args.weights.gc_content_gt = val ;
7811 }
7812
7813 void
p3_set_gs_primer_wt_gc_percent_lt(p3_global_settings * p,double val)7814 p3_set_gs_primer_wt_gc_percent_lt(p3_global_settings * p , double val) {
7815 p->p_args.weights.gc_content_lt = val ;
7816 }
7817
7818 void
p3_set_gs_primer_wt_size_lt(p3_global_settings * p,double val)7819 p3_set_gs_primer_wt_size_lt(p3_global_settings * p , double val) {
7820 p->p_args.weights.length_lt = val ;
7821 }
7822
7823 void
p3_set_gs_primer_wt_size_gt(p3_global_settings * p,double val)7824 p3_set_gs_primer_wt_size_gt(p3_global_settings * p , double val) {
7825 p->p_args.weights.length_gt = val ;
7826 }
7827
7828 void
p3_set_gs_primer_wt_compl_any(p3_global_settings * p,double val)7829 p3_set_gs_primer_wt_compl_any(p3_global_settings * p , double val) {
7830 p->p_args.weights.compl_any = val ;
7831 }
7832
7833 void
p3_set_gs_primer_wt_compl_any_th(p3_global_settings * p,double val)7834 p3_set_gs_primer_wt_compl_any_th(p3_global_settings * p , double val) {
7835 p->p_args.weights.compl_any_th = val ;
7836 }
7837
7838 void
p3_set_gs_primer_wt_compl_end(p3_global_settings * p,double val)7839 p3_set_gs_primer_wt_compl_end(p3_global_settings * p , double val) {
7840 p->p_args.weights.compl_end = val ;
7841 }
7842
7843 void
p3_set_gs_primer_wt_compl_end_th(p3_global_settings * p,double val)7844 p3_set_gs_primer_wt_compl_end_th(p3_global_settings * p , double val) {
7845 p->p_args.weights.compl_end_th = val ;
7846 }
7847
7848 void
p3_set_gs_primer_wt_hairpin_th(p3_global_settings * p,double val)7849 p3_set_gs_primer_wt_hairpin_th(p3_global_settings * p , double val) {
7850 p->p_args.weights.hairpin_th = val ;
7851 }
7852
7853 void
p3_set_gs_primer_wt_num_ns(p3_global_settings * p,double val)7854 p3_set_gs_primer_wt_num_ns(p3_global_settings * p , double val) {
7855 p->p_args.weights.num_ns = val ;
7856 }
7857
7858 void
p3_set_gs_primer_wt_rep_sim(p3_global_settings * p,double val)7859 p3_set_gs_primer_wt_rep_sim(p3_global_settings * p , double val) {
7860 p->p_args.weights.repeat_sim = val ;
7861 }
7862
7863 void
p3_set_gs_primer_wt_seq_qual(p3_global_settings * p,double val)7864 p3_set_gs_primer_wt_seq_qual(p3_global_settings * p , double val) {
7865 p->p_args.weights.seq_quality = val ;
7866 }
7867
7868 void
p3_set_gs_primer_wt_end_qual(p3_global_settings * p,double val)7869 p3_set_gs_primer_wt_end_qual(p3_global_settings * p , double val) {
7870 p->p_args.weights.end_quality = val ;
7871 }
7872
7873 void
p3_set_gs_primer_wt_pos_penalty(p3_global_settings * p,double val)7874 p3_set_gs_primer_wt_pos_penalty(p3_global_settings * p , double val){
7875 p->p_args.weights.pos_penalty = val ;
7876 }
7877
7878 void
p3_set_gs_primer_wt_end_stability(p3_global_settings * p,double val)7879 p3_set_gs_primer_wt_end_stability(p3_global_settings * p , double val) {
7880 p->p_args.weights.end_stability = val ;
7881 }
7882
7883 void
p3_set_gs_primer_wt_template_mispriming(p3_global_settings * p,double val)7884 p3_set_gs_primer_wt_template_mispriming(p3_global_settings * p , double val) {
7885 p->p_args.weights.template_mispriming = val ;
7886 }
7887
7888 void
p3_set_gs_primer_wt_template_mispriming_th(p3_global_settings * p,double val)7889 p3_set_gs_primer_wt_template_mispriming_th(p3_global_settings * p , double val) {
7890 p->p_args.weights.template_mispriming_th = val ;
7891 }
7892
7893 void
p3_set_gs_primer_io_wt_tm_gt(p3_global_settings * p,double val)7894 p3_set_gs_primer_io_wt_tm_gt(p3_global_settings * p , double val) {
7895 p->o_args.weights.temp_gt = val ;
7896 }
7897
7898 void
p3_set_gs_primer_io_wt_tm_lt(p3_global_settings * p,double val)7899 p3_set_gs_primer_io_wt_tm_lt(p3_global_settings * p , double val){
7900 p->o_args.weights.temp_lt = val ;
7901 }
7902
7903 void
p3_set_gs_primer_io_wt_gc_percent_gt(p3_global_settings * p,double val)7904 p3_set_gs_primer_io_wt_gc_percent_gt(p3_global_settings * p , double val) {
7905 p->o_args.weights.gc_content_gt = val ;
7906 }
7907
7908 void
p3_set_gs_primer_io_wt_gc_percent_lt(p3_global_settings * p,double val)7909 p3_set_gs_primer_io_wt_gc_percent_lt(p3_global_settings * p , double val) {
7910 p->o_args.weights.gc_content_lt = val ;
7911
7912 }
7913
7914 void
p3_set_gs_primer_io_wt_size_lt(p3_global_settings * p,double val)7915 p3_set_gs_primer_io_wt_size_lt(p3_global_settings * p , double val) {
7916 p->o_args.weights.length_lt = val ;
7917 }
7918
7919 void
p3_set_gs_primer_io_wt_size_gt(p3_global_settings * p,double val)7920 p3_set_gs_primer_io_wt_size_gt(p3_global_settings * p , double val) {
7921 p->o_args.weights.length_gt = val ;
7922 }
7923
7924 void
p3_set_gs_primer_io_wt_wt_compl_any(p3_global_settings * p,double val)7925 p3_set_gs_primer_io_wt_wt_compl_any(p3_global_settings * p , double val) {
7926 p->o_args.weights.compl_any = val ;
7927 }
7928
7929 void
p3_set_gs_primer_io_wt_wt_compl_any_th(p3_global_settings * p,double val)7930 p3_set_gs_primer_io_wt_wt_compl_any_th(p3_global_settings * p , double val) {
7931 p->o_args.weights.compl_any_th = val ;
7932 }
7933
7934 void
p3_set_gs_primer_io_wt_compl_end(p3_global_settings * p,double val)7935 p3_set_gs_primer_io_wt_compl_end(p3_global_settings * p , double val) {
7936 p->o_args.weights.compl_end = val ;
7937 }
7938
7939 void
p3_set_gs_primer_io_wt_compl_end_th(p3_global_settings * p,double val)7940 p3_set_gs_primer_io_wt_compl_end_th(p3_global_settings * p , double val) {
7941 p->o_args.weights.compl_end_th = val ;
7942 }
7943
7944 void
p3_set_gs_primer_io_wt_hairpin_th(p3_global_settings * p,double val)7945 p3_set_gs_primer_io_wt_hairpin_th(p3_global_settings * p , double val) {
7946 p->o_args.weights.hairpin_th = val ;
7947 }
7948
7949 void
p3_set_gs_primer_io_wt_num_ns(p3_global_settings * p,double val)7950 p3_set_gs_primer_io_wt_num_ns(p3_global_settings * p , double val) {
7951 p->o_args.weights.num_ns = val ;
7952 }
7953
7954 void
p3_set_gs_primer_io_wt_rep_sim(p3_global_settings * p,double val)7955 p3_set_gs_primer_io_wt_rep_sim(p3_global_settings * p , double val) {
7956 p->o_args.weights.repeat_sim = val ;
7957 }
7958
7959 void
p3_set_gs_primer_io_wt_seq_qual(p3_global_settings * p,double val)7960 p3_set_gs_primer_io_wt_seq_qual(p3_global_settings * p , double val) {
7961 p->o_args.weights.seq_quality = val ;
7962 }
7963
7964 void
p3_set_gs_primer_io_wt_end_qual(p3_global_settings * p,double val)7965 p3_set_gs_primer_io_wt_end_qual(p3_global_settings * p , double val) {
7966 p->o_args.weights.end_quality = val ;
7967 }
7968
7969 void
p3_set_gs_primer_pair_wt_pr_penalty(p3_global_settings * p,double val)7970 p3_set_gs_primer_pair_wt_pr_penalty(p3_global_settings * p , double val) {
7971 p->pr_pair_weights.primer_quality = val ;
7972 }
7973
7974 void
p3_set_gs_primer_pair_wt_io_penalty(p3_global_settings * p,double val)7975 p3_set_gs_primer_pair_wt_io_penalty(p3_global_settings * p , double val) {
7976 p->pr_pair_weights.io_quality = val ;
7977 }
7978
7979 void
p3_set_gs_primer_pair_wt_diff_tm(p3_global_settings * p,double val)7980 p3_set_gs_primer_pair_wt_diff_tm(p3_global_settings * p , double val) {
7981 p->pr_pair_weights.diff_tm = val ;
7982 }
7983
7984 void
p3_set_gs_primer_pair_wt_compl_any(p3_global_settings * p,double val)7985 p3_set_gs_primer_pair_wt_compl_any(p3_global_settings * p , double val) {
7986 p->pr_pair_weights.compl_any = val ;
7987 }
7988
7989 void
p3_set_gs_primer_pair_wt_compl_any_th(p3_global_settings * p,double val)7990 p3_set_gs_primer_pair_wt_compl_any_th(p3_global_settings * p , double val) {
7991 p->pr_pair_weights.compl_any_th = val ;
7992 }
7993
7994 void
p3_set_gs_primer_pair_wt_compl_end(p3_global_settings * p,double val)7995 p3_set_gs_primer_pair_wt_compl_end(p3_global_settings * p , double val) {
7996 p->pr_pair_weights.compl_end = val ;
7997 }
7998
7999 void
p3_set_gs_primer_pair_wt_compl_end_th(p3_global_settings * p,double val)8000 p3_set_gs_primer_pair_wt_compl_end_th(p3_global_settings * p , double val) {
8001 p->pr_pair_weights.compl_end_th = val ;
8002 }
8003
8004 void
p3_set_gs_primer_pair_wt_product_tm_lt(p3_global_settings * p,double val)8005 p3_set_gs_primer_pair_wt_product_tm_lt(p3_global_settings * p , double val) {
8006 p->pr_pair_weights.product_tm_lt = val ;
8007 }
8008
8009 void
p3_set_gs_primer_pair_wt_product_tm_gt(p3_global_settings * p,double val)8010 p3_set_gs_primer_pair_wt_product_tm_gt(p3_global_settings * p , double val) {
8011 p->pr_pair_weights.product_tm_gt = val ;
8012 }
8013
8014 void
p3_set_gs_primer_pair_wt_product_size_gt(p3_global_settings * p,double val)8015 p3_set_gs_primer_pair_wt_product_size_gt(p3_global_settings * p , double val) {
8016 p->pr_pair_weights.product_size_gt = val ;
8017 }
8018
8019 void
p3_set_gs_primer_pair_wt_product_size_lt(p3_global_settings * p,double val)8020 p3_set_gs_primer_pair_wt_product_size_lt(p3_global_settings * p , double val) {
8021 p->pr_pair_weights.product_size_lt = val ;
8022 }
8023
8024 void
p3_set_gs_primer_pair_wt_rep_sim(p3_global_settings * p,double val)8025 p3_set_gs_primer_pair_wt_rep_sim(p3_global_settings * p , double val) {
8026 p->pr_pair_weights.repeat_sim = val ;
8027 }
8028
8029 void
p3_set_gs_primer_pair_wt_template_mispriming(p3_global_settings * p,double val)8030 p3_set_gs_primer_pair_wt_template_mispriming(p3_global_settings * p , double val) {
8031 p->pr_pair_weights.template_mispriming = val ;
8032 }
8033
8034 void
p3_set_gs_primer_pair_wt_template_mispriming_th(p3_global_settings * p,double val)8035 p3_set_gs_primer_pair_wt_template_mispriming_th(p3_global_settings * p , double val){
8036 p->pr_pair_weights.template_mispriming_th = val ;
8037 }
8038
8039 void
p3_set_gs_lib_ambiguity_codes_consensus(p3_global_settings * p,int lib_ambiguity_codes_consensus)8040 p3_set_gs_lib_ambiguity_codes_consensus(p3_global_settings * p,
8041 int lib_ambiguity_codes_consensus)
8042 {
8043 p->lib_ambiguity_codes_consensus = lib_ambiguity_codes_consensus;
8044 }
8045
8046 void
p3_set_gs_quality_range_min(p3_global_settings * p,int quality_range_min)8047 p3_set_gs_quality_range_min(p3_global_settings * p , int quality_range_min){
8048 p->quality_range_min = quality_range_min;
8049 }
8050
8051 void
p3_set_gs_quality_range_max(p3_global_settings * p,int quality_range_max)8052 p3_set_gs_quality_range_max(p3_global_settings * p , int quality_range_max){
8053 p->quality_range_max = quality_range_max ;
8054 }
8055
8056 void
p3_set_gs_max_end_gc(p3_global_settings * p,int max_end_gc)8057 p3_set_gs_max_end_gc(p3_global_settings *p, int max_end_gc) {
8058 p->max_end_gc = max_end_gc;
8059 }
8060
8061 void
p3_set_gs_max_end_stability(p3_global_settings * p,int max_end_stability)8062 p3_set_gs_max_end_stability(p3_global_settings * p , int max_end_stability){
8063 p->max_end_stability = max_end_stability;
8064 }
8065
8066 void
p3_set_gs_lowercase_masking(p3_global_settings * p,int lowercase_masking)8067 p3_set_gs_lowercase_masking(p3_global_settings * p , int lowercase_masking){
8068 p->lowercase_masking = lowercase_masking;
8069 }
8070
8071 void
p3_set_gs_outside_penalty(p3_global_settings * p,double outside_penalty)8072 p3_set_gs_outside_penalty(p3_global_settings * p , double outside_penalty){
8073 p->outside_penalty = outside_penalty;
8074 }
8075
8076 void
p3_set_gs_inside_penalty(p3_global_settings * p,double inside_penalty)8077 p3_set_gs_inside_penalty(p3_global_settings * p , double inside_penalty){
8078 p->inside_penalty = inside_penalty;
8079 }
8080
8081 void
p3_set_gs_pair_max_template_mispriming(p3_global_settings * p,double pair_max_template_mispriming)8082 p3_set_gs_pair_max_template_mispriming(p3_global_settings * p,
8083 double pair_max_template_mispriming)
8084 {
8085 p->pair_max_template_mispriming = pair_max_template_mispriming;
8086 }
8087
8088 void
p3_set_gs_pair_max_template_mispriming_th(p3_global_settings * p,double pair_max_template_mispriming_th)8089 p3_set_gs_pair_max_template_mispriming_th(p3_global_settings * p,
8090 double pair_max_template_mispriming_th)
8091 {
8092 p->pair_max_template_mispriming_th = pair_max_template_mispriming_th;
8093 }
8094
8095
8096 void
p3_set_gs_pair_repeat_compl(p3_global_settings * p,double pair_repeat_compl)8097 p3_set_gs_pair_repeat_compl(p3_global_settings * p, double pair_repeat_compl)
8098 {
8099 p->pair_repeat_compl = pair_repeat_compl;
8100 }
8101
8102 void
p3_set_gs_pair_compl_any(p3_global_settings * p,double pair_compl_any)8103 p3_set_gs_pair_compl_any(p3_global_settings * p , double pair_compl_any)
8104 {
8105 p->pair_compl_any = pair_compl_any;
8106 }
8107
8108 void
p3_set_gs_pair_compl_any_th(p3_global_settings * p,double pair_compl_any_th)8109 p3_set_gs_pair_compl_any_th(p3_global_settings * p , double pair_compl_any_th)
8110 {
8111 p->pair_compl_any_th = pair_compl_any_th;
8112 }
8113
8114 void
p3_set_gs_pair_compl_end(p3_global_settings * p,double pair_compl_end)8115 p3_set_gs_pair_compl_end(p3_global_settings * p , double pair_compl_end)
8116 {
8117 p->pair_compl_end = pair_compl_end;
8118 }
8119
8120 void
p3_set_gs_pair_compl_end_th(p3_global_settings * p,double pair_compl_end_th)8121 p3_set_gs_pair_compl_end_th(p3_global_settings * p , double pair_compl_end_th)
8122 {
8123 p->pair_compl_end = pair_compl_end_th;
8124 }
8125
8126 void
p3_set_gs_min_left_three_prime_distance(p3_global_settings * p,int min_distance)8127 p3_set_gs_min_left_three_prime_distance(p3_global_settings *p, int min_distance)
8128 {
8129 p->min_left_three_prime_distance = min_distance;
8130 }
8131
8132 void
p3_set_gs_min_right_three_prime_distance(p3_global_settings * p,int min_distance)8133 p3_set_gs_min_right_three_prime_distance(p3_global_settings *p, int min_distance)
8134 {
8135 p->min_right_three_prime_distance = min_distance;
8136 }
8137
8138 void
p3_set_gs_min_5_prime_overlap_of_junction(p3_global_settings * p,int min_5_prime)8139 p3_set_gs_min_5_prime_overlap_of_junction(p3_global_settings *p, int min_5_prime)
8140 {
8141 p->min_5_prime_overlap_of_junction = min_5_prime;
8142 }
8143
8144 void
p3_set_gs_min_3_prime_overlap_of_junction(p3_global_settings * p,int min_3_prime)8145 p3_set_gs_min_3_prime_overlap_of_junction(p3_global_settings *p, int min_3_prime)
8146 {
8147 p->min_3_prime_overlap_of_junction = min_3_prime;
8148 }
8149
8150 void
p3_set_gs_max_diff_tm(p3_global_settings * p,double max_diff_tm)8151 p3_set_gs_max_diff_tm(p3_global_settings * p , double max_diff_tm) {
8152 p->max_diff_tm = max_diff_tm;
8153 }
8154
8155 void
p3_set_gs_primer_pick_anyway(p3_global_settings * p,int val)8156 p3_set_gs_primer_pick_anyway(p3_global_settings * p , int val) {
8157 p->pick_anyway = val ;
8158 }
8159
8160 void
p3_set_gs_primer_gc_clamp(p3_global_settings * p,int val)8161 p3_set_gs_primer_gc_clamp(p3_global_settings * p , int val) {
8162 p->gc_clamp = val;
8163 }
8164
8165 void
p3_empty_gs_product_size_range(p3_global_settings * pgs)8166 p3_empty_gs_product_size_range(p3_global_settings *pgs) {
8167 pgs->num_intervals = 0;
8168 }
8169
8170 int
p3_add_to_gs_product_size_range(p3_global_settings * pgs,int n1,int n2)8171 p3_add_to_gs_product_size_range(p3_global_settings *pgs,
8172 int n1, int n2) {
8173 if (pgs->num_intervals >= PR_MAX_INTERVAL_ARRAY)
8174 return 1;
8175 pgs->pr_min[pgs->num_intervals] = n1;
8176 pgs->pr_max[pgs->num_intervals] = n2;
8177 pgs->num_intervals++;
8178 return 0;
8179 }
8180
8181 /* ============================================================ */
8182 /* END 'set' functions for p3_global_settings */
8183 /* ============================================================ */
8184
8185
8186 /* ============================================================ */
8187 /* START functions for setting and getting oligo problems */
8188 /* ============================================================ */
8189
8190 static void
initialize_op(primer_rec * oligo)8191 initialize_op(primer_rec *oligo) {
8192 oligo->problems.prob = 0UL; /* 0UL is the unsigned long zero */
8193 }
8194
8195 /* We use bitfields to store all primer data. The idea is that
8196 * a primer is uninitialized if all bits are 0. It was evaluated
8197 * if OP_PARTIALLY_WRITTEN is true. If OP_COMPLETELY_WRITTEN is
8198 * also true the primer was evaluated till the end - meaning if
8199 * all OP_... are false, the primer is OK, if some are true
8200 * primer3 was forced to use it (must_use). */
8201
8202
8203 #define OP_PARTIALLY_WRITTEN (1UL << 0)
8204 #define OP_COMPLETELY_WRITTEN (1UL << 1)
8205 #define BF_OVERLAPS_TARGET (1UL << 2)
8206 #define BF_OVERLAPS_EXCL_REGION (1UL << 3)
8207 #define BF_INFINITE_POSITION_PENALTY (1UL << 4)
8208 /* Space for more bitfields */
8209
8210 #define OP_NOT_IN_ANY_OK_REGION (1UL << 7)
8211 #define OP_TOO_MANY_NS (1UL << 8) /* 3prime problem*/
8212 #define OP_OVERLAPS_TARGET (1UL << 9) /* 3prime problem*/
8213 #define OP_HIGH_GC_CONTENT (1UL << 10)
8214 #define OP_LOW_GC_CONTENT (1UL << 11)
8215 #define OP_HIGH_TM (1UL << 12)
8216 #define OP_LOW_TM (1UL << 13)
8217 #define OP_OVERLAPS_EXCL_REGION (1UL << 14) /* 3prime problem*/
8218 #define OP_HIGH_SELF_ANY (1UL << 15) /* 3prime problem*/
8219 #define OP_HIGH_SELF_END (1UL << 16)
8220 #define OP_NO_GC_CLAMP (1UL << 17) /* 3prime problem*/
8221 #define OP_HIGH_END_STABILITY (1UL << 18) /* 3prime problem*/
8222 #define OP_HIGH_POLY_X (1UL << 19) /* 3prime problem*/
8223 #define OP_LOW_SEQUENCE_QUALITY (1UL << 20) /* 3prime problem*/
8224 #define OP_LOW_END_SEQUENCE_QUALITY (1UL << 21) /* 3prime problem*/
8225 #define OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ (1UL << 22) /* 3prime problem*/
8226 #define OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES (1UL << 23)
8227 #define OP_OVERLAPS_MASKED_SEQ (1UL << 24)
8228 #define OP_TOO_LONG (1UL << 25) /* 3prime problem*/
8229 #define OP_TOO_SHORT (1UL << 26)
8230 #define OP_DOES_NOT_AMPLIFY_ORF (1UL << 27)
8231 #define OP_TOO_MANY_GC_AT_END (1UL << 28) /* 3prime problem*/
8232 #define OP_HIGH_HAIRPIN (1UL << 29) /* 3prime problem*/
8233 #define OP_MUST_MATCH_ERR (1UL << 30)
8234
8235 /* Space for more Errors */
8236
8237 /* Tip: the calculator of windows (in scientific mode) can easily convert
8238 between decimal and binary numbers */
8239
8240 /* all bits 1 except bits 0 to 6 */
8241 /* (~0UL) ^ 127UL = 1111 1111 1111 1111 1111 1111 1000 0000 */
8242 static unsigned long int any_problem = (~0UL) ^ 127UL;
8243 /* 310297344UL = 0001 0010 0111 1110 1100 0011 0000 0000 */
8244 static unsigned long int five_prime_problem = 310297344UL;
8245
8246 int
p3_ol_is_uninitialized(const primer_rec * oligo)8247 p3_ol_is_uninitialized(const primer_rec *oligo) {
8248 return (oligo->problems.prob == 0UL);
8249 }
8250
8251 int
p3_ol_is_ok(const primer_rec * oligo)8252 p3_ol_is_ok(const primer_rec *oligo) {
8253 return (oligo->problems.prob & OP_COMPLETELY_WRITTEN) != 0;
8254 }
8255
8256 /*
8257 Return 1 iff the argument 'oligo' has any problems -- i.e.
8258 violations of design constraints.
8259 */
8260 int
p3_ol_has_any_problem(const primer_rec * oligo)8261 p3_ol_has_any_problem(const primer_rec *oligo) {
8262 return (oligo->problems.prob & any_problem) != 0;
8263 }
8264
8265 static int
any_5_prime_ol_extension_has_problem(const primer_rec * oligo)8266 any_5_prime_ol_extension_has_problem(const primer_rec *oligo) {
8267 return (oligo->problems.prob & five_prime_problem) != 0;
8268 }
8269
8270 /*
8271 Return a string details the the problems in 'oligo', i.e. the
8272 constraints that 'oligo' violates. WARNING: Returns a pointer to
8273 static storage, which is over-written on next call.
8274 */
8275 #define ADD_OP_STR(COND, STR) if (prob & COND) { tmp = STR; strcpy(next, tmp); next += strlen(tmp); }
8276 const char *
p3_get_ol_problem_string(const primer_rec * oligo)8277 p3_get_ol_problem_string(const primer_rec *oligo) {
8278 static char output[4096*2]; /* WARNING, make sure all error strings
8279 concatenated will not overflow this
8280 buffer. */
8281 char *next = output;
8282 const char *tmp;
8283 unsigned long int prob = oligo->problems.prob;
8284 output[0] = '\0';
8285
8286 if (
8287 (prob & OP_PARTIALLY_WRITTEN)
8288 &&
8289 !(prob & OP_COMPLETELY_WRITTEN)
8290 ) {
8291 tmp = " Not completely checked;";
8292 strcpy(next, tmp);
8293 next += strlen(tmp);
8294 }
8295
8296 {
8297 ADD_OP_STR(OP_TOO_MANY_NS,
8298 " Too many Ns;")
8299 ADD_OP_STR(OP_OVERLAPS_TARGET,
8300 " Overlaps target;")
8301 ADD_OP_STR(OP_HIGH_GC_CONTENT,
8302 " GC content too high;")
8303 ADD_OP_STR(OP_LOW_GC_CONTENT,
8304 " GC content too low;")
8305 ADD_OP_STR(OP_HIGH_TM,
8306 " Temperature too high;")
8307 ADD_OP_STR(OP_LOW_TM,
8308 " Temperature too low;")
8309 ADD_OP_STR(OP_OVERLAPS_EXCL_REGION,
8310 " Overlaps an excluded region;")
8311 ADD_OP_STR(OP_NOT_IN_ANY_OK_REGION,
8312 " Not in any ok region;")
8313 ADD_OP_STR(OP_HIGH_SELF_ANY,
8314 " Similarity to self too high;")
8315 ADD_OP_STR(OP_HIGH_SELF_END,
8316 " Similary to 3' end of self too high;")
8317 ADD_OP_STR(OP_HIGH_HAIRPIN,
8318 " Hairpin stability too high;")
8319 ADD_OP_STR(OP_NO_GC_CLAMP,
8320 " No 3' GC clamp;")
8321 ADD_OP_STR(OP_TOO_MANY_GC_AT_END,
8322 " Too many GCs at 3' end;")
8323 ADD_OP_STR(OP_HIGH_END_STABILITY,
8324 " 3' end too stable (delta-G too high);")
8325 ADD_OP_STR(OP_HIGH_POLY_X,
8326 " Contains too-long poly nucleotide tract;")
8327 ADD_OP_STR(OP_LOW_SEQUENCE_QUALITY,
8328 " Template sequence quality too low;")
8329 ADD_OP_STR(OP_LOW_END_SEQUENCE_QUALITY,
8330 " Template sequence quality at 3' end too low;")
8331 ADD_OP_STR(OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ,
8332 " Similarity to non-template sequence too high;")
8333 ADD_OP_STR(OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES,
8334 " Similarity to multiple sites in template;")
8335 ADD_OP_STR(OP_OVERLAPS_MASKED_SEQ,
8336 " 3' base overlaps masked sequence;")
8337 ADD_OP_STR(OP_TOO_LONG,
8338 " Too long;")
8339 ADD_OP_STR(OP_TOO_SHORT,
8340 " Too short;")
8341 ADD_OP_STR(OP_DOES_NOT_AMPLIFY_ORF,
8342 " Would not amplify an open reading frame;")
8343 ADD_OP_STR(OP_MUST_MATCH_ERR,
8344 " Failed must_match requirements;")
8345 }
8346 return output;
8347 }
8348 #undef ADD_OP_STR
8349
8350 static void
bf_set_overlaps_target(primer_rec * oligo,int val)8351 bf_set_overlaps_target(primer_rec *oligo, int val){
8352 if (val == 0) {
8353 oligo->problems.prob |= BF_OVERLAPS_TARGET;
8354 oligo->problems.prob ^= BF_OVERLAPS_TARGET;
8355 } else {
8356 oligo->problems.prob |= BF_OVERLAPS_TARGET;
8357 }
8358 }
8359
8360 static int
bf_get_overlaps_target(const primer_rec * oligo)8361 bf_get_overlaps_target(const primer_rec *oligo) {
8362 return (oligo->problems.prob & BF_OVERLAPS_TARGET) != 0;
8363 }
8364
8365 static void
bf_set_overlaps_excl_region(primer_rec * oligo,int val)8366 bf_set_overlaps_excl_region(primer_rec *oligo, int val){
8367 if (val == 0) {
8368 oligo->problems.prob |= BF_OVERLAPS_EXCL_REGION;
8369 oligo->problems.prob ^= BF_OVERLAPS_EXCL_REGION;
8370 } else {
8371 oligo->problems.prob |= BF_OVERLAPS_EXCL_REGION;
8372 }
8373 }
8374
8375 static int
bf_get_overlaps_excl_region(const primer_rec * oligo)8376 bf_get_overlaps_excl_region(const primer_rec *oligo) {
8377 return (oligo->problems.prob & BF_OVERLAPS_EXCL_REGION) != 0;
8378 }
8379
8380 static void
bf_set_infinite_pos_penalty(primer_rec * oligo,int val)8381 bf_set_infinite_pos_penalty(primer_rec *oligo, int val){
8382 if (val == 0) {
8383 oligo->problems.prob |= BF_INFINITE_POSITION_PENALTY;
8384 oligo->problems.prob ^= BF_INFINITE_POSITION_PENALTY;
8385 } else {
8386 oligo->problems.prob |= BF_INFINITE_POSITION_PENALTY;
8387 }
8388 }
8389
8390 static int
bf_get_infinite_pos_penalty(const primer_rec * oligo)8391 bf_get_infinite_pos_penalty(const primer_rec *oligo) {
8392 return (oligo->problems.prob & BF_INFINITE_POSITION_PENALTY) != 0;
8393 }
8394
8395 static void
op_set_does_not_amplify_orf(primer_rec * oligo)8396 op_set_does_not_amplify_orf(primer_rec *oligo) {
8397 oligo->problems.prob |= OP_DOES_NOT_AMPLIFY_ORF;
8398 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8399 }
8400
8401 static void
op_set_completely_written(primer_rec * oligo)8402 op_set_completely_written(primer_rec *oligo) {
8403 oligo->problems.prob |= OP_COMPLETELY_WRITTEN;
8404 }
8405
8406 static void
op_set_must_match_err(primer_rec * oligo)8407 op_set_must_match_err(primer_rec *oligo) {
8408 oligo->problems.prob |= OP_MUST_MATCH_ERR;
8409 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8410 }
8411
8412 static void
op_set_too_many_ns(primer_rec * oligo)8413 op_set_too_many_ns(primer_rec *oligo) {
8414 oligo->problems.prob |= OP_TOO_MANY_NS;
8415 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8416 }
8417
8418 static void
op_set_overlaps_target(primer_rec * oligo)8419 op_set_overlaps_target(primer_rec *oligo) {
8420 oligo->problems.prob |= OP_OVERLAPS_TARGET;
8421 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8422 }
8423
8424 static void
op_set_high_gc_content(primer_rec * oligo)8425 op_set_high_gc_content(primer_rec *oligo) {
8426 oligo->problems.prob |= OP_HIGH_GC_CONTENT;
8427 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8428 }
8429
8430 static void
op_set_low_gc_content(primer_rec * oligo)8431 op_set_low_gc_content(primer_rec *oligo) {
8432 oligo->problems.prob |= OP_LOW_GC_CONTENT;
8433 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8434 }
8435
8436 static void
op_set_high_tm(primer_rec * oligo)8437 op_set_high_tm(primer_rec *oligo) {
8438 oligo->problems.prob |= OP_HIGH_TM;
8439 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8440 }
8441
8442 static void
op_set_low_tm(primer_rec * oligo)8443 op_set_low_tm(primer_rec *oligo) {
8444 oligo->problems.prob |= OP_LOW_TM;
8445 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8446 }
8447
8448 static void
op_set_overlaps_excluded_region(primer_rec * oligo)8449 op_set_overlaps_excluded_region(primer_rec *oligo) {
8450 oligo->problems.prob |= OP_OVERLAPS_EXCL_REGION;
8451 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8452 }
8453
8454 static void
op_set_not_in_any_ok_region(primer_rec * oligo)8455 op_set_not_in_any_ok_region(primer_rec *oligo) {
8456 oligo->problems.prob |= OP_NOT_IN_ANY_OK_REGION;
8457 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8458 }
8459
8460 static void
op_set_high_self_any(primer_rec * oligo)8461 op_set_high_self_any(primer_rec *oligo) {
8462 oligo->problems.prob |= OP_HIGH_SELF_ANY;
8463 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8464 }
8465
8466 static void
op_set_high_self_end(primer_rec * oligo)8467 op_set_high_self_end(primer_rec *oligo) {
8468 oligo->problems.prob |= OP_HIGH_SELF_END;
8469 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8470 }
8471
8472 static void
op_set_high_hairpin_th(primer_rec * oligo)8473 op_set_high_hairpin_th(primer_rec *oligo) {
8474 oligo->problems.prob |= OP_HIGH_HAIRPIN;
8475 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8476 }
8477
8478 static void
op_set_no_gc_glamp(primer_rec * oligo)8479 op_set_no_gc_glamp(primer_rec *oligo) {
8480 oligo->problems.prob |= OP_NO_GC_CLAMP;
8481 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8482 }
8483
8484 static void
op_set_too_many_gc_at_end(primer_rec * oligo)8485 op_set_too_many_gc_at_end(primer_rec *oligo) {
8486 oligo->problems.prob |= OP_TOO_MANY_GC_AT_END;
8487 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8488 }
8489
8490 /* Must not be called on a hybridization probe / internal oligo */
8491 static void
op_set_high_end_stability(primer_rec * oligo)8492 op_set_high_end_stability(primer_rec *oligo) {
8493 oligo->problems.prob |= OP_HIGH_END_STABILITY;
8494 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8495 }
8496
8497 static void
op_set_high_poly_x(primer_rec * oligo)8498 op_set_high_poly_x(primer_rec *oligo) {
8499 oligo->problems.prob |= OP_HIGH_POLY_X;
8500 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8501 }
8502
8503 static void
op_set_low_sequence_quality(primer_rec * oligo)8504 op_set_low_sequence_quality(primer_rec *oligo) {
8505 oligo->problems.prob |= OP_LOW_SEQUENCE_QUALITY;
8506 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8507 }
8508
8509 static void
op_set_low_end_sequence_quality(primer_rec * oligo)8510 op_set_low_end_sequence_quality(primer_rec *oligo) {
8511 oligo->problems.prob |= OP_LOW_END_SEQUENCE_QUALITY;
8512 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8513 }
8514
8515 static void
op_set_high_similarity_to_non_template_seq(primer_rec * oligo)8516 op_set_high_similarity_to_non_template_seq(primer_rec *oligo) {
8517 oligo->problems.prob |= OP_HIGH_SIM_TO_NON_TEMPLATE_SEQ;
8518 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8519 }
8520
8521 static void
op_set_high_similarity_to_multiple_template_sites(primer_rec * oligo)8522 op_set_high_similarity_to_multiple_template_sites(primer_rec *oligo) {
8523 oligo->problems.prob |= OP_HIGH_SIM_TO_MULTI_TEMPLATE_SITES;
8524 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8525 }
8526
8527 static void
op_set_overlaps_masked_sequence(primer_rec * oligo)8528 op_set_overlaps_masked_sequence(primer_rec *oligo) {
8529 oligo->problems.prob |= OP_OVERLAPS_MASKED_SEQ;
8530 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8531 }
8532
8533 static void
op_set_too_long(primer_rec * oligo)8534 op_set_too_long(primer_rec *oligo) {
8535 oligo->problems.prob |= OP_TOO_LONG;
8536 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8537 }
8538
8539 static void
op_set_too_short(primer_rec * oligo)8540 op_set_too_short(primer_rec *oligo) {
8541 oligo->problems.prob |= OP_TOO_SHORT;
8542 oligo->problems.prob |= OP_PARTIALLY_WRITTEN;
8543 }
8544
8545 /* ============================================================ */
8546 /* END functions for setting and getting oligo problems */
8547 /* ============================================================ */
8548
8549
8550 /* ============================================================ */
8551 /* START functions for getting values from p3retvals */
8552 /* ============================================================ */
8553
8554 char *
p3_get_rv_and_gs_warnings(const p3retval * retval,const p3_global_settings * pa)8555 p3_get_rv_and_gs_warnings(const p3retval *retval,
8556 const p3_global_settings *pa) {
8557
8558 pr_append_str warning;
8559
8560 PR_ASSERT(NULL != pa);
8561
8562 init_pr_append_str(&warning);
8563
8564 if (seq_lib_warning_data(pa->p_args.repeat_lib))
8565 pr_append_new_chunk(&warning, seq_lib_warning_data(pa->p_args.repeat_lib));
8566
8567 if(seq_lib_warning_data(pa->o_args.repeat_lib)) {
8568 pr_append_new_chunk(&warning, seq_lib_warning_data(pa->o_args.repeat_lib));
8569 pr_append(&warning, " (for internal oligo)");
8570 }
8571
8572 if (!pr_is_empty(&retval->warnings))
8573 pr_append_new_chunk(&warning, retval->warnings.data);
8574
8575 return pr_is_empty(&warning) ? NULL : warning.data;
8576 }
8577
8578 const char *
p3_get_rv_global_errors(const p3retval * retval)8579 p3_get_rv_global_errors(const p3retval *retval) {
8580 return retval->glob_err.data;
8581 }
8582
8583 const char *
p3_get_rv_per_sequence_errors(const p3retval * retval)8584 p3_get_rv_per_sequence_errors(const p3retval *retval) {
8585 return retval->per_sequence_err.data;
8586 }
8587
8588 p3_output_type
p3_get_rv_output_type(const p3retval * r)8589 p3_get_rv_output_type(const p3retval *r) {
8590 return r->output_type;
8591 }
8592
8593 const char *
p3_get_rv_warnings(const p3retval * r)8594 p3_get_rv_warnings(const p3retval *r) {
8595 return pr_append_str_chars(&r->warnings);
8596 }
8597
8598 int
p3_get_rv_stop_codon_pos(p3retval * r)8599 p3_get_rv_stop_codon_pos(p3retval *r) {
8600 return r->stop_codon_pos;
8601 }
8602
8603 /* ============================================================ */
8604 /* END functions for getting values from p3retvals */
8605 /* ============================================================ */
8606
8607 void
p3_print_args(const p3_global_settings * p,seq_args * s)8608 p3_print_args(const p3_global_settings *p, seq_args *s)
8609 {
8610 int i;
8611
8612 if (p != NULL) {
8613 printf("=============\n");
8614 printf("BEGIN GLOBAL ARGS\n") ;
8615 printf(" primer_task %i\n", p->primer_task);
8616 printf(" pick_left_primer %i\n", p->pick_left_primer);
8617 printf(" pick_right_primer %i\n", p->pick_right_primer);
8618 printf(" pick_internal_oligo %i\n", p->pick_internal_oligo);
8619 printf(" file_flag %i\n", p->file_flag) ;
8620 printf(" first_base_index %i\n", p->first_base_index);
8621 printf(" liberal_base %i\n", p->liberal_base );
8622 printf(" num_return %i\n", p->num_return) ;
8623 printf(" pick_anyway %i\n", p->pick_anyway);
8624 printf(" lib_ambiguity_codes_consensus %i\n",
8625 p->lib_ambiguity_codes_consensus) ;
8626 printf(" quality_range_min %i\n", p->quality_range_min) ;
8627 printf(" quality_range_max %i\n", p->quality_range_max) ;
8628
8629 printf(" tm_santalucia %i\n", p->tm_santalucia) ;
8630 printf(" salt_corrections %i\n", p->salt_corrections) ;
8631 printf(" max_end_stability %f\n", p->max_end_stability) ;
8632 printf(" gc_clamp %i\n", p->gc_clamp) ;
8633 printf(" max_end_gc %i\n", p->max_end_gc);
8634 printf(" lowercase_masking %i\n", p->lowercase_masking) ;
8635 printf(" thermodynamic_oligo_alignment %i\n", p->thermodynamic_oligo_alignment);
8636 printf(" thermodynamic_template_alignment %i\n", p->thermodynamic_template_alignment);
8637 printf(" outside_penalty %f\n", p->outside_penalty) ;
8638 printf(" inside_penalty %f\n", p->inside_penalty) ;
8639 printf(" number of product size ranges: %d\n", p->num_intervals);
8640 printf(" product size ranges:\n");
8641 for (i = 0; i < p->num_intervals; i++) {
8642 printf(" %d - %d \n", p->pr_min[i], p->pr_max[i]);
8643 }
8644 printf(" product_opt_size %i\n", p->product_opt_size) ;
8645 printf(" product_max_tm %f\n", p->product_max_tm) ;
8646 printf(" product_min_tm %f\n", p->product_min_tm) ;
8647 printf(" product_opt_tm %f\n", p->product_opt_tm) ;
8648 printf(" pair_max_template_mispriming %f\n", p->pair_max_template_mispriming) ;
8649 printf(" pair_max_template_mispriming_th %f\n", p->pair_max_template_mispriming_th) ;
8650 printf(" pair_repeat_compl %f\n", p->pair_repeat_compl) ;
8651 printf(" pair_compl_any %f\n", p->pair_compl_any) ;
8652 printf(" pair_compl_end %f\n", p->pair_compl_end) ;
8653 printf(" pair_compl_any_th %f\n", p->pair_compl_any_th) ;
8654 printf(" pair_compl_end_th %f\n", p->pair_compl_end_th) ;
8655
8656 printf(" min_left_three_prime_distance %i\n", p->min_left_three_prime_distance) ;
8657 printf(" min_right_three_prime_distance %i\n", p->min_right_three_prime_distance) ;
8658 printf(" min_5_prime_overlap_of_junction %i\n", p->min_5_prime_overlap_of_junction);
8659 printf(" min_3_prime_overlap_of_junction %i\n", p->min_3_prime_overlap_of_junction);
8660 printf(" dump %i\n", p->dump);
8661
8662 printf(" begin pr_pair_weights\n") ;
8663 printf(" primer_quality %f\n", p->pr_pair_weights.primer_quality) ;
8664 printf(" io_quality %f\n", p->pr_pair_weights.io_quality) ;
8665 printf(" diff_tm %f\n", p->pr_pair_weights.diff_tm) ;
8666 printf(" compl_any %f\n", p->pr_pair_weights.compl_any) ;
8667 printf(" compl_end %f\n", p->pr_pair_weights.compl_end) ;
8668 printf(" compl_any_th %f\n", p->pr_pair_weights.compl_any_th) ;
8669 printf(" compl_end_th %f\n", p->pr_pair_weights.compl_end_th) ;
8670 printf(" product_tm_lt %f\n", p->pr_pair_weights.product_tm_lt) ;
8671 printf(" product_tm_gt %f\n", p->pr_pair_weights.product_tm_gt) ;
8672 printf(" product_size_lt %f\n", p->pr_pair_weights.product_size_lt) ;
8673 printf(" product_size_gt %f\n", p->pr_pair_weights.product_size_gt) ;
8674 printf(" repeat_sim %f\n", p->pr_pair_weights.repeat_sim) ;
8675 printf(" template_mispriming %f\n", p->pr_pair_weights.template_mispriming) ;
8676 printf(" template_mispriming_th %f\n", p->pr_pair_weights.template_mispriming_th) ;
8677 printf(" end pair_weights\n") ;
8678
8679
8680 printf("\n\n");
8681 printf("=============\n");
8682 printf("BEGIN primer_args\n");
8683 printf("begin oligo_weights\n");
8684 printf("temp_gt %f\n", p->p_args.weights.temp_gt ) ;
8685 printf("temp_gt %f\n", p->p_args.weights.temp_gt) ;
8686 printf("temp_lt %f\n", p->p_args.weights.temp_lt) ;
8687 printf("gc_content_gt %f\n", p->p_args.weights.gc_content_gt) ;
8688 printf("gc_content_lt %f\n", p->p_args.weights.gc_content_lt) ;
8689 printf("compl_any %f\n", p->p_args.weights.compl_any) ;
8690 printf("compl_end %f\n", p->p_args.weights.compl_end) ;
8691 printf("compl_any_th %f\n", p->p_args.weights.compl_any_th) ;
8692 printf("compl_end_th %f\n", p->p_args.weights.compl_end_th) ;
8693 printf("hairpin %f\n", p->p_args.weights.hairpin_th) ;
8694 printf("repeat_sim %f\n", p->p_args.weights.repeat_sim) ;
8695 printf("length_lt %f\n", p->p_args.weights.length_lt) ;
8696 printf("length_gt %f\n", p->p_args.weights.length_gt) ;
8697 printf("seq_quality %f\n", p->p_args.weights.seq_quality) ;
8698 printf("end_quality %f\n", p->p_args.weights.end_quality) ;
8699 printf("pos_penalty %f\n", p->p_args.weights.pos_penalty) ;
8700 printf("end_stability %f\n", p->p_args.weights.end_stability) ;
8701 printf("num_ns %f\n", p->p_args.weights.num_ns) ;
8702 printf("template_mispriming %f\n", p->p_args.weights.template_mispriming) ;
8703 printf("template_mispriming_th %f\n", p->p_args.weights.template_mispriming_th) ;
8704 printf("end oligo_weights\n") ;
8705
8706 printf("opt_tm %f\n", p->p_args.opt_tm) ;
8707 printf("min_tm %f\n", p->p_args.min_tm) ;
8708 printf("max_tm %f\n", p->p_args.max_tm) ;
8709 printf("opt_gc_content %f\n", p->p_args.opt_gc_content) ;
8710 printf("max_gc %f\n", p->p_args.max_gc) ;
8711 printf("min_gc %f\n", p->p_args.min_gc) ;
8712 printf("divalent_conc %f\n", p->p_args.divalent_conc) ;
8713 printf("dntp_conc %f\n", p->p_args.dntp_conc) ;
8714 printf("dna_conc %f\n", p->p_args.dna_conc) ;
8715 printf("num_ns_accepted %i\n", p->p_args.num_ns_accepted) ;
8716 printf("opt_size %i\n", p->p_args.opt_size) ;
8717 printf("min_size %i\n", p->p_args.min_size) ;
8718 printf("max_size %i\n", p->p_args.max_size) ;
8719 printf("max_poly_x %i\n", p->p_args.max_poly_x) ;
8720 printf("min_end_quality %i\n", p->p_args.min_end_quality) ;
8721 printf("min_quality %i\n", p->p_args.min_quality) ;
8722 printf("max_self_any %f\n", p->p_args.max_self_any) ;
8723 printf("max_self_end %f\n", p->p_args.max_self_end) ;
8724 printf("max_self_any_th %f\n", p->p_args.max_self_any_th) ;
8725 printf("max_self_end_th %f\n", p->p_args.max_self_end_th) ;
8726 printf("max_hairpin %f\n", p->p_args.max_hairpin_th) ;
8727 printf("max_repeat_compl %f\n", p->p_args.max_repeat_compl) ;
8728 printf("max_template_mispriming %f\n", p->p_args.max_template_mispriming) ;
8729 printf("max_template_mispriming_th %f\n", p->p_args.max_template_mispriming_th) ;
8730 printf("end primer args\n") ;
8731
8732 printf("begin internal oligo args (p->o_args.)\n") ;
8733
8734 printf(" begin internal oligo_weights (p->o_args.weights.)\n") ;
8735 printf(" temp_gt %f\n", p->o_args.weights.temp_gt) ;
8736 printf(" temp_lt %f\n", p->o_args.weights.temp_lt) ;
8737 printf(" gc_content_gt %f\n", p->o_args.weights.gc_content_gt) ;
8738 printf(" gc_content_lt %f\n", p->o_args.weights.gc_content_lt) ;
8739 printf(" compl_any %f\n", p->o_args.weights.compl_any) ;
8740 printf(" compl_end %f\n", p->o_args.weights.compl_end) ;
8741 printf(" compl_any_th %f\n", p->o_args.weights.compl_any_th) ;
8742 printf(" compl_end_th %f\n", p->o_args.weights.compl_end_th) ;
8743 printf(" hairpin %f\n", p->o_args.weights.hairpin_th) ;
8744 printf(" repeat_sim %f\n", p->o_args.weights.repeat_sim) ;
8745 printf(" length_lt %f\n", p->o_args.weights.length_lt) ;
8746 printf(" length_gt %f\n", p->o_args.weights.length_gt) ;
8747 printf(" seq_quality %f\n", p->o_args.weights.seq_quality) ;
8748 printf(" end_quality %f\n", p->o_args.weights.end_quality) ;
8749 printf(" pos_penalty %f\n", p->o_args.weights.pos_penalty) ;
8750 printf(" end_stability %f\n", p->o_args.weights.end_stability) ;
8751 printf(" num_ns %f\n", p->o_args.weights.num_ns) ;
8752 printf(" end internal oligo_weights\n") ;
8753
8754 printf(" opt_tm %f\n", p->o_args.opt_tm) ;
8755 printf(" min_tm %f\n", p->o_args.min_tm) ;
8756 printf(" max_tm %f\n", p->o_args.max_tm) ;
8757 printf(" opt_gc_content %f\n", p->o_args.opt_gc_content) ;
8758 printf(" max_gc %f\n", p->o_args.max_gc) ;
8759 printf(" min_gc %f\n", p->o_args.min_gc) ;
8760 printf(" divalent_conc %f\n", p->o_args.divalent_conc) ;
8761 printf(" dntp_conc %f\n", p->o_args.dntp_conc) ;
8762 printf(" dna_conc %f\n", p->o_args.dna_conc) ;
8763 printf(" num_ns_accepted %i\n", p->o_args.num_ns_accepted) ;
8764 printf(" opt_size %i\n", p->o_args.opt_size) ;
8765 printf(" min_size %i\n", p->o_args.min_size) ;
8766 printf(" max_size %i\n", p->o_args.max_size) ;
8767 printf(" max_poly_x %i\n", p->o_args.max_poly_x) ;
8768 printf(" min_end_quality %i\n", p->o_args.min_end_quality) ;
8769 printf(" min_quality %i\n", p->o_args.min_quality) ;
8770 printf(" max_self_any %f\n", p->o_args.max_self_any) ;
8771 printf(" max_self_end %f\n", p->o_args.max_self_end) ;
8772 printf(" max_repeat_compl %f\n", p->o_args.max_repeat_compl) ;
8773 printf(" end internal oligo args\n");
8774 printf("\n");
8775 printf("END GLOBAL ARGS\n");
8776 printf("=============\n");
8777 printf("\n");
8778 }
8779
8780 if (s != NULL) {
8781 printf("=============\n");
8782 printf("BEGIN SEQUENCE ARGS\n") ;
8783 /* TO DO: complete the statments for dumping this data
8784 printf("interval_array_t2 tar2 %i\n",
8785 int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
8786 int count) ;
8787 printf("interval_array_t2 excl2 %i\n",
8788 int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
8789 int count) ;
8790 printf("interval_array_t2 excl_internal2 %i\n",
8791 int pairs[PR_MAX_INTERVAL_ARRAY][2]) ;
8792 int count) ;
8793 printf("ok_regions \n");
8794 */
8795
8796 if (s->primer_overlap_junctions_count > 0) {
8797 printf("primer_overlap_junctions_count %i\n",
8798 s->primer_overlap_junctions_count);
8799 printf("primer_overlap_junctions_list [\n");
8800 for (i = 0; i < s->primer_overlap_junctions_count; i++) {
8801 printf(" %i\n", s->primer_overlap_junctions[i]);
8802 }
8803 printf("]\n");
8804 }
8805
8806 printf("incl_s %i\n", s->incl_s) ;
8807 printf("incl_l %i\n", s->incl_l) ;
8808 printf("start_codon_pos %i\n", s->start_codon_pos) ;
8809 printf("n_quality %i\n", s->n_quality) ;
8810 /* TO DO printf("quality%i\", s->quality) ; */
8811 printf("quality_storage_size %i\n", s->quality_storage_size) ;
8812 printf("*sequence %s\n", s->sequence) ;
8813 printf("*sequence_name %s\n", s->sequence_name) ;
8814 printf("*sequence_file %s\n", s->sequence_file) ;
8815 printf("*trimmed_seq %s\n", s->trimmed_seq) ;
8816 printf("*trimmed_orig_seq %s\n", s->trimmed_orig_seq) ;
8817 printf("*upcased_seq %s\n", s->upcased_seq) ;
8818 printf("*upcased_seq_r %s\n", s->upcased_seq_r) ;
8819 printf("*left_input %s\n", s->left_input) ;
8820 printf("*right_input %s\n", s->right_input) ;
8821 printf("*internal_input %s\n", s->internal_input) ;
8822 printf("force_left_start %i\n", s->force_left_start) ;
8823 printf("force_left_end %i\n", s->force_left_end) ;
8824 printf("force_right_start %i\n", s->force_right_start) ;
8825 printf("force_right_end %i\n", s->force_right_end) ;
8826 printf("END SEQUENCE ARGS\n") ;
8827 printf("=============\n");
8828 printf("\n");
8829 }
8830 }
8831